Hide work apps when work profile is paused
- hide overlay icon in landscape mode
- don't show edu if user has already seen legacy work profile edu
- make sure personal tab is highlighted when work profile is reinstalled
- always go home after a work profile is added or removed
- add tests for work edu flow
Bug: 150122946
Test: Manual
Change-Id: I8f80ac763acf03ca31a534464f4ddfd84528d329
diff --git a/res/layout/work_apps_paused.xml b/res/layout/work_apps_paused.xml
index 1c18076..cf1e835 100644
--- a/res/layout/work_apps_paused.xml
+++ b/res/layout/work_apps_paused.xml
@@ -15,19 +15,10 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="?attr/allAppsScrimColor"
- android:padding="8dp"
+ android:padding="48dp"
android:orientation="vertical"
android:gravity="center">
- <ImageView
- android:id="@+id/icon"
- android:contentDescription="@string/work_apps_paused_title"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:tint="?attr/workProfileOverlayTextColor"
- android:src="@drawable/ic_corp_off" />
-
<TextView
style="@style/TextHeadline"
android:textColor="?attr/workProfileOverlayTextColor"
diff --git a/res/layout/work_profile_edu.xml b/res/layout/work_profile_edu.xml
index 04094c4..5506b94 100644
--- a/res/layout/work_profile_edu.xml
+++ b/res/layout/work_profile_edu.xml
@@ -41,6 +41,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:layout_marginBottom="48dp"
+ android:gravity="center"
android:text="@string/work_profile_edu_personal_apps"
android:textAlignment="center"
android:textColor="@android:color/white"
diff --git a/res/layout/work_tab_footer.xml b/res/layout/work_tab_footer.xml
index 2cffedd..dbcdbdb 100644
--- a/res/layout/work_tab_footer.xml
+++ b/res/layout/work_tab_footer.xml
@@ -19,19 +19,20 @@
android:layout_height="wrap_content"
android:id="@+id/work_toggle_container"
android:focusable="true"
- android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_padding_vertical"
android:orientation="horizontal"
- android:paddingLeft="@dimen/all_apps_work_profile_tab_footer_padding_horizontal"
android:background="?attr/allAppsScrimColor"
- android:paddingRight="@dimen/all_apps_work_profile_tab_footer_padding_horizontal"
- android:paddingTop="@dimen/all_apps_work_profile_tab_footer_padding_vertical">
+ android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_padding"
+ android:paddingLeft="@dimen/all_apps_work_profile_tab_footer_padding"
+ android:paddingRight="@dimen/all_apps_work_profile_tab_footer_padding"
+ android:paddingTop="@dimen/all_apps_work_profile_tab_footer_padding">
<TextView
+ style="@style/PrimaryMediumText"
android:id="@+id/work_mode_label"
android:layout_width="0dp"
android:layout_weight="1"
android:drawableStart="@drawable/ic_corp"
- android:drawablePadding="3dp"
+ android:drawablePadding="16dp"
android:drawableTint="?attr/workProfileOverlayTextColor"
android:textColor="?attr/workProfileOverlayTextColor"
android:layout_height="wrap_content"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index edae7f4..871651d 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -85,8 +85,7 @@
<dimen name="all_apps_tabs_side_padding">12dp</dimen>
<dimen name="all_apps_divider_height">1dp</dimen>
- <dimen name="all_apps_work_profile_tab_footer_padding_vertical">20dp</dimen>
- <dimen name="all_apps_work_profile_tab_footer_padding_horizontal">24dp</dimen>
+ <dimen name="all_apps_work_profile_tab_footer_padding">20dp</dimen>
<!-- Search bar in All Apps -->
<dimen name="all_apps_header_max_elevation">3dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index cee268b..bc6ab45 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -225,6 +225,7 @@
<style name="DropTargetButton" parent="DropTargetButtonBase" />
<style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" />
+ <style name="PrimaryMediumText" parent="@android:style/TextAppearance.DeviceDefault.Medium"/>
<style name="TextTitle" parent="@android:style/TextAppearance.DeviceDefault" />
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index 864fa6e..38e1201 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -22,11 +22,11 @@
import android.view.View;
import android.view.ViewGroup;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.views.RecyclerViewFastScroller;
-import androidx.recyclerview.widget.RecyclerView;
-
/**
* A base {@link RecyclerView}, which does the following:
@@ -138,7 +138,7 @@
if (getCurrentScrollY() == 0) {
return true;
}
- return false;
+ return getAdapter() == null || getAdapter().getItemCount() == 0;
}
/**
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index a2957bc..e085ff0 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.allapps;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.makeMeasureSpec;
-
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import android.animation.ValueAnimator;
@@ -395,7 +392,7 @@
rebindAdapters(showTabs, false /* force */);
}
- private void rebindAdapters(boolean showTabs, boolean force) {
+ protected void rebindAdapters(boolean showTabs, boolean force) {
if (showTabs == mUsingTabs && !force) {
return;
}
@@ -463,6 +460,7 @@
public void onTabChanged(int pos) {
mHeader.setMainActive(pos == 0);
reset(true /* animate */);
+ mViewPager.getPageIndicator().updateTabTextColor(pos);
if (mAH[pos].recyclerView != null) {
mAH[pos].recyclerView.bindFastScrollbar();
@@ -608,6 +606,7 @@
public static final int MAIN = 0;
public static final int WORK = 1;
+ private ItemInfoMatcher mInfoMatcher;
private final boolean mIsWork;
public final AllAppsGridAdapter adapter;
final LinearLayoutManager layoutManager;
@@ -627,6 +626,7 @@
}
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
+ mInfoMatcher = matcher;
appsList.updateItemFilter(matcher);
recyclerView = (AllAppsRecyclerView) rv;
recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
@@ -647,19 +647,14 @@
void setupOverlay() {
if (!mIsWork || recyclerView == null) return;
boolean workDisabled = UserCache.INSTANCE.get(mLauncher).isAnyProfileQuietModeEnabled();
- recyclerView.getOverlay().clear();
+ if (mWorkDisabled == workDisabled) return;
if (workDisabled) {
- View pausedOverlay = mLauncher.getLayoutInflater().inflate(
- R.layout.work_apps_paused, null);
- recyclerView.post(() -> {
- int width = recyclerView.getWidth();
- int height = recyclerView.getHeight() - mWorkFooterContainer.getHeight();
- pausedOverlay.measure(makeMeasureSpec(recyclerView.getWidth(), EXACTLY),
- makeMeasureSpec(recyclerView.getHeight(), EXACTLY));
- pausedOverlay.layout(0, 0, width, height);
- applyPadding();
- });
- recyclerView.getOverlay().add(pausedOverlay);
+ appsList.updateItemFilter((info, cn) -> false);
+ recyclerView.addAutoSizedOverlay(
+ mLauncher.getLayoutInflater().inflate(R.layout.work_apps_paused, null));
+ } else if (mInfoMatcher != null) {
+ appsList.updateItemFilter(mInfoMatcher);
+ recyclerView.clearAutoSizedOverlays();
}
mWorkDisabled = workDisabled;
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index c228ddf..8fe4633 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -15,7 +15,9 @@
*/
package com.android.launcher3.allapps;
+import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.UNSPECIFIED;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
@@ -62,6 +64,8 @@
private AllAppsBackgroundDrawable mEmptySearchBackground;
private int mEmptySearchBackgroundTopOffset;
+ private ArrayList<View> mAutoSizedOverlays = new ArrayList<>();
+
public AllAppsRecyclerView(Context context) {
this(context, null);
}
@@ -145,6 +149,30 @@
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
updateEmptySearchBackgroundBounds();
updatePoolSize();
+ for (int i = 0; i < mAutoSizedOverlays.size(); i++) {
+ View overlay = mAutoSizedOverlays.get(i);
+ overlay.measure(makeMeasureSpec(w, EXACTLY), makeMeasureSpec(w, EXACTLY));
+ overlay.layout(0, 0, w, h);
+ }
+ }
+
+ /**
+ * Adds an overlay that automatically rescales with the recyclerview.
+ */
+ public void addAutoSizedOverlay(View overlay) {
+ mAutoSizedOverlays.add(overlay);
+ getOverlay().add(overlay);
+ onSizeChanged(getWidth(), getHeight(), getWidth(), getHeight());
+ }
+
+ /**
+ * Clears auto scaling overlay views added by #addAutoSizedOverlay
+ */
+ public void clearAutoSizedOverlays() {
+ for (View v : mAutoSizedOverlays) {
+ getOverlay().remove(v);
+ }
+ mAutoSizedOverlays.clear();
}
@Override
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index 0e39bbe..3e40392 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -71,12 +71,10 @@
mIsRtl = Utilities.isRtl(getResources());
}
- private void updateIndicatorPosition(float scrollOffset) {
- mScrollOffset = scrollOffset;
- updateIndicatorPosition();
- }
-
- private void updateTabTextColor(int pos) {
+ /**
+ * Highlights tab with index pos
+ */
+ public void updateTabTextColor(int pos) {
mSelectedPosition = pos;
for (int i = 0; i < getChildCount(); i++) {
Button tab = (Button) getChildAt(i);
@@ -84,6 +82,11 @@
}
}
+ private void updateIndicatorPosition(float scrollOffset) {
+ mScrollOffset = scrollOffset;
+ updateIndicatorPosition();
+ }
+
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
diff --git a/src/com/android/launcher3/views/WorkEduView.java b/src/com/android/launcher3/views/WorkEduView.java
index 81f8327..d849138 100644
--- a/src/com/android/launcher3/views/WorkEduView.java
+++ b/src/com/android/launcher3/views/WorkEduView.java
@@ -46,7 +46,8 @@
public class WorkEduView extends AbstractSlideInView implements Insettable {
private static final int DEFAULT_CLOSE_DURATION = 200;
- private static final String KEY_WORK_EDU_STEP = "showed_work_profile_edu";
+ public static final String KEY_WORK_EDU_STEP = "showed_work_profile_edu";
+ public static final String KEY_LEGACY_WORK_EDU_SEEN = "showed_bottom_user_education";
private static final int WORK_EDU_NOT_STARTED = 0;
private static final int WORK_EDU_PERSONAL_APPS = 1;
@@ -102,6 +103,8 @@
mProceedButton = findViewById(R.id.proceed);
mContentText = findViewById(R.id.content_text);
+ // make sure layout does not shrink when we change the text
+ mContentText.post(() -> mContentText.setMinLines(mContentText.getLineCount()));
if (mLauncher.getAppsView().getContentView() instanceof AllAppsPagedView) {
mAllAppsPagedView = (AllAppsPagedView) mLauncher.getAppsView().getContentView();
}
@@ -179,8 +182,8 @@
if (oldListener != null) {
launcher.getStateManager().removeStateListener(oldListener);
}
- if (launcher.getSharedPrefs().getInt(KEY_WORK_EDU_STEP, WORK_EDU_NOT_STARTED)
- != WORK_EDU_NOT_STARTED) {
+ if (hasSeenLegacyEdu(launcher) || launcher.getSharedPrefs().getInt(KEY_WORK_EDU_STEP,
+ WORK_EDU_NOT_STARTED) != WORK_EDU_NOT_STARTED) {
return null;
}
@@ -210,8 +213,8 @@
* Shows work apps edu if user had dismissed full edu flow
*/
public static void showWorkEduIfNeeded(Launcher launcher) {
- if (launcher.getSharedPrefs().getInt(KEY_WORK_EDU_STEP, WORK_EDU_NOT_STARTED)
- != WORK_EDU_PERSONAL_APPS) {
+ if (hasSeenLegacyEdu(launcher) || launcher.getSharedPrefs().getInt(KEY_WORK_EDU_STEP,
+ WORK_EDU_NOT_STARTED) != WORK_EDU_PERSONAL_APPS) {
return;
}
LayoutInflater layoutInflater = LayoutInflater.from(launcher);
@@ -220,4 +223,8 @@
v.show();
v.goToWorkTab(false);
}
+
+ private static boolean hasSeenLegacyEdu(Launcher launcher) {
+ return launcher.getSharedPrefs().getBoolean(KEY_LEGACY_WORK_EDU_SEEN, false);
+ }
}
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 6fe6739..db2d974 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -16,8 +16,6 @@
package com.android.launcher3.ui;
import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.UNBUNDLED_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -25,13 +23,16 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.widget.TextView;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsPagedView;
-import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.views.WorkEduView;
import com.android.launcher3.views.WorkFooterContainer;
import org.junit.After;
@@ -48,6 +49,8 @@
private int mProfileUserId;
+ private static final int WORK_PAGE = AllAppsContainerView.AdapterHolder.WORK;
+
@Before
public void createWorkProfile() throws Exception {
String output =
@@ -67,8 +70,6 @@
}
@Test
- // b/143285809 Remove @Stability on 02/21/20 if the test doesn't flake.
- @TestStabilityRule.Stability(flavors = LOCAL | UNBUNDLED_POSTSUBMIT)
public void workTabExists() {
mDevice.pressHome();
waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -80,8 +81,6 @@
}
@Test
- // b/143285809 Remove @Stability on 02/21/20 if the test doesn't flake.
- @TestStabilityRule.Stability(flavors = LOCAL | UNBUNDLED_POSTSUBMIT)
public void toggleWorks() {
mDevice.pressHome();
waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
@@ -112,4 +111,78 @@
l -> l.getSystemService(UserManager.class).isQuietModeEnabled(workProfile));
}
+ @Test
+ public void testWorkEduFlow() {
+ mDevice.pressHome();
+ waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
+ executeOnLauncher(launcher -> launcher.getSharedPrefs().edit().remove(
+ WorkEduView.KEY_WORK_EDU_STEP).remove(
+ WorkEduView.KEY_LEGACY_WORK_EDU_SEEN).commit());
+
+ waitForLauncherCondition("Work tab not setup",
+ launcher -> launcher.getAppsView().getContentView() instanceof AllAppsPagedView,
+ 60000);
+
+ executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
+ WorkEduView workEduView = getEduView();
+ // verify personal app edu is seen first and click "next"
+ executeOnLauncher(l -> {
+ assertEquals(((TextView) workEduView.findViewById(R.id.content_text)).getText(),
+ l.getResources().getString(R.string.work_profile_edu_personal_apps));
+ workEduView.findViewById(R.id.proceed).callOnClick();
+ });
+ // verify work edu is seen next
+ waitForLauncherCondition("Launcher did not show the next edu screen", l ->
+ ((AllAppsPagedView) l.getAppsView().getContentView()).getCurrentPage() == WORK_PAGE
+ && ((TextView) workEduView.findViewById(
+ R.id.content_text)).getText().equals(
+ l.getResources().getString(R.string.work_profile_edu_work_apps)));
+ }
+
+ @Test
+ public void testWorkEduIntermittent() {
+ mDevice.pressHome();
+ waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
+ executeOnLauncher(launcher -> launcher.getSharedPrefs().edit().remove(
+ WorkEduView.KEY_WORK_EDU_STEP).remove(
+ WorkEduView.KEY_LEGACY_WORK_EDU_SEEN).commit());
+
+
+ waitForLauncherCondition("Work tab not setup",
+ launcher -> launcher.getAppsView().getContentView() instanceof AllAppsPagedView,
+ 60000);
+ executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
+
+ // verify personal app edu is seen
+ getEduView();
+
+ // dismiss personal edu
+ mDevice.pressHome();
+
+ // open work tab
+ executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
+ executeOnLauncher(launcher -> {
+ AllAppsPagedView pagedView = (AllAppsPagedView) launcher.getAppsView().getContentView();
+ pagedView.setCurrentPage(WORK_PAGE);
+ });
+
+ WorkEduView workEduView = getEduView();
+
+ // verify work tab edu is shown
+ waitForLauncherCondition("Launcher did not show the next edu screen",
+ l -> ((TextView) workEduView.findViewById(R.id.content_text)).getText().equals(
+ l.getResources().getString(R.string.work_profile_edu_work_apps)));
+ }
+
+
+ private WorkEduView getEduView() {
+ waitForLauncherCondition("Edu did not show", l -> {
+ DragLayer dragLayer = l.getDragLayer();
+ return dragLayer.getChildCount() > 0 && dragLayer.getChildAt(
+ dragLayer.getChildCount() - 1) instanceof WorkEduView;
+ });
+ return getFromLauncher(launcher -> (WorkEduView) launcher.getDragLayer().getChildAt(
+ launcher.getDragLayer().getChildCount() - 1));
+ }
+
}
\ No newline at end of file