Merge "Fixes rebinding worktab layout vs single recycler view (on workprofile change)" into ub-launcher3-master
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 20abdc7..a48a65c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -45,7 +45,9 @@
}
public static void onWorkspaceLongPress(Launcher launcher) {
- PopupMenu menu = new PopupMenu(launcher, launcher.getWorkspace().getPageIndicator());
+ PopupMenu menu = new PopupMenu(launcher.getApplicationContext(),
+ launcher.getWorkspace().getPageIndicator());
+
menu.getMenu().add(R.string.wallpaper_button_text).setOnMenuItemClickListener((i) -> {
launcher.onClickWallpaperPicker(null);
return true;
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index af82fe9..4c3a9ad 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -62,7 +62,8 @@
private static final long RECENTS_VIEW_VISIBILITY_DELAY = 120;
private static final long RECENTS_VIEW_VISIBILITY_DURATION = 150;
- private static final long DEFAULT_SWIPE_DURATION = 200;
+ private static final long MAX_SWIPE_DURATION = 200;
+ private static final long MIN_SWIPE_DURATION = 80;
// Ideal velocity for a smooth transition
private static final float PIXEL_PER_MS = 2f;
@@ -128,8 +129,8 @@
new Handler().postDelayed(() -> mStateCallback.setState(STATE_RECENTS_DELAY_COMPLETE),
RECENTS_VIEW_VISIBILITY_DELAY);
- long duration = Math.min(DEFAULT_SWIPE_DURATION,
- Math.max((long) (-mCurrentDisplacement / PIXEL_PER_MS), 0));
+ long duration = Math.min(MAX_SWIPE_DURATION,
+ Math.max((long) (-mCurrentDisplacement / PIXEL_PER_MS), MIN_SWIPE_DURATION));
if (mCurrentShift.getCurrentAnimation() != null) {
ObjectAnimator anim = mCurrentShift.getCurrentAnimation();
long theirDuration = anim.getDuration() - anim.getCurrentPlayTime();
@@ -264,7 +265,7 @@
float flingThreshold = res.getDimension(R.dimen.quickstep_fling_threshold_velocity);
boolean isFling = Math.abs(endVelocity) > flingThreshold;
- long duration = DEFAULT_SWIPE_DURATION;
+ long duration = MAX_SWIPE_DURATION;
final float endShift;
if (!isFling) {
endShift = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW ? 1 : 0;
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 55fd448..eacc393 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -87,6 +87,7 @@
private int mActivePointerId = INVALID_POINTER_ID;
private VelocityTracker mVelocityTracker;
private int mTouchSlop;
+ private float mStartDisplacement;
private NavBarSwipeInteractionHandler mInteractionHandler;
private ISystemUiProxy mISystemUiProxy;
@@ -184,11 +185,12 @@
float displacement = ev.getY(pointerIndex) - mDownPos.y;
if (mInteractionHandler == null) {
if (Math.abs(displacement) >= mTouchSlop) {
+ mStartDisplacement = Math.signum(displacement) * mTouchSlop;
startTouchTracking();
}
} else {
// Move
- mInteractionHandler.updateDisplacement(displacement);
+ mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
}
break;
}
diff --git a/res/drawable/ic_corp.xml b/res/drawable/ic_corp.xml
new file mode 100644
index 0000000..48f5007
--- /dev/null
+++ b/res/drawable/ic_corp.xml
@@ -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>
\ No newline at end of file
diff --git a/res/layout/work_tab_footer.xml b/res/layout/work_tab_footer.xml
new file mode 100644
index 0000000..48578d7
--- /dev/null
+++ b/res/layout/work_tab_footer.xml
@@ -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>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index b44a31e..42fee80 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -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>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 266e0b0..e7f45c2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -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>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fdd4d8d..cbba9a2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -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>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8cc4743..c714841 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -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>
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 71069bd..da4367f 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -121,8 +121,8 @@
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
@@ -549,6 +549,9 @@
}
private void setupHeader() {
+ if (mFloatingHeaderHandler == null) {
+ return;
+ }
mHeader.setVisibility(View.VISIBLE);
int contentHeight = mLauncher.getDeviceProfile().allAppsCellHeightPx;
if (!mUsingTabs) {
@@ -633,8 +636,8 @@
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);
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index ac8d367..da4d9f0 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -18,6 +18,7 @@
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.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.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 @@
// 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 @@
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 @@
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 @@
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 @@
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;
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 09357f7..5789b67 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -143,7 +143,7 @@
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 @@
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,
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 7cf2d95..12715cb 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -140,9 +140,9 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
break;
}
}
+
+ // Add the work profile footer if required.
+ if (mIsWork) {
+ mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
+ mAdapterItems.add(AdapterItem.asWorkTabFooter(position++));
+ }
}
public boolean isAppDiscoveryRunning() {
diff --git a/src/com/android/launcher3/allapps/PredictionRowView.java b/src/com/android/launcher3/allapps/PredictionRowView.java
index 45ef6c1..ea91770 100644
--- a/src/com/android/launcher3/allapps/PredictionRowView.java
+++ b/src/com/android/launcher3/allapps/PredictionRowView.java
@@ -68,7 +68,10 @@
* Sets the number of apps per row.
*/
public void setNumAppsPerRow(int numPredictedAppsPerRow) {
- mNumPredictedAppsPerRow = numPredictedAppsPerRow;
+ if (mNumPredictedAppsPerRow != numPredictedAppsPerRow) {
+ mNumPredictedAppsPerRow = numPredictedAppsPerRow;
+ onAppsUpdated();
+ }
}
/**
diff --git a/src/com/android/launcher3/views/SlidingTabStrip.java b/src/com/android/launcher3/views/SlidingTabStrip.java
index 45c6261..c2ef41b 100644
--- a/src/com/android/launcher3/views/SlidingTabStrip.java
+++ b/src/com/android/launcher3/views/SlidingTabStrip.java
@@ -34,7 +34,7 @@
private int mSelectedIndicatorHeight;
private int mIndicatorLeft = -1;
private int mIndicatorRight = -1;
- private int mSelectedPosition = -1;
+ private int mSelectedPosition = 0;
private float mSelectionOffset;
public SlidingTabStrip(@NonNull Context context, @Nullable AttributeSet attrs) {
@@ -63,8 +63,8 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
- updateTabTextColor(0);
- updateIndicatorPosition(0, 0);
+ updateTabTextColor(mSelectedPosition);
+ updateIndicatorPosition(mSelectedPosition, 0);
}
private void updateIndicatorPosition() {