From 60e68c91e93395f7ebe51d3d9a3986ff5d381c8e Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 12 Aug 2020 13:59:27 -0700 Subject: [PATCH] Removing static state management from the install shortcut queue Change-Id: I0b74a843b2081ee314e0840d5ea8ab8ddabde32b --- src/com/android/launcher3/Launcher.java | 24 ++-- src/com/android/launcher3/LauncherModel.java | 4 +- .../launcher3/SessionCommitReceiver.java | 4 +- .../launcher3/dragndrop/AddItemActivity.java | 7 +- .../android/launcher3/model/BgDataModel.java | 3 +- .../ItemInstallQueue.java} | 126 ++++++++++++------ .../launcher3/model/PackageUpdatedTask.java | 4 +- .../launcher3/pm/InstallSessionHelper.java | 6 +- 8 files changed, 113 insertions(+), 65 deletions(-) rename src/com/android/launcher3/{InstallShortcutReceiver.java => model/ItemInstallQueue.java} (81%) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 3f64df3702..2ddaaea4db 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -24,7 +24,6 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE; import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE; import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR; -import static com.android.launcher3.InstallShortcutReceiver.FLAG_DRAG_AND_DROP; import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS; @@ -43,6 +42,9 @@ import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKG import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONSTOP; import static com.android.launcher3.logging.StatsLogManager.containerTypeToAtomState; +import static com.android.launcher3.model.ItemInstallQueue.FLAG_ACTIVITY_PAUSED; +import static com.android.launcher3.model.ItemInstallQueue.FLAG_DRAG_AND_DROP; +import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING; import static com.android.launcher3.popup.SystemShortcut.APP_INFO; import static com.android.launcher3.popup.SystemShortcut.INSTALL; import static com.android.launcher3.popup.SystemShortcut.WIDGETS; @@ -120,6 +122,7 @@ import com.android.launcher3.logging.FileLog; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.BgDataModel.Callbacks; +import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.model.ModelUtils; import com.android.launcher3.model.ModelWriter; import com.android.launcher3.model.data.AppInfo; @@ -912,8 +915,8 @@ public class Launcher extends StatefulActivity implements Launche getUserEventDispatcher().startSession(); // Process any items that were added while Launcher was away. - InstallShortcutReceiver.disableAndFlushInstallQueue( - InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this); + ItemInstallQueue.INSTANCE.get(this) + .resumeModelPush(FLAG_ACTIVITY_PAUSED); // Refresh shortcuts if the permission changed. mModel.validateModelDataOnResume(); @@ -1007,7 +1010,7 @@ public class Launcher extends StatefulActivity implements Launche if (state == SPRING_LOADED) { // Prevent any Un/InstallShortcutReceivers from updating the db while we are // not on homescreen - InstallShortcutReceiver.enableInstallQueue(FLAG_DRAG_AND_DROP); + ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_DRAG_AND_DROP); getRotationHelper().setCurrentStateRequest(REQUEST_LOCK); mWorkspace.showPageIndicatorAtCurrentScroll(); @@ -1032,7 +1035,8 @@ public class Launcher extends StatefulActivity implements Launche if (state == NORMAL) { // Re-enable any Un/InstallShortcutReceiver and now process any queued items - InstallShortcutReceiver.disableAndFlushInstallQueue(FLAG_DRAG_AND_DROP, this); + ItemInstallQueue.INSTANCE.get(this) + .resumeModelPush(FLAG_DRAG_AND_DROP); // Clear any rotation locks when going to normal state getRotationHelper().setCurrentStateRequest(REQUEST_NONE); @@ -1066,7 +1070,7 @@ public class Launcher extends StatefulActivity implements Launche @Override protected void onPause() { // Ensure that items added to Launcher are queued until Launcher returns - InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED); + ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_ACTIVITY_PAUSED); super.onPause(); mDragController.cancelDrag(); @@ -2421,8 +2425,8 @@ public class Launcher extends StatefulActivity implements Launche mPendingActivityResult = null; } - InstallShortcutReceiver.disableAndFlushInstallQueue( - InstallShortcutReceiver.FLAG_LOADER_RUNNING, this); + ItemInstallQueue.INSTANCE.get(this) + .resumeModelPush(FLAG_LOADER_RUNNING); // When undoing the removal of the last item on a page, return to that page. // Since we are just resetting the current page without user interaction, @@ -2449,8 +2453,8 @@ public class Launcher extends StatefulActivity implements Launche private ValueAnimator createNewAppBounceAnimation(View v, int i) { ValueAnimator bounceAnim = new PropertyListBuilder().alpha(1).scale(1).build(v) - .setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION); - bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY); + .setDuration(ItemInstallQueue.NEW_SHORTCUT_BOUNCE_DURATION); + bounceAnim.setStartDelay(i * ItemInstallQueue.NEW_SHORTCUT_STAGGER_DELAY); bounceAnim.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION)); return bounceAnim; } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index e2568d5ef6..f306c78d02 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -43,6 +43,7 @@ import com.android.launcher3.model.BaseModelUpdateTask; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.CacheDataUpdatedTask; +import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.model.LoaderResults; import com.android.launcher3.model.LoaderTask; import com.android.launcher3.model.ModelDelegate; @@ -330,7 +331,8 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi */ public boolean startLoader() { // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems - InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING); + ItemInstallQueue.INSTANCE.get(mApp.getContext()) + .pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING); synchronized (mLock) { // Don't bother to start the thread if we know it's not going to do anything final Callbacks[] callbacksList = getCallbacks(); diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java index e48ffb95ea..007e5f5370 100644 --- a/src/com/android/launcher3/SessionCommitReceiver.java +++ b/src/com/android/launcher3/SessionCommitReceiver.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.os.UserHandle; import android.text.TextUtils; +import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.pm.InstallSessionHelper; /** @@ -59,7 +60,8 @@ public class SessionCommitReceiver extends BroadcastReceiver { return; } - InstallShortcutReceiver.queueApplication(info.getAppPackageName(), user, context); + ItemInstallQueue.INSTANCE.get(context) + .queueItem(info.getAppPackageName(), user); } public static boolean isEnabled(Context context) { diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index 0df67133ab..2d625c5373 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -43,13 +43,13 @@ import android.view.View.OnLongClickListener; import android.view.View.OnTouchListener; import com.android.launcher3.BaseActivity; -import com.android.launcher3.InstallShortcutReceiver; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetHost; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.R; +import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.pm.PinRequestHelper; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; @@ -249,7 +249,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener */ public void onPlaceAutomaticallyClick(View v) { if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) { - InstallShortcutReceiver.queueShortcut(mRequest.getShortcutInfo(), this); + ItemInstallQueue.INSTANCE.get(this).queueItem(mRequest.getShortcutInfo()); logCommand(Action.Command.CONFIRM); mRequest.accept(); finish(); @@ -270,7 +270,8 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener } private void acceptWidget(int widgetId) { - InstallShortcutReceiver.queueWidget(mRequest.getAppWidgetProviderInfo(this), widgetId, this); + ItemInstallQueue.INSTANCE.get(this) + .queueItem(mRequest.getAppWidgetProviderInfo(this), widgetId); mWidgetOptions.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); mRequest.accept(mWidgetOptions); logCommand(Action.Command.CONFIRM); diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 140342f98c..7e45021bf3 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -31,7 +31,6 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; -import com.android.launcher3.InstallShortcutReceiver; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Workspace; @@ -298,7 +297,7 @@ public class BgDataModel { .filter(wi -> wi.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) .map(ShortcutKey::fromItemInfo), // Pending shortcuts - InstallShortcutReceiver.getPendingShortcuts(context) + ItemInstallQueue.INSTANCE.get(context).getPendingShortcuts() .stream().filter(si -> si.user.equals(user))) .collect(groupingBy(ShortcutKey::getPackageName, mapping(ShortcutKey::getId, Collectors.toSet()))); diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/model/ItemInstallQueue.java similarity index 81% rename from src/com/android/launcher3/InstallShortcutReceiver.java rename to src/com/android/launcher3/model/ItemInstallQueue.java index d2b05c5b01..6238db3152 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/model/ItemInstallQueue.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.launcher3; +package com.android.launcher3.model; import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID; @@ -42,13 +42,19 @@ import android.util.Pair; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.Utilities; 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.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; +import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.Preconditions; import org.json.JSONException; @@ -63,16 +69,15 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -public class InstallShortcutReceiver { +/** + * Class to maintain a queue of pending items to be added to the workspace. + */ +public class ItemInstallQueue { public static final int FLAG_ACTIVITY_PAUSED = 1; public static final int FLAG_LOADER_RUNNING = 2; public static final int FLAG_DRAG_AND_DROP = 4; - // Determines whether to defer installing shortcuts immediately until - // processAllPendingInstalls() is called. - private static int sInstallQueueDisabledFlags = 0; - private static final String TAG = "InstallShortcutReceiver"; private static final boolean DBG = false; @@ -82,10 +87,23 @@ public class InstallShortcutReceiver { public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450; public static final int NEW_SHORTCUT_STAGGER_DELAY = 85; + public static MainThreadInitializedObject INSTANCE = + new MainThreadInitializedObject<>(ItemInstallQueue::new); + + private final Context mContext; + + // Determines whether to defer installing shortcuts immediately until + // processAllPendingInstalls() is called. + private int mInstallQueueDisabledFlags = 0; + + private ItemInstallQueue(Context context) { + mContext = context; + } + @WorkerThread - private static void addToQueue(Context context, PendingInstallShortcutInfo info) { - String encoded = info.encodeToString(context); - SharedPreferences prefs = Utilities.getPrefs(context); + private void addToQueue(PendingInstallShortcutInfo info) { + String encoded = info.encodeToString(mContext); + SharedPreferences prefs = Utilities.getPrefs(mContext); Set strings = prefs.getStringSet(APPS_PENDING_INSTALL, null); strings = (strings != null) ? new HashSet<>(strings) : new HashSet<>(1); strings.add(encoded); @@ -93,14 +111,15 @@ public class InstallShortcutReceiver { } @WorkerThread - private static void flushQueueInBackground(Context context) { - if (Launcher.ACTIVITY_TRACKER.getCreatedActivity() == null) { + private void flushQueueInBackground() { + Launcher launcher = Launcher.ACTIVITY_TRACKER.getCreatedActivity(); + if (launcher == null) { // Launcher not loaded return; } ArrayList> installQueue = new ArrayList<>(); - SharedPreferences prefs = Utilities.getPrefs(context); + SharedPreferences prefs = Utilities.getPrefs(mContext); Set strings = prefs.getStringSet(APPS_PENDING_INSTALL, null); if (DBG) Log.d(TAG, "Getting and clearing APPS_PENDING_INSTALL: " + strings); if (strings == null) { @@ -108,29 +127,31 @@ public class InstallShortcutReceiver { } for (String encoded : strings) { - PendingInstallShortcutInfo info = decode(encoded, context); + PendingInstallShortcutInfo info = decode(encoded, mContext); if (info == null) { continue; } // Generate a shortcut info to add into the model - installQueue.add(info.getItemInfo(context)); + installQueue.add(info.getItemInfo(mContext)); } prefs.edit().remove(APPS_PENDING_INSTALL).apply(); if (!installQueue.isEmpty()) { - LauncherAppState.getInstance(context).getModel() - .addAndBindAddedWorkspaceItems(installQueue); + launcher.getModel().addAndBindAddedWorkspaceItems(installQueue); } } - public static void removeFromInstallQueue(Context context, HashSet packageNames, - UserHandle user) { + /** + * Removes previously added items from the queue. + */ + @WorkerThread + public void removeFromInstallQueue(HashSet packageNames, UserHandle user) { if (packageNames.isEmpty()) { return; } Preconditions.assertWorkerThread(); - SharedPreferences sp = Utilities.getPrefs(context); + SharedPreferences sp = Utilities.getPrefs(mContext); Set strings = sp.getStringSet(APPS_PENDING_INSTALL, null); if (DBG) { Log.d(TAG, "APPS_PENDING_INSTALL: " + strings @@ -144,7 +165,7 @@ public class InstallShortcutReceiver { while (newStringsIter.hasNext()) { String encoded = newStringsIter.next(); try { - Decoder decoder = new Decoder(encoded, context); + Decoder decoder = new Decoder(encoded, mContext); if (packageNames.contains(getIntentPackage(decoder.intent)) && user.equals(decoder.user)) { newStringsIter.remove(); @@ -157,30 +178,42 @@ public class InstallShortcutReceiver { sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).apply(); } - public static void queueShortcut(ShortcutInfo info, Context context) { - queuePendingShortcutInfo(new PendingInstallShortcutInfo(info), context); + /** + * Adds an item to the install queue + */ + public void queueItem(ShortcutInfo info) { + queuePendingShortcutInfo(new PendingInstallShortcutInfo(info)); } - public static void queueWidget(AppWidgetProviderInfo info, int widgetId, Context context) { - queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, widgetId), context); + /** + * Adds an item to the install queue + */ + public void queueItem(AppWidgetProviderInfo info, int widgetId) { + queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, widgetId)); } - public static void queueApplication( - String packageName, UserHandle userHandle, Context context) { - queuePendingShortcutInfo(new PendingInstallShortcutInfo(packageName, userHandle), context); + /** + * Adds an item to the install queue + */ + public void queueItem(String packageName, UserHandle userHandle) { + queuePendingShortcutInfo(new PendingInstallShortcutInfo(packageName, userHandle)); } - public static HashSet getPendingShortcuts(Context context) { + /** + * Returns all pending shorts in the queue + */ + @WorkerThread + public HashSet getPendingShortcuts() { HashSet result = new HashSet<>(); - Set strings = Utilities.getPrefs(context).getStringSet(APPS_PENDING_INSTALL, null); + Set strings = Utilities.getPrefs(mContext).getStringSet(APPS_PENDING_INSTALL, null); if (strings == null || ((Collection) strings).isEmpty()) { return result; } for (String encoded : strings) { try { - Decoder decoder = new Decoder(encoded, context); + Decoder decoder = new Decoder(encoded, mContext); if (decoder.optInt(Favorites.ITEM_TYPE, -1) == ITEM_TYPE_DEEP_SHORTCUT) { result.add(ShortcutKey.fromIntent(decoder.intent, decoder.user)); } @@ -191,28 +224,35 @@ public class InstallShortcutReceiver { return result; } - private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) { + private void queuePendingShortcutInfo(PendingInstallShortcutInfo info) { // Queue the item up for adding if launcher has not loaded properly yet - MODEL_EXECUTOR.post(() -> addToQueue(context, info)); - flushInstallQueue(context); + MODEL_EXECUTOR.post(() -> addToQueue(info)); + flushInstallQueue(); } - public static void enableInstallQueue(int flag) { - sInstallQueueDisabledFlags |= flag; - } - public static void disableAndFlushInstallQueue(int flag, Context context) { - sInstallQueueDisabledFlags &= ~flag; - flushInstallQueue(context); + /** + * Pauses the push-to-model flow until unpaused. All items are held in the queue and + * not added to the model. + */ + public void pauseModelPush(int flag) { + mInstallQueueDisabledFlags |= flag; } - static void flushInstallQueue(Context context) { - if (sInstallQueueDisabledFlags != 0) { + /** + * Adds all the queue items to the model if the use is completely resumed. + */ + public void resumeModelPush(int flag) { + mInstallQueueDisabledFlags &= ~flag; + flushInstallQueue(); + } + + private void flushInstallQueue() { + if (mInstallQueueDisabledFlags != 0) { return; } - MODEL_EXECUTOR.post(() -> flushQueueInBackground(context)); + MODEL_EXECUTOR.post(this::flushQueueInBackground); } - private static class PendingInstallShortcutInfo extends ItemInfo { final Intent intent; diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index c0ae6f903c..896bfb666e 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -28,7 +28,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.Log; -import com.android.launcher3.InstallShortcutReceiver; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.config.FeatureFlags; @@ -320,7 +319,8 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { deleteAndBindComponentsRemoved(removeMatch); // Remove any queued items from the install queue - InstallShortcutReceiver.removeFromInstallQueue(context, removedPackages, mUser); + ItemInstallQueue.INSTANCE.get(context) + .removeFromInstallQueue(removedPackages, mUser); } if (mOp == OP_ADD) { diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java index d546013fca..753a6dd85e 100644 --- a/src/com/android/launcher3/pm/InstallSessionHelper.java +++ b/src/com/android/launcher3/pm/InstallSessionHelper.java @@ -32,11 +32,11 @@ import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; -import com.android.launcher3.InstallShortcutReceiver; import com.android.launcher3.LauncherSettings; import com.android.launcher3.SessionCommitReceiver; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.LooperExecutor; @@ -213,8 +213,8 @@ public class InstallSessionHelper { && !mPromiseIconIds.contains(sessionInfo.getSessionId()) && new PackageManagerHelper(mAppContext).getApplicationInfo( sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), 0) == null) { - InstallShortcutReceiver.queueApplication( - sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), mAppContext); + ItemInstallQueue.INSTANCE.get(mAppContext) + .queueItem(sessionInfo.getAppPackageName(), getUserHandle(sessionInfo)); mPromiseIconIds.add(sessionInfo.getSessionId()); updatePromiseIconPrefs();