Merge "No more waiting around for resume" into ub-launcher3-master
diff --git a/res/drawable/bg_deferred_app_widget.xml b/res/drawable/bg_deferred_app_widget.xml
new file mode 100644
index 0000000..07bae48
--- /dev/null
+++ b/res/drawable/bg_deferred_app_widget.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2015, 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.
+*/
+-->
+
+<inset
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:inset="8dp">
+    <color android:color="#77000000" />
+</inset>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 1e95333..7648e30 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -19,6 +19,7 @@
 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.util.FocusLogic;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 public class AppWidgetResizeFrame extends AbstractFloatingView implements View.OnKeyListener {
     private static final int SNAP_DURATION = 150;
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 01b6ca9..4087df1 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -60,6 +60,7 @@
 import com.android.launcher3.util.ParcelableSparseArray;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 44660ec..9eaa6c7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -29,8 +29,6 @@
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
-import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_APPS;
-import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_WIDGETS;
 
 import android.Manifest;
 import android.animation.Animator;
@@ -127,15 +125,16 @@
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.PendingRequestArgs;
-import com.android.launcher3.util.RunnableWithId;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.util.UiThreadHelper;
 import com.android.launcher3.util.ViewOnDrawExecutor;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
 import com.android.launcher3.widget.WidgetAddFlowHandler;
 import com.android.launcher3.widget.WidgetHostViewLoader;
 import com.android.launcher3.widget.WidgetListRowEntry;
@@ -237,9 +236,7 @@
     @Thunk boolean mWorkspaceLoading = true;
 
     private boolean mPaused = true;
-    private boolean mOnResumeNeedsLoad;
 
-    private final ArrayList<Runnable> mBindOnResumeCallbacks = new ArrayList<>();
     private OnResumeCallback mOnResumeCallback;
 
     private ViewOnDrawExecutor mPendingExecutor;
@@ -811,20 +808,6 @@
         mAppLaunchSuccess = false;
         getUserEventDispatcher().resetElapsedSessionMillis();
         mPaused = false;
-        if (mOnResumeNeedsLoad) {
-            setWorkspaceLoading(true);
-            mModel.startLoader(getCurrentWorkspaceScreen());
-            mOnResumeNeedsLoad = false;
-        }
-        if (mBindOnResumeCallbacks.size() > 0) {
-            // We might have postponed some bind calls until onResume (see waitUntilResume) --
-            // execute them here
-            for (int i = 0; i < mBindOnResumeCallbacks.size(); i++) {
-                mBindOnResumeCallbacks.get(i).run();
-            }
-            mBindOnResumeCallbacks.clear();
-        }
-
         setOnResumeCallback(null);
         // Process any items that were added while Launcher was away.
         InstallShortcutReceiver.disableAndFlushInstallQueue(
@@ -1161,20 +1144,12 @@
     };
 
     public void updateIconBadges(final Set<PackageUserKey> updatedBadges) {
-        Runnable r = new Runnable() {
-            @Override
-            public void run() {
-                mWorkspace.updateIconBadges(updatedBadges);
-                mAppsView.updateIconBadges(updatedBadges);
+        mWorkspace.updateIconBadges(updatedBadges);
+        mAppsView.updateIconBadges(updatedBadges);
 
-                PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(Launcher.this);
-                if (popup != null) {
-                    popup.updateNotificationHeader(updatedBadges);
-                }
-            }
-        };
-        if (!waitUntilResume(r)) {
-            r.run();
+        PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(Launcher.this);
+        if (popup != null) {
+            popup.updateNotificationHeader(updatedBadges);
         }
     }
 
@@ -2156,33 +2131,6 @@
         return result;
     }
 
-    /**
-     * If the activity is currently paused, signal that we need to run the passed Runnable
-     * in onResume.
-     *
-     * This needs to be called from incoming places where resources might have been loaded
-     * while the activity is paused. That is because the Configuration (e.g., rotation)  might be
-     * wrong when we're not running, and if the activity comes back to what the configuration was
-     * when we were paused, activity is not restarted.
-     *
-     * Implementation of the method from LauncherModel.Callbacks.
-     *
-     * @return {@code true} if we are currently paused. The caller might be able to skip some work
-     */
-    @Thunk boolean waitUntilResume(Runnable run) {
-        if (mPaused) {
-            if (LOGD) Log.d(TAG, "Deferring update until onResume");
-            if (run instanceof RunnableWithId) {
-                // Remove any runnables which have the same id
-                while (mBindOnResumeCallbacks.remove(run)) { }
-            }
-            mBindOnResumeCallbacks.add(run);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
     public void setOnResumeCallback(OnResumeCallback callback) {
         if (mOnResumeCallback != null) {
             mOnResumeCallback.onLauncherResume();
@@ -2191,31 +2139,6 @@
     }
 
     /**
-     * If the activity is currently paused, signal that we need to re-run the loader
-     * in onResume.
-     *
-     * This needs to be called from incoming places where resources might have been loaded
-     * while we are paused.  That is becaues the Configuration might be wrong
-     * when we're not running, and if it comes back to what it was when we
-     * were paused, we are not restarted.
-     *
-     * Implementation of the method from LauncherModel.Callbacks.
-     *
-     * @return true if we are currently paused.  The caller might be able to
-     * skip some work in that case since we will come back again.
-     */
-    @Override
-    public boolean setLoadOnResume() {
-        if (mPaused) {
-            if (LOGD) Log.d(TAG, "setLoadOnResume");
-            mOnResumeNeedsLoad = true;
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
      * Implementation of the method from LauncherModel.Callbacks.
      */
     @Override
@@ -2233,7 +2156,6 @@
      */
     @Override
     public void clearPendingBinds() {
-        mBindOnResumeCallbacks.clear();
         if (mPendingExecutor != null) {
             mPendingExecutor.markCompleted();
             mPendingExecutor = null;
@@ -2297,18 +2219,8 @@
     }
 
     @Override
-    public void bindAppsAdded(final ArrayList<Long> newScreens,
-                              final ArrayList<ItemInfo> addNotAnimated,
-                              final ArrayList<ItemInfo> addAnimated) {
-        Runnable r = new Runnable() {
-            public void run() {
-                bindAppsAdded(newScreens, addNotAnimated, addAnimated);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
-
+    public void bindAppsAdded(ArrayList<Long> newScreens, ArrayList<ItemInfo> addNotAnimated,
+            ArrayList<ItemInfo> addAnimated) {
         // Add the new screens
         if (newScreens != null) {
             bindAddScreens(newScreens);
@@ -2334,15 +2246,6 @@
      */
     @Override
     public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {
-        Runnable r = new Runnable() {
-            public void run() {
-                bindItems(items, forceAnimateIcons);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
-
         // Get the list of added items and intersect them with the set of items here
         final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
         final Collection<Animator> bounceAnims = new ArrayList<>();
@@ -2585,7 +2488,7 @@
         }
 
         if (((PendingAppWidgetHostView) view).isReinflateIfNeeded()) {
-            view.reinflate();
+            view.reInflate();
         }
 
         getModelWriter().updateItemInDatabase(info);
@@ -2613,27 +2516,11 @@
 
     @Override
     public void finishFirstPageBind(final ViewOnDrawExecutor executor) {
-        Runnable r = new Runnable() {
-            public void run() {
-                finishFirstPageBind(executor);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
-
-        Runnable onComplete = new Runnable() {
-            @Override
-            public void run() {
-                if (executor != null) {
-                    executor.onLoadAnimationCompleted();
-                }
-            }
-        };
         if (mDragLayer.getAlpha() < 1) {
-            mDragLayer.animate().alpha(1).withEndAction(onComplete).start();
-        } else {
-            onComplete.run();
+            mDragLayer.animate().alpha(1).withEndAction(
+                    executor == null ? null : executor::onLoadAnimationCompleted).start();
+        } else if (executor != null) {
+            executor.onLoadAnimationCompleted();
         }
     }
 
@@ -2643,10 +2530,6 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void finishBindingItems() {
-        Runnable r = this::finishBindingItems;
-        if (waitUntilResume(r)) {
-            return;
-        }
         TraceHelper.beginSection("finishBindingItems");
         mWorkspace.restoreInstanceStateForRemainingPages();
 
@@ -2687,21 +2570,12 @@
      *
      * Implementation of the method from LauncherModel.Callbacks.
      */
-    public void bindAllApplications(final ArrayList<AppInfo> apps) {
-        Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_APPS) {
-            public void run() {
-                bindAllApplications(apps);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
-
+    public void bindAllApplications(ArrayList<AppInfo> apps) {
         if (mAppsView != null) {
             Executor pendingExecutor = getPendingExecutor();
             if (pendingExecutor != null && !isInState(ALL_APPS)) {
                 // Wait until the fade in animation has finished before setting all apps list.
-                pendingExecutor.execute(r);
+                pendingExecutor.execute(() -> bindAllApplications(apps));
                 return;
             }
 
@@ -2734,47 +2608,22 @@
      *
      * Implementation of the method from LauncherModel.Callbacks.
      */
-    public void bindAppsAddedOrUpdated(final ArrayList<AppInfo> apps) {
-        Runnable r = new Runnable() {
-            public void run() {
-                bindAppsAddedOrUpdated(apps);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
-
+    @Override
+    public void bindAppsAddedOrUpdated(ArrayList<AppInfo> apps) {
         if (mAppsView != null) {
             mAppsView.addOrUpdateApps(apps);
         }
     }
 
     @Override
-    public void bindPromiseAppProgressUpdated(final PromiseAppInfo app) {
-        Runnable r = new Runnable() {
-            public void run() {
-                bindPromiseAppProgressUpdated(app);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
-
+    public void bindPromiseAppProgressUpdated(PromiseAppInfo app) {
         if (mAppsView != null) {
             mAppsView.updatePromiseAppProgress(app);
         }
     }
 
     @Override
-    public void bindWidgetsRestored(final ArrayList<LauncherAppWidgetInfo> widgets) {
-        Runnable r = new Runnable() {
-            public void run() {
-                bindWidgetsRestored(widgets);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
+    public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) {
         mWorkspace.widgetsRestored(widgets);
     }
 
@@ -2785,16 +2634,7 @@
      * @param updated list of shortcuts which have changed.
      */
     @Override
-    public void bindShortcutsChanged(final ArrayList<ShortcutInfo> updated, final UserHandle user) {
-        Runnable r = new Runnable() {
-            public void run() {
-                bindShortcutsChanged(updated, user);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
-
+    public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated, final UserHandle user) {
         if (!updated.isEmpty()) {
             mWorkspace.updateShortcuts(updated);
         }
@@ -2806,16 +2646,7 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     @Override
-    public void bindRestoreItemsChange(final HashSet<ItemInfo> updates) {
-        Runnable r = new Runnable() {
-            public void run() {
-                bindRestoreItemsChange(updates);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
-
+    public void bindRestoreItemsChange(HashSet<ItemInfo> updates) {
         mWorkspace.updateRestoreItems(updates);
     }
 
@@ -2828,29 +2659,12 @@
      */
     @Override
     public void bindWorkspaceComponentsRemoved(final ItemInfoMatcher matcher) {
-        Runnable r = new Runnable() {
-            public void run() {
-                bindWorkspaceComponentsRemoved(matcher);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
         mWorkspace.removeItemsByMatcher(matcher);
         mDragController.onAppsRemoved(matcher);
     }
 
     @Override
     public void bindAppInfosRemoved(final ArrayList<AppInfo> appInfos) {
-        Runnable r = new Runnable() {
-            public void run() {
-                bindAppInfosRemoved(appInfos);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
-
         // Update AllApps
         if (mAppsView != null) {
             mAppsView.removeApps(appInfos);
@@ -2860,16 +2674,6 @@
     @Override
     public void bindAllWidgets(final ArrayList<WidgetListRowEntry> allWidgets) {
         mPopupDataProvider.setAllWidgets(allWidgets);
-        Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_WIDGETS) {
-            @Override
-            public void run() {
-                bindAllWidgets(allWidgets);
-            }
-        };
-        if (waitUntilResume(r)) {
-            return;
-        }
-
         AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
         if (topView != null) {
             topView.onWidgetsBound();
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 0136c70..a46692b 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -27,6 +27,7 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.PackageInstallerCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.notification.NotificationListener;
 import com.android.launcher3.util.ConfigMonitor;
 import com.android.launcher3.util.Preconditions;
@@ -39,6 +40,8 @@
 
 public class LauncherAppState {
 
+    public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher";
+
     // We do not need any synchronization for this variable as its only written on UI thread.
     private static LauncherAppState INSTANCE;
 
@@ -103,6 +106,10 @@
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
 
+        if (FeatureFlags.IS_DOGFOOD_BUILD) {
+            filter.addAction(ACTION_FORCE_ROLOAD);
+        }
+
         mContext.registerReceiver(mModel, filter);
         UserManagerCompat.getInstance(mContext).enableAndResetCache();
         new ConfigMonitor(mContext).register();
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 9aa74b3..7bc7139 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -26,11 +26,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
+import android.util.Log;
 import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.widget.Toast;
 
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.widget.DeferredAppWidgetHostView;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 import java.util.ArrayList;
 
@@ -84,6 +87,14 @@
             // have been established by this point, and we will end up populating the
             // widgets upon bind anyway. See issue 14255011 for more context.
         }
+
+        // We go in reverse order and inflate any deferred widget
+        for (int i = mViews.size() - 1; i >= 0; i--) {
+            LauncherAppWidgetHostView view = mViews.valueAt(i);
+            if (view instanceof DeferredAppWidgetHostView) {
+                view.reInflate();
+            }
+        }
     }
 
     @Override
@@ -178,6 +189,11 @@
             inflater.inflate(appWidget.initialLayout, lahv);
             lahv.setAppWidget(0, appWidget);
             return lahv;
+        } else if ((mFlags & FLAG_LISTENING) == 0) {
+            DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context);
+            view.setAppWidget(appWidgetId, appWidget);
+            mViews.put(appWidgetId, view);
+            return view;
         } else {
             try {
                 return super.createView(context, appWidgetId, appWidget);
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 469c5f1..35bf9e9 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -16,6 +16,9 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
+import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
+
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProviderOperation;
@@ -37,6 +40,7 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.LauncherIcons;
 import com.android.launcher3.model.AddWorkspaceItemsTask;
 import com.android.launcher3.model.BgDataModel;
@@ -135,7 +139,6 @@
     };
 
     public interface Callbacks {
-        public boolean setLoadOnResume();
         public int getCurrentWorkspaceScreen();
         public void clearPendingBinds();
         public void startBinding();
@@ -405,6 +408,8 @@
                     enqueueModelUpdateTask(new UserLockStateChangedTask(user));
                 }
             }
+        } else if (IS_DOGFOOD_BUILD && ACTION_FORCE_ROLOAD.equals(action)) {
+            forceReload();
         }
     }
 
@@ -419,25 +424,11 @@
             mModelLoaded = false;
         }
 
-        // Do this here because if the launcher activity is running it will be restarted.
-        // If it's not running startLoaderFromBackground will merely tell it that it needs
-        // to reload.
-        startLoaderFromBackground();
-    }
-
-    /**
-     * When the launcher is in the background, it's possible for it to miss paired
-     * configuration changes.  So whenever we trigger the loader from the background
-     * tell the launcher that it needs to re-run the loader when it comes back instead
-     * of doing it now.
-     */
-    public void startLoaderFromBackground() {
+        // Start the loader if launcher is already running, otherwise the loader will run,
+        // the next time launcher starts
         Callbacks callbacks = getCallback();
         if (callbacks != null) {
-            // Only actually run the loader if they're not paused.
-            if (!callbacks.setLoadOnResume()) {
-                startLoader(callbacks.getCurrentWorkspaceScreen());
-            }
+            startLoader(callbacks.getCurrentWorkspaceScreen());
         }
     }
 
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 841c0cd..1a63326 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -23,6 +23,7 @@
 import android.view.ViewGroup;
 
 import com.android.launcher3.CellLayout.ContainerType;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 public class ShortcutAndWidgetContainer extends ViewGroup {
     static final String TAG = "ShortcutAndWidgetContainer";
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 417366d..efafb9c 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -88,8 +88,10 @@
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.WallpaperOffsetInterpolator;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -3510,7 +3512,7 @@
                 return false;
             });
             for (PendingAppWidgetHostView view : views) {
-                view.reinflate();
+                view.reInflate();
             }
         }
 
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 512db72..3b6fea9 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -21,20 +21,17 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.ButtonDropTarget;
 import com.android.launcher3.CellLayout;
-import com.android.launcher3.DeleteDropTarget;
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.FolderInfo;
-import com.android.launcher3.InfoDropTarget;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.LauncherAppWidgetInfo;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.UninstallDropTarget;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragController.DragListener;
 import com.android.launcher3.dragndrop.DragOptions;
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 902906f..6a328e9 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -31,7 +31,7 @@
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
diff --git a/src/com/android/launcher3/util/RunnableWithId.java b/src/com/android/launcher3/util/RunnableWithId.java
deleted file mode 100644
index 030eb09..0000000
--- a/src/com/android/launcher3/util/RunnableWithId.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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;
-
-/**
- * A runnable with an id associated which is used for equality check.
- */
-public abstract class RunnableWithId implements Runnable {
-
-    public static final int RUNNABLE_ID_BIND_APPS = 1;
-    public static final int RUNNABLE_ID_BIND_WIDGETS = 2;
-
-    public final int id;
-
-    public RunnableWithId(int id) {
-        this.id = id;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        return obj instanceof RunnableWithId && ((RunnableWithId) obj).id == id;
-    }
-}
diff --git a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
new file mode 100644
index 0000000..37e5efcb
--- /dev/null
+++ b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
@@ -0,0 +1,83 @@
+/*
+ * 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.widget;
+
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.text.Layout;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.util.TypedValue;
+import android.widget.RemoteViews;
+
+import com.android.launcher3.R;
+
+/**
+ * A widget host views created while the host has not bind to the system service.
+ */
+public class DeferredAppWidgetHostView extends LauncherAppWidgetHostView {
+
+    private final TextPaint mPaint;
+    private Layout mSetupTextLayout;
+
+    public DeferredAppWidgetHostView(Context context) {
+        super(context);
+        setWillNotDraw(false);
+
+        mPaint = new TextPaint();
+        mPaint.setColor(Color.WHITE);
+        mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
+                mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
+        setBackgroundResource(R.drawable.bg_deferred_app_widget);
+    }
+
+    @Override
+    public void updateAppWidget(RemoteViews remoteViews) {
+        // Not allowed
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        AppWidgetProviderInfo info = getAppWidgetInfo();
+        if (info == null || TextUtils.isEmpty(info.label)) {
+            return;
+        }
+
+        // Use double padding so that there is extra space between background and text
+        int availableWidth = getMeasuredWidth() - 2 * (getPaddingLeft() + getPaddingRight());
+        if (mSetupTextLayout != null && mSetupTextLayout.getText().equals(info.label)
+                && mSetupTextLayout.getWidth() == availableWidth) {
+            return;
+        }
+        mSetupTextLayout = new StaticLayout(info.label, mPaint, availableWidth,
+                Layout.Alignment.ALIGN_CENTER, 1, 0, true);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mSetupTextLayout != null) {
+            canvas.translate(getPaddingLeft() * 2,
+                    (getHeight() - mSetupTextLayout.getHeight()) / 2);
+            mSetupTextLayout.draw(canvas);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
similarity index 92%
rename from src/com/android/launcher3/LauncherAppWidgetHostView.java
rename to src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 6f953e5..0b1474a 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.launcher3;
+package com.android.launcher3.widget;
 
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
@@ -37,6 +37,15 @@
 import android.widget.Advanceable;
 import android.widget.RemoteViews;
 
+import com.android.launcher3.CheckLongPressHelper;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.SimpleOnStylusPressListener;
+import com.android.launcher3.StylusEventHelper;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragLayer.TouchCompleteListener;
 
@@ -59,14 +68,10 @@
 
     private final CheckLongPressHelper mLongPressHelper;
     private final StylusEventHelper mStylusEventHelper;
-    private final Launcher mLauncher;
-
-    private static final int DONT_REINFLATE = 0;
-    private static final int REINFLATE_ON_RESUME = 1;
-    private static final int REINFLATE_ON_CONFIG_CHANGE = 2;
+    protected final Launcher mLauncher;
 
     @ViewDebug.ExportedProperty(category = "launcher")
-    private int mReinflateStatus;
+    private boolean mReinflateOnConfigChange;
 
     private float mSlop;
 
@@ -128,12 +133,7 @@
         // Consequently, the widgets will be inflated for the orientation of the foreground activity
         // (framework issue). On resuming, we ensure that any widgets are inflated for the current
         // orientation.
-        if (mReinflateStatus == DONT_REINFLATE && !isSameOrientation()) {
-            mReinflateStatus = REINFLATE_ON_RESUME;
-            if (!mLauncher.waitUntilResume(new ReInflateRunnable())) {
-                mReinflateStatus = REINFLATE_ON_CONFIG_CHANGE;
-            }
-        }
+        mReinflateOnConfigChange = !isSameOrientation();
     }
 
     private boolean isSameOrientation() {
@@ -485,40 +485,20 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
 
-        if (mReinflateStatus == REINFLATE_ON_CONFIG_CHANGE) {
-            // We are finally in the same orientation
-            reinflateIfNecessary();
+        // Only reinflate when the final configuration is same as the required configuration
+        if (mReinflateOnConfigChange && isSameOrientation()) {
+            mReinflateOnConfigChange = false;
+            if (isAttachedToWindow()) {
+                reInflate();
+            }
         }
     }
 
-    private void reinflateIfNecessary() {
-        if (!isSameOrientation()) {
-            // We cannot reinflate yet, wait until next config change
-            mReinflateStatus = REINFLATE_ON_CONFIG_CHANGE;
-            return;
-        }
-
-        mReinflateStatus = DONT_REINFLATE;
-        if (isAttachedToWindow()) {
-            LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
-            reinflate();
-        }
-    }
-
-    public void reinflate() {
+    public void reInflate() {
         LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
         // Remove and rebind the current widget (which was inflated in the wrong
         // orientation), but don't delete it from the database
         mLauncher.removeItem(this, info, false  /* deleteFromDb */);
         mLauncher.bindAppWidget(info);
     }
-
-    private class ReInflateRunnable implements Runnable {
-        @Override
-        public void run() {
-            if (mReinflateStatus == REINFLATE_ON_RESUME) {
-                reinflateIfNecessary();
-            }
-        }
-    }
 }
diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
similarity index 96%
rename from src/com/android/launcher3/PendingAppWidgetHostView.java
rename to src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index b86d413..24bcebb 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.launcher3;
+package com.android.launcher3.widget;
 
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -32,10 +32,19 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.IconCache;
 import com.android.launcher3.IconCache.ItemInfoUpdateReceiver;
+import com.android.launcher3.ItemInfoWithIcon;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.graphics.DrawableFactory;
 import com.android.launcher3.model.PackageItemInfo;
 import com.android.launcher3.util.Themes;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
         implements OnClickListener, ItemInfoUpdateReceiver {
@@ -48,7 +57,6 @@
     private final LauncherAppWidgetInfo mInfo;
     private final int mStartState;
     private final boolean mDisabledForSafeMode;
-    private Launcher mLauncher;
 
     private Bitmap mIcon;
 
@@ -64,7 +72,6 @@
             IconCache cache, boolean disabledForSafeMode) {
         super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme));
 
-        mLauncher = Launcher.getLauncher(context);
         mInfo = info;
         mStartState = info.restoreStatus;
         mDisabledForSafeMode = disabledForSafeMode;
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 87103d7..32f90a6 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -30,12 +30,12 @@
 import android.support.test.uiautomator.UiSelector;
 
 import com.android.launcher3.LauncherAppWidgetHost;
-import com.android.launcher3.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.LauncherAppWidgetInfo;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.PendingAppWidgetHostView;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.PackageInstallerCompat;