Merge "Separating the config and flags in different directories so that it is easier to override one or the other" into ub-launcher3-master
diff --git a/src/com/android/launcher3/DeferredHandler.java b/src/com/android/launcher3/DeferredHandler.java
deleted file mode 100644
index a43ab67..0000000
--- a/src/com/android/launcher3/DeferredHandler.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.MessageQueue;
-
-import com.android.launcher3.util.Thunk;
-
-import java.util.LinkedList;
-
-/**
- * Queue of things to run on a looper thread.  Items posted with {@link #post} will not
- * be actually enqued on the handler until after the last one has run, to keep from
- * starving the thread.
- *
- * This class is fifo.
- */
-public class DeferredHandler {
-    @Thunk LinkedList<Runnable> mQueue = new LinkedList<>();
-    private MessageQueue mMessageQueue = Looper.myQueue();
-    private Impl mHandler = new Impl();
-
-    @Thunk class Impl extends Handler implements MessageQueue.IdleHandler {
-        public void handleMessage(Message msg) {
-            Runnable r;
-            synchronized (mQueue) {
-                if (mQueue.size() == 0) {
-                    return;
-                }
-                r = mQueue.removeFirst();
-            }
-            r.run();
-            synchronized (mQueue) {
-                scheduleNextLocked();
-            }
-        }
-
-        public boolean queueIdle() {
-            handleMessage(null);
-            return false;
-        }
-    }
-
-    private class IdleRunnable implements Runnable {
-        Runnable mRunnable;
-
-        IdleRunnable(Runnable r) {
-            mRunnable = r;
-        }
-
-        public void run() {
-            mRunnable.run();
-        }
-    }
-
-    public DeferredHandler() {
-    }
-
-    /** Schedule runnable to run after everything that's on the queue right now. */
-    public void post(Runnable runnable) {
-        synchronized (mQueue) {
-            mQueue.add(runnable);
-            if (mQueue.size() == 1) {
-                scheduleNextLocked();
-            }
-        }
-    }
-
-    /** Schedule runnable to run when the queue goes idle. */
-    public void postIdle(final Runnable runnable) {
-        post(new IdleRunnable(runnable));
-    }
-
-    public void cancelAll() {
-        synchronized (mQueue) {
-            mQueue.clear();
-        }
-    }
-
-    /** Runs all queued Runnables from the calling thread. */
-    public void flush() {
-        LinkedList<Runnable> queue = new LinkedList<>();
-        synchronized (mQueue) {
-            queue.addAll(mQueue);
-            mQueue.clear();
-        }
-        for (Runnable r : queue) {
-            r.run();
-        }
-    }
-
-    void scheduleNextLocked() {
-        if (mQueue.size() > 0) {
-            Runnable peek = mQueue.getFirst();
-            if (peek instanceof IdleRunnable) {
-                mMessageQueue.addIdleHandler(mHandler);
-            } else {
-                mHandler.sendEmptyMessage(1);
-            }
-        }
-    }
-}
-
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 4cc1f64..35811d3 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -72,6 +72,7 @@
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.LooperIdleLock;
 import com.android.launcher3.util.ManagedProfileHeuristic;
 import com.android.launcher3.util.MultiHashMap;
 import com.android.launcher3.util.PackageManagerHelper;
@@ -110,9 +111,9 @@
     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
     private static final long INVALID_SCREEN_ID = -1L;
 
+    private final MainThreadExecutor mUiExecutor = new MainThreadExecutor();
     @Thunk final LauncherAppState mApp;
     @Thunk final Object mLock = new Object();
-    @Thunk DeferredHandler mHandler = new DeferredHandler();
     @Thunk LoaderTask mLoaderTask;
     @Thunk boolean mIsLoaderTaskRunning;
     @Thunk boolean mHasLoaderCompletedOnce;
@@ -218,17 +219,6 @@
         mUserManager = UserManagerCompat.getInstance(context);
     }
 
-    /** Runs the specified runnable immediately if called from the main thread, otherwise it is
-     * posted on the main thread handler. */
-    private void runOnMainThread(Runnable r) {
-        if (sWorkerThread.getThreadId() == Process.myTid()) {
-            // If we are on the worker thread, post onto the main handler
-            mHandler.post(r);
-        } else {
-            r.run();
-        }
-    }
-
     /** Runs the specified runnable immediately if called from the worker thread, otherwise it is
      * posted on the worker thread handler. */
     private static void runOnWorkerThread(Runnable r) {
@@ -378,8 +368,6 @@
     public void initialize(Callbacks callbacks) {
         synchronized (mLock) {
             Preconditions.assertUIThread();
-            // Remove any queued UI runnables
-            mHandler.cancelAll();
             mCallbacks = new WeakReference<>(callbacks);
         }
     }
@@ -543,11 +531,11 @@
             if (mCallbacks != null && mCallbacks.get() != null) {
                 final Callbacks oldCallbacks = mCallbacks.get();
                 // Clear any pending bind-runnables from the synchronized load process.
-                runOnMainThread(new Runnable() {
-                    public void run() {
-                        oldCallbacks.clearPendingBinds();
-                    }
-                });
+                mUiExecutor.execute(new Runnable() {
+                            public void run() {
+                                oldCallbacks.clearPendingBinds();
+                            }
+                        });
 
                 // If there is already one running, tell it to stop.
                 stopLoaderLocked();
@@ -598,7 +586,6 @@
 
         @Thunk boolean mIsLoadingAndBindingWorkspace;
         private boolean mStopped;
-        @Thunk boolean mLoadAndBindStepFinished;
 
         LoaderTask(Context context, int pageToBindFirst) {
             mContext = context;
@@ -610,34 +597,10 @@
             // This way we don't start loading all apps until the workspace has settled
             // down.
             synchronized (LoaderTask.this) {
-                final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-
-                mHandler.postIdle(new Runnable() {
-                        public void run() {
-                            synchronized (LoaderTask.this) {
-                                mLoadAndBindStepFinished = true;
-                                if (DEBUG_LOADERS) {
-                                    Log.d(TAG, "done with previous binding step");
-                                }
-                                LoaderTask.this.notify();
-                            }
-                        }
-                    });
-
-                while (!mStopped && !mLoadAndBindStepFinished) {
-                    try {
-                        // Just in case mFlushingWorkerThread changes but we aren't woken up,
-                        // wait no longer than 1sec at a time
-                        this.wait(1000);
-                    } catch (InterruptedException ex) {
-                        // Ignore
-                    }
-                }
-                if (DEBUG_LOADERS) {
-                    Log.d(TAG, "waited "
-                            + (SystemClock.uptimeMillis()-workspaceWaitTime)
-                            + "ms for previous step to finish binding");
-                }
+                LooperIdleLock idleLock = new LooperIdleLock(this, Looper.getMainLooper());
+                // Just in case mFlushingWorkerThread changes but we aren't woken up,
+                // wait no longer than 1sec at a time
+                while (!mStopped && idleLock.awaitLocked(1000));
             }
         }
 
@@ -660,15 +623,6 @@
                 }
             }
 
-            // XXX: Throw an exception if we are already loading (since we touch the worker thread
-            //      data structures, we can't allow any other thread to touch that data, but because
-            //      this call is synchronous, we can get away with not locking).
-
-            // The LauncherModel is static in the LauncherAppState and mHandler may have queued
-            // operations from the previous activity.  We need to ensure that all queued operations
-            // are executed before any synchronous binding work is done.
-            mHandler.flush();
-
             // Divide the set of loaded items into those that we are binding synchronously, and
             // everything else that is to be bound normally (asynchronously).
             bindWorkspace(synchronousBindPage);
@@ -696,6 +650,7 @@
             }
 
             try {
+                long now = 0;
                 if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
                 // Set to false in bindWorkspace()
                 mIsLoadingAndBindingWorkspace = true;
@@ -706,8 +661,12 @@
                 bindWorkspace(mPageToBindFirst);
 
                 // Take a break
-                if (DEBUG_LOADERS) Log.d(TAG, "step 1 completed, wait for idle");
+                if (DEBUG_LOADERS) {
+                    Log.d(TAG, "step 1 completed, wait for idle");
+                    now = SystemClock.uptimeMillis();
+                }
                 waitForIdle();
+                if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms");
                 verifyNotStopped();
 
                 // second step
@@ -719,8 +678,12 @@
                 updateIconCache();
 
                 // Take a break
-                if (DEBUG_LOADERS) Log.d(TAG, "step 2 completed, wait for idle");
+                if (DEBUG_LOADERS) {
+                    Log.d(TAG, "step 2 completed, wait for idle");
+                    now = SystemClock.uptimeMillis();
+                }
                 waitForIdle();
+                if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms");
                 verifyNotStopped();
 
                 // third step
@@ -1433,7 +1396,7 @@
                     }
                 }
             };
-            runOnMainThread(r);
+            mUiExecutor.execute(r);
         }
 
         private void bindWorkspaceItems(final Callbacks oldCallbacks,
@@ -1539,11 +1502,11 @@
                     }
                 }
             };
-            runOnMainThread(r);
+            mUiExecutor.execute(r);
 
             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);
 
-            Executor mainExecutor = new DeferredMainThreadExecutor();
+            Executor mainExecutor = mUiExecutor;
             // Load items on the current page.
             bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets, mainExecutor);
 
@@ -1553,7 +1516,7 @@
             // This ensures that the first screen is immediately visible (eg. during rotation)
             // In case of !validFirstPage, bind all pages one after other.
             final Executor deferredExecutor =
-                    validFirstPage ? new ViewOnDrawExecutor(mHandler) : mainExecutor;
+                    validFirstPage ? new ViewOnDrawExecutor(mUiExecutor) : mainExecutor;
 
             mainExecutor.execute(new Runnable() {
                 @Override
@@ -1613,7 +1576,7 @@
                         }
                     }
                 };
-                runOnMainThread(r);
+                mUiExecutor.execute(r);
             }
         }
 
@@ -1663,7 +1626,7 @@
                     }
                 }
             };
-            runOnMainThread(r);
+            mUiExecutor.execute(r);
         }
 
         private void loadAllApps() {
@@ -1711,21 +1674,21 @@
                             heuristic.processUserApps(apps);
                         }
                     };
-                    runOnMainThread(new Runnable() {
+                    mUiExecutor.execute(new Runnable() {
 
-                        @Override
-                        public void run() {
-                            // Check isLoadingWorkspace on the UI thread, as it is updated on
-                            // the UI thread.
-                            if (mIsLoadingAndBindingWorkspace) {
-                                synchronized (mBindCompleteRunnables) {
-                                    mBindCompleteRunnables.add(r);
-                                }
-                            } else {
-                                runOnWorkerThread(r);
-                            }
-                        }
-                    });
+                                    @Override
+                                    public void run() {
+                                        // Check isLoadingWorkspace on the UI thread, as it is updated on
+                                        // the UI thread.
+                                        if (mIsLoadingAndBindingWorkspace) {
+                                            synchronized (mBindCompleteRunnables) {
+                                                mBindCompleteRunnables.add(r);
+                                            }
+                                        } else {
+                                            runOnWorkerThread(r);
+                                        }
+                                    }
+                                });
                 }
             }
             // Huh? Shouldn't this be inside the Runnable below?
@@ -1733,7 +1696,7 @@
             mBgAllAppsList.added = new ArrayList<AppInfo>();
 
             // Post callback on main thread
-            mHandler.post(new Runnable() {
+            mUiExecutor.execute(new Runnable() {
                 public void run() {
 
                     final long bindTime = SystemClock.uptimeMillis();
@@ -1787,7 +1750,7 @@
                 }
             }
         };
-        runOnMainThread(r);
+        mUiExecutor.execute(r);
     }
 
     /**
@@ -1838,12 +1801,12 @@
     public static abstract class BaseModelUpdateTask implements Runnable {
 
         private LauncherModel mModel;
-        private DeferredHandler mUiHandler;
+        private Executor mUiExecutor;
 
         /* package private */
         void init(LauncherModel model) {
             mModel = model;
-            mUiHandler = mModel.mHandler;
+            mUiExecutor = mModel.mUiExecutor;
         }
 
         @Override
@@ -1866,7 +1829,7 @@
          */
         public final void scheduleCallbackTask(final CallbackTask task) {
             final Callbacks callbacks = mModel.getCallback();
-            mUiHandler.post(new Runnable() {
+            mUiExecutor.execute(new Runnable() {
                 public void run() {
                     Callbacks cb = mModel.getCallback();
                     if (callbacks == cb && cb != null) {
@@ -1911,7 +1874,7 @@
     private void bindWidgetsModel(final Callbacks callbacks) {
         final MultiHashMap<PackageItemInfo, WidgetItem> widgets
                 = mBgWidgetsModel.getWidgetsMap().clone();
-        mHandler.post(new Runnable() {
+        mUiExecutor.execute(new Runnable() {
             @Override
             public void run() {
                 Callbacks cb = getCallback();
@@ -1968,14 +1931,6 @@
         }
     }
 
-    @Thunk class DeferredMainThreadExecutor implements Executor {
-
-        @Override
-        public void execute(Runnable command) {
-            runOnMainThread(command);
-        }
-    }
-
     /**
      * @return the looper for the worker thread which can be used to start background tasks.
      */
diff --git a/src/com/android/launcher3/MainThreadExecutor.java b/src/com/android/launcher3/MainThreadExecutor.java
index 4ca0a59..5094682 100644
--- a/src/com/android/launcher3/MainThreadExecutor.java
+++ b/src/com/android/launcher3/MainThreadExecutor.java
@@ -18,14 +18,14 @@
 
 import android.os.Looper;
 
-import com.android.launcher3.util.LooperExecuter;
+import com.android.launcher3.util.LooperExecutor;
 
 /**
  * An executor service that executes its tasks on the main thread.
  *
  * Shutting down this executor is not supported.
  */
-public class MainThreadExecutor extends LooperExecuter {
+public class MainThreadExecutor extends LooperExecutor {
 
     public MainThreadExecutor() {
         super(Looper.getMainLooper());
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index fe8f0ce..15bdea9 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -770,10 +770,14 @@
         }
         mDragController.removeDropTarget(this);
         clearFocus();
-        if (wasAnimated) {
-            mFolderIcon.requestFocus();
+        if (mFolderIcon != null) {
+            mFolderIcon.setVisibility(View.VISIBLE);
+            if (wasAnimated) {
+                mFolderIcon.requestFocus();
+            }
         }
 
+
         if (mRearrangeOnClose) {
             rearrangeChildren();
             mRearrangeOnClose = false;
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index d14bb40..9ce1c57 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -135,12 +135,6 @@
     public AnimatorSet getClosingAnimator() {
         AnimatorSet a = getAnimatorSet(false /* isOpening */);
         a.setInterpolator(mClosingInterpolator);
-        a.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mFolderIcon.setVisibility(View.VISIBLE);
-            }
-        });
         return a;
     }
 
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 4931dca..032ed78 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -34,7 +34,7 @@
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.LooperExecuter;
+import com.android.launcher3.util.LooperExecutor;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -55,7 +55,7 @@
     public ModelWriter(Context context, BgDataModel dataModel, boolean hasVerticalHotseat) {
         mContext = context;
         mBgDataModel = dataModel;
-        mWorkerExecutor = new LooperExecuter(LauncherModel.getWorkerLooper());
+        mWorkerExecutor = new LooperExecutor(LauncherModel.getWorkerLooper());
         mHasVerticalHotseat = hasVerticalHotseat;
     }
 
diff --git a/src/com/android/launcher3/util/LooperExecuter.java b/src/com/android/launcher3/util/LooperExecutor.java
similarity index 94%
rename from src/com/android/launcher3/util/LooperExecuter.java
rename to src/com/android/launcher3/util/LooperExecutor.java
index 4db999b..5b7c20b 100644
--- a/src/com/android/launcher3/util/LooperExecuter.java
+++ b/src/com/android/launcher3/util/LooperExecutor.java
@@ -25,11 +25,11 @@
 /**
  * Extension of {@link AbstractExecutorService} which executed on a provided looper.
  */
-public class LooperExecuter extends AbstractExecutorService {
+public class LooperExecutor extends AbstractExecutorService {
 
     private final Handler mHandler;
 
-    public LooperExecuter(Looper looper) {
+    public LooperExecutor(Looper looper) {
         mHandler = new Handler(looper);
     }
 
diff --git a/src/com/android/launcher3/util/LooperIdleLock.java b/src/com/android/launcher3/util/LooperIdleLock.java
new file mode 100644
index 0000000..35cac14
--- /dev/null
+++ b/src/com/android/launcher3/util/LooperIdleLock.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 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.util;
+
+import android.os.Looper;
+import android.os.MessageQueue;
+
+import com.android.launcher3.Utilities;
+
+/**
+ * Utility class to block execution until the UI looper is idle.
+ */
+public class LooperIdleLock implements MessageQueue.IdleHandler, Runnable {
+
+    private final Object mLock;
+
+    private boolean mIsLocked;
+
+    public LooperIdleLock(Object lock, Looper looper) {
+        mLock = lock;
+        mIsLocked = true;
+        if (Utilities.ATLEAST_MARSHMALLOW) {
+            looper.getQueue().addIdleHandler(this);
+        } else {
+            // Looper.myQueue() only gives the current queue. Move the execution to the UI thread
+            // so that the IdleHandler is attached to the correct message queue.
+            new LooperExecutor(looper).execute(this);
+        }
+    }
+
+    @Override
+    public void run() {
+        Looper.myQueue().addIdleHandler(this);
+    }
+
+    @Override
+    public boolean queueIdle() {
+        synchronized (mLock) {
+            mIsLocked = false;
+            mLock.notify();
+        }
+        return false;
+    }
+
+    public boolean awaitLocked(long ms) {
+        if (mIsLocked) {
+            try {
+                // Just in case mFlushingWorkerThread changes but we aren't woken up,
+                // wait no longer than 1sec at a time
+                mLock.wait(ms);
+            } catch (InterruptedException ex) {
+                // Ignore
+            }
+        }
+        return mIsLocked;
+    }
+}
diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
index 9bd2882..4cb6ca8 100644
--- a/src/com/android/launcher3/util/ViewOnDrawExecutor.java
+++ b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
@@ -16,12 +16,10 @@
 
 package com.android.launcher3.util;
 
-import android.util.Log;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewTreeObserver.OnDrawListener;
 
-import com.android.launcher3.DeferredHandler;
 import com.android.launcher3.Launcher;
 
 import java.util.ArrayList;
@@ -34,7 +32,7 @@
         OnAttachStateChangeListener {
 
     private final ArrayList<Runnable> mTasks = new ArrayList<>();
-    private final DeferredHandler mHandler;
+    private final Executor mExecutor;
 
     private Launcher mLauncher;
     private View mAttachedView;
@@ -43,8 +41,8 @@
     private boolean mLoadAnimationCompleted;
     private boolean mFirstDrawCompleted;
 
-    public ViewOnDrawExecutor(DeferredHandler handler) {
-        mHandler = handler;
+    public ViewOnDrawExecutor(Executor executor) {
+        mExecutor = executor;
     }
 
     public void attachTo(Launcher launcher) {
@@ -92,7 +90,7 @@
         // Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called.
         if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) {
             for (final Runnable r : mTasks) {
-                mHandler.post(r);
+                mExecutor.execute(r);
             }
             markCompleted();
         }
diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index 2ad3cba..13e0986 100644
--- a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -16,7 +16,6 @@
 import com.android.launcher3.AllAppsList;
 import com.android.launcher3.AppFilter;
 import com.android.launcher3.AppInfo;
-import com.android.launcher3.DeferredHandler;
 import com.android.launcher3.IconCache;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.ItemInfo;
@@ -36,6 +35,7 @@
 import java.lang.reflect.Field;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Mockito.atLeast;
@@ -102,14 +102,14 @@
         f.setAccessible(true);
         f.set(task, mockModel);
 
-        DeferredHandler mockHandler = mock(DeferredHandler.class);
-        f = BaseModelUpdateTask.class.getDeclaredField("mUiHandler");
+        Executor mockExecutor = mock(Executor.class);
+        f = BaseModelUpdateTask.class.getDeclaredField("mUiExecutor");
         f.setAccessible(true);
-        f.set(task, mockHandler);
+        f.set(task, mockExecutor);
 
         task.execute(appState, bgDataModel, allAppsList);
         ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
-        verify(mockHandler, atLeast(0)).post(captor.capture());
+        verify(mockExecutor, atLeast(0)).execute(captor.capture());
 
         return captor.getAllValues();
     }
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index df2b662..97f7b50 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -39,13 +39,12 @@
 import com.android.launcher3.compat.PackageInstallerCompat;
 import com.android.launcher3.ui.LauncherInstrumentationTestCase;
 import com.android.launcher3.util.ContentWriter;
-import com.android.launcher3.util.LooperExecuter;
+import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
 import com.android.launcher3.widget.WidgetHostViewLoader;
 
 import java.util.Set;
 import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -340,7 +339,7 @@
      * Blocks the current thread until all the jobs in the main worker thread are complete.
      */
     private void waitUntilLoaderIdle() throws Exception {
-        new LooperExecuter(LauncherModel.getWorkerLooper())
+        new LooperExecutor(LauncherModel.getWorkerLooper())
                 .submit(new Runnable() {
                     @Override
                     public void run() { }