Merge "Defining the list of predefined device profiles in xml. This allows the profiles to be easily customized by derivatives." into ub-launcher3-calgary
diff --git a/protos/backup.proto b/protos/backup.proto
deleted file mode 100644
index 62f935c..0000000
--- a/protos/backup.proto
+++ /dev/null
@@ -1,131 +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.
- */
-
-syntax = "proto2";
-
-package launcher_backup;
-
-option java_package = "com.android.launcher3.backup.nano";
-option java_outer_classname = "BackupProtos";
-
-message Key {
-  enum Type {
-    FAVORITE = 1;
-    SCREEN = 2;
-    ICON = 3;
-    WIDGET = 4;
-  }
-  required Type type = 1;
-  optional string name = 2;  // keep this short
-  optional int64 id = 3;
-  optional int64 checksum = 4;
-}
-
-message CheckedMessage {
-  required bytes payload = 1;
-  required int64 checksum = 2;
-}
-
-message DeviceProfieData {
-  required float desktop_rows = 1;
-  required float desktop_cols = 2;
-  required float hotseat_count = 3;
-  required int32 allapps_rank = 4;
-}
-
-message Journal {
-  required int32 app_version = 1;
-
-  // Time when the backup was created
-  required int64 t = 2;
-
-  // Total bytes written during the last backup
-  // OBSOLETE: A state may contain entries which are already present in the backup
-  // and were not written in the last backup
-  optional int64 bytes = 3;
-
-  // Total entries written during the last backup
-  // OBSOLETE: A state may contain entries which are already present in the backup
-  // and were not written in the last backup
-  optional int32 rows = 4;
-
-  // Valid keys for this state
-  repeated Key key = 5;
-
-  // Backup format version.
-  optional int32 backup_version = 6 [default = 1];
-
-  optional DeviceProfieData profile = 7;
-}
-
-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;
-  optional int32 container = 4;
-  optional int32 screen = 5;
-  optional int32 cellX = 6;
-  optional int32 cellY = 7;
-  optional int32 spanX = 8;
-  optional int32 spanY = 9;
-  optional int32 displayMode = 10;
-  optional int32 appWidgetId = 11;
-  optional string appWidgetProvider = 12;
-  optional string intent = 13;
-  optional string uri = 14;
-  optional int32 iconType = 15 [deprecated = true];
-  optional string iconPackage = 16;
-  optional string iconResource = 17;
-  optional bytes icon = 18;
-
-  // Added in backup version 4
-  optional TargetType targetType = 19 [default = TARGET_NONE];
-  optional int32 rank = 20;
-}
-
-message Screen {
-  required int64 id = 1;
-  optional int32 rank = 2;
-}
-
-message Resource {
-  required int32 dpi = 1;
-  required bytes data = 2;
-}
-
-message Widget {
-  required string provider = 1;
-  optional string label = 2;
-  optional bool configure = 3;
-  optional Resource icon = 4;
-  optional Resource preview = 5;
-
-  // Added in backup version 3
-  // Assume that a widget is resizable upto 2x2 if no data is available
-  optional int32 minSpanX = 6 [default = 2];
-  optional int32 minSpanY = 7 [default = 2];
-}
diff --git a/res/drawable/all_apps_search_bg.xml b/res/drawable/all_apps_search_bg.xml
deleted file mode 100644
index cf63d41..0000000
--- a/res/drawable/all_apps_search_bg.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
--->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:top="@dimen/all_apps_search_bar_bg_overflow"
-        android:left="@dimen/all_apps_search_bar_bg_overflow"
-        android:right="@dimen/all_apps_search_bar_bg_overflow"
-        android:bottom="0dp">
-
-        <shape android:shape="rectangle">
-            <solid android:color="@android:color/transparent" />
-            <stroke
-                android:width="@dimen/all_apps_search_bar_divider_width"
-                android:color="?android:attr/colorAccent"/>
-        </shape>
-    </item>
-</layer-list>
\ No newline at end of file
diff --git a/res/drawable/horizontal_line.xml b/res/drawable/horizontal_line.xml
deleted file mode 100644
index 3f3f17e3..0000000
--- a/res/drawable/horizontal_line.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <size android:height="1dp" />
-    <solid android:color="#ddd" />
-</shape>
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 8c2010f..d55fda7 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -66,7 +66,6 @@
             android:layout_gravity="center|top"
             android:paddingLeft="@dimen/container_fastscroll_thumb_max_width"
             android:paddingRight="@dimen/container_fastscroll_thumb_max_width"
-            android:background="@drawable/all_apps_search_bg"
             android:gravity="center|bottom"
             android:orientation="horizontal"
             android:saveEnabled="false">
diff --git a/res/layout/all_apps_divider.xml b/res/layout/all_apps_divider.xml
new file mode 100644
index 0000000..b2ee7c1
--- /dev/null
+++ b/res/layout/all_apps_divider.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+    android:importantForAccessibility="no"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/all_apps_divider_height"
+    android:layout_marginBottom="@dimen/all_apps_divider_margin_vertical"
+    android:layout_marginLeft="@dimen/container_fastscroll_thumb_max_width"
+    android:layout_marginRight="@dimen/container_fastscroll_thumb_max_width"
+    android:layout_marginTop="@dimen/all_apps_divider_margin_vertical"
+    android:background="@color/all_apps_divider_color"
+    android:focusable="false" />
\ No newline at end of file
diff --git a/res/layout/all_apps_prediction_bar_icon.xml b/res/layout/all_apps_prediction_bar_icon.xml
index 295b0b7..3836fed 100644
--- a/res/layout/all_apps_prediction_bar_icon.xml
+++ b/res/layout/all_apps_prediction_bar_icon.xml
@@ -21,8 +21,8 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="center"
-    android:paddingTop="@dimen/all_apps_prediction_icon_top_padding"
-    android:paddingBottom="@dimen/all_apps_prediction_icon_bottom_padding"
+    android:paddingTop="@dimen/all_apps_icon_top_bottom_padding"
+    android:paddingBottom="@dimen/all_apps_icon_top_bottom_padding"
     android:focusable="true"
     launcher:iconDisplay="all_apps" />
 
diff --git a/res/layout/all_apps_search_market.xml b/res/layout/all_apps_search_market.xml
index 741c96a..0199212 100644
--- a/res/layout/all_apps_search_market.xml
+++ b/res/layout/all_apps_search_market.xml
@@ -19,8 +19,8 @@
     android:layout_width="match_parent"
     android:layout_height="48dp"
     android:gravity="start|center_vertical"
-    android:paddingLeft="16dp"
-    android:paddingRight="16dp"
+    android:paddingLeft="@dimen/container_fastscroll_thumb_max_width"
+    android:paddingRight="@dimen/container_fastscroll_thumb_max_width"
     android:fontFamily="sans-serif-medium"
     android:textSize="14sp"
     android:textColor="?android:attr/colorAccent"
diff --git a/res/layout/all_apps_search_market_divider.xml b/res/layout/all_apps_search_market_divider.xml
deleted file mode 100644
index 3909781..0000000
--- a/res/layout/all_apps_search_market_divider.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?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.
--->
-<ImageView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    android:paddingTop="16dp"
-    android:paddingBottom="8dp"
-    android:paddingLeft="16dp"
-    android:paddingRight="16dp"
-    android:focusable="false"
-    android:scaleType="matrix"
-    android:src="@drawable/horizontal_line" />
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index d411a4f..937b2f0 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -35,6 +35,7 @@
     <color name="quantum_panel_bg_color">#FFF5F5F5</color>
 
     <color name="outline_color">#FFFFFFFF</color>
+    <color name="all_apps_divider_color">#1E000000</color>
 
     <color name="spring_loaded_panel_color">#40FFFFFF</color>
     <color name="spring_loaded_highlighted_panel_border_color">#FFF</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c8a05b7..9abe3e6 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -58,20 +58,18 @@
     <dimen name="container_min_margin">8dp</dimen>
     <dimen name="container_max_width">0dp</dimen>
 
-<!-- All Apps -->
+    <!-- All Apps -->
     <dimen name="all_apps_button_scale_down">0dp</dimen>
     <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
     <dimen name="all_apps_grid_section_y_offset">8dp</dimen>
     <dimen name="all_apps_grid_section_text_size">24sp</dimen>
     <dimen name="all_apps_search_bar_height">60dp</dimen>
+    <dimen name="all_apps_search_bar_margin_top">5dp</dimen>
     <dimen name="all_apps_search_bar_icon_margin_right">4dp</dimen>
     <dimen name="all_apps_search_bar_icon_margin_top">1dp</dimen>
     <dimen name="all_apps_icon_top_bottom_padding">8dp</dimen>
     <dimen name="all_apps_icon_width_gap">24dp</dimen>
-    <!-- The top padding should account for the existing all_apps_list_top_bottom_padding -->
-    <dimen name="all_apps_prediction_icon_top_padding">8dp</dimen>
-    <dimen name="all_apps_prediction_icon_bottom_padding">18dp</dimen>
-    <dimen name="all_apps_list_top_bottom_padding">8dp</dimen>
+    <dimen name="all_apps_list_bottom_padding">8dp</dimen>
     <dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
     <dimen name="all_apps_empty_search_bg_top_offset">144dp</dimen>
     <dimen name="all_apps_background_canvas_width">700dp</dimen>
@@ -82,13 +80,8 @@
     <dimen name="all_apps_header_scroll_to_elevation">16dp</dimen>
     <dimen name="all_apps_header_shadow_height">6dp</dimen>
 
-    <!-- The overflow is used to create a bottom border, by drawing other three sides
-        outside the bounds. Ensure that:
-            all_apps_search_bar_bg_overflow < (-3 * all_apps_search_bar_divider_width)
-        -6dp is picked at random, any smaller value would do.
-    -->
-    <dimen name="all_apps_search_bar_bg_overflow">-6dp</dimen>
-    <dimen name="all_apps_search_bar_divider_width">1dp</dimen>
+    <dimen name="all_apps_divider_height">1dp</dimen>
+    <dimen name="all_apps_divider_margin_vertical">8dp</dimen>
 
     <dimen name="all_apps_bezel_swipe_height">24dp</dimen>
 <!-- Widget tray -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 65baf46..1ac6620 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -63,7 +63,7 @@
     <string name="hotseat_out_of_space">No more room in the Favorites tray</string>
 
     <!-- All applications label -->
-    <string name="all_apps_button_label">Apps</string>
+    <string name="all_apps_button_label">Apps list</string>
     <!-- Label for button in all applications label to go back home (to the workspace / desktop)
          for accessibilty (spoken when the button gets focus). -->
     <string name="all_apps_home_button_label">Home</string>
@@ -149,9 +149,9 @@
 
     <!-- Strings for settings -->
     <!-- Title for Allow Rotation setting. [CHAR LIMIT=50] -->
-    <string name="allow_rotation_title">Allow homescreen rotation</string>
+    <string name="allow_rotation_title">Allow Home screen rotation</string>
     <!-- Text explaining when the home screen will get rotated. [CHAR LIMIT=100] -->
-    <string name="allow_rotation_desc">When device is rotated</string>
+    <string name="allow_rotation_desc">When phone is rotated</string>
     <!-- Text explaining that rotation is disabled in Display settings. 'Display' refers to the Display section in system settings [CHAR LIMIT=100] -->
     <string name="allow_rotation_blocked_desc">Current Display setting doesn\'t permit rotation</string>
 
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index f8ef1e1..4cb050e 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -264,7 +264,7 @@
         // Calculate the current scroll position, the scrollY of the recycler view accounts for the
         // view padding, while the scrollBarY is drawn right up to the background padding (ignoring
         // padding)
-        int scrollY = getScrollTop(scrollPosState);
+        int scrollY = Math.max(0, getScrollTop(scrollPosState));
         int scrollBarY = mBackgroundPadding.top +
                 (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
 
diff --git a/src/com/android/launcher3/CommonAppTypeParser.java b/src/com/android/launcher3/CommonAppTypeParser.java
index a4a92b6..c2bd883 100644
--- a/src/com/android/launcher3/CommonAppTypeParser.java
+++ b/src/com/android/launcher3/CommonAppTypeParser.java
@@ -25,7 +25,6 @@
 
 import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
 import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.backup.nano.BackupProtos.Favorite;
 import com.android.launcher3.util.Thunk;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -43,6 +42,12 @@
 
     private static final int RESTORE_FLAG_BIT_SHIFT = 4;
 
+    public static final int TARGET_PHONE = 1;
+    public static final int TARGET_MESSENGER = 2;
+    public static final int TARGET_EMAIL = 3;
+    public static final int TARGET_BROWSER = 4;
+    public static final int TARGET_GALLERY = 5;
+    public static final int TARGET_CAMERA = 6;
 
     private final long mItemId;
     @Thunk final int mResId;
@@ -118,22 +123,22 @@
 
     public static int getResourceForItemType(int type) {
         switch (type) {
-            case Favorite.TARGET_PHONE:
+            case TARGET_PHONE:
                 return R.xml.app_target_phone;
 
-            case Favorite.TARGET_MESSENGER:
+            case TARGET_MESSENGER:
                 return R.xml.app_target_messenger;
 
-            case Favorite.TARGET_EMAIL:
+            case TARGET_EMAIL:
                 return R.xml.app_target_email;
 
-            case Favorite.TARGET_BROWSER:
+            case TARGET_BROWSER:
                 return R.xml.app_target_browser;
 
-            case Favorite.TARGET_GALLERY:
+            case TARGET_GALLERY:
                 return R.xml.app_target_gallery;
 
-            case Favorite.TARGET_CAMERA:
+            case TARGET_CAMERA:
                 return R.xml.app_target_camera;
 
             default:
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 86f22d5..72bb343 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -194,9 +194,7 @@
         updateIconSize(1f, drawablePadding, res, dm);
         float usedHeight = (cellHeightPx * inv.numRows);
 
-        // We only care about the top and bottom workspace padding, which is not affected by RTL.
-        Rect workspacePadding = getWorkspacePadding();
-        int maxHeight = (availableHeightPx - workspacePadding.top - workspacePadding.bottom);
+        int maxHeight = (availableHeightPx - getTotalWorkspacePadding().y);
         if (usedHeight > maxHeight) {
             scale = maxHeight / usedHeight;
             drawablePadding = 0;
@@ -291,15 +289,23 @@
         Point result = new Point();
         // Since we are only concerned with the overall padding, layout direction does
         // not matter.
-        Rect padding = getWorkspacePadding();
-        result.x = calculateCellWidth(availableWidthPx - padding.left - padding.right,
-                inv.numColumns);
-        result.y = calculateCellHeight(availableHeightPx - padding.top - padding.bottom,
-                inv.numRows);
+        Point padding = getTotalWorkspacePadding();
+        result.x = calculateCellWidth(availableWidthPx - padding.x, inv.numColumns);
+        result.y = calculateCellHeight(availableHeightPx - padding.y, inv.numRows);
         return result;
     }
 
-    /** Returns the workspace padding in the specified orientation */
+    public Point getTotalWorkspacePadding() {
+        Rect padding = getWorkspacePadding();
+        return new Point(padding.left + padding.right, padding.top + padding.bottom);
+    }
+
+    /**
+     * Returns the workspace padding in the specified orientation.
+     * Note that it assumes that while in verticalBarLayout, the nav bar is on the right, as such
+     * this value is not reliable.
+     * Use {@link #getTotalWorkspacePadding()} instead.
+     */
     public Rect getWorkspacePadding() {
         Rect padding = new Rect();
         if (isVerticalBarLayout()) {
@@ -353,17 +359,6 @@
         return zoneHeight;
     }
 
-    // The rect returned will be extended to below the system ui that covers the workspace
-    public boolean isInHotseatRect(int x, int y) {
-        if (isVerticalBarLayout()) {
-            return (x >= (availableWidthPx - hotseatBarHeightPx))
-                    && (y >= 0) && (y <= availableHeightPx);
-        } else {
-            return (x >= 0) && (x <= availableWidthPx)
-                    && (y >= (availableHeightPx - hotseatBarHeightPx));
-        }
-    }
-
     public static int calculateCellWidth(int width, int countX) {
         return width / countX;
     }
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index f245cd3..1a4153f 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -63,18 +63,18 @@
         LauncherAppState app = LauncherAppState.getInstance();
         InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
 
-        Rect paddingLand = idp.landscapeProfile.getWorkspacePadding();
-        Rect paddingPort = idp.portraitProfile.getWorkspacePadding();
+        Point paddingLand = idp.landscapeProfile.getTotalWorkspacePadding();
+        Point paddingPort = idp.portraitProfile.getTotalWorkspacePadding();
 
         // Always assume we're working with the smallest span to make sure we
         // reserve enough space in both orientations.
         float smallestCellWidth = DeviceProfile.calculateCellWidth(Math.min(
-                idp.landscapeProfile.widthPx - paddingLand.left - paddingLand.right,
-                idp.portraitProfile.widthPx - paddingPort.left - paddingPort.right),
+                idp.landscapeProfile.widthPx - paddingLand.x,
+                idp.portraitProfile.widthPx - paddingPort.x),
                 idp.numColumns);
         float smallestCellHeight = DeviceProfile.calculateCellWidth(Math.min(
-                idp.landscapeProfile.heightPx - paddingLand.top - paddingLand.bottom,
-                idp.portraitProfile.heightPx - paddingPort.top - paddingPort.bottom),
+                idp.landscapeProfile.heightPx - paddingLand.y,
+                idp.portraitProfile.heightPx - paddingPort.y),
                 idp.numRows);
 
         // We want to account for the extra amount of padding that we are adding to the widget
diff --git a/src/com/android/launcher3/LauncherBackupAgentHelper.java b/src/com/android/launcher3/LauncherBackupAgentHelper.java
deleted file mode 100644
index c2ab20a..0000000
--- a/src/com/android/launcher3/LauncherBackupAgentHelper.java
+++ /dev/null
@@ -1,137 +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.app.backup.BackupAgentHelper;
-import android.app.backup.BackupDataInput;
-import android.app.backup.BackupManager;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import com.android.launcher3.model.GridSizeMigrationTask;
-
-import java.io.IOException;
-
-public class LauncherBackupAgentHelper extends BackupAgentHelper {
-
-    private static final String TAG = "LauncherBAHelper";
-
-    private static final String KEY_LAST_NOTIFIED_TIME = "backup_manager_last_notified";
-
-    private static final String LAUNCHER_DATA_PREFIX = "L";
-
-    static final boolean VERBOSE = false;
-    static final boolean DEBUG = false;
-
-    /**
-     * Notify the backup manager that out database is dirty.
-     *
-     * <P>This does not force an immediate backup.
-     *
-     * @param context application context
-     */
-    public static void dataChanged(Context context) {
-        dataChanged(context, 0);
-    }
-
-    /**
-     * Notify the backup manager that out database is dirty.
-     *
-     * <P>This does not force an immediate backup.
-     *
-     * @param context application context
-     * @param throttleMs duration in ms for which two consecutive calls to backup manager should
-     *                   not be made.
-     */
-    public static void dataChanged(Context context, long throttleMs) {
-        SharedPreferences prefs = Utilities.getPrefs(context);
-        long now = System.currentTimeMillis();
-        long lastTime = prefs.getLong(KEY_LAST_NOTIFIED_TIME, 0);
-
-        // User can manually change the system time, which could lead to now < lastTime.
-        // Re-backup in that case, as the backup will have a wrong lastModifiedTime.
-        if (now < lastTime || now >= (lastTime + throttleMs)) {
-            BackupManager.dataChanged(context.getPackageName());
-            prefs.edit().putLong(KEY_LAST_NOTIFIED_TIME, now).apply();
-        }
-    }
-
-    private LauncherBackupHelper mHelper;
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mHelper = new LauncherBackupHelper(this);
-        addHelper(LAUNCHER_DATA_PREFIX, mHelper);
-    }
-
-    @Override
-    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
-            throws IOException {
-        if (!Utilities.ATLEAST_LOLLIPOP) {
-            // No restore for old devices.
-            Log.i(TAG, "You shall not pass!!!");
-            Log.d(TAG, "Restore is only supported on devices running Lollipop and above.");
-            return;
-        }
-
-        // Clear dB before restore
-        LauncherSettings.Settings.call(getContentResolver(),
-                LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
-
-        boolean hasData;
-        try {
-            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, null, null, null, null);
-            hasData = c.moveToNext();
-            c.close();
-        } catch (Exception e) {
-            // If the restore fails, we should do a fresh start.
-            Log.e(TAG, "Restore failed", e);
-            hasData = false;
-        }
-
-        if (hasData && mHelper.restoreSuccessful) {
-            LauncherSettings.Settings.call(getContentResolver(),
-                    LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
-            LauncherClings.markFirstRunClingDismissed(this);
-
-            // Rank was added in v4.
-            if (mHelper.restoredBackupVersion <= 3) {
-                LauncherSettings.Settings.call(getContentResolver(),
-                        LauncherSettings.Settings.METHOD_UPDATE_FOLDER_ITEMS_RANK);
-            }
-
-            if (GridSizeMigrationTask.ENABLED && mHelper.shouldAttemptWorkspaceMigration()) {
-                GridSizeMigrationTask.markForMigration(getApplicationContext(),
-                        mHelper.widgetSizes, mHelper.migrationCompatibleProfileData);
-            }
-
-            LauncherSettings.Settings.call(getContentResolver(),
-                    LauncherSettings.Settings.METHOD_CONVERT_SHORTCUTS_TO_ACTIVITIES);
-        } else {
-            if (VERBOSE) Log.v(TAG, "Nothing was restored, clearing DB");
-            LauncherSettings.Settings.call(getContentResolver(),
-                    LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
deleted file mode 100644
index e987a9b..0000000
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ /dev/null
@@ -1,1257 +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.app.backup.BackupDataInputStream;
-import android.app.backup.BackupDataOutput;
-import android.app.backup.BackupHelper;
-import android.app.backup.BackupManager;
-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;
-import android.graphics.Point;
-import android.graphics.drawable.Drawable;
-import android.os.ParcelFileDescriptor;
-import android.text.TextUtils;
-import android.util.Base64;
-import android.util.Log;
-
-import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.LauncherSettings.WorkspaceScreens;
-import com.android.launcher3.backup.nano.BackupProtos;
-import com.android.launcher3.backup.nano.BackupProtos.CheckedMessage;
-import com.android.launcher3.backup.nano.BackupProtos.DeviceProfieData;
-import com.android.launcher3.backup.nano.BackupProtos.Favorite;
-import com.android.launcher3.backup.nano.BackupProtos.Journal;
-import com.android.launcher3.backup.nano.BackupProtos.Key;
-import com.android.launcher3.backup.nano.BackupProtos.Resource;
-import com.android.launcher3.backup.nano.BackupProtos.Screen;
-import com.android.launcher3.backup.nano.BackupProtos.Widget;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
-import com.android.launcher3.compat.UserHandleCompat;
-import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.model.GridSizeMigrationTask;
-import com.android.launcher3.util.Thunk;
-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.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.zip.CRC32;
-
-/**
- * Persist the launcher home state across calamities.
- */
-public class LauncherBackupHelper implements BackupHelper {
-    private static final String TAG = "LauncherBackupHelper";
-    private static final boolean VERBOSE = LauncherBackupAgentHelper.VERBOSE;
-    private static final boolean DEBUG = LauncherBackupAgentHelper.DEBUG;
-
-    private static final int BACKUP_VERSION = 4;
-    private static final int MAX_JOURNAL_SIZE = 1000000;
-
-    // Journal key is such that it is always smaller than any dynamically generated
-    // key (any Base64 encoded string).
-    private static final String JOURNAL_KEY = "#";
-
-    /** icons are large, dribble them out */
-    private static final int MAX_ICONS_PER_PASS = 10;
-
-    /** widgets contain previews, which are very large, dribble them out */
-    private static final int MAX_WIDGETS_PER_PASS = 5;
-
-    private static final String[] FAVORITE_PROJECTION = {
-        Favorites._ID,                     // 0
-        Favorites.MODIFIED,                // 1
-        Favorites.INTENT,                  // 2
-        Favorites.APPWIDGET_PROVIDER,      // 3
-        Favorites.APPWIDGET_ID,            // 4
-        Favorites.CELLX,                   // 5
-        Favorites.CELLY,                   // 6
-        Favorites.CONTAINER,               // 7
-        Favorites.ICON,                    // 8
-        Favorites.ICON_PACKAGE,            // 9
-        Favorites.ICON_RESOURCE,           // 10
-        Favorites.ITEM_TYPE,               // 11
-        Favorites.SCREEN,                  // 12
-        Favorites.SPANX,                   // 13
-        Favorites.SPANY,                   // 14
-        Favorites.TITLE,                   // 15
-        Favorites.PROFILE_ID,              // 16
-        Favorites.RANK,                    // 17
-    };
-
-    private static final int ID_INDEX = 0;
-    private static final int ID_MODIFIED = 1;
-    private static final int INTENT_INDEX = 2;
-    private static final int APPWIDGET_PROVIDER_INDEX = 3;
-    private static final int APPWIDGET_ID_INDEX = 4;
-    private static final int CELLX_INDEX = 5;
-    private static final int CELLY_INDEX = 6;
-    private static final int CONTAINER_INDEX = 7;
-    private static final int ICON_INDEX = 8;
-    private static final int ICON_PACKAGE_INDEX = 9;
-    private static final int ICON_RESOURCE_INDEX = 10;
-    private static final int ITEM_TYPE_INDEX = 11;
-    private static final int SCREEN_INDEX = 12;
-    private static final int SPANX_INDEX = 13;
-    private static final int SPANY_INDEX = 14;
-    private static final int TITLE_INDEX = 15;
-    private static final int RANK_INDEX = 17;
-
-    private static final String[] SCREEN_PROJECTION = {
-        WorkspaceScreens._ID,              // 0
-        WorkspaceScreens.MODIFIED,         // 1
-        WorkspaceScreens.SCREEN_RANK       // 2
-    };
-
-    private static final int SCREEN_RANK_INDEX = 2;
-
-    @Thunk final Context mContext;
-    private final HashSet<String> mExistingKeys;
-    private final ArrayList<Key> mKeys;
-    private final ItemTypeMatcher[] mItemTypeMatchers;
-    private final long mUserSerial;
-
-    private BackupManager mBackupManager;
-    private byte[] mBuffer = new byte[512];
-    private long mLastBackupRestoreTime;
-    private boolean mBackupDataWasUpdated;
-
-    private IconCache mIconCache;
-    private DeviceProfieData mDeviceProfileData;
-    private InvariantDeviceProfile mIdp;
-
-    DeviceProfieData migrationCompatibleProfileData;
-    HashSet<String> widgetSizes = new HashSet<>();
-
-    boolean restoreSuccessful;
-    int restoredBackupVersion = 1;
-
-    // When migrating from a device which different hotseat configuration, the icons are shifted
-    // to center along the new all-apps icon.
-    private int mHotseatShift = 0;
-
-    public LauncherBackupHelper(Context context) {
-        mContext = context;
-        mExistingKeys = new HashSet<String>();
-        mKeys = new ArrayList<Key>();
-        restoreSuccessful = true;
-        mItemTypeMatchers = new ItemTypeMatcher[CommonAppTypeParser.SUPPORTED_TYPE_COUNT];
-
-        UserManagerCompat userManager = UserManagerCompat.getInstance(mContext);
-        mUserSerial = userManager.getSerialNumberForUser(UserHandleCompat.myUserHandle());
-    }
-
-    private void dataChanged() {
-        if (mBackupManager == null) {
-            mBackupManager = new BackupManager(mContext);
-        }
-        mBackupManager.dataChanged();
-    }
-
-    private void applyJournal(Journal journal) {
-        mLastBackupRestoreTime = journal.t;
-        mExistingKeys.clear();
-        if (journal.key != null) {
-            for (Key key : journal.key) {
-                mExistingKeys.add(keyToBackupKey(key));
-            }
-        }
-        restoredBackupVersion = journal.backupVersion;
-    }
-
-    /**
-     * Back up launcher data so we can restore the user's state on a new device.
-     *
-     * <P>The journal is a timestamp and a list of keys that were saved as of that time.
-     *
-     * <P>Keys may come back in any order, so each key/value is one complete row of the database.
-     *
-     * @param oldState notes from the last backup
-     * @param data incremental key/value pairs to persist off-device
-     * @param newState notes for the next backup
-     */
-    @Override
-    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-            ParcelFileDescriptor newState) {
-        if (VERBOSE) Log.v(TAG, "onBackup");
-
-        Journal in = readJournal(oldState);
-        if (!launcherIsReady()) {
-            dataChanged();
-            // Perform backup later.
-            writeJournal(newState, in);
-            return;
-        }
-
-        if (mDeviceProfileData == null) {
-            LauncherAppState app = LauncherAppState.getInstance();
-            mIdp = app.getInvariantDeviceProfile();
-            mDeviceProfileData = initDeviceProfileData(mIdp);
-            mIconCache = app.getIconCache();
-        }
-
-        Log.v(TAG, "lastBackupTime = " + in.t);
-        mKeys.clear();
-        applyJournal(in);
-
-        // Record the time before performing backup so that entries edited while the backup
-        // was going on, do not get missed in next backup.
-        long newBackupTime = System.currentTimeMillis();
-        mBackupDataWasUpdated = false;
-        try {
-            backupFavorites(data);
-            backupScreens(data);
-            backupIcons(data);
-            backupWidgets(data);
-
-            // Delete any key which still exist in the old backup, but is not valid anymore.
-            HashSet<String> validKeys = new HashSet<String>();
-            for (Key key : mKeys) {
-                validKeys.add(keyToBackupKey(key));
-            }
-            mExistingKeys.removeAll(validKeys);
-
-            // Delete anything left in the existing keys.
-            for (String deleted: mExistingKeys) {
-                if (VERBOSE) Log.v(TAG, "dropping deleted item " + deleted);
-                data.writeEntityHeader(deleted, -1);
-                mBackupDataWasUpdated = true;
-            }
-
-            mExistingKeys.clear();
-            if (!mBackupDataWasUpdated) {
-                // Check if any metadata has changed
-                mBackupDataWasUpdated = (in.profile == null)
-                        || !Arrays.equals(DeviceProfieData.toByteArray(in.profile),
-                            DeviceProfieData.toByteArray(mDeviceProfileData))
-                        || (in.backupVersion != BACKUP_VERSION)
-                        || (in.appVersion != getAppVersion());
-            }
-
-            if (mBackupDataWasUpdated) {
-                mLastBackupRestoreTime = newBackupTime;
-
-                // We store the journal at two places.
-                //   1) Storing it in newState allows us to do partial backups by comparing old state
-                //   2) Storing it in backup data allows us to validate keys during restore
-                Journal state = getCurrentStateJournal();
-                writeRowToBackup(JOURNAL_KEY, state, data);
-            } else {
-                if (DEBUG) Log.d(TAG, "Nothing was written during backup");
-            }
-        } catch (IOException e) {
-            Log.e(TAG, "launcher backup has failed", e);
-        }
-
-        writeNewStateDescription(newState);
-    }
-
-    /**
-     * @return true if the backup corresponding to oldstate can be successfully applied
-     * to this device.
-     */
-    private boolean isBackupCompatible(Journal oldState) {
-        DeviceProfieData currentProfile = mDeviceProfileData;
-        DeviceProfieData oldProfile = oldState.profile;
-
-        if (oldProfile == null || oldProfile.desktopCols == 0) {
-            // Profile info is not valid, ignore the check.
-            return true;
-        }
-
-        boolean isHotseatCompatible = false;
-        if (currentProfile.allappsRank >= oldProfile.hotseatCount) {
-            isHotseatCompatible = true;
-            mHotseatShift = 0;
-        }
-
-        if ((currentProfile.allappsRank >= oldProfile.allappsRank)
-                && ((currentProfile.hotseatCount - currentProfile.allappsRank) >=
-                        (oldProfile.hotseatCount - oldProfile.allappsRank))) {
-            // There is enough space on both sides of the hotseat.
-            isHotseatCompatible = true;
-            mHotseatShift = currentProfile.allappsRank - oldProfile.allappsRank;
-        }
-
-        if (!isHotseatCompatible) {
-            return false;
-        }
-        if ((currentProfile.desktopCols >= oldProfile.desktopCols)
-                && (currentProfile.desktopRows >= oldProfile.desktopRows)) {
-            return true;
-        }
-
-        if (GridSizeMigrationTask.ENABLED) {
-            // One time migrate the workspace when launcher starts.
-            migrationCompatibleProfileData = initDeviceProfileData(mIdp);
-            migrationCompatibleProfileData.desktopCols = oldProfile.desktopCols;
-            migrationCompatibleProfileData.desktopRows = oldProfile.desktopRows;
-            migrationCompatibleProfileData.hotseatCount = oldProfile.hotseatCount;
-            migrationCompatibleProfileData.allappsRank = oldProfile.allappsRank;
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Restore launcher configuration from the restored data stream.
-     * It assumes that the keys will arrive in lexical order. So if the journal was present in the
-     * backup, it should arrive first.
-     *
-     * @param data the key/value pair from the server
-     */
-    @Override
-    public void restoreEntity(BackupDataInputStream data) {
-        if (!restoreSuccessful) {
-            return;
-        }
-
-        if (mDeviceProfileData == null) {
-            // This call does not happen on a looper thread. So LauncherAppState
-            // can't be created . Instead initialize required dependencies directly.
-            mIdp = new InvariantDeviceProfile(mContext);
-            mDeviceProfileData = initDeviceProfileData(mIdp);
-            mIconCache = new IconCache(mContext, mIdp);
-        }
-
-        int dataSize = data.size();
-        if (mBuffer.length < dataSize) {
-            mBuffer = new byte[dataSize];
-        }
-        try {
-            int bytesRead = data.read(mBuffer, 0, dataSize);
-            if (DEBUG) Log.d(TAG, "read " + bytesRead + " of " + dataSize + " available");
-            String backupKey = data.getKey();
-
-            if (JOURNAL_KEY.equals(backupKey)) {
-                if (VERBOSE) Log.v(TAG, "Journal entry restored");
-                if (!mKeys.isEmpty()) {
-                    // We received the journal key after a restore key.
-                    Log.wtf(TAG, keyToBackupKey(mKeys.get(0)) + " received after " + JOURNAL_KEY);
-                    restoreSuccessful = false;
-                    return;
-                }
-
-                Journal journal = new Journal();
-                MessageNano.mergeFrom(journal, readCheckedBytes(mBuffer, dataSize));
-                applyJournal(journal);
-                restoreSuccessful = isBackupCompatible(journal);
-                return;
-            }
-
-            if (!mExistingKeys.isEmpty() && !mExistingKeys.contains(backupKey)) {
-                if (DEBUG) Log.e(TAG, "Ignoring key not present in the backup state " + backupKey);
-                return;
-            }
-            Key key = backupKeyToKey(backupKey);
-            mKeys.add(key);
-            switch (key.type) {
-                case Key.FAVORITE:
-                    restoreFavorite(key, mBuffer, dataSize);
-                    break;
-
-                case Key.SCREEN:
-                    restoreScreen(key, mBuffer, dataSize);
-                    break;
-
-                case Key.ICON:
-                    restoreIcon(key, mBuffer, dataSize);
-                    break;
-
-                case Key.WIDGET:
-                    restoreWidget(key, mBuffer, dataSize);
-                    break;
-
-                default:
-                    Log.w(TAG, "unknown restore entity type: " + key.type);
-                    mKeys.remove(key);
-                    break;
-            }
-        } catch (IOException e) {
-            Log.w(TAG, "ignoring unparsable backup entry", e);
-        }
-    }
-
-    /**
-     * Record the restore state for the next backup.
-     *
-     * @param newState notes about the backup state after restore.
-     */
-    @Override
-    public void writeNewStateDescription(ParcelFileDescriptor newState) {
-        writeJournal(newState, getCurrentStateJournal());
-    }
-
-    private Journal getCurrentStateJournal() {
-        Journal journal = new Journal();
-        journal.t = mLastBackupRestoreTime;
-        journal.key = mKeys.toArray(new BackupProtos.Key[mKeys.size()]);
-        journal.appVersion = getAppVersion();
-        journal.backupVersion = BACKUP_VERSION;
-        journal.profile = mDeviceProfileData;
-        return journal;
-    }
-
-    private int getAppVersion() {
-        try {
-            return mContext.getPackageManager()
-                    .getPackageInfo(mContext.getPackageName(), 0).versionCode;
-        } catch (NameNotFoundException e) {
-            return 0;
-        }
-    }
-
-    private DeviceProfieData initDeviceProfileData(InvariantDeviceProfile profile) {
-        DeviceProfieData data = new DeviceProfieData();
-        data.desktopRows = profile.numRows;
-        data.desktopCols = profile.numColumns;
-        data.hotseatCount = profile.numHotseatIcons;
-        return data;
-    }
-
-    /**
-     * Write all modified favorites to the data stream.
-     *
-     * @param data output stream for key/value pairs
-     * @throws IOException
-     */
-    private void backupFavorites(BackupDataOutput data) throws IOException {
-        // persist things that have changed since the last backup
-        ContentResolver cr = mContext.getContentResolver();
-        // Don't backup apps in other profiles for now.
-        Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
-                getUserSelectionArg(), null, null);
-        try {
-            cursor.moveToPosition(-1);
-            while(cursor.moveToNext()) {
-                final long id = cursor.getLong(ID_INDEX);
-                final long updateTime = cursor.getLong(ID_MODIFIED);
-                Key key = getKey(Key.FAVORITE, id);
-                mKeys.add(key);
-                final String backupKey = keyToBackupKey(key);
-
-                // Favorite proto changed in v4. Backup again if the version is old.
-                if (!mExistingKeys.contains(backupKey) || updateTime >= mLastBackupRestoreTime
-                        || restoredBackupVersion < 4) {
-                    writeRowToBackup(key, packFavorite(cursor), data);
-                } else {
-                    if (DEBUG) Log.d(TAG, "favorite already backup up: " + id);
-                }
-            }
-        } finally {
-            cursor.close();
-        }
-    }
-
-    /**
-     * Read a favorite from the stream.
-     *
-     * <P>Keys arrive in any order, so screens and containers may not exist yet.
-     *
-     * @param key identifier for the row
-     * @param buffer the serialized proto from the stream, may be larger than dataSize
-     * @param dataSize the size of the proto from the stream
-     */
-    private void restoreFavorite(Key key, byte[] buffer, int dataSize) throws IOException {
-        if (VERBOSE) Log.v(TAG, "unpacking favorite " + key.id);
-        if (DEBUG) Log.d(TAG, "read (" + buffer.length + "): " +
-                Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP));
-
-        ContentResolver cr = mContext.getContentResolver();
-        ContentValues values = unpackFavorite(buffer, dataSize);
-        cr.insert(Favorites.CONTENT_URI, values);
-    }
-
-    /**
-     * Write all modified screens to the data stream.
-     *
-     * @param data output stream for key/value pairs
-     * @throws IOException
-     */
-    private void backupScreens(BackupDataOutput data) throws IOException {
-        // persist things that have changed since the last backup
-        ContentResolver cr = mContext.getContentResolver();
-        Cursor cursor = cr.query(WorkspaceScreens.CONTENT_URI, SCREEN_PROJECTION,
-                null, null, null);
-        try {
-            cursor.moveToPosition(-1);
-            if (DEBUG) Log.d(TAG, "dumping screens after: " + mLastBackupRestoreTime);
-            while(cursor.moveToNext()) {
-                final long id = cursor.getLong(ID_INDEX);
-                final long updateTime = cursor.getLong(ID_MODIFIED);
-                Key key = getKey(Key.SCREEN, id);
-                mKeys.add(key);
-                final String backupKey = keyToBackupKey(key);
-                if (!mExistingKeys.contains(backupKey) || updateTime >= mLastBackupRestoreTime) {
-                    writeRowToBackup(key, packScreen(cursor), data);
-                } else {
-                    if (VERBOSE) Log.v(TAG, "screen already backup up " + id);
-                }
-            }
-        } finally {
-            cursor.close();
-        }
-    }
-
-    /**
-     * Read a screen from the stream.
-     *
-     * <P>Keys arrive in any order, so children of this screen may already exist.
-     *
-     * @param key identifier for the row
-     * @param buffer the serialized proto from the stream, may be larger than dataSize
-     * @param dataSize the size of the proto from the stream
-     */
-    private void restoreScreen(Key key, byte[] buffer, int dataSize) throws IOException {
-        if (VERBOSE) Log.v(TAG, "unpacking screen " + key.id);
-        if (DEBUG) Log.d(TAG, "read (" + buffer.length + "): " +
-                Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP));
-
-        ContentResolver cr = mContext.getContentResolver();
-        ContentValues values = unpackScreen(buffer, dataSize);
-        cr.insert(WorkspaceScreens.CONTENT_URI, values);
-    }
-
-    /**
-     * Write all the static icon resources we need to render placeholders
-     * for a package that is not installed.
-     *
-     * @param data output stream for key/value pairs
-     */
-    private void backupIcons(BackupDataOutput data) throws IOException {
-        // persist icons that haven't been persisted yet
-        final ContentResolver cr = mContext.getContentResolver();
-        final int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
-        final UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
-        int backupUpIconCount = 0;
-
-        // Don't backup apps in other profiles for now.
-        String where = "(" + Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPLICATION + " OR " +
-                Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_SHORTCUT + " OR " +
-                Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_DEEP_SHORTCUT + ") AND " +
-                getUserSelectionArg();
-        Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
-                where, null, null);
-        try {
-            cursor.moveToPosition(-1);
-            while(cursor.moveToNext()) {
-                final long id = cursor.getLong(ID_INDEX);
-                final String intentDescription = cursor.getString(INTENT_INDEX);
-                try {
-                    Intent intent = Intent.parseUri(intentDescription, 0);
-                    ComponentName cn = intent.getComponent();
-                    Key key = null;
-                    String backupKey = null;
-                    if (cn != null) {
-                        key = getKey(Key.ICON, cn.flattenToShortString());
-                        backupKey = keyToBackupKey(key);
-                    } else {
-                        Log.w(TAG, "empty intent on application favorite: " + id);
-                    }
-                    if (mExistingKeys.contains(backupKey)) {
-                        if (DEBUG) Log.d(TAG, "already saved icon " + backupKey);
-
-                        // remember that we already backed this up previously
-                        mKeys.add(key);
-                    } else if (backupKey != null) {
-                        if (DEBUG) Log.d(TAG, "I can count this high: " + backupUpIconCount);
-                        if (backupUpIconCount < MAX_ICONS_PER_PASS) {
-                            if (DEBUG) Log.d(TAG, "saving icon " + backupKey);
-                            Bitmap icon = mIconCache.getIcon(intent, myUserHandle);
-                            if (icon != null && !mIconCache.isDefaultIcon(icon, myUserHandle)) {
-                                writeRowToBackup(key, packIcon(dpi, icon), data);
-                                mKeys.add(key);
-                                backupUpIconCount ++;
-                            }
-                        } else {
-                            if (VERBOSE) Log.v(TAG, "deferring icon backup " + backupKey);
-                            // too many icons for this pass, request another.
-                            dataChanged();
-                        }
-                    }
-                } catch (URISyntaxException e) {
-                    Log.e(TAG, "invalid URI on application favorite: " + id);
-                } catch (IOException e) {
-                    Log.e(TAG, "unable to save application icon for favorite: " + id);
-                }
-
-            }
-        } finally {
-            cursor.close();
-        }
-    }
-
-    /**
-     * Read an icon from the stream.
-     *
-     * <P>Keys arrive in any order, so shortcuts that use this icon may already exist.
-     *
-     * @param key identifier for the row
-     * @param buffer the serialized proto from the stream, may be larger than dataSize
-     * @param dataSize the size of the proto from the stream
-     */
-    private void restoreIcon(Key key, byte[] buffer, int dataSize) throws IOException {
-        if (VERBOSE) Log.v(TAG, "unpacking icon " + key.id);
-        if (DEBUG) Log.d(TAG, "read (" + buffer.length + "): " +
-                Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP));
-
-        Resource res = unpackProto(new Resource(), buffer, dataSize);
-        if (DEBUG) {
-            Log.d(TAG, "unpacked " + res.dpi + " dpi icon");
-        }
-        Bitmap icon = BitmapFactory.decodeByteArray(res.data, 0, res.data.length);
-        if (icon == null) {
-            Log.w(TAG, "failed to unpack icon for " + key.name);
-        } else {
-            if (VERBOSE) Log.v(TAG, "saving restored icon as: " + key.name);
-            mIconCache.preloadIcon(ComponentName.unflattenFromString(key.name), icon, res.dpi,
-                    "" /* label */, mUserSerial, mIdp);
-        }
-    }
-
-    /**
-     * Write all the static widget resources we need to render placeholders
-     * for a package that is not installed.
-     *
-     * @param data output stream for key/value pairs
-     * @throws IOException
-     */
-    private void backupWidgets(BackupDataOutput data) throws IOException {
-        // persist static widget info that hasn't been persisted yet
-        final ContentResolver cr = mContext.getContentResolver();
-        final int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
-        int backupWidgetCount = 0;
-
-        String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPWIDGET + " AND "
-                + getUserSelectionArg();
-        Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
-                where, null, null);
-        AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(mContext);
-        try {
-            cursor.moveToPosition(-1);
-            while(cursor.moveToNext()) {
-                final long id = cursor.getLong(ID_INDEX);
-                final String providerName = cursor.getString(APPWIDGET_PROVIDER_INDEX);
-                final ComponentName provider = ComponentName.unflattenFromString(providerName);
-
-                Key key = null;
-                String backupKey = null;
-                if (provider != null) {
-                    key = getKey(Key.WIDGET, providerName);
-                    backupKey = keyToBackupKey(key);
-                } else {
-                    Log.w(TAG, "empty intent on appwidget: " + id);
-                }
-
-                // Widget backup proto changed in v3. So add it again if the original backup is old.
-                if (mExistingKeys.contains(backupKey) && restoredBackupVersion >= 3) {
-                    if (DEBUG) Log.d(TAG, "already saved widget " + backupKey);
-
-                    // remember that we already backed this up previously
-                    mKeys.add(key);
-                } else if (backupKey != null) {
-                    if (DEBUG) Log.d(TAG, "I can count this high: " + backupWidgetCount);
-                    if (backupWidgetCount < MAX_WIDGETS_PER_PASS) {
-                        LauncherAppWidgetProviderInfo widgetInfo = widgetManager
-                                .getLauncherAppWidgetInfo(cursor.getInt(APPWIDGET_ID_INDEX));
-                        if (widgetInfo != null) {
-                            if (DEBUG) Log.d(TAG, "saving widget " + backupKey);
-                            writeRowToBackup(key, packWidget(dpi, widgetInfo), data);
-                            mKeys.add(key);
-                            backupWidgetCount ++;
-                        }
-                    } else {
-                        if (VERBOSE) Log.v(TAG, "deferring widget backup " + backupKey);
-                        // too many widgets for this pass, request another.
-                        dataChanged();
-                    }
-                }
-            }
-        } finally {
-            cursor.close();
-        }
-    }
-
-    /**
-     * Read a widget from the stream.
-     *
-     * <P>Keys arrive in any order, so widgets that use this data may already exist.
-     *
-     * @param key identifier for the row
-     * @param buffer the serialized proto from the stream, may be larger than dataSize
-     * @param dataSize the size of the proto from the stream
-     */
-    private void restoreWidget(Key key, byte[] buffer, int dataSize) throws IOException {
-        if (VERBOSE) Log.v(TAG, "unpacking widget " + key.id);
-        if (DEBUG) Log.d(TAG, "read (" + buffer.length + "): " +
-                Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP));
-        Widget widget = unpackProto(new Widget(), buffer, dataSize);
-        if (DEBUG) Log.d(TAG, "unpacked " + widget.provider);
-        if (widget.icon.data != null)  {
-            Bitmap icon = BitmapFactory
-                    .decodeByteArray(widget.icon.data, 0, widget.icon.data.length);
-            if (icon == null) {
-                Log.w(TAG, "failed to unpack widget icon for " + key.name);
-            } else {
-                mIconCache.preloadIcon(ComponentName.unflattenFromString(widget.provider),
-                        icon, widget.icon.dpi, widget.label, mUserSerial, mIdp);
-            }
-        }
-
-        // Cache widget min sizes incase migration is required.
-        widgetSizes.add(widget.provider + "#" + widget.minSpanX + "," + widget.minSpanY);
-    }
-
-    /** create a new key, with an integer ID.
-     *
-     * <P> Keys contain their own checksum instead of using
-     * the heavy-weight CheckedMessage wrapper.
-     */
-    private Key getKey(int type, long id) {
-        Key key = new Key();
-        key.type = type;
-        key.id = id;
-        key.checksum = checkKey(key);
-        return key;
-    }
-
-    /** create a new key for a named object.
-     *
-     * <P> Keys contain their own checksum instead of using
-     * the heavy-weight CheckedMessage wrapper.
-     */
-    private Key getKey(int type, String name) {
-        Key key = new Key();
-        key.type = type;
-        key.name = name;
-        key.checksum = checkKey(key);
-        return key;
-    }
-
-    /** keys need to be strings, serialize and encode. */
-    private String keyToBackupKey(Key key) {
-        return Base64.encodeToString(Key.toByteArray(key), Base64.NO_WRAP);
-    }
-
-    /** keys need to be strings, decode and parse. */
-    private Key backupKeyToKey(String backupKey) throws InvalidBackupException {
-        try {
-            Key key = Key.parseFrom(Base64.decode(backupKey, Base64.DEFAULT));
-            if (key.checksum != checkKey(key)) {
-                throw new InvalidBackupException("invalid key read from stream" + backupKey);
-            }
-            return key;
-        } catch (InvalidProtocolBufferNanoException | IllegalArgumentException e) {
-            throw new InvalidBackupException(e);
-        }
-    }
-
-    /** Compute the checksum over the important bits of a key. */
-    private long checkKey(Key key) {
-        CRC32 checksum = new CRC32();
-        checksum.update(key.type);
-        checksum.update((int) (key.id & 0xffff));
-        checksum.update((int) ((key.id >> 32) & 0xffff));
-        if (!TextUtils.isEmpty(key.name)) {
-            checksum.update(key.name.getBytes());
-        }
-        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
-                || favorite.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT);
-    }
-
-    /** Serialize a Favorite for persistence, including a checksum wrapper. */
-    private Favorite packFavorite(Cursor c) {
-        Favorite favorite = new Favorite();
-        favorite.id = c.getLong(ID_INDEX);
-        favorite.screen = c.getInt(SCREEN_INDEX);
-        favorite.container = c.getInt(CONTAINER_INDEX);
-        favorite.cellX = c.getInt(CELLX_INDEX);
-        favorite.cellY = c.getInt(CELLY_INDEX);
-        favorite.spanX = c.getInt(SPANX_INDEX);
-        favorite.spanY = c.getInt(SPANY_INDEX);
-        favorite.rank = c.getInt(RANK_INDEX);
-
-        String title = c.getString(TITLE_INDEX);
-        if (!TextUtils.isEmpty(title)) {
-            favorite.title = title;
-        }
-        String intentDescription = c.getString(INTENT_INDEX);
-        Intent intent = null;
-        if (!TextUtils.isEmpty(intentDescription)) {
-            try {
-                intent = Intent.parseUri(intentDescription, 0);
-                intent.removeExtra(ItemInfo.EXTRA_PROFILE);
-                favorite.intent = intent.toUri(0);
-            } catch (URISyntaxException e) {
-                Log.e(TAG, "Invalid intent", e);
-            }
-        }
-        favorite.itemType = c.getInt(ITEM_TYPE_INDEX);
-        if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) {
-            favorite.appWidgetId = c.getInt(APPWIDGET_ID_INDEX);
-            String appWidgetProvider = c.getString(APPWIDGET_PROVIDER_INDEX);
-            if (!TextUtils.isEmpty(appWidgetProvider)) {
-                favorite.appWidgetProvider = appWidgetProvider;
-            }
-        } else if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT
-                || favorite.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-            String iconPackage = c.getString(ICON_PACKAGE_INDEX);
-            String iconResource = c.getString(ICON_RESOURCE_INDEX);
-            if (!TextUtils.isEmpty(iconPackage) && !TextUtils.isEmpty(iconResource)) {
-                favorite.iconResource = iconResource;
-                favorite.iconPackage = iconPackage;
-            }
-
-            byte[] blob = c.getBlob(ICON_INDEX);
-            if (blob != null && blob.length > 0) {
-                favorite.icon = blob;
-            }
-        }
-
-        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;
-    }
-
-    /** Deserialize a Favorite from persistence, after verifying checksum wrapper. */
-    private ContentValues unpackFavorite(byte[] buffer, int dataSize)
-            throws IOException {
-        Favorite favorite = unpackProto(new Favorite(), buffer, dataSize);
-
-        // If it is a hotseat item, move it accordingly.
-        if (favorite.container == Favorites.CONTAINER_HOTSEAT) {
-            favorite.screen += mHotseatShift;
-        }
-
-        ContentValues values = new ContentValues();
-        values.put(Favorites._ID, favorite.id);
-        values.put(Favorites.SCREEN, favorite.screen);
-        values.put(Favorites.CONTAINER, favorite.container);
-        values.put(Favorites.CELLX, favorite.cellX);
-        values.put(Favorites.CELLY, favorite.cellY);
-        values.put(Favorites.SPANX, favorite.spanX);
-        values.put(Favorites.SPANY, favorite.spanY);
-        values.put(Favorites.RANK, favorite.rank);
-
-        if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT
-                || favorite.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-            values.put(Favorites.ICON_PACKAGE, favorite.iconPackage);
-            values.put(Favorites.ICON_RESOURCE, favorite.iconResource);
-            values.put(Favorites.ICON, favorite.icon);
-        }
-
-        if (!TextUtils.isEmpty(favorite.title)) {
-            values.put(Favorites.TITLE, favorite.title);
-        } else {
-            values.put(Favorites.TITLE, "");
-        }
-        if (!TextUtils.isEmpty(favorite.intent)) {
-            values.put(Favorites.INTENT, favorite.intent);
-        }
-        values.put(Favorites.ITEM_TYPE, favorite.itemType);
-
-        UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
-        long userSerialNumber =
-                UserManagerCompat.getInstance(mContext).getSerialNumberForUser(myUserHandle);
-        values.put(LauncherSettings.Favorites.PROFILE_ID, userSerialNumber);
-
-        // If we will attempt grid resize, use the original profile to validate grid size, as
-        // anything which fits in the original grid should fit in the current grid after
-        // grid migration.
-        DeviceProfieData currentProfile = migrationCompatibleProfileData == null
-                ? mDeviceProfileData : migrationCompatibleProfileData;
-
-        if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) {
-            if (!TextUtils.isEmpty(favorite.appWidgetProvider)) {
-                values.put(Favorites.APPWIDGET_PROVIDER, favorite.appWidgetProvider);
-            }
-            values.put(Favorites.APPWIDGET_ID, favorite.appWidgetId);
-            values.put(LauncherSettings.Favorites.RESTORED,
-                    LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
-                    LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY |
-                    LauncherAppWidgetInfo.FLAG_UI_NOT_READY);
-
-            // Verify placement
-            if (((favorite.cellX + favorite.spanX) > currentProfile.desktopCols)
-                    || ((favorite.cellY + favorite.spanY) > currentProfile.desktopRows)) {
-                restoreSuccessful = false;
-                throw new InvalidBackupException("Widget not in screen bounds, aborting restore");
-            }
-        } else {
-            // 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) {
-                if ((favorite.screen >= currentProfile.hotseatCount)
-                        || (favorite.screen == currentProfile.allappsRank)) {
-                    restoreSuccessful = false;
-                    throw new InvalidBackupException("Item not in hotseat bounds, aborting restore");
-                }
-            } else {
-                if ((favorite.cellX >= currentProfile.desktopCols)
-                        || (favorite.cellY >= currentProfile.desktopRows)) {
-                    restoreSuccessful = false;
-                    throw new InvalidBackupException("Item not in desktop bounds, aborting restore");
-                }
-            }
-        }
-
-        return values;
-    }
-
-    /** Serialize a Screen for persistence, including a checksum wrapper. */
-    private Screen packScreen(Cursor c) {
-        Screen screen = new Screen();
-        screen.id = c.getLong(ID_INDEX);
-        screen.rank = c.getInt(SCREEN_RANK_INDEX);
-        return screen;
-    }
-
-    /** Deserialize a Screen from persistence, after verifying checksum wrapper. */
-    private ContentValues unpackScreen(byte[] buffer, int dataSize)
-            throws InvalidProtocolBufferNanoException {
-        Screen screen = unpackProto(new Screen(), buffer, dataSize);
-        ContentValues values = new ContentValues();
-        values.put(WorkspaceScreens._ID, screen.id);
-        values.put(WorkspaceScreens.SCREEN_RANK, screen.rank);
-        return values;
-    }
-
-    /** Serialize an icon Resource for persistence, including a checksum wrapper. */
-    private Resource packIcon(int dpi, Bitmap icon) {
-        Resource res = new Resource();
-        res.dpi = dpi;
-        res.data = Utilities.flattenBitmap(icon);
-        return res;
-    }
-
-    /** Serialize a widget for persistence, including a checksum wrapper. */
-    private Widget packWidget(int dpi, LauncherAppWidgetProviderInfo info) {
-        Widget widget = new Widget();
-        widget.provider = info.provider.flattenToShortString();
-        widget.label = info.label;
-        widget.configure = info.configure != null;
-        if (info.icon != 0) {
-            widget.icon = new Resource();
-            Drawable fullResIcon = mIconCache.getFullResIcon(info.provider.getPackageName(), info.icon);
-            Bitmap icon = Utilities.createIconBitmap(fullResIcon, mContext);
-            widget.icon.data = Utilities.flattenBitmap(icon);
-            widget.icon.dpi = dpi;
-        }
-
-        Point spans = info.getMinSpans(mIdp, mContext);
-        widget.minSpanX = spans.x;
-        widget.minSpanY = spans.y;
-        return widget;
-    }
-
-    /**
-     * Deserialize a proto after verifying checksum wrapper.
-     */
-    private <T extends MessageNano> T unpackProto(T proto, byte[] buffer, int dataSize)
-            throws InvalidProtocolBufferNanoException {
-        MessageNano.mergeFrom(proto, readCheckedBytes(buffer, dataSize));
-        if (DEBUG) Log.d(TAG, "unpacked proto " + proto);
-        return proto;
-    }
-
-    /**
-     * Read the old journal from the input file.
-     *
-     * In the event of any error, just pretend we didn't have a journal,
-     * in that case, do a full backup.
-     *
-     * @param oldState the read-0only file descriptor pointing to the old journal
-     * @return a Journal protocol buffer
-     */
-    private Journal readJournal(ParcelFileDescriptor oldState) {
-        Journal journal = new Journal();
-        if (oldState == null) {
-            return journal;
-        }
-        FileInputStream inStream = new FileInputStream(oldState.getFileDescriptor());
-        try {
-            int availableBytes = inStream.available();
-            if (DEBUG) Log.d(TAG, "available " + availableBytes);
-            if (availableBytes < MAX_JOURNAL_SIZE) {
-                byte[] buffer = new byte[availableBytes];
-                int bytesRead = 0;
-                boolean valid = false;
-                InvalidProtocolBufferNanoException lastProtoException = null;
-                while (availableBytes > 0) {
-                    try {
-                        // OMG what are you doing? This is crazy inefficient!
-                        // If we read a byte that is not ours, we will cause trouble: b/12491813
-                        // However, we don't know how many bytes to expect (oops).
-                        // So we have to step through *slowly*, watching for the end.
-                        int result = inStream.read(buffer, bytesRead, 1);
-                        if (result > 0) {
-                            availableBytes -= result;
-                            bytesRead += result;
-                        } else {
-                            Log.w(TAG, "unexpected end of file while reading journal.");
-                            // stop reading and see what there is to parse
-                            availableBytes = 0;
-                        }
-                    } catch (IOException e) {
-                        buffer = null;
-                        availableBytes = 0;
-                    }
-
-                    // check the buffer to see if we have a valid journal
-                    try {
-                        MessageNano.mergeFrom(journal, readCheckedBytes(buffer, bytesRead));
-                        // if we are here, then we have read a valid, checksum-verified journal
-                        valid = true;
-                        availableBytes = 0;
-                        if (VERBOSE) Log.v(TAG, "read " + bytesRead + " bytes of journal");
-                    } catch (InvalidProtocolBufferNanoException e) {
-                        // if we don't have the whole journal yet, mergeFrom will throw. keep going.
-                        lastProtoException = e;
-                        journal.clear();
-                    }
-                }
-                if (DEBUG) Log.d(TAG, "journal bytes read: " + bytesRead);
-                if (!valid) {
-                    Log.w(TAG, "could not find a valid journal", lastProtoException);
-                }
-            }
-        } catch (IOException e) {
-            Log.w(TAG, "failed to close the journal", e);
-        } finally {
-            try {
-                inStream.close();
-            } catch (IOException e) {
-                Log.w(TAG, "failed to close the journal", e);
-            }
-        }
-        return journal;
-    }
-
-    private void writeRowToBackup(Key key, MessageNano proto, BackupDataOutput data)
-            throws IOException {
-        writeRowToBackup(keyToBackupKey(key), proto, data);
-    }
-
-    private void writeRowToBackup(String backupKey, MessageNano proto,
-            BackupDataOutput data) throws IOException {
-        byte[] blob = writeCheckedBytes(proto);
-        data.writeEntityHeader(backupKey, blob.length);
-        data.writeEntityData(blob, blob.length);
-        mBackupDataWasUpdated = true;
-        if (VERBOSE) Log.v(TAG, "Writing New entry " + backupKey);
-    }
-
-    /**
-     * Write the new journal to the output file.
-     *
-     * In the event of any error, just pretend we didn't have a journal,
-     * in that case, do a full backup.
-
-     * @param newState the write-only file descriptor pointing to the new journal
-     * @param journal a Journal protocol buffer
-     */
-    private void writeJournal(ParcelFileDescriptor newState, Journal journal) {
-        try {
-            FileOutputStream outStream = new FileOutputStream(newState.getFileDescriptor());
-            final byte[] journalBytes = writeCheckedBytes(journal);
-            outStream.write(journalBytes);
-            outStream.close();
-            if (VERBOSE) Log.v(TAG, "wrote " + journalBytes.length + " bytes of journal");
-        } catch (IOException e) {
-            Log.w(TAG, "failed to write backup journal", e);
-        }
-    }
-
-    /** Wrap a proto in a CheckedMessage and compute the checksum. */
-    private byte[] writeCheckedBytes(MessageNano proto) {
-        CheckedMessage wrapper = new CheckedMessage();
-        wrapper.payload = MessageNano.toByteArray(proto);
-        CRC32 checksum = new CRC32();
-        checksum.update(wrapper.payload);
-        wrapper.checksum = checksum.getValue();
-        return MessageNano.toByteArray(wrapper);
-    }
-
-    /** Unwrap a proto message from a CheckedMessage, verifying the checksum. */
-    private static byte[] readCheckedBytes(byte[] buffer, int dataSize)
-            throws InvalidProtocolBufferNanoException {
-        CheckedMessage wrapper = new CheckedMessage();
-        MessageNano.mergeFrom(wrapper, buffer, 0, dataSize);
-        CRC32 checksum = new CRC32();
-        checksum.update(wrapper.payload);
-        if (wrapper.checksum != checksum.getValue()) {
-            throw new InvalidProtocolBufferNanoException("checksum does not match");
-        }
-        return wrapper.payload;
-    }
-
-    /**
-     * @return true if the launcher is in a state to support backup
-     */
-    private boolean launcherIsReady() {
-        ContentResolver cr = mContext.getContentResolver();
-        Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION, null, null, null);
-        if (cursor == null) {
-            // launcher data has been wiped, do nothing
-            return false;
-        }
-        cursor.close();
-
-        if (LauncherAppState.getInstanceNoCreate() == null) {
-            // launcher services are unavailable, try again later
-            return false;
-        }
-
-        return true;
-    }
-
-    private String getUserSelectionArg() {
-        return Favorites.PROFILE_ID + '=' + UserManagerCompat.getInstance(mContext)
-                .getSerialNumberForUser(UserHandleCompat.myUserHandle());
-    }
-
-    @Thunk class InvalidBackupException extends IOException {
-
-        private static final long serialVersionUID = 8931456637211665082L;
-
-        @Thunk InvalidBackupException(Throwable cause) {
-            super(cause);
-        }
-
-        @Thunk InvalidBackupException(String reason) {
-            super(reason);
-        }
-    }
-
-    public boolean shouldAttemptWorkspaceMigration() {
-        return migrationCompatibleProfileData != null;
-    }
-
-    /**
-     * 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/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index f5b32ed..a79df0d 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -382,14 +382,6 @@
                 loadDefaultFavoritesIfNecessary();
                 return null;
             }
-            case LauncherSettings.Settings.METHOD_UPDATE_FOLDER_ITEMS_RANK: {
-                mOpenHelper.updateFolderItemsRank(mOpenHelper.getWritableDatabase(), false);
-                return null;
-            }
-            case LauncherSettings.Settings.METHOD_CONVERT_SHORTCUTS_TO_ACTIVITIES: {
-                mOpenHelper.convertShortcutsToLauncherActivities(mOpenHelper.getWritableDatabase());
-                return null;
-            }
             case LauncherSettings.Settings.METHOD_DELETE_DB: {
                 // Are you sure? (y/n)
                 mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
@@ -439,8 +431,6 @@
      * Overridden in tests
      */
     protected void notifyListeners() {
-        // always notify the backup agent
-        LauncherBackupAgentHelper.dataChanged(getContext());
         mListenerHandler.sendEmptyMessage(ChangeListenerWrapper.MSG_LAUNCHER_PROVIDER_CHANGED);
     }
 
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 104af52..7bcf5d0 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -15,7 +15,9 @@
 
     private final Paint mOpaquePaint;
     @ViewDebug.ExportedProperty(category = "launcher")
-    private boolean mDrawRightInsetBar;
+    private boolean mDrawSideInsetBar;
+    @ViewDebug.ExportedProperty(category = "launcher")
+    private int mLeftInsetBarWidth;
     @ViewDebug.ExportedProperty(category = "launcher")
     private int mRightInsetBarWidth;
 
@@ -42,13 +44,14 @@
     @TargetApi(23)
     @Override
     protected boolean fitSystemWindows(Rect insets) {
-        mDrawRightInsetBar = insets.right > 0 &&
+        mDrawSideInsetBar = (insets.right > 0 || insets.left > 0) &&
                 (!Utilities.ATLEAST_MARSHMALLOW ||
                 getContext().getSystemService(ActivityManager.class).isLowRamDevice());
         mRightInsetBarWidth = insets.right;
-        setInsets(mDrawRightInsetBar ? new Rect(0, insets.top, 0, insets.bottom) : insets);
+        mLeftInsetBarWidth = insets.left;
+        setInsets(mDrawSideInsetBar ? new Rect(0, insets.top, 0, insets.bottom) : insets);
 
-        if (mAlignedView != null && mDrawRightInsetBar) {
+        if (mAlignedView != null && mDrawSideInsetBar) {
             // Apply margins on aligned view to handle left/right insets.
             MarginLayoutParams lp = (MarginLayoutParams) mAlignedView.getLayoutParams();
             if (lp.leftMargin != insets.left || lp.rightMargin != insets.right) {
@@ -66,9 +69,14 @@
         super.dispatchDraw(canvas);
 
         // If the right inset is opaque, draw a black rectangle to ensure that is stays opaque.
-        if (mDrawRightInsetBar) {
-            int width = getWidth();
-            canvas.drawRect(width - mRightInsetBarWidth, 0, width, getHeight(), mOpaquePaint);
+        if (mDrawSideInsetBar) {
+            if (mRightInsetBarWidth > 0) {
+                int width = getWidth();
+                canvas.drawRect(width - mRightInsetBarWidth, 0, width, getHeight(), mOpaquePaint);
+            }
+            if (mLeftInsetBarWidth > 0) {
+                canvas.drawRect(0, 0, mLeftInsetBarWidth, getHeight(), mOpaquePaint);
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index c213c8d..8157eb3 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -285,9 +285,6 @@
         public static final String METHOD_CLEAR_EMPTY_DB_FLAG = "clear_empty_db_flag";
 
         public static final String METHOD_DELETE_EMPTY_FOLDERS = "delete_empty_folders";
-        public static final String METHOD_UPDATE_FOLDER_ITEMS_RANK = "update_folder_items_rank";
-        public static final String METHOD_CONVERT_SHORTCUTS_TO_ACTIVITIES =
-                "convert_shortcuts_to_launcher_activities";
 
         public static final String METHOD_NEW_ITEM_ID = "generate_new_item_id";
         public static final String METHOD_NEW_SCREEN_ID = "generate_new_screen_id";
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 2d3e8dd..a37fe5b 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -251,7 +251,7 @@
         if (mPageIndicatorViewId > -1) {
             mPageIndicator = (PageIndicator) parent.findViewById(mPageIndicatorViewId);
             mPageIndicator.setMarkersCount(getChildCount());
-            mPageIndicator.setContentDescription(getCurrentPageDescription());
+            mPageIndicator.setContentDescription(getPageIndicatorDescription());
         }
     }
 
@@ -442,7 +442,7 @@
     private void updatePageIndicator() {
         // Update the page indicator (when we aren't reordering)
         if (mPageIndicator != null) {
-            mPageIndicator.setContentDescription(getCurrentPageDescription());
+            mPageIndicator.setContentDescription(getPageIndicatorDescription());
             if (!isReordering(false)) {
                 mPageIndicator.setActiveMarker(getNextPage());
             }
@@ -2276,6 +2276,10 @@
         return false;
     }
 
+    protected String getPageIndicatorDescription() {
+        return getCurrentPageDescription();
+    }
+
     protected String getCurrentPageDescription() {
         return getContext().getString(R.string.default_scroll_format,
                 getNextPage() + 1, getChildCount());
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index dd54495..1b3f5df 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -357,7 +357,16 @@
 
     @Override
     public void setInsets(Rect insets) {
+        int extraLeftPadding = insets.left - mInsets.left;
         mInsets.set(insets);
+        if (extraLeftPadding != 0) {
+            /**
+             * Initial layout assumes that the insets is on the right,
+             * {@link DeviceProfile#getWorkspacePadding()}. Compensate for the difference.
+             */
+            setPadding(getPaddingLeft() + extraLeftPadding, getPaddingTop(),
+                    getPaddingRight() - extraLeftPadding, getPaddingBottom());
+        }
 
         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);
         if (customScreen != null) {
@@ -550,8 +559,9 @@
         // Add the first page
         CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, 0);
 
-        if (!mIsRtl || !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-            // Let the cell layout extend the start padding.
+        if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+            // Let the cell layout extend the start padding. On transposed layout, there is page
+            // indicator on left and hotseat on right, as such workspace does not touch the edge.
             ((LayoutParams) firstPage.getLayoutParams()).matchStartEdge = true;
             firstPage.setPaddingRelative(getPaddingStart(), 0, 0, 0);
         }
@@ -3087,7 +3097,11 @@
        mTempXY[0] = x;
        mTempXY[1] = y;
        mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY, true);
-       return mLauncher.getDeviceProfile().isInHotseatRect(mTempXY[0], mTempXY[1]);
+       View hotseat = mLauncher.getHotseat();
+       return mTempXY[0] >= hotseat.getLeft() &&
+               mTempXY[0] <= hotseat.getRight() &&
+               mTempXY[1] >= hotseat.getTop() &&
+               mTempXY[1] <= hotseat.getBottom();
    }
 
    void mapPointFromSelfToHotseatLayout(Hotseat hotseat, float[] xy) {
@@ -4410,6 +4424,11 @@
     }
 
     @Override
+    protected String getPageIndicatorDescription() {
+        return getResources().getString(R.string.all_apps_button_label);
+    }
+
+    @Override
     protected String getCurrentPageDescription() {
         if (hasCustomContent() && getNextPage() == 0) {
             return mCustomContentDescription;
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 79a15b9..717ce74 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -32,7 +32,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -72,7 +71,7 @@
             AlphabeticalAppsList.SectionInfo withSection,
             int sectionAppCount, int numAppsPerRow, int mergeCount) {
         // Don't merge the predicted apps
-        if (section.firstAppItem.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+        if (section.firstAppItem.viewType != AllAppsGridAdapter.VIEW_TYPE_ICON) {
             return false;
         }
         // Otherwise, merge every other section
@@ -104,7 +103,7 @@
             AlphabeticalAppsList.SectionInfo withSection,
             int sectionAppCount, int numAppsPerRow, int mergeCount) {
         // Don't merge the predicted apps
-        if (section.firstAppItem.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+        if (section.firstAppItem.viewType != AllAppsGridAdapter.VIEW_TYPE_ICON) {
             return false;
         }
 
@@ -153,13 +152,14 @@
     private ExtendedEditText mSearchInput;
     private ImageView mSearchIcon;
     private HeaderElevationController mElevationController;
+    private int mSearchContainerOffsetTop;
 
     private SpannableStringBuilder mSearchQueryBuilder = null;
 
     private int mSectionNamesMargin;
     private int mNumAppsPerRow;
     private int mNumPredictedAppsPerRow;
-    private int mRecyclerViewTopBottomPadding;
+    private int mRecyclerViewBottomPadding;
     // This coordinate is relative to this container view
     private final Point mBoundsCheckLastTouchDownPos = new Point(-1, -1);
 
@@ -184,11 +184,11 @@
         mItemDecoration = mAdapter.getItemDecoration();
         DeviceProfile grid = mLauncher.getDeviceProfile();
         if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && !grid.isVerticalBarLayout()) {
-            mRecyclerViewTopBottomPadding = 0;
+            mRecyclerViewBottomPadding = 0;
             setPadding(0, 0, 0, 0);
         } else {
-            mRecyclerViewTopBottomPadding =
-                    res.getDimensionPixelSize(R.dimen.all_apps_list_top_bottom_padding);
+            mRecyclerViewBottomPadding =
+                    res.getDimensionPixelSize(R.dimen.all_apps_list_bottom_padding);
         }
         mSearchQueryBuilder = new SpannableStringBuilder();
         Selection.setSelection(mSearchQueryBuilder, 0);
@@ -312,6 +312,8 @@
         mSearchContainer = findViewById(R.id.search_container);
         mSearchInput = (ExtendedEditText) findViewById(R.id.search_box_input);
         mSearchIcon = (ImageView) findViewById(R.id.search_icon);
+        mSearchContainerOffsetTop = getResources().getDimensionPixelSize(
+                R.dimen.all_apps_search_bar_margin_top);
 
         final LinearLayout.LayoutParams searchParams =
                 (LinearLayout.LayoutParams) mSearchInput.getLayoutParams();
@@ -335,12 +337,8 @@
         final OnClickListener searchFocusListener = new OnClickListener() {
             @Override
             public void onClick(View view) {
-                if (!mSearchInput.isFocused()) {
-                    mSearchInput.requestFocus();
-                    final InputMethodManager imm =
-                            (InputMethodManager)getContext().getSystemService(
-                                    Context.INPUT_METHOD_SERVICE);
-                    imm.showSoftInput(mSearchInput, 0);
+                if (!mSearchBarController.isSearchFieldFocused()) {
+                    mSearchBarController.focusSearchField();
                 }
             }
         };
@@ -419,13 +417,12 @@
                 mAdapter.setNumAppsPerRow(mNumAppsPerRow);
                 mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, new FullMergeAlgorithm());
                 if (mNumAppsPerRow > 0) {
-                    int iconSize = availableWidth / mNumAppsPerRow;
-                    int iconSpacing = (iconSize - grid.allAppsIconSizePx) / 2;
+                    int rvPadding = mAppsRecyclerView.getPaddingStart(); // Assumes symmetry
                     final int thumbMaxWidth =
                             getResources().getDimensionPixelSize(
                                     R.dimen.container_fastscroll_thumb_max_width);
-                    mSearchContainer.setPaddingRelative(
-                            iconSpacing + thumbMaxWidth, 0, iconSpacing + thumbMaxWidth, 0);
+                    mSearchContainer.setPaddingRelative(rvPadding + thumbMaxWidth, 0, rvPadding +
+                            thumbMaxWidth, 0);
                 }
             }
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -485,13 +482,12 @@
         // names)
         int maxScrollBarWidth = mAppsRecyclerView.getMaxScrollbarWidth();
         int startInset = Math.max(mSectionNamesMargin, maxScrollBarWidth);
-        int topBottomPadding = mRecyclerViewTopBottomPadding;
         if (Utilities.isRtl(getResources())) {
-            mAppsRecyclerView.setPadding(bgPadding.left + maxScrollBarWidth,
-                    topBottomPadding, bgPadding.right + startInset, topBottomPadding);
+            mAppsRecyclerView.setPadding(bgPadding.left + maxScrollBarWidth, 0, bgPadding.right
+                    + startInset, mRecyclerViewBottomPadding);
         } else {
-            mAppsRecyclerView.setPadding(bgPadding.left + startInset, topBottomPadding,
-                    bgPadding.right + maxScrollBarWidth, topBottomPadding);
+            mAppsRecyclerView.setPadding(bgPadding.left + startInset, 0, bgPadding.right +
+                    maxScrollBarWidth, mRecyclerViewBottomPadding);
         }
 
         MarginLayoutParams lp = (MarginLayoutParams) mSearchContainer.getLayoutParams();
@@ -525,7 +521,7 @@
 
                 LinearLayout.LayoutParams llp =
                         (LinearLayout.LayoutParams) mSearchInput.getLayoutParams();
-                llp.topMargin = insets.top;
+                llp.topMargin = insets.top + mSearchContainerOffsetTop;
                 mSearchInput.setLayoutParams(llp);
                 mSearchIcon.setLayoutParams(llp);
 
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 6540a23..7d856c0 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -56,17 +56,34 @@
     private static final boolean DEBUG = false;
 
     // A section break in the grid
-    public static final int SECTION_BREAK_VIEW_TYPE = 0;
+    public static final int VIEW_TYPE_SECTION_BREAK = 1 << 0;
     // A normal icon
-    public static final int ICON_VIEW_TYPE = 1;
+    public static final int VIEW_TYPE_ICON = 1 << 1;
     // A prediction icon
-    public static final int PREDICTION_ICON_VIEW_TYPE = 2;
+    public static final int VIEW_TYPE_PREDICTION_ICON = 1 << 2;
     // The message shown when there are no filtered results
-    public static final int EMPTY_SEARCH_VIEW_TYPE = 3;
+    public static final int VIEW_TYPE_EMPTY_SEARCH = 1 << 3;
     // A divider that separates the apps list and the search market button
-    public static final int SEARCH_MARKET_DIVIDER_VIEW_TYPE = 4;
-    // The message to continue to a market search when there are no filtered results
-    public static final int SEARCH_MARKET_VIEW_TYPE = 5;
+    public static final int VIEW_TYPE_SEARCH_MARKET = 1 << 4;
+
+    // We use various dividers for various purposes.  They share enough attributes to reuse layouts,
+    // but differ in enough attributes to require different view types
+
+    // A divider that separates the apps list and the search market button
+    public static final int VIEW_TYPE_SEARCH_MARKET_DIVIDER = 1 << 5;
+    // The divider under the search field
+    public static final int VIEW_TYPE_SEARCH_DIVIDER = 1 << 6;
+    // The divider that separates prediction icons from the app list
+    public static final int VIEW_TYPE_PREDICTION_DIVIDER = 1 << 7;
+
+    // Common view type masks
+    public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_SEARCH_DIVIDER
+            | VIEW_TYPE_SEARCH_MARKET_DIVIDER
+            | VIEW_TYPE_PREDICTION_DIVIDER
+            | VIEW_TYPE_SECTION_BREAK;
+    public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON
+            | VIEW_TYPE_PREDICTION_ICON;
+
 
     public interface BindViewCallback {
         public void onBindView(ViewHolder holder);
@@ -128,11 +145,9 @@
 
         @Override
         public int getSpanSize(int position) {
-            switch (mApps.getAdapterItems().get(position).viewType) {
-                case AllAppsGridAdapter.ICON_VIEW_TYPE:
-                case AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE:
-                    return 1;
-                default:
+            if (isIconViewType(mApps.getAdapterItems().get(position).viewType)) {
+                return 1;
+            } else {
                     // Section breaks span the full width
                     return mAppsPerRow;
             }
@@ -164,7 +179,6 @@
             }
 
             List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
-            boolean hasDrawnPredictedAppsDivider = false;
             boolean showSectionNames = mSectionNamesMargin > 0;
             int childCount = parent.getChildCount();
             int lastSectionTop = 0;
@@ -176,15 +190,7 @@
                     continue;
                 }
 
-                if (shouldDrawItemDivider(holder, items) && !hasDrawnPredictedAppsDivider) {
-                    // Draw the divider under the predicted apps
-                    int top = child.getTop() + child.getHeight() + mPredictionBarDividerOffset;
-                    c.drawLine(mBackgroundPadding.left, top,
-                            parent.getWidth() - mBackgroundPadding.right, top,
-                            mPredictedAppsDividerPaint);
-                    hasDrawnPredictedAppsDivider = true;
-
-                } else if (showSectionNames && shouldDrawItemSection(holder, i, items)) {
+                if (showSectionNames && shouldDrawItemSection(holder, i, items)) {
                     // At this point, we only draw sections for each section break;
                     int viewTopOffset = (2 * child.getPaddingTop());
                     int pos = holder.getPosition();
@@ -203,7 +209,6 @@
                             continue;
                         }
 
-
                         // Find the section name bounds
                         PointF sectionBounds = getAndCacheSectionBounds(sectionName);
 
@@ -211,7 +216,7 @@
                         int sectionBaseline = (int) (viewTopOffset + sectionBounds.y);
                         int x = mIsRtl ?
                                 parent.getWidth() - mBackgroundPadding.left - mSectionNamesMargin :
-                                        mBackgroundPadding.left;
+                                mBackgroundPadding.left;
                         x += (int) ((mSectionNamesMargin - sectionBounds.x) / 2f);
                         int y = child.getTop() + sectionBaseline;
 
@@ -296,15 +301,6 @@
         }
 
         /**
-         * Returns whether to draw the divider for a given child.
-         */
-        private boolean shouldDrawItemDivider(ViewHolder holder,
-                List<AlphabeticalAppsList.AdapterItem> items) {
-            int pos = holder.getPosition();
-            return items.get(pos).viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE;
-        }
-
-        /**
          * Returns whether to draw the section for the given child.
          */
         private boolean shouldDrawItemSection(ViewHolder holder, int childIndex,
@@ -313,12 +309,12 @@
             AlphabeticalAppsList.AdapterItem item = items.get(pos);
 
             // Ensure it's an icon
-            if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+            if (item.viewType != AllAppsGridAdapter.VIEW_TYPE_ICON) {
                 return false;
             }
             // Draw the section header for the first item in each section
             return (childIndex == 0) ||
-                    (items.get(pos - 1).viewType == AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE);
+                    (items.get(pos - 1).viewType == AllAppsGridAdapter.VIEW_TYPE_SECTION_BREAK);
         }
     }
 
@@ -338,9 +334,8 @@
     private final int mSectionNamesMargin;
     private final int mSectionHeaderOffset;
     private final Paint mSectionTextPaint;
-    private final Paint mPredictedAppsDividerPaint;
+    private int mAccentColor;
 
-    private final int mPredictionBarDividerOffset;
     private int mAppsPerRow;
 
     private BindViewCallback mBindViewCallback;
@@ -352,8 +347,8 @@
     // The intent to send off to the market app, updated each time the search query changes.
     private Intent mMarketSearchIntent;
 
-    public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps,
-            View.OnClickListener iconClickListener, View.OnLongClickListener iconLongClickListener) {
+    public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListener
+            iconClickListener, View.OnLongClickListener iconLongClickListener) {
         Resources res = launcher.getResources();
         mLauncher = launcher;
         mApps = apps;
@@ -369,17 +364,24 @@
         mSectionHeaderOffset = res.getDimensionPixelSize(R.dimen.all_apps_grid_section_y_offset);
         mIsRtl = Utilities.isRtl(res);
 
+        mAccentColor = Utilities.getColorAccent(launcher);
+
         mSectionTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         mSectionTextPaint.setTextSize(res.getDimensionPixelSize(
                 R.dimen.all_apps_grid_section_text_size));
-        mSectionTextPaint.setColor(Utilities.getColorAccent(launcher));
+        mSectionTextPaint.setColor(mAccentColor);
+    }
 
-        mPredictedAppsDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mPredictedAppsDividerPaint.setStrokeWidth(Utilities.pxFromDp(1f, res.getDisplayMetrics()));
-        mPredictedAppsDividerPaint.setColor(0x1E000000);
-        mPredictionBarDividerOffset =
-                (-res.getDimensionPixelSize(R.dimen.all_apps_prediction_icon_bottom_padding) +
-                        res.getDimensionPixelSize(R.dimen.all_apps_icon_top_bottom_padding)) / 2;
+    public static boolean isDividerViewType(int viewType) {
+        return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
+    }
+
+    public static boolean isIconViewType(int viewType) {
+        return isViewType(viewType, VIEW_TYPE_MASK_ICON);
+    }
+
+    public static boolean isViewType(int viewType, int viewTypeMask) {
+        return (viewType & viewTypeMask) != 0;
     }
 
     /**
@@ -441,12 +443,13 @@
     @Override
     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         switch (viewType) {
-            case SECTION_BREAK_VIEW_TYPE:
+            case VIEW_TYPE_SECTION_BREAK:
                 return new ViewHolder(new View(parent.getContext()));
-            case ICON_VIEW_TYPE:
-            case PREDICTION_ICON_VIEW_TYPE: {
+            case VIEW_TYPE_ICON:
+                /* falls through */
+            case VIEW_TYPE_PREDICTION_ICON: {
                 BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
-                        viewType == ICON_VIEW_TYPE ? R.layout.all_apps_icon :
+                        viewType == VIEW_TYPE_ICON ? R.layout.all_apps_icon :
                                 R.layout.all_apps_prediction_bar_icon, parent, false);
                 icon.setOnClickListener(mIconClickListener);
                 icon.setOnLongClickListener(mIconLongClickListener);
@@ -455,13 +458,10 @@
                 icon.setOnFocusChangeListener(mIconFocusListener);
                 return new ViewHolder(icon);
             }
-            case EMPTY_SEARCH_VIEW_TYPE:
+            case VIEW_TYPE_EMPTY_SEARCH:
                 return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
                         parent, false));
-            case SEARCH_MARKET_DIVIDER_VIEW_TYPE:
-                return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_search_market_divider,
-                        parent, false));
-            case SEARCH_MARKET_VIEW_TYPE:
+            case VIEW_TYPE_SEARCH_MARKET:
                 View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
                         parent, false);
                 searchMarketView.setOnClickListener(new View.OnClickListener() {
@@ -471,6 +471,20 @@
                     }
                 });
                 return new ViewHolder(searchMarketView);
+            case VIEW_TYPE_SEARCH_DIVIDER:
+                final View searchDivider =
+                        mLayoutInflater.inflate(R.layout.all_apps_divider, parent, false);
+                searchDivider.setBackgroundColor(mAccentColor);
+                final GridLayoutManager.LayoutParams searchDividerParams =
+                        (GridLayoutManager.LayoutParams) searchDivider.getLayoutParams();
+                searchDividerParams.topMargin = 0;
+                searchDivider.setLayoutParams(searchDividerParams);
+                return new ViewHolder(searchDivider);
+            case VIEW_TYPE_PREDICTION_DIVIDER:
+                /* falls through */
+            case VIEW_TYPE_SEARCH_MARKET_DIVIDER:
+                return new ViewHolder(mLayoutInflater.inflate(
+                        R.layout.all_apps_divider, parent, false));
             default:
                 throw new RuntimeException("Unexpected view type");
         }
@@ -479,7 +493,7 @@
     @Override
     public void onBindViewHolder(ViewHolder holder, int position) {
         switch (holder.getItemViewType()) {
-            case ICON_VIEW_TYPE: {
+            case VIEW_TYPE_ICON: {
                 AppInfo info = mApps.getAdapterItems().get(position).appInfo;
                 BubbleTextView icon = (BubbleTextView) holder.mContent;
                 icon.applyFromApplicationInfo(info);
@@ -490,7 +504,7 @@
                 icon.setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
                 break;
             }
-            case PREDICTION_ICON_VIEW_TYPE: {
+            case VIEW_TYPE_PREDICTION_ICON: {
                 AppInfo info = mApps.getAdapterItems().get(position).appInfo;
                 BubbleTextView icon = (BubbleTextView) holder.mContent;
                 icon.applyFromApplicationInfo(info);
@@ -501,13 +515,13 @@
                 icon.setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
                 break;
             }
-            case EMPTY_SEARCH_VIEW_TYPE:
+            case VIEW_TYPE_EMPTY_SEARCH:
                 TextView emptyViewText = (TextView) holder.mContent;
                 emptyViewText.setText(mEmptySearchMessage);
                 emptyViewText.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
                         Gravity.START | Gravity.CENTER_VERTICAL);
                 break;
-            case SEARCH_MARKET_VIEW_TYPE:
+            case VIEW_TYPE_SEARCH_MARKET:
                 TextView searchView = (TextView) holder.mContent;
                 if (mMarketSearchIntent != null) {
                     searchView.setVisibility(View.VISIBLE);
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 8d5ade3..ac88113 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -98,12 +98,14 @@
 
         RecyclerView.RecycledViewPool pool = getRecycledViewPool();
         int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.EMPTY_SEARCH_VIEW_TYPE, 1);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.SEARCH_MARKET_DIVIDER_VIEW_TYPE, 1);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE, 1);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.ICON_VIEW_TYPE, approxRows * mNumAppsPerRow);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE, mNumAppsPerRow);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE, approxRows);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH, 1);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_DIVIDER, 1);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER, 1);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET, 1);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, approxRows * mNumAppsPerRow);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, mNumAppsPerRow);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_DIVIDER, 1);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SECTION_BREAK, approxRows);
     }
 
     /**
@@ -176,7 +178,7 @@
                 if (position != NO_POSITION) {
                     List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
                     AlphabeticalAppsList.AdapterItem item = items.get(position);
-                    if (item.viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                    if (item.viewType == AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON) {
                         targetParent.containerType = LauncherLogProto.PREDICTION;
                         return;
                     }
@@ -265,7 +267,7 @@
 
         // Find the index and height of the first visible row (all rows have the same height)
         int rowCount = mApps.getNumAppRows();
-        getCurScrollState(mScrollPosState, -1);
+        getCurScrollState(mScrollPosState, AllAppsGridAdapter.VIEW_TYPE_MASK_ICON);
         if (mScrollPosState.rowIndex < 0) {
             mScrollbar.setThumbOffset(-1, -1);
             return;
@@ -352,7 +354,7 @@
             int position = getChildPosition(child);
             if (position != NO_POSITION) {
                 AlphabeticalAppsList.AdapterItem item = items.get(position);
-                if ((item.viewType & viewTypeMask) != 0) {
+                if (AllAppsGridAdapter.isViewType(item.viewType, viewTypeMask)) {
                     stateOut.rowIndex = item.rowIndex;
                     stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child);
                     stateOut.itemPos = position;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 0babc1a..b42b762 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -65,6 +65,8 @@
     private float mShiftCurrent;    // [0, mShiftRange]
     private float mShiftRange;      // changes depending on the orientation
 
+    private static final float DEFAULT_SHIFT_RANGE = 10;
+
 
     private static final float RECATCH_REJECTION_FRACTION = .0875f;
 
@@ -81,6 +83,7 @@
         mLauncher = launcher;
         mDetector = new VerticalPullDetector(launcher);
         mDetector.setListener(this);
+        mShiftCurrent = mShiftRange = DEFAULT_SHIFT_RANGE;
         mBezelSwipeUpHeight = launcher.getResources().getDimensionPixelSize(
                 R.dimen.all_apps_bezel_swipe_height);
     }
@@ -436,14 +439,12 @@
     @Override
     public void onLayoutChange(View v, int left, int top, int right, int bottom,
             int oldLeft, int oldTop, int oldRight, int oldBottom) {
+        float prevShiftRatio = mShiftCurrent / mShiftRange;
         if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
             mShiftRange = top;
         } else {
             mShiftRange = bottom;
         }
-        if (!mLauncher.isAllAppsVisible()) {
-            setProgress(mShiftRange);
-        }
-        mHotseat.removeOnLayoutChangeListener(this);
+        setProgress(mShiftRange * prevShiftRatio);
     }
 }
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 9d2fe54..b70c165 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -108,7 +108,7 @@
 
         public static AdapterItem asSectionBreak(int pos, SectionInfo section) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_SECTION_BREAK;
             item.position = pos;
             item.sectionInfo = section;
             section.sectionBreakItem = item;
@@ -118,14 +118,14 @@
         public static AdapterItem asPredictedApp(int pos, SectionInfo section, String sectionName,
                 int sectionAppIndex, AppInfo appInfo, int appIndex) {
             AdapterItem item = asApp(pos, section, sectionName, sectionAppIndex, appInfo, appIndex);
-            item.viewType = AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON;
             return item;
         }
 
         public static AdapterItem asApp(int pos, SectionInfo section, String sectionName,
                 int sectionAppIndex, AppInfo appInfo, int appIndex) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.ICON_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_ICON;
             item.position = pos;
             item.sectionInfo = section;
             item.sectionName = sectionName;
@@ -137,21 +137,35 @@
 
         public static AdapterItem asEmptySearch(int pos) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.EMPTY_SEARCH_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH;
             item.position = pos;
             return item;
         }
 
-        public static AdapterItem asDivider(int pos) {
+        public static AdapterItem asPredictionDivider(int pos) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.SEARCH_MARKET_DIVIDER_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_PREDICTION_DIVIDER;
+            item.position = pos;
+            return item;
+        }
+
+        public static AdapterItem asSearchDivder(int pos) {
+            AdapterItem item = new AdapterItem();
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_DIVIDER;
+            item.position = pos;
+            return item;
+        }
+
+        public static AdapterItem asMarketDivider(int pos) {
+            AdapterItem item = new AdapterItem();
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER;
             item.position = pos;
             return item;
         }
 
         public static AdapterItem asMarketSearch(int pos) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET;
             item.position = pos;
             return item;
         }
@@ -414,6 +428,9 @@
             }
         }
 
+        // Add the search divider
+        mAdapterItems.add(AdapterItem.asSearchDivder(position++));
+
         // Process the predicted app components
         mPredictedApps.clear();
         if (mPredictedAppComponents != null && !mPredictedAppComponents.isEmpty() && !hasFilter()) {
@@ -452,6 +469,8 @@
                     mAdapterItems.add(appItem);
                     mFilteredApps.add(info);
                 }
+
+                mAdapterItems.add(AdapterItem.asPredictionDivider(position++));
             }
         }
 
@@ -491,7 +510,7 @@
             if (hasNoFilteredResults()) {
                 mAdapterItems.add(AdapterItem.asEmptySearch(position++));
             } else {
-                mAdapterItems.add(AdapterItem.asDivider(position++));
+                mAdapterItems.add(AdapterItem.asMarketDivider(position++));
             }
             mAdapterItems.add(AdapterItem.asMarketSearch(position++));
         }
@@ -507,10 +526,9 @@
             int rowIndex = -1;
             for (AdapterItem item : mAdapterItems) {
                 item.rowIndex = 0;
-                if (item.viewType == AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE) {
+                if (AllAppsGridAdapter.isDividerViewType(item.viewType)) {
                     numAppsInSection = 0;
-                } else if (item.viewType == AllAppsGridAdapter.ICON_VIEW_TYPE ||
-                        item.viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                } else if (AllAppsGridAdapter.isIconViewType(item.viewType)) {
                     if (numAppsInSection % mNumAppsPerRow == 0) {
                         numAppsInRow = 0;
                         rowIndex++;
@@ -529,8 +547,7 @@
                     float rowFraction = 1f / mNumAppRowsInAdapter;
                     for (FastScrollSectionInfo info : mFastScrollerSections) {
                         AdapterItem item = info.fastScrollToItem;
-                        if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE &&
-                                item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                        if (!AllAppsGridAdapter.isIconViewType(item.viewType)) {
                             info.touchFraction = 0f;
                             continue;
                         }
@@ -544,8 +561,7 @@
                     float cumulativeTouchFraction = 0f;
                     for (FastScrollSectionInfo info : mFastScrollerSections) {
                         AdapterItem item = info.fastScrollToItem;
-                        if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE &&
-                                item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                        if (!AllAppsGridAdapter.isIconViewType(item.viewType)) {
                             info.touchFraction = 0f;
                             continue;
                         }
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index e94e02f..556be0c 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -1052,7 +1052,7 @@
         int top = Math.min(Math.max(sTempRect.top, centeredTop),
                 sTempRect.top + sTempRect.height() - height);
 
-        int distFromEdgeOfScreen = grid.getWorkspacePadding().left + getPaddingLeft();
+        int distFromEdgeOfScreen = mLauncher.getWorkspace().getPaddingLeft() + getPaddingLeft();
 
         if (grid.isPhone && (grid.availableWidthPx - width) < 4 * distFromEdgeOfScreen) {
             // Center the folder if it is very close to being centered anyway, by virtue of
@@ -1091,10 +1091,8 @@
 
     private int getContentAreaHeight() {
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        Rect workspacePadding = grid.getWorkspacePadding();
-        int maxContentAreaHeight = grid.availableHeightPx -
-                workspacePadding.top - workspacePadding.bottom -
-                mFooterHeight;
+        int maxContentAreaHeight = grid.availableHeightPx
+                - grid.getTotalWorkspacePadding().y - mFooterHeight;
         int height = Math.min(maxContentAreaHeight,
                 mContent.getDesiredHeight());
         return Math.max(height, MIN_CONTENT_DIMEN);
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index cb1acaa..7287ced 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -24,7 +24,6 @@
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
-import com.android.launcher3.backup.nano.BackupProtos;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.PackageInstallerCompat;
 import com.android.launcher3.config.FeatureFlags;
@@ -51,10 +50,6 @@
     private static final String KEY_MIGRATION_SRC_WORKSPACE_SIZE = "migration_src_workspace_size";
     private static final String KEY_MIGRATION_SRC_HOTSEAT_COUNT = "migration_src_hotseat_count";
 
-    // Set of entries indicating minimum size a widget can be resized to. This is used during
-    // restore in case the widget has not been installed yet.
-    private static final String KEY_MIGRATION_WIDGET_MINSIZE = "migration_widget_min_size";
-
     // These are carefully selected weights for various item types (Math.random?), to allow for
     // the least absurd migration experience.
     private static final float WT_SHORTCUT = 1;
@@ -81,11 +76,9 @@
     private final int mDestHotseatSize;
 
     protected GridSizeMigrationTask(Context context, InvariantDeviceProfile idp,
-            HashSet<String> validPackages, HashMap<String, Point> widgetMinSize,
-            Point sourceSize, Point targetSize) {
+            HashSet<String> validPackages, Point sourceSize, Point targetSize) {
         mContext = context;
         mValidPackages = validPackages;
-        mWidgetMinSize.putAll(widgetMinSize);
         mIdp = idp;
 
         mSrcX = sourceSize.x;
@@ -886,16 +879,6 @@
         return String.format(Locale.ENGLISH, "%d,%d", x, y);
     }
 
-    public static void markForMigration(
-            Context context, HashSet<String> widgets, BackupProtos.DeviceProfieData srcProfile) {
-        Utilities.getPrefs(context).edit()
-                .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE,
-                        getPointString((int) srcProfile.desktopCols, (int) srcProfile.desktopRows))
-                .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, (int) srcProfile.hotseatCount)
-                .putStringSet(KEY_MIGRATION_WIDGET_MINSIZE, widgets)
-                .apply();
-    }
-
     /**
      * Migrates the workspace and hotseat in case their sizes changed.
      * @return false if the migration failed.
@@ -957,14 +940,6 @@
                             + " to " + targetSize);
                 }
 
-                // Min widget sizes
-                HashMap<String, Point> widgetMinSize = new HashMap<>();
-                for (String s : Utilities.getPrefs(context).getStringSet(KEY_MIGRATION_WIDGET_MINSIZE,
-                        Collections.<String>emptySet())) {
-                    String[] parts = s.split("#");
-                    widgetMinSize.put(parts[0], parsePoint(parts[1]));
-                }
-
                 // Migrate the workspace grid, step by step.
                 while (targetSizeIndex < sourceSizeIndex ) {
                     // We only need to migrate the grid if source size is greater
@@ -974,8 +949,7 @@
 
                     if (new GridSizeMigrationTask(context,
                             LauncherAppState.getInstance().getInvariantDeviceProfile(),
-                            validPackages, widgetMinSize,
-                            stepSourceSize, stepTargetSize).migrateWorkspace()) {
+                            validPackages, stepSourceSize, stepTargetSize).migrateWorkspace()) {
                         dbChanged = true;
                     }
                     sourceSizeIndex--;
@@ -1006,7 +980,6 @@
             prefs.edit()
                     .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
                     .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)
-                    .remove(KEY_MIGRATION_WIDGET_MINSIZE)
                     .apply();
         }
     }
diff --git a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
index bb6ed0d..4addbfa 100644
--- a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
+++ b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
@@ -47,8 +47,9 @@
     protected LossyScreenMigrationTask(
             Context context, InvariantDeviceProfile idp, SQLiteDatabase db) {
         // Decrease the rows count by 1
-        super(context, idp, getValidPackages(context), new HashMap<String, Point>(),
-                new Point(idp.numColumns, idp.numRows + 1), new Point(idp.numColumns, idp.numRows));
+        super(context, idp, getValidPackages(context),
+                new Point(idp.numColumns, idp.numRows + 1),
+                new Point(idp.numColumns, idp.numRows));
 
         mDb = db;
         mOriginalItems = new LongArrayMap<>();
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
index c250cb2..4dae42f 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
@@ -15,7 +15,6 @@
 import com.android.launcher3.util.TestLauncherProvider;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.HashSet;
 
 /**
@@ -130,7 +129,7 @@
                 {  5,  2, -1,  6},
         }});
 
-        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages, new HashMap<String, Point>(),
+        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages,
                 new Point(4, 4), new Point(3, 3)).migrateWorkspace();
 
         // Column 2 and row 2 got removed.
@@ -149,7 +148,7 @@
                 {  5,  2, -1,  6},
         }});
 
-        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages, new HashMap<String, Point>(),
+        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages,
                 new Point(4, 4), new Point(3, 3)).migrateWorkspace();
 
         // Items in the second column get moved to new screen
@@ -173,7 +172,7 @@
                 {  3,  1, -1,  4},
         }});
 
-        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages, new HashMap<String, Point>(),
+        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages,
                 new Point(4, 4), new Point(3, 3)).migrateWorkspace();
 
         // Items in the second column of the first screen should get placed on the 3rd
@@ -204,7 +203,7 @@
                 {  5,  2, -1,  6},
         }});
 
-        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages, new HashMap<String, Point>(),
+        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages,
                 new Point(4, 4), new Point(3, 3)).migrateWorkspace();
 
         // Items in the second column of the first screen should get placed on a new screen.
@@ -231,7 +230,7 @@
                 {  5,  2,  7, -1},
         }}, 0);
 
-        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages, new HashMap<String, Point>(),
+        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages,
                 new Point(4, 4), new Point(3, 4)).migrateWorkspace();
 
         // Items in the second column of the first screen should get placed on a new screen.
@@ -254,7 +253,7 @@
                 {  5,  6,  7, -1},
         }}, 0);
 
-        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages, new HashMap<String, Point>(),
+        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages,
                 new Point(4, 4), new Point(3, 3)).migrateWorkspace();
 
         // Items in the second column of the first screen should get placed on a new screen.