am 05702ccf: am 5b7d28fc: Merge "Turn off debugging for launch." into ub-now-porkchop

* commit '05702ccf79bab63fe02bba9e385cfb3cc8faada9':
diff --git a/Android.mk b/Android.mk
index 6e8365f..110117b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,8 +36,7 @@
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/
 
-# STOPSHIP(kennyguy): change to 21 once the L SDK is baked.
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 21
 
 LOCAL_PACKAGE_NAME := Launcher3
 #LOCAL_CERTIFICATE := shared
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 90b33c5..591d9b6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,7 +20,7 @@
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.launcher3">
-    <uses-sdk android:targetSdkVersion="19" android:minSdkVersion="16"/>
+    <uses-sdk android:targetSdkVersion="21" android:minSdkVersion="16"/>
 
     <permission
         android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
diff --git a/WallpaperPicker/res/drawable-xxhdpi/ic_actionbar_accept.png b/WallpaperPicker/res/drawable-xxhdpi/ic_actionbar_accept.png
new file mode 100755
index 0000000..d9ad51c
--- /dev/null
+++ b/WallpaperPicker/res/drawable-xxhdpi/ic_actionbar_accept.png
Binary files differ
diff --git a/res/drawable-hdpi/screenpanel.9.png b/res/drawable-hdpi/screenpanel.9.png
index eed0f2c..f7ae011 100644
--- a/res/drawable-hdpi/screenpanel.9.png
+++ b/res/drawable-hdpi/screenpanel.9.png
Binary files differ
diff --git a/res/drawable-hdpi/screenpanel_hover.9.png b/res/drawable-hdpi/screenpanel_hover.9.png
index 2cea8a4..ac8e83d 100644
--- a/res/drawable-hdpi/screenpanel_hover.9.png
+++ b/res/drawable-hdpi/screenpanel_hover.9.png
Binary files differ
diff --git a/res/drawable-mdpi/screenpanel.9.png b/res/drawable-mdpi/screenpanel.9.png
index 6f8b7e6..c2779fc 100644
--- a/res/drawable-mdpi/screenpanel.9.png
+++ b/res/drawable-mdpi/screenpanel.9.png
Binary files differ
diff --git a/res/drawable-mdpi/screenpanel_hover.9.png b/res/drawable-mdpi/screenpanel_hover.9.png
index 8a94984..70b3078 100644
--- a/res/drawable-mdpi/screenpanel_hover.9.png
+++ b/res/drawable-mdpi/screenpanel_hover.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/screenpanel.9.png b/res/drawable-xhdpi/screenpanel.9.png
index 2d70d7a..53a7812 100644
--- a/res/drawable-xhdpi/screenpanel.9.png
+++ b/res/drawable-xhdpi/screenpanel.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/screenpanel_hover.9.png b/res/drawable-xhdpi/screenpanel_hover.9.png
index 0032fff..a2e200f 100644
--- a/res/drawable-xhdpi/screenpanel_hover.9.png
+++ b/res/drawable-xhdpi/screenpanel_hover.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/screenpanel.9.png b/res/drawable-xxhdpi/screenpanel.9.png
index 7ed058e..2d13954 100644
--- a/res/drawable-xxhdpi/screenpanel.9.png
+++ b/res/drawable-xxhdpi/screenpanel.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/screenpanel_hover.9.png b/res/drawable-xxhdpi/screenpanel_hover.9.png
index 24d2266..369fc44 100644
--- a/res/drawable-xxhdpi/screenpanel_hover.9.png
+++ b/res/drawable-xxhdpi/screenpanel_hover.9.png
Binary files differ
diff --git a/res/layout-land/longpress_cling.xml b/res/layout-land/longpress_cling.xml
index d1b30a8..93bbc07 100644
--- a/res/layout-land/longpress_cling.xml
+++ b/res/layout-land/longpress_cling.xml
@@ -4,6 +4,7 @@
     android:id="@+id/longpress_cling"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="@color/cling_scrim_background"
     android:orientation="vertical" >
 
     <Space
diff --git a/res/layout-land/migration_cling.xml b/res/layout-land/migration_cling.xml
index 4765524..307cba8 100644
--- a/res/layout-land/migration_cling.xml
+++ b/res/layout-land/migration_cling.xml
@@ -41,8 +41,9 @@
     </FrameLayout>
 
     <LinearLayout
-        android:layout_width="280dp"
+        android:layout_width="@dimen/cling_migration_content_width"
         android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/cling_migration_content_margin"
         android:orientation="vertical"
         android:paddingLeft="24dp"
         android:paddingRight="24dp" >
diff --git a/res/layout-port/longpress_cling.xml b/res/layout-port/longpress_cling.xml
index d0f1ab7..8e35f5c 100644
--- a/res/layout-port/longpress_cling.xml
+++ b/res/layout-port/longpress_cling.xml
@@ -3,7 +3,8 @@
     xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3"
     android:id="@+id/longpress_cling"
     android:layout_width="match_parent"
-    android:layout_height="match_parent" >
+    android:layout_height="match_parent"
+    android:background="@color/cling_scrim_background" >
 
     <FrameLayout
         android:id="@+id/cling_content"
diff --git a/res/layout-port/migration_cling.xml b/res/layout-port/migration_cling.xml
index 932a9f4..dde8dbc 100644
--- a/res/layout-port/migration_cling.xml
+++ b/res/layout-port/migration_cling.xml
@@ -42,9 +42,10 @@
             android:src="@drawable/ic_migration" />
 
         <LinearLayout
-            android:layout_width="280dp"
+            android:layout_width="@dimen/cling_migration_content_width"
             android:layout_height="wrap_content"
             android:layout_below="@+id/ic_cling_migration"
+            android:layout_marginStart="@dimen/cling_migration_content_margin"
             android:orientation="vertical"
             android:paddingLeft="24dp"
             android:paddingRight="24dp" >
diff --git a/res/layout-sw600dp-port/longpress_cling.xml b/res/layout-sw600dp-port/longpress_cling.xml
index 090adc5..b42d697 100644
--- a/res/layout-sw600dp-port/longpress_cling.xml
+++ b/res/layout-sw600dp-port/longpress_cling.xml
@@ -4,6 +4,7 @@
     android:id="@+id/longpress_cling"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="@color/cling_scrim_background"
     android:orientation="vertical" >
 
     <Space
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 68f476d..28679be 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -29,5 +29,7 @@
     <dimen name="cling_migration_logo_width">274dp</dimen>
     <dimen name="cling_migration_bg_size">600dp</dimen>
     <dimen name="cling_migration_bg_shift">-300dp</dimen>
+    <dimen name="cling_migration_content_margin">64dp</dimen>
+    <dimen name="cling_migration_content_width">280dp</dimen>
 
 </resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 9ae155b..8be9964 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -25,4 +25,9 @@
      the drag view should be offset from the position of the original view. -->
     <dimen name="dragViewOffsetX">0dp</dimen>
     <dimen name="dragViewOffsetY">0dp</dimen>
+
+<!-- Cling -->
+    <dimen name="cling_migration_content_margin">96dp</dimen>
+    <dimen name="cling_migration_content_width">320dp</dimen>
+
 </resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 7ddb1e4..29837ea 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -22,6 +22,7 @@
          over the delete target or the info target -->
     <color name="delete_target_hover_tint">#DAFF0000</color>
     <color name="info_target_hover_tint">#DA0099CC</color>
+    <color name="cling_scrim_background">#80000000</color>
 
     <color name="bubble_dark_background">#20000000</color>
     <color name="focused_background">#80c6c5c5</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index befaf37..2c9e689 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -33,6 +33,8 @@
     <dimen name="cling_migration_logo_width">165dp</dimen>
     <dimen name="cling_migration_bg_size">400dp</dimen>
     <dimen name="cling_migration_bg_shift">-200dp</dimen>
+    <dimen name="cling_migration_content_margin">16dp</dimen>
+    <dimen name="cling_migration_content_width">280dp</dimen>
 
 <!-- Workspace -->
     <dimen name="workspace_max_gap">16dp</dimen>
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 931501c..00f0cf3 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -57,7 +57,7 @@
 
     /** Marker action used to discover a package which defines launcher customization */
     static final String ACTION_LAUNCHER_CUSTOMIZATION =
-            "com.android.launcher3.action.LAUNCHER_CUSTOMIZATION";
+            "android.autoinstalls.config.action.PLAY_AUTO_INSTALL";
 
     private static final String LAYOUT_RES = "default_layout";
 
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index a27e519..1890af4 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -461,7 +461,7 @@
 
         Animator openFolderAnim = null;
         final Runnable onCompleteRunnable;
-        if (!Utilities.isLmp()) {
+        if (!Utilities.isLmpOrAbove()) {
             positionAndSizeAsIcon();
             centerAboutIcon();
 
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 75be836..bb71d77 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -29,6 +29,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.util.Log;
@@ -62,7 +63,7 @@
     // Empty class name is used for storing package default entry.
     private static final String EMPTY_CLASS_NAME = ".";
 
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static class CacheEntry {
         public Bitmap icon;
@@ -229,7 +230,8 @@
             Iterator<Entry<CacheKey, CacheEntry>> it = mCache.entrySet().iterator();
             while (it.hasNext()) {
                 final CacheEntry e = it.next().getValue();
-                if (e.icon.getWidth() < grid.iconSizePx || e.icon.getHeight() < grid.iconSizePx) {
+                if ((e.icon != null) && (e.icon.getWidth() < grid.iconSizePx
+                        || e.icon.getHeight() < grid.iconSizePx)) {
                     it.remove();
                 }
             }
@@ -381,12 +383,15 @@
      */
     public void cachePackageInstallInfo(String packageName, UserHandleCompat user,
             Bitmap icon, CharSequence title) {
+        remove(packageName, user);
+
         CacheEntry entry = getEntryForPackage(packageName, user);
         if (!TextUtils.isEmpty(title)) {
             entry.title = title;
         }
         if (icon != null) {
-            entry.icon = Utilities.createIconBitmap(icon, mContext);
+            entry.icon = Utilities.createIconBitmap(
+                    new BitmapDrawable(mContext.getResources(), icon), mContext);
         }
     }
 
@@ -511,7 +516,7 @@
                 Log.w(TAG, "failed to decode pre-load icon for " + key);
             }
         } catch (FileNotFoundException e) {
-            if (DEBUG) Log.d(TAG, "there is no restored icon for: " + key, e);
+            if (DEBUG) Log.d(TAG, "there is no restored icon for: " + key);
         } catch (IOException e) {
             Log.w(TAG, "failed to read pre-load icon for: " + key, e);
         } finally {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 1b95c2b..42ec4fb 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -73,6 +73,7 @@
 import android.text.method.TextKeyListener;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -688,19 +689,20 @@
         }
     }
 
-    /**
-     * Copied from View -- the View version of the method isn't called
-     * anywhere else in our process and only exists for API level 17+,
-     * so it's ok to keep our own version with no API requirement.
-     */
     public static int generateViewId() {
-        for (;;) {
-            final int result = sNextGeneratedId.get();
-            // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
-            int newValue = result + 1;
-            if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
-            if (sNextGeneratedId.compareAndSet(result, newValue)) {
-                return result;
+        if (Build.VERSION.SDK_INT >= 17) {
+            return View.generateViewId();
+        } else {
+            // View.generateViewId() is not available. The following fallback logic is a copy
+            // of its implementation.
+            for (;;) {
+                final int result = sNextGeneratedId.get();
+                // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
+                int newValue = result + 1;
+                if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
+                if (sNextGeneratedId.compareAndSet(result, newValue)) {
+                    return result;
+                }
             }
         }
     }
@@ -721,8 +723,13 @@
      * a configuration step, this allows the proper animations to run after other transitions.
      */
     private long completeAdd(PendingAddArguments args) {
+        long screenId = args.screenId;
+        if (args.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+            // When the screen id represents an actual screen (as opposed to a rank) we make sure
+            // that the drop page actually exists.
+            screenId = ensurePendingDropLayoutExists(args.screenId);
+        }
 
-        long screenId = ensurePendingDropLayoutExists(args.screenId);
         switch (args.requestCode) {
             case REQUEST_CREATE_SHORTCUT:
                 completeAddShortcut(args.intent, args.container, screenId, args.cellX,
@@ -814,7 +821,12 @@
                 }
             } else {
                 if (!workspaceLocked) {
-                    mPendingAddInfo.screenId = ensurePendingDropLayoutExists(mPendingAddInfo.screenId);
+                    if (mPendingAddInfo.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+                        // When the screen id represents an actual screen (as opposed to a rank)
+                        // we make sure that the drop page actually exists.
+                        mPendingAddInfo.screenId =
+                                ensurePendingDropLayoutExists(mPendingAddInfo.screenId);
+                    }
                     final CellLayout dropLayout = mWorkspace.getScreenWithId(mPendingAddInfo.screenId);
 
                     dropLayout.setDropPending(true);
@@ -1123,7 +1135,9 @@
     @Override
     public Object onRetainNonConfigurationInstance() {
         // Flag the loader to stop early before switching
-        mModel.stopLoader();
+        if (mModel.isCurrentCallbacks(this)) {
+            mModel.stopLoader();
+        }
         if (mAppsCustomizeContent != null) {
             mAppsCustomizeContent.surrender();
         }
@@ -1650,7 +1664,7 @@
         // TODO(sansid): use the APIs directly when compiling against L sdk.
         // Currently we use reflection to access the flags and the API to set the transparency
         // on the System bars.
-        if (Utilities.isLmp()) {
+        if (Utilities.isLmpOrAbove()) {
             try {
                 getWindow().getAttributes().systemUiVisibility |=
                         (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
@@ -1986,8 +2000,13 @@
 
         // Stop callbacks from LauncherModel
         LauncherAppState app = (LauncherAppState.getInstance());
-        mModel.stopLoader();
-        app.setLauncher(null);
+
+        // It's possible to receive onDestroy after a new Launcher activity has
+        // been created. In this case, don't interfere with the new Launcher.
+        if (mModel.isCurrentCallbacks(this)) {
+            mModel.stopLoader();
+            app.setLauncher(null);
+        }
 
         try {
             mAppWidgetHost.stopListening();
@@ -2545,7 +2564,7 @@
 
     private void showBrokenAppInstallDialog(final String packageName,
             DialogInterface.OnClickListener onSearchClickListener) {
-        new AlertDialog.Builder(this)
+        new AlertDialog.Builder(new ContextThemeWrapper(this, android.R.style.Theme_DeviceDefault))
             .setTitle(R.string.abandoned_promises_title)
             .setMessage(R.string.abandoned_promise_explanation)
             .setPositiveButton(R.string.abandoned_search, onSearchClickListener)
@@ -2809,7 +2828,7 @@
 
             Bundle optsBundle = null;
             if (useLaunchAnimation) {
-                ActivityOptions opts = Utilities.isLmp() ?
+                ActivityOptions opts = Utilities.isLmpOrAbove() ?
                         ActivityOptions.makeCustomAnimation(this, R.anim.task_open_enter, R.anim.no_anim) :
                         ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
                 optsBundle = opts.toBundle();
@@ -2920,7 +2939,7 @@
 
         ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha,
                 scaleX, scaleY);
-        if (Utilities.isLmp()) {
+        if (Utilities.isLmpOrAbove()) {
             oa.setInterpolator(new LogDecelerateInterpolator(100, 0));
         }
         oa.setDuration(getResources().getInteger(R.integer.config_folderExpandDuration));
@@ -3194,7 +3213,7 @@
             mStateAnimation = null;
         }
 
-        boolean material = Utilities.isLmp();
+        boolean material = Utilities.isLmpOrAbove();
 
         final Resources res = getResources();
 
@@ -3376,7 +3395,7 @@
                     dispatchOnLauncherTransitionStart(toView, animated, false);
 
                     revealView.setAlpha(initAlpha);
-                    if (Utilities.isLmp()) {
+                    if (Utilities.isLmpOrAbove()) {
                         for (int i = 0; i < layerViews.size(); i++) {
                             View v = layerViews.get(i);
                             if (v != null) {
@@ -3431,7 +3450,7 @@
             mStateAnimation = null;
         }
 
-        boolean material = Utilities.isLmp();
+        boolean material = Utilities.isLmpOrAbove();
         Resources res = getResources();
 
         final int duration = res.getInteger(R.integer.config_appsCustomizeZoomOutTime);
@@ -3632,9 +3651,11 @@
                     }
 
                     // Reset page transforms
-                    page.setTranslationX(0);
-                    page.setTranslationY(0);
-                    page.setAlpha(1);
+                    if (page != null) {
+                        page.setTranslationX(0);
+                        page.setTranslationY(0);
+                        page.setAlpha(1);
+                    }
                     content.setCurrentPage(content.getNextPage());
 
                     mAppsCustomizeContent.updateCurrentPageScroll();
@@ -3651,7 +3672,7 @@
                     dispatchOnLauncherTransitionStart(fromView, animated, false);
                     dispatchOnLauncherTransitionStart(toView, animated, false);
 
-                    if (Utilities.isLmp()) {
+                    if (Utilities.isLmpOrAbove()) {
                         for (int i = 0; i < layerViews.size(); i++) {
                             View v = layerViews.get(i);
                             if (v != null) {
@@ -4589,6 +4610,7 @@
             mIntentsOnWorkspaceFromUpgradePath = mWorkspace.getUniqueComponents(true, null);
         }
         PackageInstallerCompat.getInstance(this).onFinishBind();
+        mModel.recheckRestoredItems(this);
     }
 
     private void sendLoadingCompleteBroadcastIfNecessary() {
@@ -4698,6 +4720,24 @@
     }
 
     /**
+     * Packages were restored
+     */
+    public void bindAppsRestored(final ArrayList<AppInfo> apps) {
+        Runnable r = new Runnable() {
+            public void run() {
+                bindAppsRestored(apps);
+            }
+        };
+        if (waitUntilResume(r)) {
+            return;
+        }
+
+        if (mWorkspace != null) {
+            mWorkspace.updateShortcutsAndWidgets(apps);
+        }
+    }
+
+    /**
      * Update the state of a package, typically related to install state.
      *
      * Implementation of the method from LauncherModel.Callbacks.
@@ -4710,6 +4750,18 @@
     }
 
     /**
+     * Update the label and icon of all the icons in a package
+     *
+     * Implementation of the method from LauncherModel.Callbacks.
+     */
+    @Override
+    public void updatePackageBadge(String packageName) {
+        if (mWorkspace != null) {
+            mWorkspace.updatePackageBadge(packageName, UserHandleCompat.myUserHandle());
+        }
+    }
+
+    /**
      * A package was uninstalled.  We take both the super set of packageNames
      * in addition to specific applications to remove, the reason being that
      * this can be called when a package is updated as well.  In that scenario,
@@ -4991,7 +5043,7 @@
             if (mModel.canMigrateFromOldLauncherDb(this)) {
                 launcherClings.showMigrationCling();
             } else {
-                launcherClings.showLongPressCling(false);
+                launcherClings.showLongPressCling(true);
             }
         }
     }
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index b6144f4..246278f 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -260,4 +260,11 @@
     public void setPackageState(ArrayList<PackageInstallInfo> installInfo) {
         mModel.setPackageState(installInfo);
     }
+
+    /**
+     * Updates the icons and label of all icons for the provided package name.
+     */
+    public void updatePackageBadge(String packageName) {
+        mModel.updatePackageBadge(packageName);
+    }
 }
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index 50528b1..5c6535a 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -46,6 +46,11 @@
     public static final int FLAG_UI_NOT_READY = 4;
 
     /**
+     * Indicates that the widget restore has started.
+     */
+    public static final int FLAG_RESTORE_STARTED = 8;
+
+    /**
      * Indicates that the widget hasn't been instantiated yet.
      */
     static final int NO_ID = -1;
diff --git a/src/com/android/launcher3/LauncherBackupAgentHelper.java b/src/com/android/launcher3/LauncherBackupAgentHelper.java
index 7dd8cde..c20c693 100644
--- a/src/com/android/launcher3/LauncherBackupAgentHelper.java
+++ b/src/com/android/launcher3/LauncherBackupAgentHelper.java
@@ -17,13 +17,16 @@
 package com.android.launcher3;
 
 import android.app.backup.BackupAgentHelper;
+import android.app.backup.BackupDataInput;
 import android.app.backup.BackupManager;
-import android.app.backup.SharedPreferencesBackupHelper;
 import android.content.Context;
-import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.os.ParcelFileDescriptor;
 import android.provider.Settings;
 import android.util.Log;
 
+import java.io.IOException;
+
 public class LauncherBackupAgentHelper extends BackupAgentHelper {
 
     private static final String TAG = "LauncherBackupAgentHelper";
@@ -54,7 +57,7 @@
         // modifies the file outside the normal codepaths, so it looks like another
         // process.  This forces a reload of the file, in case this process persists.
         String spKey = LauncherAppState.getSharedPreferencesKey();
-        SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);
+        getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);
         super.onDestroy();
     }
 
@@ -71,4 +74,21 @@
         addHelper(LauncherBackupHelper.LAUNCHER_PREFIX,
                 new LauncherBackupHelper(this, restoreEnabled));
     }
+
+    @Override
+    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+            throws IOException {
+        super.onRestore(data, appVersionCode, newState);
+
+        // If no favorite was migrated, clear the data and start fresh.
+        final Cursor c = getContentResolver().query(
+                LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, null, null, null, null);
+        boolean hasData = c.moveToNext();
+        c.close();
+
+        if (!hasData) {
+            if (VERBOSE) Log.v(TAG, "Nothing was restored, clearing DB");
+            LauncherAppState.getLauncherProvider().createEmptyDB();
+        }
+    }
 }
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index 1ea562b..201f3e9 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -148,11 +148,12 @@
 
     private HashMap<ComponentName, AppWidgetProviderInfo> mWidgetMap;
 
-    private ArrayList<Key> mKeys;
+    private final ArrayList<Key> mKeys;
 
     public LauncherBackupHelper(Context context, boolean restoreEnabled) {
         mContext = context;
         mRestoreEnabled = restoreEnabled;
+        mKeys = new ArrayList<Key>();
     }
 
     private void dataChanged() {
@@ -218,9 +219,6 @@
     @Override
     public void restoreEntity(BackupDataInputStream data) {
         if (VERBOSE) Log.v(TAG, "restoreEntity");
-        if (mKeys == null) {
-            mKeys = new ArrayList<Key>();
-        }
         byte[] buffer = new byte[512];
             String backupKey = data.getKey();
             int dataSize = data.size();
@@ -354,7 +352,7 @@
         try {
             ContentResolver cr = mContext.getContentResolver();
             ContentValues values = unpackFavorite(buffer, 0, dataSize);
-            cr.insert(Favorites.CONTENT_URI, values);
+            cr.insert(Favorites.CONTENT_URI_NO_NOTIFICATION, values);
         } catch (InvalidProtocolBufferNanoException e) {
             Log.e(TAG, "failed to decode favorite", e);
         }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 29cd9e3..c64506d 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -86,6 +86,7 @@
         implements LauncherAppsCompat.OnAppsChangedCallbackCompat {
     static final boolean DEBUG_LOADERS = false;
     private static final boolean DEBUG_RECEIVER = false;
+    private static final boolean REMOVE_UNRESTORED_ICONS = true;
 
     static final String TAG = "Launcher.Model";
 
@@ -197,7 +198,9 @@
                                   ArrayList<ItemInfo> addAnimated,
                                   ArrayList<AppInfo> addedApps);
         public void bindAppsUpdated(ArrayList<AppInfo> apps);
+        public void bindAppsRestored(ArrayList<AppInfo> apps);
         public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);
+        public void updatePackageBadge(String packageName);
         public void bindComponentsRemoved(ArrayList<String> packageNames,
                         ArrayList<AppInfo> appInfos, UserHandleCompat user);
         public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
@@ -347,6 +350,19 @@
         mHandler.post(r);
     }
 
+    public void updatePackageBadge(final String packageName) {
+        // Process the updated package badge
+        Runnable r = new Runnable() {
+            public void run() {
+                Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
+                if (callbacks != null) {
+                    callbacks.updatePackageBadge(packageName);
+                }
+            }
+        };
+        mHandler.post(r);
+    }
+
     public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {
         final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
 
@@ -1370,6 +1386,10 @@
         return isLaunching;
     }
 
+    public boolean isCurrentCallbacks(Callbacks callbacks) {
+        return (mCallbacks != null && mCallbacks.get() == callbacks);
+    }
+
     public void startLoader(boolean isLaunching, int synchronousBindPage) {
         startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);
     }
@@ -1885,11 +1905,12 @@
 
             synchronized (sBgLock) {
                 clearSBgDataStructures();
-                PackageInstallerCompat.getInstance(mContext).updateActiveSessionCache();
+                final HashSet<String> installingPkgs = PackageInstallerCompat
+                        .getInstance(mContext).updateAndGetActiveSessionCache();
 
                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
                 final ArrayList<Long> restoredRows = new ArrayList<Long>();
-                final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;
+                final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION;
                 if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);
                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);
 
@@ -2014,6 +2035,25 @@
                                             // installed later.
                                             Launcher.addDumpLog(TAG,
                                                     "package not yet restored: " + cn, true);
+
+                                            if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {
+                                                // Restore has started once.
+                                            } else if (installingPkgs.contains(cn.getPackageName())) {
+                                                // App restore has started. Update the flag
+                                                promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;
+                                                ContentValues values = new ContentValues();
+                                                values.put(LauncherSettings.Favorites.RESTORED,
+                                                        promiseType);
+                                                String where = BaseColumns._ID + "= ?";
+                                                String[] args = {Long.toString(id)};
+                                                contentResolver.update(contentUri, values, where, args);
+
+                                            } else if (REMOVE_UNRESTORED_ICONS) {
+                                                Launcher.addDumpLog(TAG,
+                                                        "Unrestored package removed: " + cn, true);
+                                                itemsToRemove.add(id);
+                                                continue;
+                                            }
                                         } else if (isSdCardReady) {
                                             // Do not wait for external media load anymore.
                                             // Log the invalid package, and remove it
@@ -2221,6 +2261,19 @@
                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
                                                 component);
                                         appWidgetInfo.restoreStatus = restoreStatus;
+
+                                        if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) != 0) {
+                                            // Restore has started once.
+                                        } else if (installingPkgs.contains(component.getPackageName())) {
+                                            // App restore has started. Update the flag
+                                            appWidgetInfo.restoreStatus |=
+                                                    LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
+                                        } else if (REMOVE_UNRESTORED_ICONS) {
+                                            Launcher.addDumpLog(TAG,
+                                                    "Unrestored widget removed: " + component, true);
+                                            itemsToRemove.add(id);
+                                            continue;
+                                        }
                                     }
 
                                     appWidgetInfo.id = id;
@@ -2249,19 +2302,17 @@
                                         break;
                                     }
 
-                                    if (isProviderReady) {
-                                        String providerName = provider.provider.flattenToString();
-                                        if (!providerName.equals(savedProvider) ||
-                                                (appWidgetInfo.restoreStatus != restoreStatus)) {
-                                            ContentValues values = new ContentValues();
-                                            values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
-                                                    providerName);
-                                            values.put(LauncherSettings.Favorites.RESTORED,
-                                                    appWidgetInfo.restoreStatus);
-                                            String where = BaseColumns._ID + "= ?";
-                                            String[] args = {Long.toString(id)};
-                                            contentResolver.update(contentUri, values, where, args);
-                                        }
+                                    String providerName = appWidgetInfo.providerName.flattenToString();
+                                    if (!providerName.equals(savedProvider) ||
+                                            (appWidgetInfo.restoreStatus != restoreStatus)) {
+                                        ContentValues values = new ContentValues();
+                                        values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
+                                                providerName);
+                                        values.put(LauncherSettings.Favorites.RESTORED,
+                                                appWidgetInfo.restoreStatus);
+                                        String where = BaseColumns._ID + "= ?";
+                                        String[] args = {Long.toString(id)};
+                                        contentResolver.update(contentUri, values, where, args);
                                     }
                                     sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
                                     sBgAppWidgets.add(appWidgetInfo);
@@ -2286,7 +2337,7 @@
 
                 if (itemsToRemove.size() > 0) {
                     ContentProviderClient client = contentResolver.acquireContentProviderClient(
-                            LauncherSettings.Favorites.CONTENT_URI);
+                            contentUri);
                     // Remove dead items
                     for (long id : itemsToRemove) {
                         if (DEBUG_LOADERS) {
@@ -2304,7 +2355,7 @@
 
                 if (restoredRows.size() > 0) {
                     ContentProviderClient updater = contentResolver.acquireContentProviderClient(
-                            LauncherSettings.Favorites.CONTENT_URI);
+                            contentUri);
                     // Update restored items that no longer require special handling
                     try {
                         StringBuilder selectionBuilder = new StringBuilder();
@@ -2899,6 +2950,64 @@
         }
     }
 
+    /**
+     * Workaround to re-check unrestored items, in-case they were installed but the Package-ADD
+     * runnable was missed by the launcher.
+     */
+    public void recheckRestoredItems(final Context context) {
+        Runnable r = new Runnable() {
+
+            @Override
+            public void run() {
+                LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+                HashSet<String> installedPackages = new HashSet<String>();
+                UserHandleCompat user = UserHandleCompat.myUserHandle();
+                synchronized(sBgLock) {
+                    for (ItemInfo info : sBgItemsIdMap.values()) {
+                        if (info instanceof ShortcutInfo) {
+                            ShortcutInfo si = (ShortcutInfo) info;
+                            if (si.isPromise() && si.getTargetComponent() != null
+                                    && launcherApps.isPackageEnabledForProfile(
+                                            si.getTargetComponent().getPackageName(), user)) {
+                                installedPackages.add(si.getTargetComponent().getPackageName());
+                            }
+                        } else if (info instanceof LauncherAppWidgetInfo) {
+                            LauncherAppWidgetInfo widget = (LauncherAppWidgetInfo) info;
+                            if (widget.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
+                                    && launcherApps.isPackageEnabledForProfile(
+                                            widget.providerName.getPackageName(), user)) {
+                                installedPackages.add(widget.providerName.getPackageName());
+                            }
+                        }
+                    }
+                }
+
+                if (!installedPackages.isEmpty()) {
+                    final ArrayList<AppInfo> restoredApps = new ArrayList<AppInfo>();
+                    for (String pkg : installedPackages) {
+                        for (LauncherActivityInfoCompat info : launcherApps.getActivityList(pkg, user)) {
+                            restoredApps.add(new AppInfo(context, info, user, mIconCache, null));
+                        }
+                    }
+
+                    final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
+                    if (!restoredApps.isEmpty()) {
+                        mHandler.post(new Runnable() {
+                            public void run() {
+                                Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+                                if (callbacks == cb && cb != null) {
+                                    callbacks.bindAppsRestored(restoredApps);
+                                }
+                            }
+                        });
+                    }
+
+                }
+            }
+        };
+        sWorker.post(r);
+    }
+
     private class PackageUpdatedTask implements Runnable {
         int mOp;
         String[] mPackages;
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 30086ad..6cc1688 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -308,6 +308,13 @@
     }
 
     /**
+     * Clears all the data for a fresh start.
+     */
+    synchronized public void createEmptyDB() {
+        mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
+    }
+
+    /**
      * Loads the default workspace based on the following priority scheme:
      *   1) From a package provided by play store
      *   2) From a partner configuration APK, already in the system image
@@ -908,7 +915,14 @@
             // This shouldn't happen -- throw our hands up in the air and start over.
             Log.w(TAG, "Database version downgrade from: " + oldVersion + " to " + newVersion +
                     ". Wiping databse.");
+            createEmptyDB(db);
+        }
 
+
+        /**
+         * Clears all the data for a fresh start.
+         */
+        public void createEmptyDB(SQLiteDatabase db) {
             db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
             db.execSQL("DROP TABLE IF EXISTS " + TABLE_WORKSPACE_SCREENS);
             onCreate(db);
@@ -1276,14 +1290,16 @@
                     try {
                         int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
                         values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
-                        if (appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) {
-                            return true;
+                        if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) {
+                            return false;
                         }
                     } catch (RuntimeException e) {
                         Log.e(TAG, "Failed to initialize external widget", e);
+                        return false;
                     }
+                } else {
+                    return false;
                 }
-                return false;
             }
 
             // Add screen id if not present
@@ -1539,24 +1555,11 @@
         }
 
         /**
-         * Parse folder starting at current {@link XmlPullParser} location.
+         * Parse folder items starting at {@link XmlPullParser} location. Allow recursive
+         * includes of items.
          */
-        private boolean loadFolder(SQLiteDatabase db, ContentValues values, Resources res,
-                XmlResourceParser parser) throws IOException, XmlPullParserException {
-            final String title;
-            final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
-            if (titleResId != 0) {
-                title = res.getString(titleResId);
-            } else {
-                title = mContext.getResources().getString(R.string.folder_name);
-            }
-
-            values.put(LauncherSettings.Favorites.TITLE, title);
-            long folderId = addFolder(db, values);
-            boolean added = folderId >= 0;
-
-            ArrayList<Long> folderItems = new ArrayList<Long>();
-
+        private void addToFolder(SQLiteDatabase db, Resources res, XmlResourceParser parser,
+                ArrayList<Long> folderItems, long folderId) throws IOException, XmlPullParserException {
             int type;
             int folderDepth = parser.getDepth();
             while ((type = parser.next()) != XmlPullParser.END_TAG ||
@@ -1586,10 +1589,33 @@
                     if (id >= 0) {
                         folderItems.add(id);
                     }
+                } else if (TAG_INCLUDE.equals(tag) && folderId >= 0) {
+                    addToFolder(db, res, parser, folderItems, folderId);
                 } else {
                     throw new RuntimeException("Folders can contain only shortcuts");
                 }
             }
+        }
+
+        /**
+         * Parse folder starting at current {@link XmlPullParser} location.
+         */
+        private boolean loadFolder(SQLiteDatabase db, ContentValues values, Resources res,
+                XmlResourceParser parser) throws IOException, XmlPullParserException {
+            final String title;
+            final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
+            if (titleResId != 0) {
+                title = res.getString(titleResId);
+            } else {
+                title = mContext.getResources().getString(R.string.folder_name);
+            }
+
+            values.put(LauncherSettings.Favorites.TITLE, title);
+            long folderId = addFolder(db, values);
+            boolean added = folderId >= 0;
+
+            ArrayList<Long> folderItems = new ArrayList<Long>();
+            addToFolder(db, res, parser, folderItems, folderId);
 
             // We can only have folders with >= 2 items, so we need to remove the
             // folder and clean up if less than 2 items were included, or some
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 9abfb7f..daf3434 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -55,6 +55,11 @@
     public static final int FLAG_INSTALL_SESSION_ACTIVE = 4;
 
     /**
+     * Indicates that the widget restore has started.
+     */
+    public static final int FLAG_RESTORE_STARTED = 8;
+
+    /**
      * The intent used to start the application.
      */
     Intent intent;
@@ -169,7 +174,7 @@
     }
 
     public void updateIcon(IconCache iconCache) {
-        mIcon = iconCache.getIcon(intent, user);
+        mIcon = iconCache.getIcon(promisedIntent != null ? promisedIntent : intent, user);
         usingFallbackIcon = iconCache.isDefaultIcon(mIcon, user);
     }
 
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index f20f261..1a7c9fc 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -103,11 +103,10 @@
     }
 
     /**
-     * Indicates if the device is running LMP or not.
-     * TODO(sansid): Change the check to a VERSION_CODES code check once we have a version for L.
+     * Indicates if the device is running LMP or higher.
      */
-    public static boolean isLmp() {
-        return "L".equals(Build.VERSION.CODENAME);
+    public static boolean isLmpOrAbove() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
     }
 
     /**
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index f7a0df6..774996e 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1107,7 +1107,7 @@
         case MotionEvent.ACTION_UP:
             if (mTouchState == TOUCH_STATE_REST) {
                 final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
-                if (!currentPage.lastDownOnOccupiedCell()) {
+                if (currentPage != null && !currentPage.lastDownOnOccupiedCell()) {
                     onWallpaperTap(ev);
                 }
             }
@@ -4801,6 +4801,25 @@
     }
 
     void updateShortcutsAndWidgets(ArrayList<AppInfo> apps) {
+        // Break the appinfo list per user
+        final HashMap<UserHandleCompat, ArrayList<AppInfo>> appsPerUser =
+                new HashMap<UserHandleCompat, ArrayList<AppInfo>>();
+        for (AppInfo info : apps) {
+            ArrayList<AppInfo> filtered = appsPerUser.get(info.user);
+            if (filtered == null) {
+                filtered = new ArrayList<AppInfo>();
+                appsPerUser.put(info.user, filtered);
+            }
+            filtered.add(info);
+        }
+
+        for (Map.Entry<UserHandleCompat, ArrayList<AppInfo>> entry : appsPerUser.entrySet()) {
+            updateShortcutsAndWidgetsPerUser(entry.getValue(), entry.getKey());
+        }
+    }
+
+    private void updateShortcutsAndWidgetsPerUser(ArrayList<AppInfo> apps,
+            final UserHandleCompat user) {
         // Create a map of the apps to test against
         final HashMap<ComponentName, AppInfo> appsMap = new HashMap<ComponentName, AppInfo>();
         final HashSet<String> pkgNames = new HashSet<String>();
@@ -4808,9 +4827,8 @@
             appsMap.put(ai.componentName, ai);
             pkgNames.add(ai.componentName.getPackageName());
         }
+        final HashSet<ComponentName> iconsToRemove = new HashSet<ComponentName>();
 
-        final HashMap<UserHandleCompat, HashSet<ComponentName>> iconsToRemove =
-                new HashMap<UserHandleCompat, HashSet<ComponentName>>();
         mapOverItems(MAP_RECURSE, new ItemOperator() {
             @Override
             public boolean evaluate(ItemInfo info, View v, View parent) {
@@ -4818,7 +4836,8 @@
                     ShortcutInfo shortcutInfo = (ShortcutInfo) info;
                     ComponentName cn = shortcutInfo.getTargetComponent();
                     AppInfo appInfo = appsMap.get(cn);
-                    if (cn != null && LauncherModel.isShortcutInfoUpdateable(info)
+                    if (user.equals(shortcutInfo.user) && cn != null
+                            && LauncherModel.isShortcutInfoUpdateable(info)
                             && pkgNames.contains(cn.getPackageName())) {
                         boolean promiseStateChanged = false;
                         boolean infoUpdated = false;
@@ -4841,13 +4860,7 @@
 
                                     if ((intent == null) || (appsMap == null)) {
                                         // Could not find a default activity. Remove this item.
-                                        HashSet<ComponentName> cnSet = iconsToRemove
-                                                .get(shortcutInfo.user);
-                                        if (cnSet == null) {
-                                            cnSet = new HashSet<>();
-                                            iconsToRemove.put(shortcutInfo.user, cnSet);
-                                        }
-                                        cnSet.add(shortcutInfo.getTargetComponent());
+                                        iconsToRemove.add(shortcutInfo.getTargetComponent());
 
                                         // process next shortcut.
                                         return false;
@@ -4894,12 +4907,11 @@
         });
 
         if (!iconsToRemove.isEmpty()) {
-            for (Map.Entry<UserHandleCompat, HashSet<ComponentName>> entry :
-                iconsToRemove.entrySet()) {
-                removeItemsByComponentName(entry.getValue(), entry.getKey());
-            }
+            removeItemsByComponentName(iconsToRemove, user);
         }
-        restorePendingWidgets(pkgNames);
+        if (user.equals(UserHandleCompat.myUserHandle())) {
+            restorePendingWidgets(pkgNames);
+        }
     }
 
     public void removeAbandonedPromise(String packageName, UserHandleCompat user) {
@@ -4909,6 +4921,38 @@
         removeItemsByPackageName(packages, user);
     }
 
+    public void updatePackageBadge(final String packageName, final UserHandleCompat user) {
+        mapOverItems(MAP_RECURSE, new ItemOperator() {
+            @Override
+            public boolean evaluate(ItemInfo info, View v, View parent) {
+                if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {
+                    ShortcutInfo shortcutInfo = (ShortcutInfo) info;
+                    ComponentName cn = shortcutInfo.getTargetComponent();
+                    if (user.equals(shortcutInfo.user) && cn != null
+                            && shortcutInfo.isPromise()
+                            && packageName.equals(cn.getPackageName())) {
+                        if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {
+                            // For auto install apps update the icon as well as label.
+                            mIconCache.getTitleAndIcon(shortcutInfo,
+                                    shortcutInfo.promisedIntent, user, true);
+                        } else {
+                            // Only update the icon for restored apps.
+                            shortcutInfo.updateIcon(mIconCache);
+                        }
+                        BubbleTextView shortcut = (BubbleTextView) v;
+                        shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false);
+
+                        if (parent != null) {
+                            parent.invalidate();
+                        }
+                    }
+                }
+                // process all the shortcuts
+                return false;
+            }
+        });
+    }
+
     public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) {
         HashSet<String> completedPackages = new HashSet<String>();
 
@@ -4946,6 +4990,7 @@
             }
         }
 
+        // Note that package states are sent only for myUser
         if (!completedPackages.isEmpty()) {
             restorePendingWidgets(completedPackages);
         }
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index 57fac7f..6512d42 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -38,12 +38,11 @@
 
     public static AppWidgetManagerCompat getInstance(Context context) {
         synchronized (sInstanceLock) {
-            // TODO change this to use api version once L gets an API number.
             if (sInstance == null) {
-                if (Utilities.isLmp()) {
-                    sInstance = new AppWidgetManagerCompatVL(context);
+                if (Utilities.isLmpOrAbove()) {
+                    sInstance = new AppWidgetManagerCompatVL(context.getApplicationContext());
                 } else {
-                    sInstance = new AppWidgetManagerCompatV16(context);
+                    sInstance = new AppWidgetManagerCompatV16(context.getApplicationContext());
                 }
             }
             return sInstance;
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index 7ca35b7..03d43a6 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -43,7 +43,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-@TargetApi(Build.VERSION_CODES.L)
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
 
     private final UserManager mUserManager;
@@ -121,15 +121,9 @@
         } else {
             badgeLocation.offset(bitmap.getWidth() - badgeSize - badgeMargin, top);
         }
-        Drawable drawable = null;
-        // STOPSHIP(mokani): Remove catch block once dogfood build is bigger than LRW70.
-        // This hack is just to prevent crash in older builds.
-        try {
-            drawable = mPm.getUserBadgedDrawableForDensity(new BitmapDrawable(res, bitmap),
-                    info.getProfile(), badgeLocation, 0);
-        } catch (Throwable e) {
-            return bitmap;
-        }
+
+        Drawable drawable = mPm.getUserBadgedDrawableForDensity(
+                new BitmapDrawable(res, bitmap), info.getProfile(), badgeLocation, 0);
 
         if (drawable instanceof BitmapDrawable) {
             return ((BitmapDrawable) drawable).getBitmap();
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index de8c669..6efcc00 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -23,6 +23,8 @@
 import android.os.Build;
 import android.os.Bundle;
 
+import com.android.launcher3.Utilities;
+
 import java.util.List;
 
 public abstract class LauncherAppsCompat {
@@ -48,12 +50,11 @@
 
     public static LauncherAppsCompat getInstance(Context context) {
         synchronized (sInstanceLock) {
-            // STOPSHIP(kennyguy) change this to use api version once L gets an API number.
             if (sInstance == null) {
-                if ("L".equals(Build.VERSION.CODENAME)) {
-                    sInstance = new LauncherAppsCompatVL(context);
+                if (Utilities.isLmpOrAbove()) {
+                    sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
                 } else {
-                    sInstance = new LauncherAppsCompatV16(context);
+                    sInstance = new LauncherAppsCompatV16(context.getApplicationContext());
                 }
             }
             return sInstance;
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
index c47f223..7e5e6bf 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
@@ -22,19 +22,17 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageInfo;
 import android.content.pm.ResolveInfo;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.UserHandle;
 import android.provider.Settings;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 
 /**
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index c4a9783..e0d28b5 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -82,11 +82,7 @@
         synchronized (mCallbacks) {
             mCallbacks.put(callback, wrappedCallback);
         }
-        try {
-            mLauncherApps.registerCallback(wrappedCallback);
-        } catch (Throwable e) {
-            // STOPSHIP(kennyguy): Remove when LRW71 hits googlefood
-        }
+        mLauncherApps.registerCallback(wrappedCallback);
     }
 
     public void removeOnAppsChangedCallback(
@@ -96,11 +92,7 @@
             wrappedCallback = mCallbacks.remove(callback);
         }
         if (wrappedCallback != null) {
-            try {
-                mLauncherApps.unregisterCallback(wrappedCallback);
-            } catch (Throwable e) {
-                // STOPSHIP(kennyguy): Remove when LRW71 hits googlefood
-            }
+            mLauncherApps.unregisterCallback(wrappedCallback);
         }
     }
 
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java
index 0ae52bd..0eb8754 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompat.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java
@@ -20,6 +20,8 @@
 
 import com.android.launcher3.Utilities;
 
+import java.util.HashSet;
+
 public abstract class PackageInstallerCompat {
 
     public static final int STATUS_INSTALLED = 0;
@@ -32,7 +34,7 @@
     public static PackageInstallerCompat getInstance(Context context) {
         synchronized (sInstanceLock) {
             if (sInstance == null) {
-                if (Utilities.isLmp()) {
+                if (Utilities.isLmpOrAbove()) {
                     sInstance = new PackageInstallerCompatVL(context);
                 } else {
                     sInstance = new PackageInstallerCompatV16(context) { };
@@ -42,7 +44,7 @@
         }
     }
 
-    public abstract void updateActiveSessionCache();
+    public abstract HashSet<String> updateAndGetActiveSessionCache();
 
     public abstract void onPause();
 
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
index 4cc6fc1..1910d22 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
@@ -29,6 +29,7 @@
 import org.json.JSONTokener;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 
 public class PackageInstallerCompatV16 extends PackageInstallerCompat {
 
@@ -76,9 +77,6 @@
     @Override
     public void onStop() { }
 
-    @Override
-    public void updateActiveSessionCache() { }
-
     private void replayUpdates() {
         if (DEBUG) Log.d(TAG, "updates resumed");
         LauncherAppState app = LauncherAppState.getInstanceNoCreate();
@@ -169,4 +167,9 @@
         }
         return value;
     }
+
+    @Override
+    public HashSet<String> updateAndGetActiveSessionCache() {
+        return new HashSet<String>();
+    }
 }
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index 9a0831f..16ad379 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -27,6 +27,7 @@
 import com.android.launcher3.LauncherAppState;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 
 public class PackageInstallerCompatVL extends PackageInstallerCompat {
 
@@ -34,6 +35,7 @@
     private static final boolean DEBUG = false;
 
     private final SparseArray<SessionInfo> mPendingReplays = new SparseArray<SessionInfo>();
+    private final HashSet<String> mPendingBadgeUpdates = new HashSet<String>();
     private final PackageInstaller mInstaller;
     private final IconCache mCache;
 
@@ -42,16 +44,13 @@
 
     PackageInstallerCompatVL(Context context) {
         mInstaller = context.getPackageManager().getPackageInstaller();
+        LauncherAppState.setApplicationContext(context.getApplicationContext());
         mCache = LauncherAppState.getInstance().getIconCache();
 
         mResumed = false;
         mBound = false;
 
-        // STOPSHIP(mokani): Remove catch block once dogfood build is bigger than LRW70.
-        // This hack is just to prevent crash in older builds.
-        try {
-            mInstaller.registerSessionCallback(mCallback);
-        } catch (Throwable e) { }
+        mInstaller.registerSessionCallback(mCallback);
 
         // On start, send updates for all active sessions
         for (SessionInfo info : mInstaller.getAllSessions()) {
@@ -60,11 +59,16 @@
     }
 
     @Override
-    public void updateActiveSessionCache() {
+    public HashSet<String> updateAndGetActiveSessionCache() {
+        HashSet<String> activePackages = new HashSet<String>();
         UserHandleCompat user = UserHandleCompat.myUserHandle();
         for (SessionInfo info : mInstaller.getAllSessions()) {
             addSessionInfoToCahce(info, user);
+            if (info.getAppPackageName() != null) {
+                activePackages.add(info.getAppPackageName());
+            }
         }
+        return activePackages;
     }
 
     private void addSessionInfoToCahce(SessionInfo info, UserHandleCompat user) {
@@ -77,11 +81,6 @@
 
     @Override
     public void onStop() {
-        // STOPSHIP(mokani): Remove catch block once dogfood build is bigger than LRW70.
-        // This hack is just to prevent crash in older builds.
-        try {
-            mInstaller.unregisterSessionCallback(mCallback);
-        } catch (Throwable e) { }
     }
 
     @Override
@@ -112,7 +111,7 @@
             // Not yet ready
             return;
         }
-        if ((mPendingReplays.size() == 0) && (newInfo == null)) {
+        if ((mPendingReplays.size() == 0) && (newInfo == null) && mPendingBadgeUpdates.isEmpty()) {
             // Nothing to update
             return;
         }
@@ -140,18 +139,20 @@
         if (!updates.isEmpty()) {
             app.setPackageState(updates);
         }
+
+        if (!mPendingBadgeUpdates.isEmpty()) {
+            for (String pkg : mPendingBadgeUpdates) {
+                app.updatePackageBadge(pkg);
+            }
+            mPendingBadgeUpdates.clear();
+        }
     }
 
     private final SessionCallback mCallback = new SessionCallback() {
 
         @Override
         public void onCreated(int sessionId) {
-            SessionInfo session = mInstaller.getSessionInfo(sessionId);
-            if (session != null) {
-                addSessionInfoToCahce(session, UserHandleCompat.myUserHandle());
-                mPendingReplays.put(sessionId, session);
-                replayUpdates(null);
-            }
+            pushSessionBadgeToLauncher(sessionId);
         }
 
         @Override
@@ -159,6 +160,7 @@
             mPendingReplays.remove(sessionId);
             SessionInfo session = mInstaller.getSessionInfo(sessionId);
             if ((session != null) && (session.getAppPackageName() != null)) {
+                mPendingBadgeUpdates.remove(session.getAppPackageName());
                 // Replay all updates with a one time update for this installed package. No
                 // need to store this record for future updates, as the app list will get
                 // refreshed on resume.
@@ -180,6 +182,20 @@
         public void onActiveChanged(int sessionId, boolean active) { }
 
         @Override
-        public void onBadgingChanged(int sessionId) { }
+        public void onBadgingChanged(int sessionId) {
+            pushSessionBadgeToLauncher(sessionId);
+        }
+
+        private void pushSessionBadgeToLauncher(int sessionId) {
+            SessionInfo session = mInstaller.getSessionInfo(sessionId);
+            if (session != null) {
+                addSessionInfoToCahce(session, UserHandleCompat.myUserHandle());
+                if (session.getAppPackageName() != null) {
+                    mPendingBadgeUpdates.add(session.getAppPackageName());
+                }
+                mPendingReplays.put(sessionId, session);
+                replayUpdates(null);
+            }
+        }
     };
 }
diff --git a/src/com/android/launcher3/compat/UserHandleCompat.java b/src/com/android/launcher3/compat/UserHandleCompat.java
index 4baf052..2ae6731 100644
--- a/src/com/android/launcher3/compat/UserHandleCompat.java
+++ b/src/com/android/launcher3/compat/UserHandleCompat.java
@@ -20,6 +20,8 @@
 import android.os.Build;
 import android.os.UserHandle;
 
+import com.android.launcher3.Utilities;
+
 public class UserHandleCompat {
     private UserHandle mUser;
 
@@ -86,9 +88,8 @@
      * profiles so this is a no-op.
      */
     public void addToIntent(Intent intent, String name) {
-        // TODO change this to use api version once L gets an API number.
-        if ("L".equals(Build.VERSION.CODENAME) && mUser != null) {
+        if (Utilities.isLmpOrAbove() && mUser != null) {
             intent.putExtra(name, mUser);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java
index 8effb81..1374b4e 100644
--- a/src/com/android/launcher3/compat/UserManagerCompat.java
+++ b/src/com/android/launcher3/compat/UserManagerCompat.java
@@ -20,6 +20,8 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 
+import com.android.launcher3.Utilities;
+
 import java.util.List;
 
 public abstract class UserManagerCompat {
@@ -27,8 +29,7 @@
     }
 
     public static UserManagerCompat getInstance(Context context) {
-        // TODO change this to use api version once L gets an API number.
-        if ("L".equals(Build.VERSION.CODENAME)) {
+        if (Utilities.isLmpOrAbove()) {
             return new UserManagerCompatVL(context);
         } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
             return new UserManagerCompatV17(context);
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java
index ddef431..19eeabd 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java
@@ -51,13 +51,7 @@
 
     @Override
     public Drawable getBadgedDrawableForUser(Drawable unbadged, UserHandleCompat user) {
-        // STOPSHIP(mokani): Remove catch block once dogfood build is bigger than LRW70.
-        // This hack is just to prevent crash in older builds.
-        try {
-            return mPm.getUserBadgedIcon(unbadged, user.getUser());
-        } catch (Throwable e) {
-            return unbadged;
-        }
+        return mPm.getUserBadgedIcon(unbadged, user.getUser());
     }
 
     @Override
@@ -65,13 +59,7 @@
         if (user == null) {
             return label;
         }
-        // STOPSHIP(mokani): Remove catch block once dogfood build is bigger than LRW70.
-        // This hack is just to prevent crash in older builds.
-        try {
-            return mPm.getUserBadgedLabel(label, user.getUser());
-        } catch (Throwable e) {
-            return label;
-        }
+        return mPm.getUserBadgedLabel(label, user.getUser());
     }
 }