diff --git a/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java b/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java index 2584f65c52..3a252dcce9 100644 --- a/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -92,7 +92,8 @@ public class LoaderCursorTest { SCREEN, CELLX, CELLY, RESTORED, INTENT }); - mLoaderCursor = new LoaderCursor(mCursor, LauncherSettings.Favorites.CONTENT_URI, mApp); + mLoaderCursor = new LoaderCursor(mCursor, LauncherSettings.Favorites.CONTENT_URI, mApp, + new UserManagerState()); mLoaderCursor.allUsers.put(0, Process.myUserHandle()); } diff --git a/robolectric_tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java b/robolectric_tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java index 4b0ae7ed29..87fe3c086b 100644 --- a/robolectric_tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java @@ -199,7 +199,7 @@ public class ModelMultiCallbacksTest { } @Override - public void bindAllApplications(AppInfo[] apps) { + public void bindAllApplications(AppInfo[] apps, int flags) { mAppInfos = apps; } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 1f84c42f22..ec32e62c2a 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2455,8 +2455,9 @@ public class Launcher extends StatefulActivity implements Launche * * Implementation of the method from LauncherModel.Callbacks. */ - public void bindAllApplications(AppInfo[] apps) { - mAppsView.getAppsStore().setApps(apps); + @Override + public void bindAllApplications(AppInfo[] apps, int flags) { + mAppsView.getAppsStore().setApps(apps, flags); } /** diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 3b1c7bbd67..f434c9180a 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -117,7 +117,7 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi @Override public void run() { if (mModelLoaded && hasShortcutsPermission(mApp.getContext()) - != mBgDataModel.hasShortcutHostPermission) { + != mBgAllAppsList.hasShortcutHostPermission()) { forceReload(); } } diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 1d6bb623b2..2ffe9d5f9f 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -16,6 +16,9 @@ package com.android.launcher3.allapps; import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; +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.ValueAnimator; import android.content.Context; @@ -37,7 +40,6 @@ import android.view.WindowInsets; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; -import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -54,7 +56,6 @@ import com.android.launcher3.Utilities; import com.android.launcher3.keyboard.FocusedItemDecorator; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.pm.UserCache; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.ItemInfoMatcher; @@ -195,7 +196,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo } private void resetWorkProfile() { - mWorkModeSwitch.refresh(); + mWorkModeSwitch.update(!mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED)); mAH[AdapterHolder.WORK].setupOverlay(); mAH[AdapterHolder.WORK].applyPadding(); } @@ -431,11 +432,13 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo } private void setupWorkToggle() { - mWorkModeSwitch = (WorkModeSwitch) mLauncher.getLayoutInflater().inflate( - R.layout.work_mode_switch, this, false); - this.addView(mWorkModeSwitch); - mWorkModeSwitch.setInsets(mInsets); - mWorkModeSwitch.post(() -> mAH[AdapterHolder.WORK].applyPadding()); + if (Utilities.ATLEAST_P) { + mWorkModeSwitch = (WorkModeSwitch) mLauncher.getLayoutInflater().inflate( + R.layout.work_mode_switch, this, false); + this.addView(mWorkModeSwitch); + mWorkModeSwitch.setInsets(mInsets); + mWorkModeSwitch.post(() -> mAH[AdapterHolder.WORK].applyPadding()); + } } private void replaceRVContainer(boolean showTabs) { @@ -470,7 +473,9 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo } reset(true /* animate */); if (mWorkModeSwitch != null) { - mWorkModeSwitch.setWorkTabVisible(pos == AdapterHolder.WORK); + mWorkModeSwitch.setWorkTabVisible(pos == AdapterHolder.WORK + && mAllAppsStore.hasModelFlag( + FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION)); } } @@ -580,15 +585,8 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo && valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) { int searchViewId = getSearchView().getId(); addSpringView(searchViewId); - finishWithShiftAndVelocity(1, velocity * FLING_VELOCITY_MULTIPLIER, - new DynamicAnimation.OnAnimationEndListener() { - @Override - public void onAnimationEnd(DynamicAnimation animation, - boolean canceled, float value, float velocity) { - removeSpringView(searchViewId); - } - }); + (anim, canceled, value, velocity) -> removeSpringView(searchViewId)); shouldSpring = false; } @@ -647,7 +645,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo void setupOverlay() { if (!mIsWork || recyclerView == null) return; - boolean workDisabled = UserCache.INSTANCE.get(mLauncher).isAnyProfileQuietModeEnabled(); + boolean workDisabled = mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED); if (mWorkDisabled == workDisabled) return; recyclerView.setContentDescription(workDisabled ? mLauncher.getString( R.string.work_apps_paused_content_description) : null); diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java index b11312ca20..3ae0a18137 100644 --- a/src/com/android/launcher3/allapps/AllAppsStore.java +++ b/src/com/android/launcher3/allapps/AllAppsStore.java @@ -52,6 +52,7 @@ public class AllAppsStore { private final List mUpdateListeners = new CopyOnWriteArrayList<>(); private final ArrayList mIconContainers = new ArrayList<>(); + private int mModelFlags; private int mDeferUpdatesFlags = 0; private boolean mUpdatePending = false; @@ -63,11 +64,21 @@ public class AllAppsStore { /** * Sets the current set of apps. */ - public void setApps(AppInfo[] apps) { + public void setApps(AppInfo[] apps, int flags) { mApps = apps; + mModelFlags = flags; notifyUpdate(); } + /** + * @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_QUIET_MODE_ENABLED + * @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_HAS_SHORTCUT_PERMISSION + * @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_QUIET_MODE_CHANGE_PERMISSION + */ + public boolean hasModelFlag(int mask) { + return (mModelFlags & mask) != 0; + } + public AppInfo getApp(ComponentKey key) { mTempInfo.componentName = key.componentName; mTempInfo.user = key.user; diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java index 6692af5d9a..4567ee620f 100644 --- a/src/com/android/launcher3/allapps/WorkModeSwitch.java +++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java @@ -15,11 +15,8 @@ */ package com.android.launcher3.allapps; -import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission; - import android.content.Context; import android.content.SharedPreferences; -import android.content.pm.PackageManager; import android.graphics.Rect; import android.os.AsyncTask; import android.os.Process; @@ -59,7 +56,6 @@ public class WorkModeSwitch extends Switch implements Insettable { public WorkModeSwitch(Context context, AttributeSet attrs) { super(context, attrs); init(); - } public WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr) { @@ -73,9 +69,7 @@ public class WorkModeSwitch extends Switch implements Insettable { } @Override - public void setChecked(boolean checked) { - - } + public void setChecked(boolean checked) { } @Override public void toggle() { @@ -84,20 +78,17 @@ public class WorkModeSwitch extends Switch implements Insettable { trySetQuietModeEnabledToAllProfilesAsync(isChecked()); } - private void setCheckedInternal(boolean checked) { - super.setChecked(checked); + /** + * Sets the enabled or disabled state of the button + * @param isChecked + */ + public void update(boolean isChecked) { + super.setChecked(isChecked); setCompoundDrawablesRelativeWithIntrinsicBounds( - checked ? R.drawable.ic_corp : R.drawable.ic_corp_off, 0, 0, 0); - } - - public void refresh() { - if (!shouldShowWorkSwitch()) return; - UserCache userManager = UserCache.INSTANCE.get(getContext()); - setCheckedInternal(!userManager.isAnyProfileQuietModeEnabled()); + isChecked ? R.drawable.ic_corp : R.drawable.ic_corp_off, 0, 0, 0); setEnabled(true); } - @Override public boolean onTouchEvent(MotionEvent ev) { if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { @@ -116,12 +107,6 @@ public class WorkModeSwitch extends Switch implements Insettable { return super.onTouchEvent(ev); } - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - this.setVisibility(shouldShowWorkSwitch() ? VISIBLE : GONE); - } - private void trySetQuietModeEnabledToAllProfilesAsync(boolean enabled) { new SetQuietModeEnabledAsyncTask(enabled, new WeakReference<>(this)).execute(); } @@ -138,13 +123,12 @@ public class WorkModeSwitch extends Switch implements Insettable { * Animates in/out work profile toggle panel based on the tab user is on */ public void setWorkTabVisible(boolean workTabVisible) { - if (!shouldShowWorkSwitch()) return; clearAnimation(); if (workTabVisible) { setVisibility(VISIBLE); setAlpha(0); animate().alpha(1).start(); - showTipifNeeded(); + showTipIfNeeded(); } else { animate().alpha(0).withEndAction(() -> this.setVisibility(GONE)).start(); } @@ -201,16 +185,10 @@ public class WorkModeSwitch extends Switch implements Insettable { } } - private boolean shouldShowWorkSwitch() { - return Utilities.ATLEAST_P && (hasShortcutsPermission(getContext()) - || getContext().checkSelfPermission("android.permission.MODIFY_QUIET_MODE") - == PackageManager.PERMISSION_GRANTED); - } - /** * Shows a work tip on the Nth work tab open */ - public void showTipifNeeded() { + public void showTipIfNeeded() { Context context = getContext(); SharedPreferences prefs = Utilities.getPrefs(context); int tipCounter = prefs.getInt(KEY_WORK_TIP_COUNTER, WORK_TIP_THRESHOLD); diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 4f349caaad..eb5d1068ac 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -35,6 +35,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.AppFilter; import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.icons.IconCache; +import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.pm.PackageInstallInfo; @@ -72,6 +73,13 @@ public class AllAppsList { private AlphabeticIndexCompat mIndex; + /** + * @see Callbacks#FLAG_HAS_SHORTCUT_PERMISSION + * @see Callbacks#FLAG_QUIET_MODE_ENABLED + * @see Callbacks#FLAG_QUIET_MODE_CHANGE_PERMISSION + */ + private int mFlags; + /** * Boring constructor. */ @@ -90,6 +98,33 @@ public class AllAppsList { return result; } + /** + * Helper to checking {@link Callbacks#FLAG_HAS_SHORTCUT_PERMISSION} + */ + public boolean hasShortcutHostPermission() { + return (mFlags & Callbacks.FLAG_HAS_SHORTCUT_PERMISSION) != 0; + } + + /** + * Sets or clears the provided flag + */ + public void setFlags(int flagMask, boolean enabled) { + if (enabled) { + mFlags |= flagMask; + } else { + mFlags &= ~flagMask; + } + mDataChanged = true; + } + + /** + * Returns the model flags + */ + public int getFlags() { + return mFlags; + } + + /** * Add the supplied ApplicationInfo objects to the list, and enqueue it into the * list to broadcast when notify() is called. diff --git a/src/com/android/launcher3/model/BaseLoaderResults.java b/src/com/android/launcher3/model/BaseLoaderResults.java index ab921eaad9..8b0ef7b97f 100644 --- a/src/com/android/launcher3/model/BaseLoaderResults.java +++ b/src/com/android/launcher3/model/BaseLoaderResults.java @@ -96,7 +96,8 @@ public abstract class BaseLoaderResults { public void bindAllApps() { // shallow copy AppInfo[] apps = mBgAllAppsList.copyData(); - executeCallbacksTask(c -> c.bindAllApplications(apps), mUiExecutor); + int flags = mBgAllAppsList.getFlags(); + executeCallbacksTask(c -> c.bindAllApplications(apps, flags), mUiExecutor); } public abstract void bindWidgets(); diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java index 7ce970d253..9013cba54f 100644 --- a/src/com/android/launcher3/model/BaseModelUpdateTask.java +++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java @@ -117,7 +117,8 @@ public abstract class BaseModelUpdateTask implements ModelUpdateTask { public void bindApplicationsIfNeeded() { if (mAllAppsList.getAndResetChangeFlag()) { AppInfo[] apps = mAllAppsList.copyData(); - scheduleCallbackTask(c -> c.bindAllApplications(apps)); + int flags = mAllAppsList.getFlags(); + scheduleCallbackTask(c -> c.bindAllApplications(apps, flags)); } } } diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 2522a498e6..9bef84718b 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -98,9 +98,11 @@ public class BgDataModel { public final ArrayList cachedPredictedItems = new ArrayList<>(); /** - * True if the launcher has permission to access deep shortcuts. + * @see Callbacks#FLAG_HAS_SHORTCUT_PERMISSION + * @see Callbacks#FLAG_QUIET_MODE_ENABLED + * @see Callbacks#FLAG_QUIET_MODE_CHANGE_PERMISSION */ - public boolean hasShortcutHostPermission; + public int flags; /** * Maps all launcher activities to counts of their shortcuts. @@ -347,6 +349,13 @@ public class BgDataModel { } public interface Callbacks { + // If the launcher has permission to access deep shortcuts. + int FLAG_HAS_SHORTCUT_PERMISSION = 1 << 0; + // If quiet mode is enabled for any user + int FLAG_QUIET_MODE_ENABLED = 1 << 1; + // If launcher can change quiet mode + int FLAG_QUIET_MODE_CHANGE_PERMISSION = 1 << 2; + /** * Returns the page number to bind first, synchronously if possible or -1 */ @@ -370,7 +379,7 @@ public class BgDataModel { void executeOnNextDraw(ViewOnDrawExecutor executor); void bindDeepShortcutMap(HashMap deepShortcutMap); - void bindAllApplications(AppInfo[] apps); + void bindAllApplications(AppInfo[] apps, int flags); /** * Binds predicted appInfos at at available prediction slots. diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 244de96bae..165d1eab6b 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -65,7 +65,7 @@ public class LoaderCursor extends CursorWrapper { private static final String TAG = "LoaderCursor"; - public final LongSparseArray allUsers = new LongSparseArray<>(); + public final LongSparseArray allUsers; private final Uri mContentUri; private final Context mContext; @@ -100,9 +100,11 @@ public class LoaderCursor extends CursorWrapper { public int itemType; public int restoreFlag; - public LoaderCursor(Cursor cursor, Uri contentUri, LauncherAppState app) { + public LoaderCursor(Cursor cursor, Uri contentUri, LauncherAppState app, + UserManagerState userManagerState) { super(cursor); + allUsers = userManagerState.allUsers; mContentUri = contentUri; mContext = app.getContext(); mIconCache = app.getIconCache(); diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index d05d70b044..f2073ef245 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -17,6 +17,9 @@ package com.android.launcher3.model; import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO; +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.model.ModelUtils.filterCurrentWorkspaceItems; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE; @@ -35,6 +38,7 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.net.Uri; import android.os.UserHandle; @@ -120,6 +124,8 @@ public class LoaderTask implements Runnable { private final InstallSessionHelper mSessionHelper; private final IconCache mIconCache; + private final UserManagerState mUserManagerState = new UserManagerState(); + private boolean mStopped; public LoaderTask(LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel dataModel, @@ -333,7 +339,8 @@ public class LoaderTask implements Runnable { Map shortcutKeyToPinnedShortcuts = new HashMap<>(); final LoaderCursor c = new LoaderCursor( - contentResolver.query(contentUri, null, null, null, null), contentUri, mApp); + contentResolver.query(contentUri, null, null, null, null), contentUri, mApp, + mUserManagerState); Map widgetProvidersMap = null; @@ -352,12 +359,13 @@ public class LoaderTask implements Runnable { LauncherSettings.Favorites.OPTIONS); final LongSparseArray allUsers = c.allUsers; - final LongSparseArray quietMode = new LongSparseArray<>(); final LongSparseArray unlockedUsers = new LongSparseArray<>(); + + mUserManagerState.init(mUserCache, mUserManager); + for (UserHandle user : mUserCache.getUserProfiles()) { long serialNo = mUserCache.getSerialNumberForUser(user); allUsers.put(serialNo, user); - quietMode.put(serialNo, mUserManager.isQuietModeEnabled(user)); boolean userUnlocked = mUserManager.isUserUnlocked(user); @@ -404,8 +412,8 @@ public class LoaderTask implements Runnable { continue; } - int disabledState = quietMode.get(c.serialNumber) ? - WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0; + int disabledState = mUserManagerState.isUserQuiet(c.serialNumber) + ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0; ComponentName cn = intent.getComponent(); targetPkg = cn == null ? intent.getPackage() : cn.getPackageName(); @@ -862,8 +870,8 @@ public class LoaderTask implements Runnable { for (ComponentKey key : componentKeys) { l = mLauncherApps.getActivityList(key.componentName.getPackageName(), key.user); if (l.size() == 0) continue; - boolean quietMode = mUserManager.isQuietModeEnabled(key.user); - AppInfo info = new AppInfo(l.get(0), key.user, quietMode); + AppInfo info = new AppInfo(l.get(0), key.user, + mUserManagerState.isUserQuiet(key.user)); mBgDataModel.cachedPredictedItems.add(info); mIconCache.getTitleAndIcon(info, false); } @@ -883,7 +891,7 @@ public class LoaderTask implements Runnable { if (apps == null || apps.isEmpty()) { return allActivityList; } - boolean quietMode = mUserManager.isQuietModeEnabled(user); + boolean quietMode = mUserManagerState.isUserQuiet(user); // Create the ApplicationInfos for (int i = 0; i < apps.size(); i++) { LauncherActivityInfo app = apps.get(i); @@ -905,11 +913,19 @@ public class LoaderTask implements Runnable { List l = mLauncherApps.getActivityList( item.componentName.getPackageName(), item.user); for (LauncherActivityInfo info : l) { - boolean quietMode = mUserManager.isQuietModeEnabled(item.user); + boolean quietMode = mUserManagerState.isUserQuiet(item.user); mBgAllAppsList.add(new AppInfo(info, item.user, quietMode), info); } } + mBgAllAppsList.setFlags(FLAG_QUIET_MODE_ENABLED, + mUserManagerState.isAnyProfileQuietModeEnabled()); + mBgAllAppsList.setFlags(FLAG_HAS_SHORTCUT_PERMISSION, + hasShortcutsPermission(mApp.getContext())); + mBgAllAppsList.setFlags(FLAG_QUIET_MODE_CHANGE_PERMISSION, + mApp.getContext().checkSelfPermission("android.permission.MODIFY_QUIET_MODE") + == PackageManager.PERMISSION_GRANTED); + mBgAllAppsList.getAndResetChangeFlag(); return allActivityList; } @@ -917,8 +933,8 @@ public class LoaderTask implements Runnable { private List loadDeepShortcuts() { List allShortcuts = new ArrayList<>(); mBgDataModel.deepShortcutMap.clear(); - mBgDataModel.hasShortcutHostPermission = hasShortcutsPermission(mApp.getContext()); - if (mBgDataModel.hasShortcutHostPermission) { + + if (mBgAllAppsList.hasShortcutHostPermission()) { for (UserHandle user : mUserCache.getUserProfiles()) { if (mUserManager.isUserUnlocked(user)) { List shortcuts = new ShortcutRequest(mApp.getContext(), user) diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 2fa605175d..7cd467efd6 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -15,6 +15,7 @@ */ package com.android.launcher3.model; +import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED; import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_RESTORED_ICON; @@ -41,6 +42,7 @@ import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.IntSparseArrayMap; @@ -149,14 +151,21 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { if (DEBUG) Log.d(TAG, "mAllAppsList.(un)suspend " + N); appsList.updateDisabledFlags(matcher, flagOp); break; - case OP_USER_AVAILABILITY_CHANGE: - flagOp = context.getSystemService(UserManager.class).isQuietModeEnabled(mUser) + case OP_USER_AVAILABILITY_CHANGE: { + UserManagerState ums = new UserManagerState(); + ums.init(UserCache.INSTANCE.get(context), + context.getSystemService(UserManager.class)); + flagOp = ums.isUserQuiet(mUser) ? FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER) : FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER); // We want to update all packages for this user. matcher = ItemInfoMatcher.ofUser(mUser); appsList.updateDisabledFlags(matcher, flagOp); + + // We are not synchronizing here, as int operations are atomic + appsList.setFlags(FLAG_QUIET_MODE_ENABLED, ums.isAnyProfileQuietModeEnabled()); break; + } } bindApplicationsIfNeeded(); diff --git a/src/com/android/launcher3/model/UserManagerState.java b/src/com/android/launcher3/model/UserManagerState.java new file mode 100644 index 0000000000..3a4206c144 --- /dev/null +++ b/src/com/android/launcher3/model/UserManagerState.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2018 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.model; + +import android.os.UserHandle; +import android.os.UserManager; +import android.util.LongSparseArray; +import android.util.SparseBooleanArray; + +import com.android.launcher3.pm.UserCache; + +/** + * Utility class to manager store and user manager state at any particular time + */ +public class UserManagerState { + + public final LongSparseArray allUsers = new LongSparseArray<>(); + + private final LongSparseArray mQuietUsersSerialNoMap = new LongSparseArray<>(); + private final SparseBooleanArray mQuietUsersHashCodeMap = new SparseBooleanArray(); + + /** + * Initialises the state values for all users + */ + public void init(UserCache userCache, UserManager userManager) { + for (UserHandle user : userCache.getUserProfiles()) { + long serialNo = userCache.getSerialNumberForUser(user); + boolean isUserQuiet = userManager.isQuietModeEnabled(user); + allUsers.put(serialNo, user); + mQuietUsersHashCodeMap.put(user.hashCode(), isUserQuiet); + mQuietUsersSerialNoMap.put(serialNo, isUserQuiet); + } + } + + /** + * Returns true if quiet mode is enabled for the provided user + */ + public boolean isUserQuiet(long serialNo) { + return mQuietUsersSerialNoMap.get(serialNo); + } + + /** + * Returns true if quiet mode is enabled for the provided user + */ + public boolean isUserQuiet(UserHandle user) { + return mQuietUsersHashCodeMap.get(user.hashCode()); + } + + /** + * Returns true if any user profile has quiet mode enabled. + */ + public boolean isAnyProfileQuietModeEnabled() { + for (int i = mQuietUsersHashCodeMap.size() - 1; i >= 0; i--) { + if (mQuietUsersHashCodeMap.valueAt(i)) { + return true; + } + } + return false; + } +} diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java index f723256510..5aab41a8a2 100644 --- a/src/com/android/launcher3/pm/UserCache.java +++ b/src/com/android/launcher3/pm/UserCache.java @@ -18,7 +18,6 @@ package com.android.launcher3.pm; import android.content.Context; import android.content.Intent; -import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.util.ArrayMap; @@ -106,22 +105,6 @@ public class UserCache { } } - /** - * Returns true if any user profile has quiet mode enabled. - */ - public boolean isAnyProfileQuietModeEnabled() { - List userProfiles = getUserProfiles(); - for (UserHandle userProfile : userProfiles) { - if (Process.myUserHandle().equals(userProfile)) { - continue; - } - if (mUserManager.isQuietModeEnabled(userProfile)) { - return true; - } - } - return false; - } - /** * @see UserManager#getSerialNumberForUser(UserHandle) */ @@ -160,16 +143,4 @@ public class UserCache { List users = mUserManager.getUserProfiles(); return users == null ? Collections.emptyList() : users; } - - /** - * Returns true is there is at least one user profile enabled - */ - public boolean hasWorkProfile() { - synchronized (this) { - if (mUsers != null) { - return mUsers.size() > 1; - } - } - return getUserProfiles().size() > 1; - } } diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java index 4a15af1d44..21ad2756fb 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java @@ -296,8 +296,8 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity } @Override - public void bindAllApplications(AppInfo[] apps) { - mAppsView.getAppsStore().setApps(apps); + public void bindAllApplications(AppInfo[] apps, int flags) { + mAppsView.getAppsStore().setApps(apps, flags); } public PopupDataProvider getPopupDataProvider() { diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index ddde6d3a88..86f3431b54 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -16,7 +16,6 @@ package com.android.launcher3.util; -import static android.content.pm.PackageInstaller.SessionInfo; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import android.app.AppOpsManager; @@ -45,8 +44,6 @@ import android.util.Log; import android.util.Pair; import android.widget.Toast; -import androidx.annotation.NonNull; - import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -348,15 +345,4 @@ public class PackageManagerHelper { } return false; } - - /** - * Returns the created time in millis of given session info. Returns 0 if not available. - */ - public static long getSessionCreatedTimeInMillis(@NonNull final SessionInfo info) { - try { - return (long) SessionInfo.class.getDeclaredMethod("getCreatedMillis").invoke(info); - } catch (Exception e) { - return 0; - } - } }