Add work profile footer in work tab
Screenshot(work mode is on): https://hsv.googleplex.com/6279751685636096 Screenshot (work mode is off): https://hsv.googleplex.com/6279751685636096 TODO: It is just the UX bit, once the platform change is in, we should then consume the new API to 1. Turn on / off work mode 2. Get the organization name and set the textview accordingly. BUG=69905244 Change-Id: Id94ae57625d6b629dac89c1c28f8d65f395fff6c
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M20,6h-4V4c0,-1.11 -0.89,-2 -2,-2h-4C8.89,2 8,2.89 8,4v2H4C2.89,6 2.01,6.89 2.01,8L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S13.1,15 12,15zM14,6h-4V4h4V6z"
|
||||
android:fillColor="?android:attr/textColorHint"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_bottom_padding"
|
||||
android:paddingLeft="@dimen/dynamic_grid_cell_padding_x"
|
||||
android:paddingRight="@dimen/dynamic_grid_cell_padding_x"
|
||||
android:paddingTop="@dimen/all_apps_work_profile_tab_footer_top_padding">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Switch
|
||||
android:id="@+id/work_mode_toggle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:theme="@style/WorkModeSwitchTheme"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBaseline="@id/work_mode_toggle"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="roboto-regular"
|
||||
android:lines="1"
|
||||
android:text="@string/work_profile_toggle_label"
|
||||
android:textColor="?android:attr/textColorTertiary"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_corp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/managed_by_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:paddingLeft="12dp"
|
||||
android:textColor="?android:attr/textColorHint"
|
||||
android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -40,4 +40,6 @@
|
||||
|
||||
<color name="all_apps_bg_hand_fill">#E5E5E5</color>
|
||||
<color name="all_apps_bg_hand_fill_dark">#9AA0A6</color>
|
||||
|
||||
<color name="work_profile_color">#FF6D00</color>
|
||||
</resources>
|
||||
|
||||
@@ -94,6 +94,8 @@
|
||||
<dimen name="all_apps_tabs_indicator_height">2dp</dimen>
|
||||
<dimen name="all_apps_header_top_padding">36dp</dimen>
|
||||
<dimen name="all_apps_prediction_row_divider_height">17dp</dimen>
|
||||
<dimen name="all_apps_work_profile_tab_footer_top_padding">16dp</dimen>
|
||||
<dimen name="all_apps_work_profile_tab_footer_bottom_padding">20dp</dimen>
|
||||
|
||||
<!-- Search bar in All Apps -->
|
||||
<dimen name="all_apps_header_max_elevation">3dp</dimen>
|
||||
|
||||
@@ -324,4 +324,7 @@
|
||||
<!-- Label of tab to indicate work apps -->
|
||||
<string name="all_apps_work_tab">Work</string>
|
||||
|
||||
<!-- Label of the work mode toggle -->
|
||||
<string name="work_profile_toggle_label">Work profile</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -168,4 +168,8 @@
|
||||
<item name="android:colorControlHighlight">#DFE1E5</item>
|
||||
<item name="android:colorForeground">@color/all_apps_bg_hand_fill_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="WorkModeSwitchTheme" parent="@style/LauncherTheme">
|
||||
<item name="android:colorAccent">@color/work_profile_color</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -120,8 +120,8 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
|
||||
addView(mTouchFeedbackView, size, size);
|
||||
|
||||
mAH = new AdapterHolder[2];
|
||||
mAH[AdapterHolder.MAIN] = new AdapterHolder();
|
||||
mAH[AdapterHolder.WORK] = new AdapterHolder();
|
||||
mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);
|
||||
mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -627,8 +627,8 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
|
||||
AllAppsRecyclerView recyclerView;
|
||||
boolean verticalFadingEdge;
|
||||
|
||||
AdapterHolder() {
|
||||
appsList = new AlphabeticalAppsList(mLauncher, mComponentToAppMap);
|
||||
AdapterHolder(boolean isWork) {
|
||||
appsList = new AlphabeticalAppsList(mLauncher, mComponentToAppMap, isWork);
|
||||
adapter = new AllAppsGridAdapter(mLauncher, appsList, mLauncher,
|
||||
AllAppsContainerView.this, true);
|
||||
appsList.setAdapter(adapter);
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.launcher3.allapps;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.UserHandle;
|
||||
import android.support.animation.DynamicAnimation;
|
||||
import android.support.animation.SpringAnimation;
|
||||
import android.support.v4.view.accessibility.AccessibilityEventCompat;
|
||||
@@ -32,6 +33,7 @@ import android.view.View.OnFocusChangeListener;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
@@ -41,6 +43,7 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
|
||||
import com.android.launcher3.anim.SpringAnimationHandler;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.discovery.AppDiscoveryAppInfo;
|
||||
import com.android.launcher3.discovery.AppDiscoveryItemView;
|
||||
@@ -68,14 +71,15 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||
// but differ in enough attributes to require different view types
|
||||
|
||||
// A divider that separates the apps list and the search market button
|
||||
public static final int VIEW_TYPE_SEARCH_MARKET_DIVIDER = 1 << 5;
|
||||
public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 5;
|
||||
// The divider that separates prediction icons from the app list
|
||||
public static final int VIEW_TYPE_PREDICTION_DIVIDER = 1 << 6;
|
||||
public static final int VIEW_TYPE_APPS_LOADING_DIVIDER = 1 << 7;
|
||||
public static final int VIEW_TYPE_DISCOVERY_ITEM = 1 << 8;
|
||||
public static final int VIEW_TYPE_WORK_TAB_FOOTER = 1 << 9;
|
||||
|
||||
// Common view type masks
|
||||
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_SEARCH_MARKET_DIVIDER
|
||||
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER
|
||||
| VIEW_TYPE_PREDICTION_DIVIDER;
|
||||
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON
|
||||
| VIEW_TYPE_PREDICTION_ICON;
|
||||
@@ -182,8 +186,8 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||
if (isIconViewType(mApps.getAdapterItems().get(position).viewType)) {
|
||||
return 1;
|
||||
} else {
|
||||
// Section breaks span the full width
|
||||
return mAppsPerRow;
|
||||
// Section breaks span the full width
|
||||
return mAppsPerRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,9 +327,13 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||
R.layout.all_apps_discovery_loading_divider, parent, false);
|
||||
return new ViewHolder(loadingDividerView);
|
||||
case VIEW_TYPE_PREDICTION_DIVIDER:
|
||||
case VIEW_TYPE_SEARCH_MARKET_DIVIDER:
|
||||
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
||||
return new ViewHolder(mLayoutInflater.inflate(
|
||||
R.layout.all_apps_divider, parent, false));
|
||||
case VIEW_TYPE_WORK_TAB_FOOTER:
|
||||
View footer = mLayoutInflater.inflate(R.layout.work_tab_footer, parent, false);
|
||||
// TODO: Implement the work mode toggle logic here.
|
||||
return new ViewHolder(footer);
|
||||
default:
|
||||
throw new RuntimeException("Unexpected view type");
|
||||
}
|
||||
@@ -367,9 +375,17 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||
holder.itemView.findViewById(R.id.loadingProgressBar).setVisibility(visLoading);
|
||||
holder.itemView.findViewById(R.id.loadedDivider).setVisibility(visLoaded);
|
||||
break;
|
||||
case VIEW_TYPE_SEARCH_MARKET_DIVIDER:
|
||||
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
||||
// nothing to do
|
||||
break;
|
||||
case VIEW_TYPE_WORK_TAB_FOOTER:
|
||||
Switch workModeToggle = holder.itemView.findViewById(R.id.work_mode_toggle);
|
||||
workModeToggle.setChecked(!isAnyProfileQuietModeEnabled());
|
||||
|
||||
TextView textView = holder.itemView.findViewById(R.id.managed_by_label);
|
||||
// TODO: Configure the textview properly.
|
||||
textView.setText("Managed by your company");
|
||||
break;
|
||||
}
|
||||
if (mBindViewCallback != null) {
|
||||
mBindViewCallback.onBindView(holder);
|
||||
@@ -537,4 +553,15 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||
return factor;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAnyProfileQuietModeEnabled() {
|
||||
UserManagerCompat userManager = UserManagerCompat.getInstance(mLauncher);
|
||||
List<UserHandle> userProfiles = userManager.getUserProfiles();
|
||||
for (UserHandle userProfile : userProfiles) {
|
||||
if (userManager.isQuietModeEnabled(userProfile)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
|
||||
RecyclerView.RecycledViewPool pool = getRecycledViewPool();
|
||||
int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
|
||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH, 1);
|
||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER, 1);
|
||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER, 1);
|
||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET, 1);
|
||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, approxRows * mNumAppsPerRow);
|
||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, mNumAppsPerRow);
|
||||
@@ -167,7 +167,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
|
||||
|
||||
putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
|
||||
AllAppsGridAdapter.VIEW_TYPE_PREDICTION_DIVIDER,
|
||||
AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER);
|
||||
AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER);
|
||||
putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
|
||||
AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET);
|
||||
putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
|
||||
|
||||
@@ -140,9 +140,9 @@ public class AlphabeticalAppsList {
|
||||
return item;
|
||||
}
|
||||
|
||||
public static AdapterItem asMarketDivider(int pos) {
|
||||
public static AdapterItem asAllAppsDivider(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER;
|
||||
item.viewType = AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
@@ -160,6 +160,13 @@ public class AlphabeticalAppsList {
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
public static AdapterItem asWorkTabFooter(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = AllAppsGridAdapter.VIEW_TYPE_WORK_TAB_FOOTER;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
private final Launcher mLauncher;
|
||||
@@ -179,6 +186,8 @@ public class AlphabeticalAppsList {
|
||||
// The set of predicted apps resolved from the component names and the current set of apps
|
||||
private final List<AppInfo> mPredictedApps = new ArrayList<>();
|
||||
private final List<AppDiscoveryAppInfo> mDiscoveredApps = new ArrayList<>();
|
||||
// Is it the work profile app list.
|
||||
private final boolean mIsWork;
|
||||
|
||||
// The of ordered component names as a result of a search query
|
||||
private ArrayList<ComponentKey> mSearchResults;
|
||||
@@ -191,11 +200,16 @@ public class AlphabeticalAppsList {
|
||||
private int mNumAppRowsInAdapter;
|
||||
private ItemInfoMatcher mItemFilter;
|
||||
|
||||
public AlphabeticalAppsList(Context context, HashMap<ComponentKey, AppInfo> componentToAppMap) {
|
||||
public AlphabeticalAppsList(
|
||||
Context context,
|
||||
HashMap<ComponentKey,
|
||||
AppInfo> componentToAppMap,
|
||||
boolean isWork) {
|
||||
mComponentToAppMap = componentToAppMap;
|
||||
mLauncher = Launcher.getLauncher(context);
|
||||
mIndexer = new AlphabeticIndexCompat(context);
|
||||
mAppNameComparator = new AppInfoComparator(context);
|
||||
mIsWork = isWork;
|
||||
}
|
||||
|
||||
public void updateItemFilter(ItemInfoMatcher itemFilter) {
|
||||
@@ -545,7 +559,7 @@ public class AlphabeticalAppsList {
|
||||
if (hasNoFilteredResults()) {
|
||||
mAdapterItems.add(AdapterItem.asEmptySearch(position++));
|
||||
} else {
|
||||
mAdapterItems.add(AdapterItem.asMarketDivider(position++));
|
||||
mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
|
||||
}
|
||||
mAdapterItems.add(AdapterItem.asMarketSearch(position++));
|
||||
}
|
||||
@@ -604,6 +618,12 @@ public class AlphabeticalAppsList {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the work profile footer if required.
|
||||
if (mIsWork) {
|
||||
mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
|
||||
mAdapterItems.add(AdapterItem.asWorkTabFooter(position++));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAppDiscoveryRunning() {
|
||||
|
||||
Reference in New Issue
Block a user