Merge "Significantly reduce gesture feedback when swiping up to home screen." into sc-v2-dev
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index dc92731..bc8bd3a 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -116,7 +116,6 @@
<activity android:name="com.android.quickstep.interaction.AllSetActivity"
android:autoRemoveFromRecents="true"
android:excludeFromRecents="true"
- android:screenOrientation="portrait"
android:permission="android.permission.REBOOT"
android:theme="@style/AllSetTheme"
android:label="@string/allset_title"
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
index e79e57e..4fbb8a0 100644
--- a/quickstep/res/layout/activity_allset.xml
+++ b/quickstep/res/layout/activity_allset.xml
@@ -14,7 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="@dimen/allset_page_margin_horizontal"
@@ -22,60 +23,72 @@
android:layoutDirection="locale"
android:textDirection="locale">
- <LinearLayout
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/allset_title_icon_margin_top"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ android:src="@drawable/ic_all_set"/>
+
+ <TextView
+ android:id="@+id/title"
+ style="@style/TextAppearance.GestureTutorial.Feedback.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_gravity="start"
+ android:layout_marginTop="@dimen/allset_title_margin_top"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
android:gravity="start"
- android:orientation="vertical">
+ android:text="@string/allset_title"/>
- <ImageView
- android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/allset_title_icon_margin_top"
- android:src="@drawable/ic_all_set"/>
+ <TextView
+ android:id="@+id/subtitle"
+ style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/allset_subtitle_margin_top"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintWidth_max="@dimen/allset_subtitle_width_max"
+ android:gravity="start"
+ android:text="@string/allset_description"/>
- <TextView
- android:id="@+id/title"
- style="@style/TextAppearance.GestureTutorial.Feedback.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/allset_title_margin_top"
- android:gravity="start"
- android:text="@string/allset_title"/>
-
- <TextView
- android:id="@+id/subtitle"
- style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/allset_subtitle_margin_top"
- android:gravity="start"
- android:text="@string/allset_description"/>
- </LinearLayout>
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/navigation_settings_guideline_bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_percent="0.83" />
<TextView
android:id="@+id/navigation_settings"
style="@style/TextAppearance.GestureTutorial.LinkText"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_above="@+id/hint"
- android:gravity="center"
- android:layout_marginBottom="72dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/navigation_settings_guideline_bottom"
android:minHeight="48dp"
android:background="?android:attr/selectableItemBackground"
android:text="@string/allset_navigation_settings" />
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/hint_guideline_bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_percent="0.94" />
+
<TextView
- android:id="@id/hint"
+ android:id="@+id/hint"
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/allset_hint_margin_bottom"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/hint_guideline_bottom"
android:text="@string/allset_hint"/>
-</RelativeLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 34cd1c2..38c202b 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -126,8 +126,8 @@
<dimen name="allset_page_margin_horizontal">40dp</dimen>
<dimen name="allset_title_margin_top">24dp</dimen>
<dimen name="allset_title_icon_margin_top">32dp</dimen>
- <dimen name="allset_hint_margin_bottom">52dp</dimen>
<dimen name="allset_subtitle_margin_top">24dp</dimen>
+ <dimen name="allset_subtitle_width_max">348dp</dimen>
<!-- All Apps Education tutorial -->
<dimen name="swipe_edu_padding">8dp</dimen>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index baf4c15..1cf49fc 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -128,7 +128,6 @@
<dimen name="work_card_button_height">52dp</dimen>
<dimen name="work_fab_margin">16dp</dimen>
<dimen name="work_profile_footer_padding">20dp</dimen>
- <dimen name="work_profile_footer_text_size">16sp</dimen>
<dimen name="work_edu_card_margin">16dp</dimen>
<dimen name="work_edu_card_radius">28dp</dimen>
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index a701548..9a5fd05 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -17,15 +17,11 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
-import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
-import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
-import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -34,7 +30,7 @@
import android.os.Bundle;
import android.os.Parcelable;
import android.os.Process;
-import android.text.Selection;
+import android.os.UserManager;
import android.text.SpannableStringBuilder;
import android.util.AttributeSet;
import android.util.Log;
@@ -88,11 +84,12 @@
public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
private final Paint mHeaderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Rect mInsets = new Rect();
protected final BaseDraggingActivity mLauncher;
protected final AdapterHolder[] mAH;
- private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
- private final ItemInfoMatcher mWorkMatcher = mPersonalMatcher.negate();
+ protected final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(
+ Process.myUserHandle());
private final AllAppsStore mAllAppsStore = new AllAppsStore();
private final RecyclerView.OnScrollListener mScrollListener =
@@ -102,6 +99,8 @@
updateHeaderScroll(((AllAppsRecyclerView) recyclerView).getCurrentScrollY());
}
};
+ private final WorkProfileManager mWorkManager;
+
private final Paint mNavBarScrimPaint;
private int mNavBarScrimHeight = 0;
@@ -111,8 +110,6 @@
private AllAppsPagedView mViewPager;
protected FloatingHeaderView mHeader;
- private float mHeaderTop;
- private WorkModeSwitch mWorkModeSwitch;
private SpannableStringBuilder mSearchQueryBuilder = null;
@@ -124,10 +121,7 @@
protected RecyclerViewFastScroller mTouchHandler;
protected final Point mFastScrollerOffset = new Point();
- private Rect mInsets = new Rect();
-
private SearchAdapterProvider mSearchAdapterProvider;
- private WorkAdapterProvider mWorkAdapterProvider;
private final int mScrimColor;
private final int mHeaderProtectionColor;
private final float mHeaderThreshold;
@@ -156,15 +150,11 @@
mLauncher.addOnDeviceProfileChangeListener(this);
mSearchAdapterProvider = mLauncher.createSearchAdapterProvider(this);
- mSearchQueryBuilder = new SpannableStringBuilder();
- Selection.setSelection(mSearchQueryBuilder, 0);
mAH = new AdapterHolder[2];
- mWorkAdapterProvider = new WorkAdapterProvider(mLauncher, () -> {
- if (mAH[AdapterHolder.WORK] != null) {
- mAH[AdapterHolder.WORK].appsList.updateAdapterItems();
- }
- });
+
+ mWorkManager = new WorkProfileManager(mLauncher.getSystemService(UserManager.class), this,
+ Utilities.getPrefs(mLauncher));
mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);
mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
@@ -220,8 +210,8 @@
return mAllAppsStore;
}
- public WorkModeSwitch getWorkModeSwitch() {
- return mWorkModeSwitch;
+ public WorkProfileManager getWorkManager() {
+ return mWorkManager;
}
@Override
@@ -240,7 +230,7 @@
private void onAppsUpdated() {
boolean hasWorkApps = false;
for (AppInfo app : mAllAppsStore.getApps()) {
- if (mWorkMatcher.matches(app, null)) {
+ if (mWorkManager.getMatcher().matches(app, null)) {
hasWorkApps = true;
break;
}
@@ -248,20 +238,12 @@
mHasWorkApps = hasWorkApps;
if (!mAH[AdapterHolder.MAIN].appsList.hasFilter()) {
rebindAdapters();
- if (mHasWorkApps) {
- resetWorkProfile();
+ if (hasWorkApps) {
+ mWorkManager.reset();
}
}
}
- private void resetWorkProfile() {
- boolean isEnabled = !mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED);
- if (mWorkModeSwitch != null) {
- mWorkModeSwitch.updateCurrentState(isEnabled);
- }
- mWorkAdapterProvider.updateCurrentState(isEnabled);
- }
-
/**
* Returns whether the view itself will handle the touch event or not.
*/
@@ -460,7 +442,7 @@
if (mUsingTabs) {
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
- mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
+ mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkManager.getMatcher());
mAH[AdapterHolder.WORK].recyclerView.setId(R.id.apps_list_view_work);
mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN);
findViewById(R.id.tab_personal)
@@ -488,34 +470,12 @@
mAllAppsStore.registerIconContainer(mAH[AdapterHolder.WORK].recyclerView);
}
- private void setupWorkToggle() {
- removeWorkToggle();
- if (Utilities.ATLEAST_P) {
- mWorkModeSwitch = (WorkModeSwitch) mLauncher.getLayoutInflater().inflate(
- R.layout.work_mode_fab, this, false);
- this.addView(mWorkModeSwitch);
- mWorkModeSwitch.setInsets(mInsets);
- mWorkModeSwitch.post(() -> {
- mAH[AdapterHolder.WORK].applyPadding();
- resetWorkProfile();
- });
- }
- }
-
- private void removeWorkToggle() {
- if (mWorkModeSwitch == null) return;
- if (mWorkModeSwitch.getParent() == this) {
- this.removeView(mWorkModeSwitch);
- }
- mWorkModeSwitch = null;
- }
private void replaceRVContainer(boolean showTabs) {
- for (int i = 0; i < mAH.length; i++) {
- AllAppsRecyclerView rv = mAH[i].recyclerView;
- if (rv != null) {
- rv.setLayoutManager(null);
- rv.setAdapter(null);
+ for (AdapterHolder adapterHolder : mAH) {
+ if (adapterHolder.recyclerView != null) {
+ adapterHolder.recyclerView.setLayoutManager(null);
+ adapterHolder.recyclerView.setAdapter(null);
}
}
View oldView = getRecyclerViewContainer();
@@ -532,10 +492,10 @@
mViewPager = (AllAppsPagedView) newView;
mViewPager.initParentViews(this);
mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
- setupWorkToggle();
+ mWorkManager.attachWorkModeSwitch();
} else {
+ mWorkManager.detachWorkModeSwitch();
mViewPager = null;
- removeWorkToggle();
}
}
@@ -550,11 +510,8 @@
mAH[currentActivePage].recyclerView.bindFastScrollbar();
}
reset(true /* animate */);
- if (mWorkModeSwitch != null) {
- mWorkModeSwitch.setWorkTabVisible(currentActivePage == AdapterHolder.WORK
- && mAllAppsStore.hasModelFlag(
- FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION));
- }
+
+ mWorkManager.onActivePageChanged(currentActivePage);
}
// Used by tests only
@@ -626,7 +583,6 @@
mAH[i].recyclerView.scrollToTop();
}
}
- mHeaderTop = mHeader.getTop();
}
public void setLastSearchQuery(String query) {
@@ -731,7 +687,6 @@
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;
@@ -739,17 +694,16 @@
final Rect padding = new Rect();
AllAppsRecyclerView recyclerView;
boolean verticalFadingEdge;
- private View mOverlay;
- boolean mWorkDisabled;
AdapterHolder(boolean isWork) {
mIsWork = isWork;
appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore,
- isWork ? mWorkAdapterProvider : null);
+ isWork ? mWorkManager.getAdapterProvider() : null);
BaseAdapterProvider[] adapterProviders =
- isWork ? new BaseAdapterProvider[]{mSearchAdapterProvider, mWorkAdapterProvider}
+ isWork ? new BaseAdapterProvider[]{mSearchAdapterProvider,
+ mWorkManager.getAdapterProvider()}
: new BaseAdapterProvider[]{mSearchAdapterProvider};
adapter = new AllAppsGridAdapter(mLauncher, getLayoutInflater(), appsList,
@@ -759,7 +713,6 @@
}
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
- mInfoMatcher = matcher;
appsList.updateItemFilter(matcher);
recyclerView = (AllAppsRecyclerView) rv;
recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
@@ -782,12 +735,10 @@
void applyPadding() {
if (recyclerView != null) {
- Resources res = getResources();
- int switchH = res.getDimensionPixelSize(R.dimen.work_profile_footer_padding) * 2
- + mInsets.bottom + Utilities.calculateTextHeight(
- res.getDimension(R.dimen.work_profile_footer_text_size));
-
- int bottomOffset = mWorkModeSwitch != null && mIsWork ? switchH : 0;
+ int bottomOffset = 0;
+ if (mIsWork && mWorkManager.getWorkModeSwitch() != null) {
+ bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
+ }
recyclerView.setPadding(padding.left, padding.top, padding.right,
padding.bottom + bottomOffset);
}
diff --git a/src/com/android/launcher3/allapps/WorkAdapterProvider.java b/src/com/android/launcher3/allapps/WorkAdapterProvider.java
index 13444dd..331320d 100644
--- a/src/com/android/launcher3/allapps/WorkAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/WorkAdapterProvider.java
@@ -15,12 +15,11 @@
*/
package com.android.launcher3.allapps;
+import android.content.SharedPreferences;
import android.view.LayoutInflater;
import android.view.ViewGroup;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import java.util.ArrayList;
@@ -33,13 +32,13 @@
private static final int VIEW_TYPE_WORK_EDU_CARD = 1 << 20;
private static final int VIEW_TYPE_WORK_DISABLED_CARD = 1 << 21;
- private final Runnable mRefreshCB;
- private final BaseDraggingActivity mLauncher;
- private boolean mEnabled;
- WorkAdapterProvider(BaseDraggingActivity launcher, Runnable refreshCallback) {
- mLauncher = launcher;
- mRefreshCB = refreshCallback;
+ @WorkProfileManager.WorkProfileState
+ private int mState;
+ private SharedPreferences mPreferences;
+
+ WorkAdapterProvider(SharedPreferences prefs) {
+ mPreferences = prefs;
}
@Override
@@ -61,19 +60,19 @@
* returns whether or not work apps should be visible in work tab.
*/
public boolean shouldShowWorkApps() {
- return mEnabled;
+ return mState != WorkProfileManager.STATE_DISABLED;
}
/**
* Adds work profile specific adapter items to adapterItems and returns number of items added
*/
public int addWorkItems(ArrayList<AllAppsGridAdapter.AdapterItem> adapterItems) {
- if (!mEnabled) {
+ if (mState == WorkProfileManager.STATE_DISABLED) {
//add disabled card here.
AllAppsGridAdapter.AdapterItem disabledCard = new AllAppsGridAdapter.AdapterItem();
disabledCard.viewType = VIEW_TYPE_WORK_DISABLED_CARD;
adapterItems.add(disabledCard);
- } else if (!isEduSeen()) {
+ } else if (mState == WorkProfileManager.STATE_ENABLED && !isEduSeen()) {
AllAppsGridAdapter.AdapterItem eduCard = new AllAppsGridAdapter.AdapterItem();
eduCard.viewType = VIEW_TYPE_WORK_EDU_CARD;
adapterItems.add(eduCard);
@@ -85,9 +84,8 @@
/**
* Sets the current state of work profile
*/
- public void updateCurrentState(boolean isEnabled) {
- mEnabled = isEnabled;
- mRefreshCB.run();
+ public void updateCurrentState(@WorkProfileManager.WorkProfileState int state) {
+ mState = state;
}
@Override
@@ -101,6 +99,6 @@
}
private boolean isEduSeen() {
- return Utilities.getPrefs(mLauncher).getInt(KEY_WORK_EDU_STEP, 0) != 0;
+ return mPreferences.getInt(KEY_WORK_EDU_STEP, 0) != 0;
}
}
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index 5d3af08..5d64041 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -16,43 +16,41 @@
package com.android.launcher3.allapps;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_OFF_WORK_APPS_TAP;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.os.Build;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.Button;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
-import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
/**
* Work profile toggle switch shown at the bottom of AllApps work tab
*/
-public class WorkModeSwitch extends Button implements Insettable, View.OnClickListener {
+public class WorkModeSwitch extends Button implements Insettable, View.OnClickListener,
+ KeyboardInsetAnimationCallback.KeyboardInsetListener,
+ PersonalWorkSlidingTabStrip.OnActivePageChangedListener {
- private Rect mInsets = new Rect();
+ private static final int FLAG_FADE_ONGOING = 1 << 1;
+ private static final int FLAG_TRANSLATION_ONGOING = 1 << 2;
+ private static final int FLAG_PROFILE_TOGGLE_ONGOING = 1 << 3;
+
+ private final Rect mInsets = new Rect();
+ private int mFlags;
private boolean mWorkEnabled;
+ private boolean mOnWorkTab;
- @Nullable
- private KeyboardInsetAnimationCallback mKeyboardInsetAnimationCallback;
- private boolean mWorkTabVisible;
-
public WorkModeSwitch(Context context) {
this(context, null, 0);
}
@@ -71,9 +69,12 @@
setSelected(true);
setOnClickListener(this);
if (Utilities.ATLEAST_R) {
- mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
- setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
+ KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
+ new KeyboardInsetAnimationCallback(this);
+ setWindowInsetsAnimationCallback(keyboardInsetAnimationCallback);
}
+ DeviceProfile grid = BaseDraggingActivity.fromContext(getContext()).getDeviceProfile();
+ setInsets(grid.getInsets());
}
@Override
@@ -87,57 +88,57 @@
}
}
- /**
- * Animates in/out work profile toggle panel based on the tab user is on
- */
- public void setWorkTabVisible(boolean workTabVisible) {
- clearAnimation();
- mWorkTabVisible = workTabVisible;
- if (workTabVisible && mWorkEnabled) {
- setEnabled(true);
- setVisibility(VISIBLE);
- setAlpha(0);
- animate().alpha(1).start();
- } else {
- animate().alpha(0).withEndAction(() -> this.setVisibility(GONE)).start();
- }
+
+ @Override
+ public void onActivePageChanged(int page) {
+ mOnWorkTab = page == AllAppsContainerView.AdapterHolder.WORK;
+ updateVisibility();
}
@Override
public void onClick(View view) {
- if (Utilities.ATLEAST_P && mWorkTabVisible) {
- setEnabled(false);
- Launcher.fromContext(getContext()).getStatsLogManager().logger().log(
- LAUNCHER_TURN_OFF_WORK_APPS_TAP);
- UI_HELPER_EXECUTOR.post(() -> setWorkProfileEnabled(getContext(), false));
+ if (Utilities.ATLEAST_P && isEnabled()) {
+ setFlag(FLAG_PROFILE_TOGGLE_ONGOING);
+ Launcher launcher = Launcher.getLauncher(getContext());
+ launcher.getStatsLogManager().logger().log(LAUNCHER_TURN_OFF_WORK_APPS_TAP);
+ launcher.getAppsView().getWorkManager().setWorkProfileEnabled(false);
}
}
+ @Override
+ public boolean isEnabled() {
+ return super.isEnabled() && getVisibility() == VISIBLE && mFlags == 0;
+ }
+
/**
* Sets the enabled or disabled state of the button
*/
public void updateCurrentState(boolean active) {
+ removeFlag(FLAG_PROFILE_TOGGLE_ONGOING);
mWorkEnabled = active;
- setEnabled(true);
- setVisibility(active ? VISIBLE : GONE);
+ updateVisibility();
}
- @RequiresApi(Build.VERSION_CODES.P)
- public static Boolean setWorkProfileEnabled(Context context, boolean enabled) {
- UserManager userManager = context.getSystemService(UserManager.class);
- boolean showConfirm = false;
- for (UserHandle userProfile : UserCache.INSTANCE.get(context).getUserProfiles()) {
- if (Process.myUserHandle().equals(userProfile)) {
- continue;
- }
- showConfirm |= !userManager.requestQuietModeEnabled(!enabled, userProfile);
+
+ private void updateVisibility() {
+ clearAnimation();
+ if (mWorkEnabled && mOnWorkTab) {
+ setFlag(FLAG_FADE_ONGOING);
+ setVisibility(VISIBLE);
+ setAlpha(0);
+ animate().alpha(1).withEndAction(() -> removeFlag(FLAG_FADE_ONGOING)).start();
+ } else if (getVisibility() != GONE) {
+ setFlag(FLAG_FADE_ONGOING);
+ animate().alpha(0).withEndAction(() -> {
+ removeFlag(FLAG_FADE_ONGOING);
+ this.setVisibility(GONE);
+ }).start();
}
- return showConfirm;
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- if (Utilities.ATLEAST_R && mWorkTabVisible) {
+ if (Utilities.ATLEAST_R && isEnabled()) {
setTranslationY(0);
if (insets.isVisible(WindowInsets.Type.ime())) {
Insets keyboardInsets = insets.getInsets(WindowInsets.Type.ime());
@@ -146,4 +147,22 @@
}
return insets;
}
+
+ @Override
+ public void onTranslationStart() {
+ setFlag(FLAG_TRANSLATION_ONGOING);
+ }
+
+ @Override
+ public void onTranslationEnd() {
+ removeFlag(FLAG_TRANSLATION_ONGOING);
+ }
+
+ private void setFlag(int flag) {
+ mFlags |= flag;
+ }
+
+ private void removeFlag(int flag) {
+ mFlags &= ~flag;
+ }
}
diff --git a/src/com/android/launcher3/allapps/WorkPausedCard.java b/src/com/android/launcher3/allapps/WorkPausedCard.java
index 7908b63..7593ca7 100644
--- a/src/com/android/launcher3/allapps/WorkPausedCard.java
+++ b/src/com/android/launcher3/allapps/WorkPausedCard.java
@@ -16,7 +16,6 @@
package com.android.launcher3.allapps;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_ON_WORK_APPS_TAP;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.content.Context;
import android.content.res.Configuration;
@@ -62,8 +61,8 @@
public void onClick(View view) {
if (Utilities.ATLEAST_P) {
setEnabled(false);
+ mLauncher.getAppsView().getWorkManager().setWorkProfileEnabled(true);
mLauncher.getStatsLogManager().logger().log(LAUNCHER_TURN_ON_WORK_APPS_TAP);
- UI_HELPER_EXECUTOR.post(() -> WorkModeSwitch.setWorkProfileEnabled(getContext(), true));
}
}
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
new file mode 100644
index 0000000..c53360a
--- /dev/null
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+package com.android.launcher3.allapps;
+
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.RequiresApi;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Companion class for {@link AllAppsContainerView} to manage work tab and personal tab related
+ * logic based on {@link WorkProfileState}?
+ */
+public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActivePageChangedListener {
+ private static final String TAG = "WorkProfileManager";
+
+
+ public static final int STATE_ENABLED = 1;
+ public static final int STATE_DISABLED = 2;
+ public static final int STATE_TRANSITION = 3;
+
+
+ private final UserManager mUserManager;
+
+ /**
+ * Work profile manager states
+ */
+ @IntDef(value = {
+ STATE_ENABLED,
+ STATE_DISABLED,
+ STATE_TRANSITION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WorkProfileState {
+ }
+
+ private final AllAppsContainerView mAllApps;
+ private final WorkAdapterProvider mAdapterProvider;
+ private final ItemInfoMatcher mMatcher;
+
+ private WorkModeSwitch mWorkModeSwitch;
+
+ @WorkProfileState
+ private int mCurrentState;
+
+
+ public WorkProfileManager(UserManager userManager, AllAppsContainerView allApps,
+ SharedPreferences preferences) {
+ mUserManager = userManager;
+ mAllApps = allApps;
+ mAdapterProvider = new WorkAdapterProvider(preferences);
+ mMatcher = mAllApps.mPersonalMatcher.negate();
+ }
+
+ /**
+ * Posts quite mode enable/disable call for work profile user
+ */
+ @RequiresApi(Build.VERSION_CODES.P)
+ public void setWorkProfileEnabled(boolean enabled) {
+ updateCurrentState(STATE_TRANSITION);
+ UI_HELPER_EXECUTOR.post(() -> {
+ for (UserHandle userProfile : mUserManager.getUserProfiles()) {
+ if (Process.myUserHandle().equals(userProfile)) {
+ continue;
+ }
+ mUserManager.requestQuietModeEnabled(!enabled, userProfile);
+ }
+ });
+ }
+
+ @Override
+ public void onActivePageChanged(int page) {
+ if (mWorkModeSwitch != null) {
+ mWorkModeSwitch.onActivePageChanged(page);
+ }
+ }
+
+ /**
+ * Requests work profile state from {@link AllAppsStore} and updates work profile related views
+ */
+ public void reset() {
+ boolean isEnabled = !mAllApps.getAppsStore().hasModelFlag(FLAG_QUIET_MODE_ENABLED);
+ updateCurrentState(isEnabled ? STATE_ENABLED : STATE_DISABLED);
+ }
+
+ private void updateCurrentState(@WorkProfileState int currentState) {
+ mCurrentState = currentState;
+ mAdapterProvider.updateCurrentState(currentState);
+ if (getAH() != null) {
+ getAH().appsList.updateAdapterItems();
+ }
+ if (mWorkModeSwitch != null) {
+ mWorkModeSwitch.updateCurrentState(currentState == STATE_ENABLED);
+ }
+ }
+
+ /**
+ * Creates and attaches for profile toggle button to {@link AllAppsContainerView}
+ */
+ public void attachWorkModeSwitch() {
+ if (!mAllApps.getAppsStore().hasModelFlag(
+ FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION)) {
+ Log.e(TAG, "Unable to attach widget; Missing required permissions");
+ return;
+ }
+ if (mWorkModeSwitch == null) {
+ mWorkModeSwitch = (WorkModeSwitch) mAllApps.getLayoutInflater().inflate(
+ R.layout.work_mode_fab, mAllApps, false);
+ }
+ if (mWorkModeSwitch.getParent() != mAllApps) {
+ mAllApps.addView(mWorkModeSwitch);
+ }
+ if (getAH() != null) {
+ getAH().applyPadding();
+ }
+ mWorkModeSwitch.updateCurrentState(mCurrentState == STATE_ENABLED);
+ }
+
+ /**
+ * Removes work profile toggle button from {@link AllAppsContainerView}
+ */
+ public void detachWorkModeSwitch() {
+ if (mWorkModeSwitch != null && mWorkModeSwitch.getParent() == mAllApps) {
+ mAllApps.removeView(mWorkModeSwitch);
+ }
+ mWorkModeSwitch = null;
+ }
+
+
+ public WorkAdapterProvider getAdapterProvider() {
+ return mAdapterProvider;
+ }
+
+ public ItemInfoMatcher getMatcher() {
+ return mMatcher;
+ }
+
+ public WorkModeSwitch getWorkModeSwitch() {
+ return mWorkModeSwitch;
+ }
+
+ private AllAppsContainerView.AdapterHolder getAH() {
+ return mAllApps.mAH[AllAppsContainerView.AdapterHolder.WORK];
+ }
+}
diff --git a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
index ef4ada3..9d96365 100644
--- a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
+++ b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
@@ -65,7 +65,32 @@
public WindowInsetsAnimation.Bounds onStart(WindowInsetsAnimation animation,
WindowInsetsAnimation.Bounds bounds) {
mTerminalTranslation = mView.getTranslationY();
- mView.setTranslationY(mInitialTranslation);
+ if (mView instanceof KeyboardInsetListener) {
+ ((KeyboardInsetListener) mView).onTranslationStart();
+ }
return super.onStart(animation, bounds);
}
+
+ @Override
+ public void onEnd(WindowInsetsAnimation animation) {
+ if (mView instanceof KeyboardInsetListener) {
+ ((KeyboardInsetListener) mView).onTranslationEnd();
+ }
+ super.onEnd(animation);
+ }
+
+ /**
+ * Interface Allowing views to listen for keyboard translation events
+ */
+ public interface KeyboardInsetListener {
+ /**
+ * Called from {@link KeyboardInsetAnimationCallback#onStart}
+ */
+ void onTranslationStart();
+
+ /**
+ * Called from {@link KeyboardInsetAnimationCallback#onEnd}
+ */
+ void onTranslationEnd();
+ }
}