Fixing bindAllApplications scheduled with null list.

When deferring bindAllApplications, the same global state was being
used to store the pending state. This global state was being cleared
in one deferred execution after a second execution was scheduled, causing
the second execution to get null/wrong values.

Instead using independent local/anonymous class to maintian states, so that
it does not get cleared by other methods.

Bug: 64789383
Change-Id: I78477a110fe663603b4bdeb7d1fac7c4ce0831a2
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 28b4482..e229d6c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -119,6 +119,7 @@
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
 import com.android.launcher3.util.ActivityResultInfo;
+import com.android.launcher3.util.RunnableWithId;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.MultiHashMap;
@@ -146,6 +147,9 @@
 import java.util.Set;
 import java.util.concurrent.Executor;
 
+import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_APPS;
+import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_WIDGETS;
+
 /**
  * Default launcher application.
  */
@@ -246,7 +250,6 @@
 
     // Main container view and the model for the widget tray screen.
     @Thunk WidgetsContainerView mWidgetsView;
-    @Thunk MultiHashMap<PackageItemInfo, WidgetItem> mAllWidgets;
 
     // We set the state in both onCreate and then onNewIntent in some cases, which causes both
     // scroll issues (because the workspace may not have been measured yet) and extra work.
@@ -3113,12 +3116,12 @@
      *
      * @return {@code true} if we are currently paused. The caller might be able to skip some work
      */
-    @Thunk boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
+    @Thunk boolean waitUntilResume(Runnable run) {
         if (mPaused) {
             if (LOGD) Log.d(TAG, "Deferring update until onResume");
-            if (deletePreviousRunnables) {
-                while (mBindOnResumeCallbacks.remove(run)) {
-                }
+            if (run instanceof RunnableWithId) {
+                // Remove any runnables which have the same id
+                while (mBindOnResumeCallbacks.remove(run)) { }
             }
             mBindOnResumeCallbacks.add(run);
             return true;
@@ -3127,10 +3130,6 @@
         }
     }
 
-    private boolean waitUntilResume(Runnable run) {
-        return waitUntilResume(run, false);
-    }
-
     public void addOnResumeCallback(Runnable run) {
         mOnResumeCallbacks.add(run);
     }
@@ -3664,25 +3663,17 @@
     }
 
     /**
-     * A runnable that we can dequeue and re-enqueue when all applications are bound (to prevent
-     * multiple calls to bind the same list.)
-     */
-    @Thunk ArrayList<AppInfo> mTmpAppsList;
-    private final Runnable mBindAllApplicationsRunnable = new Runnable() {
-        public void run() {
-            bindAllApplications(mTmpAppsList);
-            mTmpAppsList = null;
-        }
-    };
-
-    /**
      * Add the icons for all apps.
      *
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void bindAllApplications(final ArrayList<AppInfo> apps) {
-        if (waitUntilResume(mBindAllApplicationsRunnable, true)) {
-            mTmpAppsList = apps;
+        Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_APPS) {
+            public void run() {
+                bindAllApplications(apps);
+            }
+        };
+        if (waitUntilResume(r)) {
             return;
         }
 
@@ -3690,10 +3681,10 @@
             Executor pendingExecutor = getPendingExecutor();
             if (pendingExecutor != null && mState != State.APPS) {
                 // Wait until the fade in animation has finished before setting all apps list.
-                mTmpAppsList = apps;
-                pendingExecutor.execute(mBindAllApplicationsRunnable);
+                pendingExecutor.execute(r);
                 return;
             }
+
             mAppsView.setApps(apps);
         }
         if (mLauncherCallbacks != null) {
@@ -3887,28 +3878,25 @@
         }
     }
 
-    private final Runnable mBindAllWidgetsRunnable = new Runnable() {
+    @Override
+    public void bindAllWidgets(final MultiHashMap<PackageItemInfo, WidgetItem> allWidgets) {
+        Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_WIDGETS) {
+            @Override
             public void run() {
-                bindAllWidgets(mAllWidgets);
+                bindAllWidgets(allWidgets);
             }
         };
-
-    @Override
-    public void bindAllWidgets(MultiHashMap<PackageItemInfo, WidgetItem> allWidgets) {
-        if (waitUntilResume(mBindAllWidgetsRunnable, true)) {
-            mAllWidgets = allWidgets;
+        if (waitUntilResume(r)) {
             return;
         }
 
         if (mWidgetsView != null && allWidgets != null) {
             Executor pendingExecutor = getPendingExecutor();
             if (pendingExecutor != null && mState != State.WIDGETS) {
-                mAllWidgets = allWidgets;
-                pendingExecutor.execute(mBindAllWidgetsRunnable);
+                pendingExecutor.execute(r);
                 return;
             }
             mWidgetsView.setWidgets(allWidgets);
-            mAllWidgets = null;
         }
 
         AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);