am 8f9a7879: Launcher crashes on widget bind permission prompt

* commit '8f9a787945c3326791c61b001e786b96e9fc4341':
  Launcher crashes on widget bind permission prompt
diff --git a/Android.mk b/Android.mk
index 110117b..632dd09 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,8 +23,6 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13
-
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     $(call all-java-files-under, WallpaperPicker/src) \
     $(call all-renderscript-files-under, src) \
diff --git a/WallpaperPicker/AndroidManifest.xml b/WallpaperPicker/AndroidManifest.xml
index 5b6a007..cb1457b 100644
--- a/WallpaperPicker/AndroidManifest.xml
+++ b/WallpaperPicker/AndroidManifest.xml
@@ -4,7 +4,7 @@
         android:versionCode="1"
         android:versionName="1.0"
         >
-  
-    <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="19" />
+
+    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
     <application/>
 </manifest>
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
index a671ed2..6a816d9 100644
--- a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
+++ b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
@@ -18,17 +18,13 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
-import android.os.Build;
 import android.util.FloatMath;
 import android.util.Log;
 
 import java.io.ByteArrayOutputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 
 public class BitmapUtils {
     private static final String TAG = "BitmapUtils";
@@ -187,54 +183,6 @@
         return bitmap;
     }
 
-    public static Bitmap createVideoThumbnail(String filePath) {
-        // MediaMetadataRetriever is available on API Level 8
-        // but is hidden until API Level 10
-        Class<?> clazz = null;
-        Object instance = null;
-        try {
-            clazz = Class.forName("android.media.MediaMetadataRetriever");
-            instance = clazz.newInstance();
-
-            Method method = clazz.getMethod("setDataSource", String.class);
-            method.invoke(instance, filePath);
-
-            // The method name changes between API Level 9 and 10.
-            if (Build.VERSION.SDK_INT <= 9) {
-                return (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
-            } else {
-                byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
-                if (data != null) {
-                    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
-                    if (bitmap != null) return bitmap;
-                }
-                return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
-            }
-        } catch (IllegalArgumentException ex) {
-            // Assume this is a corrupt video file
-        } catch (RuntimeException ex) {
-            // Assume this is a corrupt video file.
-        } catch (InstantiationException e) {
-            Log.e(TAG, "createVideoThumbnail", e);
-        } catch (InvocationTargetException e) {
-            Log.e(TAG, "createVideoThumbnail", e);
-        } catch (ClassNotFoundException e) {
-            Log.e(TAG, "createVideoThumbnail", e);
-        } catch (NoSuchMethodException e) {
-            Log.e(TAG, "createVideoThumbnail", e);
-        } catch (IllegalAccessException e) {
-            Log.e(TAG, "createVideoThumbnail", e);
-        } finally {
-            try {
-                if (instance != null) {
-                    clazz.getMethod("release").invoke(instance);
-                }
-            } catch (Exception ignored) {
-            }
-        }
-        return null;
-    }
-
     public static byte[] compressToBytes(Bitmap bitmap) {
         return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY);
     }
diff --git a/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java b/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
index c4e493b..b0292e6 100644
--- a/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
+++ b/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
@@ -20,9 +20,9 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.support.v4.util.LongSparseArray;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.LongSparseArray;
 import android.util.Pools.Pool;
 import android.util.Pools.SynchronizedPool;
 import android.view.View;
diff --git a/protos/backup.proto b/protos/backup.proto
index 44c4b09..09330ee 100644
--- a/protos/backup.proto
+++ b/protos/backup.proto
@@ -72,6 +72,17 @@
 }
 
 message Favorite {
+  // Type of the app, this target represents
+  enum TargetType {
+    TARGET_NONE = 0;
+    TARGET_PHONE = 1;
+    TARGET_MESSENGER = 2;
+    TARGET_EMAIL = 3;
+    TARGET_BROWSER = 4;
+    TARGET_GALLERY = 5;
+    TARGET_CAMERA = 6;
+  }
+
   required int64 id = 1;
   required int32 itemType = 2;
   optional string title = 3;
@@ -90,6 +101,7 @@
   optional string iconPackage = 16;
   optional string iconResource = 17;
   optional bytes icon = 18;
+  optional TargetType targetType = 19 [default = TARGET_NONE];
  }
 
 message Screen {
diff --git a/res/xml/app_target_browser.xml b/res/xml/app_target_browser.xml
new file mode 100644
index 0000000..d7c3ed5
--- /dev/null
+++ b/res/xml/app_target_browser.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+    <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" />
+    <favorite launcher:uri="http://www.example.com/" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_camera.xml b/res/xml/app_target_camera.xml
new file mode 100644
index 0000000..f65a2b1
--- /dev/null
+++ b/res/xml/app_target_camera.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+    <favorite launcher:uri="#Intent;action=android.media.action.STILL_IMAGE_CAMERA;end" />
+    <favorite launcher:uri="#Intent;action=android.intent.action.CAMERA_BUTTON;end" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_email.xml b/res/xml/app_target_email.xml
new file mode 100644
index 0000000..44f0a40
--- /dev/null
+++ b/res/xml/app_target_email.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+    <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_EMAIL;end" />
+    <favorite launcher:uri="mailto:" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_gallery.xml b/res/xml/app_target_gallery.xml
new file mode 100644
index 0000000..c9d3492
--- /dev/null
+++ b/res/xml/app_target_gallery.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+    <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_GALLERY;end" />
+    <favorite launcher:uri="#Intent;type=images/*;end" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_messenger.xml b/res/xml/app_target_messenger.xml
new file mode 100644
index 0000000..278eb5c
--- /dev/null
+++ b/res/xml/app_target_messenger.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+    <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MESSAGING;end" />
+    <favorite launcher:uri="sms:" />
+    <favorite launcher:uri="smsto:" />
+    <favorite launcher:uri="mms:" />
+    <favorite launcher:uri="mmsto:" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_phone.xml b/res/xml/app_target_phone.xml
new file mode 100644
index 0000000..5d6ca31
--- /dev/null
+++ b/res/xml/app_target_phone.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 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.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+    <favorite launcher:uri="#Intent;action=android.intent.action.DIAL;end" />
+    <favorite launcher:uri="tel:123" />
+    <favorite launcher:uri="#Intent;action=android.intent.action.CALL_BUTTON;end" />
+
+</resolve>
\ No newline at end of file
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 3820660..908bd3d 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -116,7 +116,7 @@
 
     private final Context mContext;
     private final AppWidgetHost mAppWidgetHost;
-    private final LayoutParserCallback mCallback;
+    protected final LayoutParserCallback mCallback;
 
     protected final PackageManager mPackageManager;
     protected final Resources mSourceRes;
@@ -126,13 +126,20 @@
 
     private final long[] mTemp = new long[2];
     private final ContentValues mValues;
-    private final String mRootTag;
+    protected final String mRootTag;
 
     protected SQLiteDatabase mDb;
 
     public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
             LayoutParserCallback callback, Resources res,
             int layoutId, String rootTag) {
+        this(context, appWidgetHost, callback, res, layoutId, rootTag,
+                LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile().hotseatAllAppsRank);
+    }
+
+    public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
+            LayoutParserCallback callback, Resources res,
+            int layoutId, String rootTag, int hotseatAllAppsRank) {
         mContext = context;
         mAppWidgetHost = appWidgetHost;
         mCallback = callback;
@@ -143,8 +150,7 @@
 
         mSourceRes = res;
         mLayoutId = layoutId;
-        mHotseatAllAppsRank = LauncherAppState.getInstance()
-                .getDynamicGrid().getDeviceProfile().hotseatAllAppsRank;
+        mHotseatAllAppsRank = hotseatAllAppsRank;
     }
 
     /**
diff --git a/src/com/android/launcher3/CommonAppTypeParser.java b/src/com/android/launcher3/CommonAppTypeParser.java
new file mode 100644
index 0000000..fe2fbd7
--- /dev/null
+++ b/src/com/android/launcher3/CommonAppTypeParser.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.XmlResourceParser;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.backup.BackupProtos.Favorite;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * A class that parses content values corresponding to some common app types.
+ */
+public class CommonAppTypeParser implements LayoutParserCallback {
+    private static final String TAG = "CommonAppTypeParser";
+
+    // Including TARGET_NONE
+    public static final int SUPPORTED_TYPE_COUNT = 7;
+
+    private static final int RESTORE_FLAG_BIT_SHIFT = 4;
+
+
+    private final long mItemId;
+    private final int mResId;
+    private final Context mContext;
+
+    ContentValues parsedValues;
+    Intent parsedIntent;
+    String parsedTitle;
+
+    public CommonAppTypeParser(long itemId, int itemType, Context context) {
+        mItemId = itemId;
+        mContext = context;
+        mResId = getResourceForItemType(itemType);
+    }
+
+    @Override
+    public long generateNewItemId() {
+        return mItemId;
+    }
+
+    @Override
+    public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
+        parsedValues = values;
+
+        // Remove unwanted values
+        values.put(Favorites.ICON_TYPE, (Integer) null);
+        values.put(Favorites.ICON_PACKAGE, (String) null);
+        values.put(Favorites.ICON_RESOURCE, (String) null);
+        values.put(Favorites.ICON, (byte[]) null);
+        return 1;
+    }
+
+    /**
+     * Tries to find a suitable app to the provided app type.
+     */
+    public boolean findDefaultApp() {
+        if (mResId == 0) {
+            return false;
+        }
+
+        parsedIntent = null;
+        parsedValues = null;
+        new MyLayoutParser().parseValues();
+        return (parsedValues != null) && (parsedIntent != null);
+    }
+
+    private class MyLayoutParser extends DefaultLayoutParser {
+
+        public MyLayoutParser() {
+            super(mContext, null, CommonAppTypeParser.this,
+                    mContext.getResources(), mResId, TAG_RESOLVE, 0);
+        }
+
+        @Override
+        protected long addShortcut(String title, Intent intent, int type) {
+            if (type == Favorites.ITEM_TYPE_APPLICATION) {
+                parsedIntent = intent;
+                parsedTitle = title;
+            }
+            return super.addShortcut(title, intent, type);
+        }
+
+        public void parseValues() {
+            XmlResourceParser parser = mSourceRes.getXml(mLayoutId);
+            try {
+                beginDocument(parser, mRootTag);
+                new ResolveParser().parseAndAdd(parser);
+            } catch (IOException | XmlPullParserException e) {
+                Log.e(TAG, "Unable to parse default app info", e);
+            }
+            parser.close();
+        }
+    }
+
+    public static int getResourceForItemType(int type) {
+        switch (type) {
+            case Favorite.TARGET_PHONE:
+                return R.xml.app_target_phone;
+
+            case Favorite.TARGET_MESSENGER:
+                return R.xml.app_target_messenger;
+
+            case Favorite.TARGET_EMAIL:
+                return R.xml.app_target_email;
+
+            case Favorite.TARGET_BROWSER:
+                return R.xml.app_target_browser;
+
+            case Favorite.TARGET_GALLERY:
+                return R.xml.app_target_gallery;
+
+            case Favorite.TARGET_CAMERA:
+                return R.xml.app_target_camera;
+
+            default:
+                return 0;
+        }
+    }
+
+    public static int encodeItemTypeToFlag(int itemType) {
+        return itemType << RESTORE_FLAG_BIT_SHIFT;
+    }
+
+    public static int decodeItemTypeFromFlag(int flag) {
+        return (flag & ShortcutInfo.FLAG_RESTORED_APP_TYPE) >> RESTORE_FLAG_BIT_SHIFT;
+    }
+
+}
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index 986ae81..6c3008b 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -28,15 +28,15 @@
 public class DefaultLayoutParser extends AutoInstallsLayout {
     private static final String TAG = "DefaultLayoutParser";
 
-    private static final String TAG_RESOLVE = "resolve";
+    protected static final String TAG_RESOLVE = "resolve";
     private static final String TAG_FAVORITES = "favorites";
-    private static final String TAG_FAVORITE = "favorite";
+    protected static final String TAG_FAVORITE = "favorite";
     private static final String TAG_APPWIDGET = "appwidget";
     private static final String TAG_SHORTCUT = "shortcut";
     private static final String TAG_FOLDER = "folder";
     private static final String TAG_PARTNER_FOLDER = "partner-folder";
 
-    private static final String ATTR_URI = "uri";
+    protected static final String ATTR_URI = "uri";
     private static final String ATTR_CONTAINER = "container";
     private static final String ATTR_SCREEN = "screen";
     private static final String ATTR_FOLDER_ITEMS = "folderItems";
@@ -44,7 +44,12 @@
     public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
             LayoutParserCallback callback, Resources sourceRes, int layoutId) {
         super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES);
-        Log.e(TAG, "Default layout parser initialized");
+    }
+
+    public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
+            LayoutParserCallback callback, Resources sourceRes, int layoutId, String rootTag,
+            int hotseatAllAppsRank) {
+        super(context, appWidgetHost, callback, sourceRes, layoutId, rootTag, hotseatAllAppsRank);
     }
 
     @Override
@@ -196,7 +201,7 @@
     /**
      * Contains a list of <favorite> nodes, and accepts the first successfully parsed node.
      */
-    private class ResolveParser implements TagParser {
+    protected class ResolveParser implements TagParser {
 
         private final AppShortcutWithUriParser mChildParser = new AppShortcutWithUriParser();
 
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 66b6568..6925477 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -21,12 +21,13 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.SystemClock;
-import android.support.v4.widget.AutoScrollHelper;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
@@ -123,8 +124,6 @@
 
     private boolean mDestroyed;
 
-    private AutoScrollHelper mAutoScrollHelper;
-
     private Runnable mDeferredAction;
     private boolean mDeferDropAfterUninstall;
     private boolean mUninstallSuccessful;
@@ -208,7 +207,6 @@
         mFolderName.setSelectAllOnFocus(true);
         mFolderName.setInputType(mFolderName.getInputType() |
                 InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
-        mAutoScrollHelper = new FolderAutoScrollHelper(mScrollView);
     }
 
     private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@@ -700,6 +698,7 @@
         }
     }
 
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     public boolean isLayoutRtl() {
         return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
     }
@@ -715,29 +714,19 @@
         final MotionEvent translatedEv = MotionEvent.obtain(
                 downTime, downTime, MotionEvent.ACTION_MOVE, d.x, d.y, 0);
 
-        if (!mAutoScrollHelper.isEnabled()) {
-            mAutoScrollHelper.setEnabled(true);
-        }
-
-        final boolean handled = mAutoScrollHelper.onTouch(this, translatedEv);
         translatedEv.recycle();
-
-        if (handled) {
+        mTargetCell = mContent.findNearestArea(
+                (int) r[0], (int) r[1] + scrollOffset, 1, 1, mTargetCell);
+        if (isLayoutRtl()) {
+            mTargetCell[0] = mContent.getCountX() - mTargetCell[0] - 1;
+        }
+        if (mTargetCell[0] != mPreviousTargetCell[0]
+                || mTargetCell[1] != mPreviousTargetCell[1]) {
             mReorderAlarm.cancelAlarm();
-        } else {
-            mTargetCell = mContent.findNearestArea(
-                    (int) r[0], (int) r[1] + scrollOffset, 1, 1, mTargetCell);
-            if (isLayoutRtl()) {
-                mTargetCell[0] = mContent.getCountX() - mTargetCell[0] - 1;
-            }
-            if (mTargetCell[0] != mPreviousTargetCell[0]
-                    || mTargetCell[1] != mPreviousTargetCell[1]) {
-                mReorderAlarm.cancelAlarm();
-                mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
-                mReorderAlarm.setAlarm(REORDER_DELAY);
-                mPreviousTargetCell[0] = mTargetCell[0];
-                mPreviousTargetCell[1] = mTargetCell[1];
-            }
+            mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
+            mReorderAlarm.setAlarm(REORDER_DELAY);
+            mPreviousTargetCell[0] = mTargetCell[0];
+            mPreviousTargetCell[1] = mTargetCell[1];
         }
     }
 
@@ -783,8 +772,6 @@
     }
 
     public void onDragExit(DragObject d) {
-        // Exiting folder; stop the auto scroller.
-        mAutoScrollHelper.setEnabled(false);
         // We only close the folder if this is a true drag exit, ie. not because
         // a drop has occurred above the folder.
         if (!d.dragComplete) {
diff --git a/src/com/android/launcher3/FolderAutoScrollHelper.java b/src/com/android/launcher3/FolderAutoScrollHelper.java
deleted file mode 100644
index 40e8884..0000000
--- a/src/com/android/launcher3/FolderAutoScrollHelper.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.support.v4.widget.AutoScrollHelper;
-import android.widget.ScrollView;
-
-/**
- * An implementation of {@link AutoScrollHelper} that knows how to scroll
- * through a {@link Folder}.
- */
-public class FolderAutoScrollHelper extends AutoScrollHelper {
-    private static final float MAX_SCROLL_VELOCITY = 1500f;
-
-    private final ScrollView mTarget;
-
-    public FolderAutoScrollHelper(ScrollView target) {
-        super(target);
-
-        mTarget = target;
-
-        setActivationDelay(0);
-        setEdgeType(EDGE_TYPE_INSIDE_EXTEND);
-        setExclusive(true);
-        setMaximumVelocity(MAX_SCROLL_VELOCITY, MAX_SCROLL_VELOCITY);
-        setRampDownDuration(0);
-        setRampUpDuration(0);
-    }
-
-    @Override
-    public void scrollTargetBy(int deltaX, int deltaY) {
-        mTarget.scrollBy(deltaX, deltaY);
-    }
-
-    @Override
-    public boolean canTargetScrollHorizontally(int direction) {
-        // List do not scroll horizontally.
-        return false;
-    }
-
-    @Override
-    public boolean canTargetScrollVertically(int direction) {
-        return mTarget.canScrollVertically(direction);
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 84476b7..61915b7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -115,9 +115,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.text.DateFormat;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -1686,40 +1683,19 @@
      * Sets up transparent navigation and status bars in LMP.
      * This method is a no-op for other platform versions.
      */
-    @TargetApi(19)
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     private void setupTransparentSystemBarsForLmp() {
-        // 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.isLmpOrAbove()) {
-            try {
-                getWindow().getAttributes().systemUiVisibility |=
-                        (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
-                        | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
-                Field drawsSysBackgroundsField = WindowManager.LayoutParams.class.getField(
-                        "FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS");
-                getWindow().addFlags(drawsSysBackgroundsField.getInt(null));
-
-                Method setStatusBarColorMethod =
-                        Window.class.getDeclaredMethod("setStatusBarColor", int.class);
-                Method setNavigationBarColorMethod =
-                        Window.class.getDeclaredMethod("setNavigationBarColor", int.class);
-                setStatusBarColorMethod.invoke(getWindow(), Color.TRANSPARENT);
-                setNavigationBarColorMethod.invoke(getWindow(), Color.TRANSPARENT);
-            } catch (NoSuchFieldException e) {
-                Log.w(TAG, "NoSuchFieldException while setting up transparent bars");
-            } catch (NoSuchMethodException ex) {
-                Log.w(TAG, "NoSuchMethodException while setting up transparent bars");
-            } catch (IllegalAccessException e) {
-                Log.w(TAG, "IllegalAccessException while setting up transparent bars");
-            } catch (IllegalArgumentException e) {
-                Log.w(TAG, "IllegalArgumentException while setting up transparent bars");
-            } catch (InvocationTargetException e) {
-                Log.w(TAG, "InvocationTargetException while setting up transparent bars");
-            } finally {}
+            Window window = getWindow();
+            window.getAttributes().systemUiVisibility |=
+                    (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            window.setStatusBarColor(Color.TRANSPARENT);
+            window.setNavigationBarColor(Color.TRANSPARENT);
         }
     }
 
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index 32bea5b..353bf3f 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -19,13 +19,16 @@
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupHelper;
 import android.app.backup.BackupManager;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.res.XmlResourceParser;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -51,6 +54,9 @@
 import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
 import com.google.protobuf.nano.MessageNano;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -58,7 +64,6 @@
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.zip.CRC32;
 
@@ -138,6 +143,7 @@
     private final Context mContext;
     private final HashSet<String> mExistingKeys;
     private final ArrayList<Key> mKeys;
+    private final ItemTypeMatcher[] mItemTypeMatchers;
 
     private IconCache mIconCache;
     private BackupManager mBackupManager;
@@ -154,6 +160,7 @@
         mExistingKeys = new HashSet<String>();
         mKeys = new ArrayList<Key>();
         restoreSuccessful = true;
+        mItemTypeMatchers = new ItemTypeMatcher[CommonAppTypeParser.SUPPORTED_TYPE_COUNT];
     }
 
     private void dataChanged() {
@@ -753,6 +760,17 @@
         return checksum.getValue();
     }
 
+    /**
+     * @return true if its an hotseat item, that can be replaced during restore.
+     * TODO: Extend check for folders in hotseat.
+     */
+    private boolean isReplaceableHotseatItem(Favorite favorite) {
+        return favorite.container == Favorites.CONTAINER_HOTSEAT
+                && favorite.intent != null
+                && (favorite.itemType == Favorites.ITEM_TYPE_APPLICATION
+                || favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT);
+    }
+
     /** Serialize a Favorite for persistence, including a checksum wrapper. */
     private Favorite packFavorite(Cursor c) {
         Favorite favorite = new Favorite();
@@ -785,9 +803,10 @@
             favorite.title = title;
         }
         String intentDescription = c.getString(INTENT_INDEX);
+        Intent intent = null;
         if (!TextUtils.isEmpty(intentDescription)) {
             try {
-                Intent intent = Intent.parseUri(intentDescription, 0);
+                intent = Intent.parseUri(intentDescription, 0);
                 intent.removeExtra(ItemInfo.EXTRA_PROFILE);
                 favorite.intent = intent.toUri(0);
             } catch (URISyntaxException e) {
@@ -803,6 +822,31 @@
             }
         }
 
+        if (isReplaceableHotseatItem(favorite)) {
+            if (intent != null && intent.getComponent() != null) {
+                PackageManager pm = mContext.getPackageManager();
+                ActivityInfo activity = null;;
+                try {
+                    activity = pm.getActivityInfo(intent.getComponent(), 0);
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "Target not found", e);
+                }
+                if (activity == null) {
+                    return favorite;
+                }
+                for (int i = 0; i < mItemTypeMatchers.length; i++) {
+                    if (mItemTypeMatchers[i] == null) {
+                        mItemTypeMatchers[i] = new ItemTypeMatcher(
+                                CommonAppTypeParser.getResourceForItemType(i));
+                    }
+                    if (mItemTypeMatchers[i].matches(activity, pm)) {
+                        favorite.targetType = i;
+                        break;
+                    }
+                }
+            }
+        }
+
         return favorite;
     }
 
@@ -810,6 +854,7 @@
     private ContentValues unpackFavorite(byte[] buffer, int dataSize)
             throws IOException {
         Favorite favorite = unpackProto(new Favorite(), buffer, dataSize);
+
         ContentValues values = new ContentValues();
         values.put(Favorites._ID, favorite.id);
         values.put(Favorites.SCREEN, favorite.screen);
@@ -860,8 +905,17 @@
                 throw new InvalidBackupException("Widget not in screen bounds, aborting restore");
             }
         } else {
-            // Let LauncherModel know we've been here.
-            values.put(LauncherSettings.Favorites.RESTORED, 1);
+            // Check if it is an hotseat item, that can be replaced.
+            if (isReplaceableHotseatItem(favorite)
+                    && favorite.targetType != Favorite.TARGET_NONE
+                    && favorite.targetType < CommonAppTypeParser.SUPPORTED_TYPE_COUNT) {
+                Log.e(TAG, "Added item type flag");
+                values.put(LauncherSettings.Favorites.RESTORED,
+                        1 | CommonAppTypeParser.encodeItemTypeToFlag(favorite.targetType));
+            } else {
+                // Let LauncherModel know we've been here.
+                values.put(LauncherSettings.Favorites.RESTORED, 1);
+            }
 
             // Verify placement
             if (favorite.container == Favorites.CONTAINER_HOTSEAT) {
@@ -1128,6 +1182,9 @@
     }
 
     private class InvalidBackupException extends IOException {
+
+        private static final long serialVersionUID = 8931456637211665082L;
+
         private InvalidBackupException(Throwable cause) {
             super(cause);
         }
@@ -1136,4 +1193,54 @@
             super(reason);
         }
     }
+
+    /**
+     * A class to check if an activity can handle one of the intents from a list of
+     * predefined intents.
+     */
+    private class ItemTypeMatcher {
+
+        private final ArrayList<Intent> mIntents;
+
+        ItemTypeMatcher(int xml_res) {
+            mIntents = xml_res == 0 ? new ArrayList<Intent>() : parseIntents(xml_res);
+        }
+
+        private ArrayList<Intent> parseIntents(int xml_res) {
+            ArrayList<Intent> intents = new ArrayList<Intent>();
+            XmlResourceParser parser = mContext.getResources().getXml(xml_res);
+            try {
+                DefaultLayoutParser.beginDocument(parser, DefaultLayoutParser.TAG_RESOLVE);
+                final int depth = parser.getDepth();
+                int type;
+                while (((type = parser.next()) != XmlPullParser.END_TAG ||
+                        parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+                    if (type != XmlPullParser.START_TAG) {
+                        continue;
+                    } else if (DefaultLayoutParser.TAG_FAVORITE.equals(parser.getName())) {
+                        final String uri = DefaultLayoutParser.getAttributeValue(
+                                parser, DefaultLayoutParser.ATTR_URI);
+                        intents.add(Intent.parseUri(uri, 0));
+                    }
+                }
+            } catch (URISyntaxException | XmlPullParserException | IOException e) {
+                Log.e(TAG, "Unable to parse " + xml_res, e);
+            } finally {
+                parser.close();
+            }
+            return intents;
+        }
+
+        public boolean matches(ActivityInfo activity, PackageManager pm) {
+            for (Intent intent : mIntents) {
+                intent.setPackage(activity.packageName);
+                ResolveInfo info = pm.resolveActivity(intent, 0);
+                if (info != null && (info.activityInfo.name.equals(activity.name)
+                        || info.activityInfo.name.equals(activity.targetActivity))) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 9f97631..f3d94db 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -75,7 +75,6 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.TreeMap;
 
 /**
  * Maintains in-memory state of the Launcher. It is expected that there should be only one
@@ -491,13 +490,7 @@
         Runnable r = new Runnable() {
             public void run() {
                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();
-
-                ArrayList<Long> workspaceScreens = new ArrayList<Long>();
-                TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);
-                for (Integer i : orderedScreens.keySet()) {
-                    long screenId = orderedScreens.get(i);
-                    workspaceScreens.add(screenId);
-                }
+                ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);
 
                 // Find appropriate space for the item.
                 Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,
@@ -549,13 +542,7 @@
                 // Get the list of workspace screens.  We need to append to this list and
                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been
                 // called.
-                ArrayList<Long> workspaceScreens = new ArrayList<Long>();
-                TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);
-                for (Integer i : orderedScreens.keySet()) {
-                    long screenId = orderedScreens.get(i);
-                    workspaceScreens.add(screenId);
-                }
-
+                ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);
                 synchronized(sBgLock) {
                     for (ItemInfo item : workspaceApps) {
                         if (!allowDuplicate) {
@@ -1443,40 +1430,31 @@
         }
     }
 
-    /** Loads the workspace screens db into a map of Rank -> ScreenId */
-    private static TreeMap<Integer, Long> loadWorkspaceScreensDb(Context context) {
+    /**
+     * Loads the workspace screen ids in an ordered list.
+     */
+    private static ArrayList<Long> loadWorkspaceScreensDb(Context context) {
         final ContentResolver contentResolver = context.getContentResolver();
         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
-        final Cursor sc = contentResolver.query(screensUri, null, null, null, null);
-        TreeMap<Integer, Long> orderedScreens = new TreeMap<Integer, Long>();
 
+        // Get screens ordered by rank.
+        final Cursor sc = contentResolver.query(screensUri, null, null, null,
+                LauncherSettings.WorkspaceScreens.SCREEN_RANK);
+        ArrayList<Long> screenIds = new ArrayList<Long>();
         try {
-            final int idIndex = sc.getColumnIndexOrThrow(
-                    LauncherSettings.WorkspaceScreens._ID);
-            final int rankIndex = sc.getColumnIndexOrThrow(
-                    LauncherSettings.WorkspaceScreens.SCREEN_RANK);
+            final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);
             while (sc.moveToNext()) {
                 try {
-                    long screenId = sc.getLong(idIndex);
-                    int rank = sc.getInt(rankIndex);
-                    orderedScreens.put(rank, screenId);
+                    screenIds.add(sc.getLong(idIndex));
                 } catch (Exception e) {
-                    Launcher.addDumpLog(TAG, "Desktop items loading interrupted - invalid screens: " + e, true);
+                    Launcher.addDumpLog(TAG, "Desktop items loading interrupted"
+                            + " - invalid screens: " + e, true);
                 }
             }
         } finally {
             sc.close();
         }
-
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - loadWorkspaceScreensDb()", true);
-        ArrayList<String> orderedScreensPairs= new ArrayList<String>();
-        for (Integer i : orderedScreens.keySet()) {
-            orderedScreensPairs.add("{ " + i + ": " + orderedScreens.get(i) + " }");
-        }
-        Launcher.addDumpLog(TAG, "11683562 -   screens: " +
-                TextUtils.join(", ", orderedScreensPairs), true);
-        return orderedScreens;
+        return screenIds;
     }
 
     public boolean isAllAppsLoaded() {
@@ -1977,6 +1955,7 @@
                                 user = mUserManager.getUserForSerialNumber(serialNumber);
                                 int promiseType = c.getInt(restoredIndex);
                                 int disabledState = 0;
+                                boolean itemReplaced = false;
                                 if (user == null) {
                                     // User has been deleted remove the item.
                                     itemsToRemove.add(id);
@@ -2008,9 +1987,7 @@
                                                     ContentValues values = new ContentValues();
                                                     values.put(LauncherSettings.Favorites.INTENT,
                                                             intent.toUri(0));
-                                                    String where = BaseColumns._ID + "= ?";
-                                                    String[] args = {Long.toString(id)};
-                                                    contentResolver.update(contentUri, values, where, args);
+                                                    updateItem(id, values);
                                                 }
                                             }
 
@@ -2040,10 +2017,27 @@
                                                 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);
+                                                updateItem(id, values);
+                                            } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE) != 0) {
+                                                // This is a common app. Try to replace this.
+                                                int appType = CommonAppTypeParser.decodeItemTypeFromFlag(promiseType);
+                                                CommonAppTypeParser parser = new CommonAppTypeParser(id, appType, context);
+                                                if (parser.findDefaultApp()) {
+                                                    // Default app found. Replace it.
+                                                    intent = parser.parsedIntent;
+                                                    cn = intent.getComponent();
+                                                    ContentValues values = parser.parsedValues;
+                                                    values.put(LauncherSettings.Favorites.RESTORED, 0);
+                                                    updateItem(id, values);
+                                                    restored = false;
+                                                    itemReplaced = true;
 
+                                                } else if (REMOVE_UNRESTORED_ICONS) {
+                                                    Launcher.addDumpLog(TAG,
+                                                            "Unrestored package removed: " + cn, true);
+                                                    itemsToRemove.add(id);
+                                                    continue;
+                                                }
                                             } else if (REMOVE_UNRESTORED_ICONS) {
                                                 Launcher.addDumpLog(TAG,
                                                         "Unrestored package removed: " + cn, true);
@@ -2089,7 +2083,16 @@
                                     continue;
                                 }
 
-                                if (restored) {
+                                if (itemReplaced) {
+                                    if (user.equals(UserHandleCompat.myUserHandle())) {
+                                        info = getShortcutInfo(manager, intent, user, context, null,
+                                                iconIndex, titleIndex, mLabelCache, false);
+                                    } else {
+                                        // Don't replace items for other profiles.
+                                        itemsToRemove.add(id);
+                                        continue;
+                                    }
+                                } else if (restored) {
                                     if (user.equals(UserHandleCompat.myUserHandle())) {
                                         Launcher.addDumpLog(TAG,
                                                 "constructing info for partially restored package",
@@ -2323,9 +2326,7 @@
                                                     providerName);
                                             values.put(LauncherSettings.Favorites.RESTORED,
                                                     appWidgetInfo.restoreStatus);
-                                            String where = BaseColumns._ID + "= ?";
-                                            String[] args = {Long.toString(id)};
-                                            contentResolver.update(contentUri, values, where, args);
+                                            updateItem(id, values);
                                         }
                                     }
                                     sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
@@ -2422,10 +2423,7 @@
                     }
                     LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);
                 } else {
-                    TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);
-                    for (Integer i : orderedScreens.keySet()) {
-                        sBgWorkspaceScreens.add(orderedScreens.get(i));
-                    }
+                    sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));
                     // Log to disk
                     Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +
                             TextUtils.join(", ", sBgWorkspaceScreens), true);
@@ -2480,6 +2478,17 @@
             return loadedOldDb;
         }
 
+        /**
+         * Partially updates the item without any notification. Must be called on the worker thread.
+         */
+        private void updateItem(long itemId, ContentValues update) {
+            mContext.getContentResolver().update(
+                    LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
+                    update,
+                    BaseColumns._ID + "= ?",
+                    new String[]{Long.toString(itemId)});
+        }
+
         /** Filters the set of items who are directly or indirectly (via another container) on the
          * specified screen. */
         private void filterCurrentWorkspaceItems(long currentScreenId,
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index bb6e8c8..196f57c 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -57,7 +57,6 @@
     private static final String TAG = "Launcher.LauncherProvider";
     private static final boolean LOGD = false;
 
-    private static final int MIN_DATABASE_VERSION = 12;
     private static final int DATABASE_VERSION = 21;
 
     static final String OLD_AUTHORITY = "com.android.launcher2.settings";
@@ -492,117 +491,100 @@
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
             if (LOGD) Log.d(TAG, "onUpgrade triggered: " + oldVersion);
-
-            int version = oldVersion;
-            if (version < MIN_DATABASE_VERSION) {
-                // The version cannot be lower that this, as Launcher3 never supported a lower
+            switch (oldVersion) {
+                // The version cannot be lower that 12, as Launcher3 never supported a lower
                 // version of the DB.
-                createEmptyDB(db);
-                version = DATABASE_VERSION;
-            }
-
-            if (version < 13) {
-                // With the new shrink-wrapped and re-orderable workspaces, it makes sense
-                // to persist workspace screens and their relative order.
-                mMaxScreenId = 0;
-
-                addWorkspacesTable(db);
-                version = 13;
-            }
-
-            if (version < 14) {
-                db.beginTransaction();
-                try {
-                    // Insert new column for holding widget provider name
-                    db.execSQL("ALTER TABLE favorites " +
-                            "ADD COLUMN appWidgetProvider TEXT;");
-                    db.setTransactionSuccessful();
-                    version = 14;
-                } catch (SQLException ex) {
-                    // Old version remains, which means we wipe old data
-                    Log.e(TAG, ex.getMessage(), ex);
-                } finally {
-                    db.endTransaction();
+                case 12: {
+                    // With the new shrink-wrapped and re-orderable workspaces, it makes sense
+                    // to persist workspace screens and their relative order.
+                    mMaxScreenId = 0;
+                    addWorkspacesTable(db);
+                }
+                case 13: {
+                    db.beginTransaction();
+                    try {
+                        // Insert new column for holding widget provider name
+                        db.execSQL("ALTER TABLE favorites " +
+                                "ADD COLUMN appWidgetProvider TEXT;");
+                        db.setTransactionSuccessful();
+                    } catch (SQLException ex) {
+                        Log.e(TAG, ex.getMessage(), ex);
+                        // Old version remains, which means we wipe old data
+                        break;
+                    } finally {
+                        db.endTransaction();
+                    }
+                }
+                case 14: {
+                    db.beginTransaction();
+                    try {
+                        // Insert new column for holding update timestamp
+                        db.execSQL("ALTER TABLE favorites " +
+                                "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
+                        db.execSQL("ALTER TABLE workspaceScreens " +
+                                "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
+                        db.setTransactionSuccessful();
+                    } catch (SQLException ex) {
+                        Log.e(TAG, ex.getMessage(), ex);
+                        // Old version remains, which means we wipe old data
+                        break;
+                    } finally {
+                        db.endTransaction();
+                    }
+                }
+                case 15: {
+                    db.beginTransaction();
+                    try {
+                        // Insert new column for holding restore status
+                        db.execSQL("ALTER TABLE favorites " +
+                                "ADD COLUMN restored INTEGER NOT NULL DEFAULT 0;");
+                        db.setTransactionSuccessful();
+                    } catch (SQLException ex) {
+                        Log.e(TAG, ex.getMessage(), ex);
+                        // Old version remains, which means we wipe old data
+                        break;
+                    } finally {
+                        db.endTransaction();
+                    }
+                }
+                case 16: {
+                    // We use the db version upgrade here to identify users who may not have seen
+                    // clings yet (because they weren't available), but for whom the clings are now
+                    // available (tablet users). Because one of the possible cling flows (migration)
+                    // is very destructive (wipes out workspaces), we want to prevent this from showing
+                    // until clear data. We do so by marking that the clings have been shown.
+                    LauncherClings.synchonouslyMarkFirstRunClingDismissed(mContext);
+                }
+                case 17: {
+                    // No-op
+                }
+                case 18: {
+                    // Due to a data loss bug, some users may have items associated with screen ids
+                    // which no longer exist. Since this can cause other problems, and since the user
+                    // will never see these items anyway, we use database upgrade as an opportunity to
+                    // clean things up.
+                    removeOrphanedItems(db);
+                }
+                case 19: {
+                    // Add userId column
+                    if (!addProfileColumn(db)) {
+                        // Old version remains, which means we wipe old data
+                        break;
+                    }
+                }
+                case 20:
+                    if (!updateFolderItemsRank(db, true)) {
+                        break;
+                    }
+                case 21: {
+                    // DB Upgraded successfully
+                    return;
                 }
             }
 
-            if (version < 15) {
-                db.beginTransaction();
-                try {
-                    // Insert new column for holding update timestamp
-                    db.execSQL("ALTER TABLE favorites " +
-                            "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
-                    db.execSQL("ALTER TABLE workspaceScreens " +
-                            "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
-                    db.setTransactionSuccessful();
-                    version = 15;
-                } catch (SQLException ex) {
-                    // Old version remains, which means we wipe old data
-                    Log.e(TAG, ex.getMessage(), ex);
-                } finally {
-                    db.endTransaction();
-                }
-            }
-
-
-            if (version < 16) {
-                db.beginTransaction();
-                try {
-                    // Insert new column for holding restore status
-                    db.execSQL("ALTER TABLE favorites " +
-                            "ADD COLUMN restored INTEGER NOT NULL DEFAULT 0;");
-                    db.setTransactionSuccessful();
-                    version = 16;
-                } catch (SQLException ex) {
-                    // Old version remains, which means we wipe old data
-                    Log.e(TAG, ex.getMessage(), ex);
-                } finally {
-                    db.endTransaction();
-                }
-            }
-
-            if (version < 17) {
-                // We use the db version upgrade here to identify users who may not have seen
-                // clings yet (because they weren't available), but for whom the clings are now
-                // available (tablet users). Because one of the possible cling flows (migration)
-                // is very destructive (wipes out workspaces), we want to prevent this from showing
-                // until clear data. We do so by marking that the clings have been shown.
-                LauncherClings.synchonouslyMarkFirstRunClingDismissed(mContext);
-                version = 17;
-            }
-
-            if (version < 18) {
-                // No-op
-                version = 18;
-            }
-
-            if (version < 19) {
-                // Due to a data loss bug, some users may have items associated with screen ids
-                // which no longer exist. Since this can cause other problems, and since the user
-                // will never see these items anyway, we use database upgrade as an opportunity to
-                // clean things up.
-                removeOrphanedItems(db);
-                version = 19;
-            }
-
-            if (version < 20) {
-                // Add userId column
-                if (addProfileColumn(db)) {
-                    version = 20;
-                }
-                // else old version remains, which means we wipe old data
-            }
-
-            if (version < 21) {
-                if (updateFolderItemsRank(db, true)) {
-                    version  = 21;
-                }
-            }
-
-            if (version != DATABASE_VERSION) {
-                Log.w(TAG, "Destroying all old data.");
-                createEmptyDB(db);
-            }
+            // DB was not upgraded
+            Log.w(TAG, "Destroying all old data.");
+            createEmptyDB(db);
         }
 
         @Override
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 01f7931..15d6a3e 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -46,18 +46,24 @@
      * be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout
      * parsing.
      */
-    public static final int FLAG_AUTOINTALL_ICON = 2;
+    public static final int FLAG_AUTOINTALL_ICON = 2; //0B10;
 
     /**
      * The icon is being installed. If {@link FLAG_RESTORED_ICON} or {@link FLAG_AUTOINTALL_ICON}
      * is set, then the icon is either being installed or is in a broken state.
      */
-    public static final int FLAG_INSTALL_SESSION_ACTIVE = 4;
+    public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; // 0B100;
 
     /**
      * Indicates that the widget restore has started.
      */
-    public static final int FLAG_RESTORE_STARTED = 8;
+    public static final int FLAG_RESTORE_STARTED = 8; //0B1000;
+
+    /**
+     * Indicates if it represents a common type mentioned in {@link CommonAppTypeParser}.
+     * Upto 15 different types supported.
+     */
+    public static final int FLAG_RESTORED_APP_TYPE = 0B0011110000;
 
     /**
      * The intent used to start the application.
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 44d7757..66e370b 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -48,7 +48,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcelable;
-import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -492,7 +491,7 @@
         CellLayout cl = ((CellLayout) child);
         cl.setOnInterceptTouchListener(this);
         cl.setClickable(true);
-        cl.setImportantForAccessibility(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
+        cl.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
         super.onChildViewAdded(parent, child);
     }
 
@@ -2210,8 +2209,8 @@
 
     private void updateAccessibilityFlags() {
         int accessible = mState == State.NORMAL ?
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES :
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
+                IMPORTANT_FOR_ACCESSIBILITY_YES :
+                IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
         setImportantForAccessibility(accessible);
     }