Merge "Avoiding blocking worker thread when adding icons to DB" into ub-launcher3-burnaby
diff --git a/res/drawable-hdpi/ic_widget_resize_handle.png b/res/drawable-hdpi/ic_widget_resize_handle.png
new file mode 100644
index 0000000..844f3cf
--- /dev/null
+++ b/res/drawable-hdpi/ic_widget_resize_handle.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_frame.9.png b/res/drawable-hdpi/widget_resize_frame.9.png
new file mode 100644
index 0000000..5772672
--- /dev/null
+++ b/res/drawable-hdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_frame_holo.9.png b/res/drawable-hdpi/widget_resize_frame_holo.9.png
deleted file mode 100644
index 2d6fcf5..0000000
--- a/res/drawable-hdpi/widget_resize_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_bottom.png b/res/drawable-hdpi/widget_resize_handle_bottom.png
deleted file mode 100644
index f0afd61..0000000
--- a/res/drawable-hdpi/widget_resize_handle_bottom.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_left.png b/res/drawable-hdpi/widget_resize_handle_left.png
deleted file mode 100644
index 47613b2..0000000
--- a/res/drawable-hdpi/widget_resize_handle_left.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_right.png b/res/drawable-hdpi/widget_resize_handle_right.png
deleted file mode 100644
index acc28be..0000000
--- a/res/drawable-hdpi/widget_resize_handle_right.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_top.png b/res/drawable-hdpi/widget_resize_handle_top.png
deleted file mode 100644
index 2c60be0..0000000
--- a/res/drawable-hdpi/widget_resize_handle_top.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_shadow.9.png b/res/drawable-hdpi/widget_resize_shadow.9.png
new file mode 100644
index 0000000..a67da6e
--- /dev/null
+++ b/res/drawable-hdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_widget_resize_handle.png b/res/drawable-mdpi/ic_widget_resize_handle.png
new file mode 100644
index 0000000..c3b287f
--- /dev/null
+++ b/res/drawable-mdpi/ic_widget_resize_handle.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_frame.9.png b/res/drawable-mdpi/widget_resize_frame.9.png
new file mode 100644
index 0000000..8bc8a5c
--- /dev/null
+++ b/res/drawable-mdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_frame_holo.9.png b/res/drawable-mdpi/widget_resize_frame_holo.9.png
deleted file mode 100644
index 028bd62..0000000
--- a/res/drawable-mdpi/widget_resize_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_bottom.png b/res/drawable-mdpi/widget_resize_handle_bottom.png
deleted file mode 100644
index c838bf4..0000000
--- a/res/drawable-mdpi/widget_resize_handle_bottom.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_left.png b/res/drawable-mdpi/widget_resize_handle_left.png
deleted file mode 100644
index ff0b0d3..0000000
--- a/res/drawable-mdpi/widget_resize_handle_left.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_right.png b/res/drawable-mdpi/widget_resize_handle_right.png
deleted file mode 100644
index fc4808e..0000000
--- a/res/drawable-mdpi/widget_resize_handle_right.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_top.png b/res/drawable-mdpi/widget_resize_handle_top.png
deleted file mode 100644
index 3b1df01..0000000
--- a/res/drawable-mdpi/widget_resize_handle_top.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_shadow.9.png b/res/drawable-mdpi/widget_resize_shadow.9.png
new file mode 100644
index 0000000..2bae2b6
--- /dev/null
+++ b/res/drawable-mdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_widget_resize_handle.png b/res/drawable-xhdpi/ic_widget_resize_handle.png
new file mode 100644
index 0000000..f445a1c
--- /dev/null
+++ b/res/drawable-xhdpi/ic_widget_resize_handle.png
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_frame.9.png b/res/drawable-xhdpi/widget_resize_frame.9.png
new file mode 100644
index 0000000..e6cf0af
--- /dev/null
+++ b/res/drawable-xhdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_frame_holo.9.png b/res/drawable-xhdpi/widget_resize_frame_holo.9.png
deleted file mode 100644
index 76cec60..0000000
--- a/res/drawable-xhdpi/widget_resize_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_handle_bottom.png b/res/drawable-xhdpi/widget_resize_handle_bottom.png
deleted file mode 100644
index 19437d7..0000000
--- a/res/drawable-xhdpi/widget_resize_handle_bottom.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_handle_left.png b/res/drawable-xhdpi/widget_resize_handle_left.png
deleted file mode 100644
index 28c5487..0000000
--- a/res/drawable-xhdpi/widget_resize_handle_left.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_handle_right.png b/res/drawable-xhdpi/widget_resize_handle_right.png
deleted file mode 100644
index 4f672a6..0000000
--- a/res/drawable-xhdpi/widget_resize_handle_right.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_handle_top.png b/res/drawable-xhdpi/widget_resize_handle_top.png
deleted file mode 100644
index e866c00..0000000
--- a/res/drawable-xhdpi/widget_resize_handle_top.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_shadow.9.png b/res/drawable-xhdpi/widget_resize_shadow.9.png
new file mode 100644
index 0000000..99e9e78
--- /dev/null
+++ b/res/drawable-xhdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_widget_resize_handle.png b/res/drawable-xxhdpi/ic_widget_resize_handle.png
new file mode 100644
index 0000000..144cac9
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_widget_resize_handle.png
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_frame.9.png b/res/drawable-xxhdpi/widget_resize_frame.9.png
new file mode 100644
index 0000000..7a49d01
--- /dev/null
+++ b/res/drawable-xxhdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_frame_holo.9.png b/res/drawable-xxhdpi/widget_resize_frame_holo.9.png
deleted file mode 100644
index 1681387..0000000
--- a/res/drawable-xxhdpi/widget_resize_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_handle_bottom.png b/res/drawable-xxhdpi/widget_resize_handle_bottom.png
deleted file mode 100644
index d549fcd..0000000
--- a/res/drawable-xxhdpi/widget_resize_handle_bottom.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_handle_left.png b/res/drawable-xxhdpi/widget_resize_handle_left.png
deleted file mode 100644
index dd56dad..0000000
--- a/res/drawable-xxhdpi/widget_resize_handle_left.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_handle_right.png b/res/drawable-xxhdpi/widget_resize_handle_right.png
deleted file mode 100644
index 296a1c1..0000000
--- a/res/drawable-xxhdpi/widget_resize_handle_right.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_handle_top.png b/res/drawable-xxhdpi/widget_resize_handle_top.png
deleted file mode 100644
index e86270a..0000000
--- a/res/drawable-xxhdpi/widget_resize_handle_top.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_shadow.9.png b/res/drawable-xxhdpi/widget_resize_shadow.9.png
new file mode 100644
index 0000000..ae0f564
--- /dev/null
+++ b/res/drawable-xxhdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_widget_resize_handle.png b/res/drawable-xxxhdpi/ic_widget_resize_handle.png
new file mode 100644
index 0000000..4bde6b9
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_widget_resize_handle.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/widget_resize_frame.9.png b/res/drawable-xxxhdpi/widget_resize_frame.9.png
new file mode 100644
index 0000000..9b711f2
--- /dev/null
+++ b/res/drawable-xxxhdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/widget_resize_shadow.9.png b/res/drawable-xxxhdpi/widget_resize_shadow.9.png
new file mode 100644
index 0000000..defb311
--- /dev/null
+++ b/res/drawable-xxxhdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/layout/apps_grid_icon_view.xml b/res/layout/apps_grid_icon_view.xml
index 67d7d50..7165f38 100644
--- a/res/layout/apps_grid_icon_view.xml
+++ b/res/layout/apps_grid_icon_view.xml
@@ -25,6 +25,5 @@
     android:paddingBottom="@dimen/apps_icon_top_bottom_padding"
     android:focusable="true"
     android:background="@drawable/focusable_view_bg"
-    launcher:deferShadowGeneration="true"
     launcher:iconDisplay="all_apps" />
 
diff --git a/res/layout/apps_list_view.xml b/res/layout/apps_list_view.xml
index 03ba646..6f9be05 100644
--- a/res/layout/apps_list_view.xml
+++ b/res/layout/apps_list_view.xml
@@ -14,7 +14,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.AppsRecyclerViewContainer
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/apps_list"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -101,4 +102,4 @@
             android:src="@drawable/ic_search_grey" />
     </FrameLayout>
 
-</FrameLayout>
\ No newline at end of file
+</com.android.launcher3.AppsRecyclerViewContainer>
\ No newline at end of file
diff --git a/res/layout/apps_prediction_bar_icon_view.xml b/res/layout/apps_prediction_bar_icon_view.xml
index 4a6f157..1e75d14 100644
--- a/res/layout/apps_prediction_bar_icon_view.xml
+++ b/res/layout/apps_prediction_bar_icon_view.xml
@@ -24,6 +24,5 @@
     android:layout_weight="1"
     android:focusable="true"
     android:background="@drawable/focusable_view_bg"
-    launcher:deferShadowGeneration="true"
     launcher:iconDisplay="all_apps" />
 
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 500cf10..7fefeba 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -39,16 +39,15 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:gravity="start"
-            android:singleLine="true"
             android:ellipsize="end"
             android:fadingEdge="horizontal"
-            android:textColor="@color/widgets_view_item_text_color"
-            android:textSize="14sp"
-            android:textAlignment="viewStart"
             android:fontFamily="sans-serif-condensed"
+            android:gravity="start"
+            android:shadowColor="#B0000000"
             android:shadowRadius="2.0"
-            android:shadowColor="#B0000000" />
+            android:singleLine="true"
+            android:textColor="@color/widgets_view_item_text_color"
+            android:textSize="14sp" />
 
         <!-- The original dimensions of the widget (can't be the same text as above due to different
              style. -->
@@ -58,22 +57,18 @@
             android:layout_height="wrap_content"
             android:layout_marginStart="5dp"
             android:layout_marginLeft="5dp"
-            android:layout_weight="0"
-            android:gravity="start"
             android:textColor="@color/widgets_view_item_text_color"
             android:textSize="14sp"
-            android:textAlignment="viewStart"
             android:fontFamily="sans-serif-condensed"
             android:shadowRadius="2.0"
             android:shadowColor="#B0000000" />
     </LinearLayout>
 
-    <!-- The image of the widget. -->
+    <!-- The image of the widget. This view does not support padding. Any placement adjustment
+         should be done using margins. -->
     <com.android.launcher3.widget.WidgetImageView
         android:id="@+id/widget_preview"
-        style="@style/WidgetImageView"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:scaleType="matrix" />
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
 </com.android.launcher3.widget.WidgetCell>
\ No newline at end of file
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index dc1bcce..67b4acb 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -19,6 +19,7 @@
     android:id="@+id/widgets_cell_list_container"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:background="@color/widgets_cell_color"
     android:orientation="vertical"
     android:focusable="true"
     android:descendantFocusability="afterDescendants">
@@ -52,7 +53,7 @@
         android:id="@+id/widgets_scroll_container"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:scrollbars="none" >
+        android:scrollbars="none">
         <LinearLayout
             android:id="@+id/widgets_cell_list"
             android:layout_width="wrap_content"
@@ -61,7 +62,6 @@
             android:layout_marginLeft="@dimen/widget_row_padding"
             android:orientation="horizontal"
             android:divider="@drawable/widgets_row_divider"
-            android:showDividers="middle"
-            android:background="@color/widgets_cell_color"/>
+            android:showDividers="middle"/>
     </HorizontalScrollView>
 </LinearLayout>
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
index 1857595..9d9fa10 100644
--- a/res/layout/widgets_view.xml
+++ b/res/layout/widgets_view.xml
@@ -34,19 +34,12 @@
         android:focusable="false"
         android:visibility="invisible" />
 
-    <LinearLayout
-        android:id="@+id/widgets_content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        android:elevation="15dp"
-        android:visibility="gone"
-        android:orientation="vertical" >
-
         <com.android.launcher3.widget.WidgetsContainerRecyclerView
-                android:id="@+id/widgets_list_view"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:background="@drawable/quantum_panel_dark"/>
-    </LinearLayout>
+            android:id="@+id/widgets_list_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@drawable/quantum_panel_dark"
+            android:elevation="15dp"
+            android:visibility="gone" />
+
 </com.android.launcher3.widget.WidgetsContainerView>
\ No newline at end of file
diff --git a/res/values-v17/styles.xml b/res/values-v17/styles.xml
deleted file mode 100644
index 3589e80..0000000
--- a/res/values-v17/styles.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <style name="WidgetImageView">
-        <item name="android:paddingStart">@dimen/widget_preview_horizontal_padding</item>
-    </style>
-</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index d2f6237..60591e1 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -28,7 +28,10 @@
     <dimen name="dynamic_grid_overview_bar_item_width">80dp</dimen>
     <dimen name="dynamic_grid_overview_bar_spacer_width">20dp</dimen>
 
+<!-- App Widget resize frame -->
     <dimen name="default_widget_padding">8dp</dimen>
+    <dimen name="widget_handle_margin">13dp</dimen>
+    <dimen name="resize_frame_background_padding">24dp</dimen>
 
 <!-- Cling -->
     <dimen name="cling_migration_logo_height">240dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 51ad51f..18f97c8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -182,76 +182,76 @@
     </string>
 
 <!-- Strings for accessibility actions -->
-    <!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
-    <string name="action_add_to_workspace">Add to home screen</string>
+    <!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] -->
+    <string name="action_add_to_workspace">Add to Home screen</string>
 
-    <!-- Accessibility action to move item to the current location. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
-    <string name="action_move_here">Move here</string>
+    <!-- Accessibility action to move item to the current location. [CHAR_LIMIT=30] -->
+    <string name="action_move_here">Move item here</string>
 
-    <!-- Accessibility confirmation for item added to workspace [DO NOT TRANSLATE] -->
+    <!-- Accessibility confirmation for item added to workspace. -->
     <string name="item_added_to_workspace">Item added to home screen</string>
 
-    <!-- Accessibility confirmation for item removed [DO NOT TRANSLATE] -->
+    <!-- Accessibility confirmation for item removed. -->
     <string name="item_removed">Item removed</string>
 
-    <!-- Accessibility action to move an item on the workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
-    <string name="action_move">Move Item</string>
+    <!-- Accessibility action to move an item on the workspace. [CHAR_LIMIT=30] -->
+    <string name="action_move">Move item</string>
 
-    <!-- Accessibility description to move item to empty cell. [DO NOT TRANSLATE] -->
+    <!-- Accessibility description to move item to empty cell. -->
     <string name="move_to_empty_cell">Move to row <xliff:g id="number" example="1">%1$s</xliff:g> column <xliff:g id="number" example="1">%2$s</xliff:g></string>
 
-    <!-- Accessibility description to move item inside a folder. [DO NOT TRANSLATE] -->
+    <!-- Accessibility description to move item inside a folder. -->
     <string name="move_to_position">Move to position <xliff:g id="number" example="1">%1$s</xliff:g></string>
 
-    <!-- Accessibility description to move item to the hotseat. [DO NOT TRANSLATE] -->
+    <!-- Accessibility description to move item to the hotseat. -->
     <string name="move_to_hotseat_position">Move to favorites position <xliff:g id="number" example="1">%1$s</xliff:g></string>
 
-    <!-- Accessibility confirmation for item move [DO NOT TRANSLATE]-->
+    <!-- Accessibility confirmation for item move. -->
     <string name="item_moved">Item moved</string>
 
-    <!-- Accessibility description to move item into an existing folder. [DO NOT TRANSLATE]-->
+    <!-- Accessibility description to move item into an existing folder. -->
     <string name="add_to_folder">Add to folder: <xliff:g id="name" example="Games">%1$s</xliff:g></string>
 
-    <!-- Accessibility description to move item into an existing folder containing an app. [DO NOT TRANSLATE]-->
+    <!-- Accessibility description to move item into an existing folder containing an app. -->
     <string name="add_to_folder_with_app">Add to folder with <xliff:g id="name" example="Messenger">%1$s</xliff:g></string>
 
-    <!-- Accessibility confirmation for item added to folder [DO NOT TRANSLATE] -->
+    <!-- Accessibility confirmation for item added to folder. -->
     <string name="added_to_folder">Item added to folder</string>
 
-    <!-- Accessibility description to create folder with another item. [DO NOT TRANSLATE] -->
+    <!-- Accessibility description to create folder with another item. -->
     <string name="create_folder_with">Create folder with: <xliff:g id="name" example="Game">%1$s</xliff:g></string>
 
-    <!-- Accessibility confirmation for folder created [DO NOT TRANSLATE] -->
+    <!-- Accessibility confirmation for folder created. -->
     <string name="folder_created">Folder created</string>
 
-    <!-- Accessibility action to move an item from folder to workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
-    <string name="action_move_to_workspace">Move to home screen</string>
+    <!-- Accessibility action to move an item from folder to workspace. [CHAR_LIMIT=30] -->
+    <string name="action_move_to_workspace">Move to Home screen</string>
 
-    <!-- Accessibility action to move an homescreen to the left. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
+    <!-- Accessibility action to move an homescreen to the left. [CHAR_LIMIT=30] -->
     <string name="action_move_screen_left">Move screen to left</string>
 
-    <!-- Accessibility action to move an homescreen to the right. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
+    <!-- Accessibility action to move an homescreen to the right. [CHAR_LIMIT=30] -->
     <string name="action_move_screen_right">Move screen to right</string>
 
-    <!-- Accessibility confirmation when a screen was moved [DO NOT TRANSLATE] -->
+    <!-- Accessibility confirmation when a screen was moved. -->
     <string name="screen_moved">Screen moved</string>
 
-    <!-- Accessibility action to resize a widget [DO NOT TRANSLATE] -->
+    <!-- Accessibility action to resize a widget. [CHAR_LIMIT=30] -->
     <string name="action_resize">Resize</string>
 
-    <!-- Accessibility action to increase width of a widget [DO NOT TRANSLATE] -->
+    <!-- Accessibility action to increase width of a widget. [CHAR_LIMIT=30] -->
     <string name="action_increase_width">Increase width</string>
 
-    <!-- Accessibility action to increase height of a widget [DO NOT TRANSLATE] -->
+    <!-- Accessibility action to increase height of a widget. [CHAR_LIMIT=30] -->
     <string name="action_increase_height">Increase height</string>
 
-    <!-- Accessibility action to decrease width of a widget [DO NOT TRANSLATE] -->
+    <!-- Accessibility action to decrease width of a widget. [CHAR_LIMIT=30] -->
     <string name="action_decrease_width">Decrease width</string>
 
-    <!-- Accessibility action to decrease height of a widget [DO NOT TRANSLATE] -->
+    <!-- Accessibility action to decrease height of a widget. [CHAR_LIMIT=30] -->
     <string name="action_decrease_height">Decrease height</string>
 
-    <!-- Accessibility confirmation for widget resize [DO NOT TRANSLATE]-->
+    <!-- Accessibility confirmation for widget resize. -->
     <string name="widget_resized">Widget resized to width <xliff:g id="number" example="2">%1$s</xliff:g> height <xliff:g id="number" example="1">%2$s</xliff:g></string>
 
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index f95debe..1496da9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -86,9 +86,4 @@
         <item name="ringOutset">4dp</item>
     </style>
 
-    <!-- Overridden in device overlays -->
-    <style name="WidgetImageView">
-        <item name="android:paddingLeft">@dimen/widget_preview_horizontal_padding</item>
-    </style>
-
 </resources>
diff --git a/src/com/android/launcher3/AlphabeticalAppsList.java b/src/com/android/launcher3/AlphabeticalAppsList.java
index eff7b06..82aaeb9 100644
--- a/src/com/android/launcher3/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/AlphabeticalAppsList.java
@@ -7,6 +7,7 @@
 import com.android.launcher3.compat.AlphabeticIndexCompat;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.model.AppNameComparator;
 
 import java.text.Collator;
 import java.util.ArrayList;
@@ -18,96 +19,6 @@
 import java.util.Map;
 import java.util.TreeMap;
 
-
-/**
- * A private class to manage access to an app name comparator.
- */
-class AppNameComparator {
-    private final UserManagerCompat mUserManager;
-    private final Collator mCollator;
-    private final Comparator<AppInfo> mAppInfoComparator;
-    private final Comparator<String> mSectionNameComparator;
-    private HashMap<UserHandleCompat, Long> mUserSerialCache = new HashMap<>();
-
-    public AppNameComparator(Context context) {
-        mCollator = Collator.getInstance();
-        mUserManager = UserManagerCompat.getInstance(context);
-        mAppInfoComparator = new Comparator<AppInfo>() {
-            public final int compare(AppInfo a, AppInfo b) {
-                // Order by the title in the current locale
-                int result = compareTitles(a.title.toString(), b.title.toString());
-                if (result == 0) {
-                    // If two apps have the same title, then order by the component name
-                    result = a.componentName.compareTo(b.componentName);
-                    if (result == 0) {
-                        // If the two apps are the same component, then prioritize by the order that
-                        // the app user was created (prioritizing the main user's apps)
-                        if (UserHandleCompat.myUserHandle().equals(a.user)) {
-                            return -1;
-                        } else {
-                            Long aUserSerial = getAndCacheUserSerial(a.user);
-                            Long bUserSerial = getAndCacheUserSerial(b.user);
-                            return aUserSerial.compareTo(bUserSerial);
-                        }
-                    }
-                }
-                return result;
-            }
-        };
-        mSectionNameComparator = new Comparator<String>() {
-            @Override
-            public int compare(String o1, String o2) {
-                return compareTitles(o1, o2);
-            }
-        };
-    }
-
-    /**
-     * Returns a locale-aware comparator that will alphabetically order a list of applications.
-     */
-    public Comparator<AppInfo> getAppInfoComparator() {
-        // Clear the user serial cache so that we get serials as needed in the comparator
-        mUserSerialCache.clear();
-        return mAppInfoComparator;
-    }
-
-    /**
-     * Returns a locale-aware comparator that will alphabetically order a list of section names.
-     */
-    public Comparator<String> getSectionNameComparator() {
-        return mSectionNameComparator;
-    }
-
-    /**
-     * Compares two titles with the same return value semantics as Comparator.
-     */
-    private int compareTitles(String titleA, String titleB) {
-        // Ensure that we de-prioritize any titles that don't start with a linguistic letter or digit
-        boolean aStartsWithLetter = Character.isLetterOrDigit(titleA.codePointAt(0));
-        boolean bStartsWithLetter = Character.isLetterOrDigit(titleB.codePointAt(0));
-        if (aStartsWithLetter && !bStartsWithLetter) {
-            return -1;
-        } else if (!aStartsWithLetter && bStartsWithLetter) {
-            return 1;
-        }
-
-        // Order by the title in the current locale
-        return mCollator.compare(titleA, titleB);
-    }
-
-    /**
-     * Returns the user serial for this user, using a cached serial if possible.
-     */
-    private Long getAndCacheUserSerial(UserHandleCompat user) {
-        Long userSerial = mUserSerialCache.get(user);
-        if (userSerial == null) {
-            userSerial = mUserManager.getSerialNumberForUser(user);
-            mUserSerialCache.put(user, userSerial);
-        }
-        return userSerial;
-    }
-}
-
 /**
  * The alphabetically sorted list of applications.
  */
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 3c698c0..e6bf525 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -15,24 +15,36 @@
 import android.widget.ImageView;
 
 public class AppWidgetResizeFrame extends FrameLayout {
-    private LauncherAppWidgetHostView mWidgetView;
-    private CellLayout mCellLayout;
-    private DragLayer mDragLayer;
-    private ImageView mLeftHandle;
-    private ImageView mRightHandle;
-    private ImageView mTopHandle;
-    private ImageView mBottomHandle;
+    private static final int SNAP_DURATION = 150;
+    private static final float DIMMED_HANDLE_ALPHA = 0f;
+    private static final float RESIZE_THRESHOLD = 0.66f;
+
+    private static Rect sTmpRect = new Rect();
+
+    private final Launcher mLauncher;
+    private final LauncherAppWidgetHostView mWidgetView;
+    private final CellLayout mCellLayout;
+    private final DragLayer mDragLayer;
+
+    private final ImageView mLeftHandle;
+    private final ImageView mRightHandle;
+    private final ImageView mTopHandle;
+    private final ImageView mBottomHandle;
+
+    private final Rect mWidgetPadding;
+
+    private final int mBackgroundPadding;
+    private final int mTouchTargetWidth;
+
+    private final int[] mDirectionVector = new int[2];
+    private final int[] mLastDirectionVector = new int[2];
+    private final int[] mTmpPt = new int[2];
 
     private boolean mLeftBorderActive;
     private boolean mRightBorderActive;
     private boolean mTopBorderActive;
     private boolean mBottomBorderActive;
 
-    private int mWidgetPaddingLeft;
-    private int mWidgetPaddingRight;
-    private int mWidgetPaddingTop;
-    private int mWidgetPaddingBottom;
-
     private int mBaselineWidth;
     private int mBaselineHeight;
     private int mBaselineX;
@@ -48,30 +60,9 @@
     private int mDeltaXAddOn;
     private int mDeltaYAddOn;
 
-    private int mBackgroundPadding;
-    private int mTouchTargetWidth;
-
     private int mTopTouchRegionAdjustment = 0;
     private int mBottomTouchRegionAdjustment = 0;
 
-    int[] mDirectionVector = new int[2];
-    int[] mLastDirectionVector = new int[2];
-    int[] mTmpPt = new int[2];
-
-    final int SNAP_DURATION = 150;
-    final int BACKGROUND_PADDING = 24;
-    final float DIMMED_HANDLE_ALPHA = 0f;
-    final float RESIZE_THRESHOLD = 0.66f;
-
-    private static Rect mTmpRect = new Rect();
-
-    public static final int LEFT = 0;
-    public static final int TOP = 1;
-    public static final int RIGHT = 2;
-    public static final int BOTTOM = 3;
-
-    private Launcher mLauncher;
-
     public AppWidgetResizeFrame(Context context,
             LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
 
@@ -87,49 +78,49 @@
         mMinHSpan = info.minSpanX;
         mMinVSpan = info.minSpanY;
 
-        setBackgroundResource(R.drawable.widget_resize_frame_holo);
+        setBackgroundResource(R.drawable.widget_resize_shadow);
+        setForeground(getResources().getDrawable(R.drawable.widget_resize_frame));
         setPadding(0, 0, 0, 0);
 
+        final int handleMargin = getResources().getDimensionPixelSize(R.dimen.widget_handle_margin);
         LayoutParams lp;
         mLeftHandle = new ImageView(context);
-        mLeftHandle.setImageResource(R.drawable.widget_resize_handle_left);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+        mLeftHandle.setImageResource(R.drawable.ic_widget_resize_handle);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
                 Gravity.LEFT | Gravity.CENTER_VERTICAL);
+        lp.leftMargin = handleMargin;
         addView(mLeftHandle, lp);
 
         mRightHandle = new ImageView(context);
-        mRightHandle.setImageResource(R.drawable.widget_resize_handle_right);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+        mRightHandle.setImageResource(R.drawable.ic_widget_resize_handle);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
                 Gravity.RIGHT | Gravity.CENTER_VERTICAL);
+        lp.rightMargin = handleMargin;
         addView(mRightHandle, lp);
 
         mTopHandle = new ImageView(context);
-        mTopHandle.setImageResource(R.drawable.widget_resize_handle_top);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+        mTopHandle.setImageResource(R.drawable.ic_widget_resize_handle);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
                 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
+        lp.topMargin = handleMargin;
         addView(mTopHandle, lp);
 
         mBottomHandle = new ImageView(context);
-        mBottomHandle.setImageResource(R.drawable.widget_resize_handle_bottom);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+        mBottomHandle.setImageResource(R.drawable.ic_widget_resize_handle);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
                 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+        lp.bottomMargin = handleMargin;
         addView(mBottomHandle, lp);
 
-        Rect p = new Rect(0, 0, 0, 0);
         if (!info.isCustomWidget) {
-            p = AppWidgetHostView.getDefaultPaddingForWidget(context,
+            mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context,
                     widgetView.getAppWidgetInfo().provider, null);
         } else {
             Resources r = context.getResources();
             int padding = r.getDimensionPixelSize(R.dimen.default_widget_padding);
-            p.set(padding, padding, padding, padding);
+            mWidgetPadding = new Rect(padding, padding, padding, padding);
         }
 
-        mWidgetPaddingLeft = p.left;
-        mWidgetPaddingTop = p.top;
-        mWidgetPaddingRight = p.right;
-        mWidgetPaddingBottom = p.bottom;
-
         if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
             mTopHandle.setVisibility(GONE);
             mBottomHandle.setVisibility(GONE);
@@ -138,8 +129,8 @@
             mRightHandle.setVisibility(GONE);
         }
 
-        final float density = mLauncher.getResources().getDisplayMetrics().density;
-        mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
+        mBackgroundPadding = getResources()
+                .getDimensionPixelSize(R.dimen.resize_frame_background_padding);
         mTouchTargetWidth = 2 * mBackgroundPadding;
 
         // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
@@ -344,9 +335,9 @@
 
     static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
             int spanX, int spanY) {
-        getWidgetSizeRanges(launcher, spanX, spanY, mTmpRect);
-        widgetView.updateAppWidgetSize(null, mTmpRect.left, mTmpRect.top,
-                mTmpRect.right, mTmpRect.bottom);
+        getWidgetSizeRanges(launcher, spanX, spanY, sTmpRect);
+        widgetView.updateAppWidgetSize(null, sTmpRect.left, sTmpRect.top,
+                sTmpRect.right, sTmpRect.bottom);
     }
 
     public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
@@ -404,19 +395,19 @@
 
     public void snapToWidget(boolean animate) {
         final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
-        int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding - mWidgetPaddingLeft -
-                mWidgetPaddingRight;
-        int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding - mWidgetPaddingTop -
-                mWidgetPaddingBottom;
+        int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding
+                - mWidgetPadding.left - mWidgetPadding.right;
+        int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding
+                - mWidgetPadding.top - mWidgetPadding.bottom;
 
         mTmpPt[0] = mWidgetView.getLeft();
         mTmpPt[1] = mWidgetView.getTop();
         mDragLayer.getDescendantCoordRelativeToSelf(mCellLayout.getShortcutsAndWidgets(), mTmpPt);
 
-        int newX = mTmpPt[0] - mBackgroundPadding + mWidgetPaddingLeft;
-        int newY = mTmpPt[1] - mBackgroundPadding + mWidgetPaddingTop;
+        int newX = mTmpPt[0] - mBackgroundPadding + mWidgetPadding.left;
+        int newY = mTmpPt[1] - mBackgroundPadding + mWidgetPadding.top;
 
-        // We need to make sure the frame's touchable regions lie fully within the bounds of the 
+        // We need to make sure the frame's touchable regions lie fully within the bounds of the
         // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
         // down accordingly to provide a proper touch target.
         if (newY < 0) {
diff --git a/src/com/android/launcher3/AppsGridAdapter.java b/src/com/android/launcher3/AppsGridAdapter.java
index d5a411e..580930c 100644
--- a/src/com/android/launcher3/AppsGridAdapter.java
+++ b/src/com/android/launcher3/AppsGridAdapter.java
@@ -1,3 +1,18 @@
+/*
+ * 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.
+ */
 package com.android.launcher3;
 
 import android.content.Context;
diff --git a/src/com/android/launcher3/AppsRecyclerViewContainer.java b/src/com/android/launcher3/AppsRecyclerViewContainer.java
new file mode 100644
index 0000000..cf4beca
--- /dev/null
+++ b/src/com/android/launcher3/AppsRecyclerViewContainer.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+package com.android.launcher3;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
+
+public class AppsRecyclerViewContainer extends FrameLayout implements BubbleTextShadowHandler {
+
+    private final ClickShadowView mTouchFeedbackView;
+
+    public AppsRecyclerViewContainer(Context context) {
+        this(context, null);
+    }
+
+    public AppsRecyclerViewContainer(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AppsRecyclerViewContainer(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        LauncherAppState app = LauncherAppState.getInstance();
+        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+
+        mTouchFeedbackView = new ClickShadowView(context);
+
+        // Make the feedback view large enough to hold the blur bitmap.
+        int size = grid.allAppsIconSizePx + mTouchFeedbackView.getExtraSize();
+        addView(mTouchFeedbackView, size, size);
+    }
+
+    @Override
+    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
+        if (icon == null || background == null) {
+            mTouchFeedbackView.setBitmap(null);
+            mTouchFeedbackView.animate().cancel();
+        } else if (mTouchFeedbackView.setBitmap(background)) {
+            mTouchFeedbackView.alignWithIconView(icon, (ViewGroup) icon.getParent());
+            mTouchFeedbackView.animateShadow();
+        }
+    }
+}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index d39e139..3b3b9bf 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -34,6 +34,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
+import android.view.ViewParent;
 import android.widget.TextView;
 
 import com.android.launcher3.IconCache.IconLoadRequest;
@@ -276,9 +277,10 @@
         }
 
         // Only show the shadow effect when persistent pressed state is set.
-        if (getParent() instanceof ShortcutAndWidgetContainer) {
-            CellLayout layout = (CellLayout) getParent().getParent();
-            layout.setPressedIcon(this, mPressedBackground);
+        ViewParent parent = getParent();
+        if (parent != null && parent.getParent() instanceof BubbleTextShadowHandler) {
+            ((BubbleTextShadowHandler) parent.getParent()).setPressedIcon(
+                    this, mPressedBackground);
         }
 
         updateIconState();
@@ -520,4 +522,11 @@
             }
         }
     }
+
+    /**
+     * Interface to be implemented by the grand parent to allow click shadow effect.
+     */
+    public static interface BubbleTextShadowHandler {
+        void setPressedIcon(BubbleTextView icon, Bitmap background);
+    }
 }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index a348008..edcdc11 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -47,6 +47,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.DecelerateInterpolator;
 
+import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
 import com.android.launcher3.FolderIcon.FolderRingAnimator;
 import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
 import com.android.launcher3.accessibility.FolderAccessibilityHelper;
@@ -61,7 +62,7 @@
 import java.util.HashMap;
 import java.util.Stack;
 
-public class CellLayout extends ViewGroup {
+public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
     public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
     public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
 
@@ -409,7 +410,8 @@
         invalidate();
     }
 
-    void setPressedIcon(BubbleTextView icon, Bitmap background) {
+    @Override
+    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
         if (icon == null || background == null) {
             mTouchFeedbackView.setBitmap(null);
             mTouchFeedbackView.animate().cancel();
@@ -3010,7 +3012,7 @@
     // 2. When long clicking on an empty cell in a CellLayout, we save information about the
     //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
     //    the CellLayout that was long clicked
-    static final class CellInfo {
+    public static final class CellInfo {
         View cell;
         int cellX = -1;
         int cellY = -1;
@@ -3019,7 +3021,7 @@
         long screenId;
         long container;
 
-        CellInfo(View v, ItemInfo info) {
+        public CellInfo(View v, ItemInfo info) {
             cell = v;
             cellX = info.cellX;
             cellY = info.cellY;
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index f5c29ae..2191455 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -174,19 +174,18 @@
      * @param dragInfo The data associated with the object that is being dragged
      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
      *        {@link #DRAG_ACTION_COPY}
+     * @param viewImageBounds the position of the image inside the view
      * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
      *          Makes dragging feel more precise, e.g. you can clip out a transparent border
      */
-    public void startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo, int dragAction,
-            Point extraPadding, float initialDragViewScale) {
+    public void startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo,
+            Rect viewImageBounds, int dragAction, float initialDragViewScale) {
         int[] loc = mCoordinatesTemp;
         mLauncher.getDragLayer().getLocationInDragLayer(v, loc);
-        int viewExtraPaddingLeft = extraPadding != null ? extraPadding.x : 0;
-        int viewExtraPaddingTop = extraPadding != null ? extraPadding.y : 0;
-        int dragLayerX = loc[0] + v.getPaddingLeft() + viewExtraPaddingLeft +
-                (int) ((initialDragViewScale * bmp.getWidth() - bmp.getWidth()) / 2);
-        int dragLayerY = loc[1] + v.getPaddingTop() + viewExtraPaddingTop +
-                (int) ((initialDragViewScale * bmp.getHeight() - bmp.getHeight()) / 2);
+        int dragLayerX = loc[0] + viewImageBounds.left
+                + (int) ((initialDragViewScale * bmp.getWidth() - bmp.getWidth()) / 2);
+        int dragLayerY = loc[1] + viewImageBounds.top
+                + (int) ((initialDragViewScale * bmp.getHeight() - bmp.getHeight()) / 2);
 
         startDrag(bmp, dragLayerX, dragLayerY, source, dragInfo, dragAction, null,
                 null, initialDragViewScale, false);
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index e25e615..423a9a3 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -39,6 +39,7 @@
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
@@ -48,34 +49,35 @@
  */
 public class DragLayer extends InsettableFrameLayout {
 
+    public static final int ANIMATION_END_DISAPPEAR = 0;
+    public static final int ANIMATION_END_FADE_OUT = 1;
+    public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
+
     // Scrim color without any alpha component.
     private static final int SCRIM_COLOR = Color.BLACK & 0x00FFFFFF;
 
+    private final int[] mTmpXY = new int[2];
+
     @Thunk DragController mDragController;
-    private int[] mTmpXY = new int[2];
 
     private int mXDown, mYDown;
     private Launcher mLauncher;
 
     // Variables relating to resizing widgets
-    private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
-            new ArrayList<AppWidgetResizeFrame>();
+    private final ArrayList<AppWidgetResizeFrame> mResizeFrames = new ArrayList<>();
     private final boolean mIsRtl;
     private AppWidgetResizeFrame mCurrentResizeFrame;
 
     // Variables relating to animation of views after drop
     private ValueAnimator mDropAnim = null;
     private ValueAnimator mFadeOutAnim = null;
-    private TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
+    private final TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
     @Thunk DragView mDropView = null;
     @Thunk int mAnchorViewInitialScrollX = 0;
     @Thunk View mAnchorView = null;
 
     private boolean mHoverPointClosesFolder = false;
-    private Rect mHitRect = new Rect();
-    public static final int ANIMATION_END_DISAPPEAR = 0;
-    public static final int ANIMATION_END_FADE_OUT = 1;
-    public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
+    private final Rect mHitRect = new Rect();
 
     private TouchCompleteListener mTouchCompleteListener;
 
@@ -87,6 +89,7 @@
     private float mBackgroundAlpha = 0;
 
     // Related to adjacent page hints
+    private final Rect mScrollChildPosition = new Rect();
     private boolean mInScrollArea;
     private boolean mShowPageHints;
     private Drawable mLeftHoverDrawable;
@@ -914,6 +917,9 @@
 
     void showPageHints() {
         mShowPageHints = true;
+        Workspace workspace = mLauncher.getWorkspace();
+        getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.getChildCount() - 1),
+                mScrollChildPosition);
         invalidate();
     }
 
@@ -937,10 +943,6 @@
         if (mShowPageHints) {
             Workspace workspace = mLauncher.getWorkspace();
             int width = getMeasuredWidth();
-            Rect childRect = new Rect();
-            getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.getChildCount() - 1),
-                    childRect);
-
             int page = workspace.getNextPage();
             CellLayout leftPage = (CellLayout) workspace.getChildAt(mIsRtl ? page + 1 : page - 1);
             CellLayout rightPage = (CellLayout) workspace.getChildAt(mIsRtl ? page - 1 : page + 1);
@@ -948,15 +950,15 @@
             if (leftPage != null && leftPage.isDragTarget()) {
                 Drawable left = mInScrollArea && leftPage.getIsDragOverlapping() ?
                         mLeftHoverDrawableActive : mLeftHoverDrawable;
-                left.setBounds(0, childRect.top,
-                        left.getIntrinsicWidth(), childRect.bottom);
+                left.setBounds(0, mScrollChildPosition.top,
+                        left.getIntrinsicWidth(), mScrollChildPosition.bottom);
                 left.draw(canvas);
             }
             if (rightPage != null && rightPage.isDragTarget()) {
                 Drawable right = mInScrollArea && rightPage.getIsDragOverlapping() ?
                         mRightHoverDrawableActive : mRightHoverDrawable;
                 right.setBounds(width - right.getIntrinsicWidth(),
-                        childRect.top, width, childRect.bottom);
+                        mScrollChildPosition.top, width, mScrollChildPosition.bottom);
                 right.draw(canvas);
             }
         }
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 69b1837..d0a7ba3 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -49,13 +49,15 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.LinearLayout;
 import android.widget.TextView;
+
 import com.android.launcher3.CellLayout.CellInfo;
 import com.android.launcher3.DragController.DragListener;
 import com.android.launcher3.FolderInfo.FolderListener;
-import com.android.launcher3.LauncherAccessibilityDelegate.AccessibilityDragSource;
 import com.android.launcher3.UninstallDropTarget.UninstallSource;
 import com.android.launcher3.Workspace.ItemOperator;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
 import com.android.launcher3.util.Thunk;
+
 import java.util.ArrayList;
 import java.util.Collections;
 
@@ -352,7 +354,7 @@
     /**
      * @return the FolderInfo object associated with this folder
      */
-    FolderInfo getInfo() {
+    public FolderInfo getInfo() {
         return mInfo;
     }
 
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index de30b60..06ed588 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -241,6 +241,11 @@
         return page;
     }
 
+    @Override
+    protected int getChildGap() {
+        return getPaddingLeft() + getPaddingRight();
+    }
+
     public void setFixedSize(int width, int height) {
         width -= (getPaddingLeft() + getPaddingRight());
         height -= (getPaddingTop() + getPaddingBottom());
diff --git a/src/com/android/launcher3/HolographicOutlineHelper.java b/src/com/android/launcher3/HolographicOutlineHelper.java
index 4a04d03..5ff85d6 100644
--- a/src/com/android/launcher3/HolographicOutlineHelper.java
+++ b/src/com/android/launcher3/HolographicOutlineHelper.java
@@ -157,6 +157,9 @@
 
     Bitmap createMediumDropShadow(BubbleTextView view) {
         Drawable icon = view.getIcon();
+        if (icon == null) {
+            return null;
+        }
         Rect rect = icon.getBounds();
 
         int bitmapWidth = (int) (rect.width() * view.getScaleX());
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 51ba2df..7b7b617 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -96,6 +96,7 @@
 
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.PagedView.PageSwitchListener;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.LauncherActivityInfoCompat;
 import com.android.launcher3.compat.LauncherAppsCompat;
@@ -3184,7 +3185,7 @@
         }
     }
 
-    void closeFolder(Folder folder) {
+    public void closeFolder(Folder folder) {
         folder.getInfo().opened = false;
 
         ViewGroup parent = (ViewGroup) folder.getParent().getParent();
@@ -3337,7 +3338,7 @@
                 true);
     }
 
-    protected void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
+    public void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
         showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated,
                 onCompleteRunnable, true);
     }
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index bde54c3..f540eb4 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -31,6 +31,7 @@
 import android.view.Display;
 import android.view.WindowManager;
 
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.PackageInstallerCompat;
 import com.android.launcher3.util.Thunk;
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 0b3049c..3e05f57 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -66,7 +66,6 @@
 import java.lang.ref.WeakReference;
 import java.net.URISyntaxException;
 import java.security.InvalidParameterException;
-import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -793,7 +792,7 @@
     /**
      * Move an item in the DB to a new <container, screen, cellX, cellY>
      */
-    static void moveItemInDatabase(Context context, final ItemInfo item, final long container,
+    public static void moveItemInDatabase(Context context, final ItemInfo item, final long container,
             final long screenId, final int cellX, final int cellY) {
         item.container = container;
         item.cellX = cellX;
@@ -889,7 +888,7 @@
     /**
      * Update an item to the database in a specified container.
      */
-    static void updateItemInDatabase(Context context, final ItemInfo item) {
+    public static void updateItemInDatabase(Context context, final ItemInfo item) {
         final ContentValues values = new ContentValues();
         item.onAddToDatabase(context, values);
         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");
@@ -3665,39 +3664,6 @@
         return folderInfo;
     }
 
-    public static class WidgetAndShortcutNameComparator implements Comparator<Object> {
-        private final AppWidgetManagerCompat mManager;
-        private final PackageManager mPackageManager;
-        private final HashMap<Object, String> mLabelCache;
-        private final Collator mCollator;
-
-        public WidgetAndShortcutNameComparator(Context context) {
-            mManager = AppWidgetManagerCompat.getInstance(context);
-            mPackageManager = context.getPackageManager();
-            mLabelCache = new HashMap<Object, String>();
-            mCollator = Collator.getInstance();
-        }
-        public final int compare(Object a, Object b) {
-            String labelA, labelB;
-            if (mLabelCache.containsKey(a)) {
-                labelA = mLabelCache.get(a);
-            } else {
-                labelA = (a instanceof LauncherAppWidgetProviderInfo)
-                        ? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) a))
-                        : Utilities.trim(((ResolveInfo) a).loadLabel(mPackageManager));
-                mLabelCache.put(a, labelA);
-            }
-            if (mLabelCache.containsKey(b)) {
-                labelB = mLabelCache.get(b);
-            } else {
-                labelB = (b instanceof LauncherAppWidgetProviderInfo)
-                        ? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) b))
-                        : Utilities.trim(((ResolveInfo) b).loadLabel(mPackageManager));
-                mLabelCache.put(b, labelB);
-            }
-            return mCollator.compare(labelA, labelB);
-        }
-    };
 
     static boolean isValidProvider(AppWidgetProviderInfo provider) {
         return (provider != null) && (provider.provider != null)
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 554a975..dda9a16 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -407,7 +407,7 @@
     /**
      * Returns the index of the currently displayed page.
      */
-    int getCurrentPage() {
+    public int getCurrentPage() {
         return mCurrentPage;
     }
 
@@ -422,7 +422,7 @@
         return getChildCount();
     }
 
-    View getPageAt(int index) {
+    public View getPageAt(int index) {
         return getChildAt(index);
     }
 
@@ -633,9 +633,6 @@
             if (mCurrentPage != getNextPage()) {
                 AccessibilityEvent ev =
                         AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
-                ev.setItemCount(getChildCount());
-                ev.setFromIndex(getNextPage());
-                ev.setToIndex(getNextPage());
 
                 sendAccessibilityEventUnchecked(ev);
             }
@@ -912,8 +909,7 @@
                     pageGap = getPaddingRight();
                 }
 
-                childLeft += childWidth + pageGap
-                        + (lp.isFullScreenPage ? 0 : (getPaddingLeft() + getPaddingRight()));
+                childLeft += childWidth + pageGap + getChildGap();
             }
         }
 
@@ -961,6 +957,10 @@
         }
     }
 
+    protected int getChildGap() {
+        return 0;
+    }
+
     private void updateMaxScrollX() {
         int childCount = getChildCount();
         if (childCount > 0) {
diff --git a/src/com/android/launcher3/SmoothPagedView.java b/src/com/android/launcher3/SmoothPagedView.java
index 4e331aa..0f9b23c 100644
--- a/src/com/android/launcher3/SmoothPagedView.java
+++ b/src/com/android/launcher3/SmoothPagedView.java
@@ -152,7 +152,7 @@
     }
 
     @Override
-    protected void snapToPage(int whichPage) {
+    public void snapToPage(int whichPage) {
        if (mScrollMode == X_LARGE_MODE) {
            super.snapToPage(whichPage);
        } else {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 58e5877..8c1c7d6 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -57,19 +57,22 @@
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.widget.TextView;
+
 import com.android.launcher3.FolderIcon.FolderRingAnimator;
 import com.android.launcher3.Launcher.CustomContentCallbacks;
 import com.android.launcher3.Launcher.LauncherOverlay;
-import com.android.launcher3.LauncherAccessibilityDelegate.AccessibilityDragSource;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.UninstallDropTarget.UninstallSource;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.util.LongArrayMap;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.WallpaperUtils;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -494,7 +497,7 @@
     /**
      * @return The open folder on the current screen, or null if there is none
      */
-    Folder getOpenFolder() {
+    public Folder getOpenFolder() {
         DragLayer dragLayer = mLauncher.getDragLayer();
         int count = dragLayer.getChildCount();
         for (int i = 0; i < count; i++) {
@@ -857,7 +860,7 @@
         return -1;
     }
 
-    ArrayList<Long> getScreenOrder() {
+    public ArrayList<Long> getScreenOrder() {
         return mScreenOrder;
     }
 
diff --git a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
index 0f17241..78accf7 100644
--- a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
@@ -26,7 +26,6 @@
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.launcher3.CellLayout;
-import com.android.launcher3.LauncherAccessibilityDelegate;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 
diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
similarity index 94%
rename from src/com/android/launcher3/LauncherAccessibilityDelegate.java
rename to src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 3992e63..eeec8c5 100644
--- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -1,4 +1,4 @@
-package com.android.launcher3;
+package com.android.launcher3.accessibility;
 
 import android.annotation.TargetApi;
 import android.app.AlertDialog;
@@ -16,6 +16,24 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeleteDropTarget;
+import com.android.launcher3.Folder;
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.InfoDropTarget;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetHostView;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.UninstallDropTarget;
+import com.android.launcher3.Workspace;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
index 6f89d0e..80ddc13 100644
--- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -23,8 +23,7 @@
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.FolderInfo;
 import com.android.launcher3.ItemInfo;
-import com.android.launcher3.LauncherAccessibilityDelegate;
-import com.android.launcher3.LauncherAccessibilityDelegate.DragType;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DragType;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
 
diff --git a/src/com/android/launcher3/model/AppNameComparator.java b/src/com/android/launcher3/model/AppNameComparator.java
new file mode 100644
index 0000000..706f751
--- /dev/null
+++ b/src/com/android/launcher3/model/AppNameComparator.java
@@ -0,0 +1,105 @@
+package com.android.launcher3.model;
+
+import android.content.Context;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+import java.text.Collator;
+import java.util.Comparator;
+import java.util.HashMap;
+
+/**
+ * Class to manage access to an app name comparator.
+ * <p>
+ * Used to sort application name in all apps view and widget tray view.
+ */
+public class AppNameComparator {
+    private final UserManagerCompat mUserManager;
+    private final Collator mCollator;
+    private final Comparator<ItemInfo> mAppInfoComparator;
+    private final Comparator<String> mSectionNameComparator;
+    private HashMap<UserHandleCompat, Long> mUserSerialCache = new HashMap<>();
+
+    public AppNameComparator(Context context) {
+        mCollator = Collator.getInstance();
+        mUserManager = UserManagerCompat.getInstance(context);
+        mAppInfoComparator = new Comparator<ItemInfo>() {
+
+            public final int compare(ItemInfo a, ItemInfo b) {
+                // Order by the title in the current locale
+                int result = compareTitles(a.title.toString(), b.title.toString());
+                if (result == 0 && a instanceof AppInfo && b instanceof AppInfo) {
+                    AppInfo aAppInfo = (AppInfo) a;
+                    AppInfo bAppInfo = (AppInfo) b;
+                    // If two apps have the same title, then order by the component name
+                    result = aAppInfo.componentName.compareTo(bAppInfo.componentName);
+                    if (result == 0) {
+                        // If the two apps are the same component, then prioritize by the order that
+                        // the app user was created (prioritizing the main user's apps)
+                        if (UserHandleCompat.myUserHandle().equals(a.user)) {
+                            return -1;
+                        } else {
+                            Long aUserSerial = getAndCacheUserSerial(a.user);
+                            Long bUserSerial = getAndCacheUserSerial(b.user);
+                            return aUserSerial.compareTo(bUserSerial);
+                        }
+                    }
+                }
+                return result;
+            }
+        };
+        mSectionNameComparator = new Comparator<String>() {
+            @Override
+            public int compare(String o1, String o2) {
+                return compareTitles(o1, o2);
+            }
+        };
+    }
+
+    /**
+     * Returns a locale-aware comparator that will alphabetically order a list of applications.
+     */
+    public Comparator<ItemInfo> getAppInfoComparator() {
+        // Clear the user serial cache so that we get serials as needed in the comparator
+        mUserSerialCache.clear();
+        return mAppInfoComparator;
+    }
+
+    /**
+     * Returns a locale-aware comparator that will alphabetically order a list of section names.
+     */
+    public Comparator<String> getSectionNameComparator() {
+        return mSectionNameComparator;
+    }
+
+    /**
+     * Compares two titles with the same return value semantics as Comparator.
+     */
+    private int compareTitles(String titleA, String titleB) {
+        // Ensure that we de-prioritize any titles that don't start with a linguistic letter or digit
+        boolean aStartsWithLetter = Character.isLetterOrDigit(titleA.codePointAt(0));
+        boolean bStartsWithLetter = Character.isLetterOrDigit(titleB.codePointAt(0));
+        if (aStartsWithLetter && !bStartsWithLetter) {
+            return -1;
+        } else if (!aStartsWithLetter && bStartsWithLetter) {
+            return 1;
+        }
+
+        // Order by the title in the current locale
+        return mCollator.compare(titleA, titleB);
+    }
+
+    /**
+     * Returns the user serial for this user, using a cached serial if possible.
+     */
+    private Long getAndCacheUserSerial(UserHandleCompat user) {
+        Long userSerial = mUserSerialCache.get(user);
+        if (userSerial == null) {
+            userSerial = mUserManager.getSerialNumberForUser(user);
+            mUserSerialCache.put(user, userSerial);
+        }
+        return userSerial;
+    }
+}
diff --git a/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java b/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java
new file mode 100644
index 0000000..61e8952
--- /dev/null
+++ b/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java
@@ -0,0 +1,68 @@
+package com.android.launcher3.model;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+
+import java.text.Collator;
+import java.util.Comparator;
+import java.util.HashMap;
+
+public class WidgetsAndShortcutNameComparator implements Comparator<Object> {
+    private final AppWidgetManagerCompat mManager;
+    private final PackageManager mPackageManager;
+    private final HashMap<Object, String> mLabelCache;
+    private final Collator mCollator;
+    private final UserHandleCompat mMainHandle;
+
+    public WidgetsAndShortcutNameComparator(Context context) {
+        mManager = AppWidgetManagerCompat.getInstance(context);
+        mPackageManager = context.getPackageManager();
+        mLabelCache = new HashMap<Object, String>();
+        mCollator = Collator.getInstance();
+        mMainHandle = UserHandleCompat.myUserHandle();
+    }
+
+    @Override
+    public final int compare(Object a, Object b) {
+        String labelA, labelB;
+        if (mLabelCache.containsKey(a)) {
+            labelA = mLabelCache.get(a);
+        } else {
+            labelA = (a instanceof LauncherAppWidgetProviderInfo)
+                    ? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) a))
+                    : Utilities.trim(((ResolveInfo) a).loadLabel(mPackageManager));
+            mLabelCache.put(a, labelA);
+        }
+        if (mLabelCache.containsKey(b)) {
+            labelB = mLabelCache.get(b);
+        } else {
+            labelB = (b instanceof LauncherAppWidgetProviderInfo)
+                    ? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) b))
+                    : Utilities.trim(((ResolveInfo) b).loadLabel(mPackageManager));
+            mLabelCache.put(b, labelB);
+        }
+
+        // Currently, there is no work profile shortcuts, hence only considering the widget cases.
+
+        boolean aWorkProfile = (a instanceof LauncherAppWidgetProviderInfo) &&
+                !mMainHandle.equals(mManager.getUser((LauncherAppWidgetProviderInfo) a));
+        boolean bWorkProfile = (b instanceof LauncherAppWidgetProviderInfo) &&
+                !mMainHandle.equals(mManager.getUser((LauncherAppWidgetProviderInfo) b));
+
+        // Independent of how the labels compare, if only one of the two widget info belongs to
+        // work profile, put that one in the back.
+        if (aWorkProfile && !bWorkProfile) {
+            return 1;
+        }
+        if (!aWorkProfile && bWorkProfile) {
+            return -1;
+        }
+        return mCollator.compare(labelA, labelB);
+    }
+};
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index e3eb76c..dcaf1f2 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -21,17 +21,14 @@
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -41,7 +38,13 @@
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 
 /**
- * Represents the individual cell of the widget inside the widget tray.
+ * Represents the individual cell of the widget inside the widget tray. The preview is drawn
+ * horizontally centered, and scaled down if needed.
+ *
+ * This view does not support padding. Since the image is scaled down to fit the view, padding will
+ * further decrease the scaling factor. Drag-n-drop uses the view bounds for showing a smooth
+ * transition from the view to drag view, so when adding padding support, DnD would need to
+ * consider the appropriate scaling factor.
  */
 public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
 
@@ -59,13 +62,11 @@
     private int mPresetPreviewSize;
     int cellSize;
 
-    private ImageView mWidgetImage;
+    private WidgetImageView mWidgetImage;
     private TextView mWidgetName;
     private TextView mWidgetDims;
-    private final Rect mOrigImgPadding = new Rect();
 
     private String mDimensionsFormatString;
-    private boolean mIsAppWidget;
     private Object mInfo;
 
     private WidgetPreviewLoader mWidgetPreviewLoader;
@@ -101,12 +102,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mWidgetImage = (ImageView) findViewById(R.id.widget_preview);
-        mOrigImgPadding.left = mWidgetImage.getPaddingLeft();
-        mOrigImgPadding.top = mWidgetImage.getPaddingTop();
-        mOrigImgPadding.right = mWidgetImage.getPaddingRight();
-        mOrigImgPadding.bottom = mWidgetImage.getPaddingBottom();
-
+        mWidgetImage = (WidgetImageView) findViewById(R.id.widget_preview);
         mWidgetName = ((TextView) findViewById(R.id.widget_name));
         mWidgetDims = ((TextView) findViewById(R.id.widget_dims));
     }
@@ -119,7 +115,7 @@
             Log.d(TAG, "reset called on:" + mWidgetName.getText());
         }
         mWidgetImage.animate().cancel();
-        mWidgetImage.setImageDrawable(null);
+        mWidgetImage.setBitmap(null);
         mWidgetName.setText(null);
         mWidgetDims.setText(null);
 
@@ -133,15 +129,11 @@
      * Apply the widget provider info to the view.
      */
     public void applyFromAppWidgetProviderInfo(LauncherAppWidgetProviderInfo info,
-            int maxWidth, WidgetPreviewLoader loader) {
+            WidgetPreviewLoader loader) {
         LauncherAppState app = LauncherAppState.getInstance();
         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
 
-        mIsAppWidget = true;
         mInfo = info;
-        if (maxWidth > -1) {
-            mWidgetImage.setMaxWidth(maxWidth);
-        }
         // TODO(hyunyoungs): setup a cache for these labels.
         mWidgetName.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info));
         int hSpan = Math.min(info.spanX, grid.numColumns);
@@ -155,7 +147,6 @@
      */
     public void applyFromResolveInfo(
             PackageManager pm, ResolveInfo info, WidgetPreviewLoader loader) {
-        mIsAppWidget = false;
         mInfo = info;
         CharSequence label = info.loadLabel(pm);
         mWidgetName.setText(label);
@@ -172,20 +163,8 @@
     }
 
     public void applyPreview(Bitmap bitmap) {
-        FastBitmapDrawable preview = new FastBitmapDrawable(bitmap);
-
-        if (preview != null) {
-            mWidgetImage.setImageDrawable(preview);
-
-            if (mIsAppWidget) {
-                // center horizontally
-                int[] imageSize = getPreviewSize();
-                int centerAmount = (imageSize[0] - preview.getIntrinsicWidth()) / 2;
-                mWidgetImage.setPadding(mOrigImgPadding.left + centerAmount,
-                        mOrigImgPadding.top,
-                        mOrigImgPadding.right,
-                        mOrigImgPadding.bottom);
-            }
+        if (bitmap != null) {
+            mWidgetImage.setBitmap(bitmap);
             mWidgetImage.setAlpha(0f);
             mWidgetImage.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
         }
diff --git a/src/com/android/launcher3/widget/WidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
index f1eaf64..6f8fd89 100644
--- a/src/com/android/launcher3/widget/WidgetImageView.java
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -17,25 +17,73 @@
 package com.android.launcher3.widget;
 
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
 import android.util.AttributeSet;
-import android.widget.ImageView;
+import android.view.View;
 
-public class WidgetImageView extends ImageView {
+/**
+ * View that draws a bitmap horizontally centered. If the image width is greater than the view
+ * width, the image is scaled down appropriately.
+ */
+public class WidgetImageView extends View {
+
+    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+    private final RectF mDstRectF = new RectF();
+    private Bitmap mBitmap;
+
+    public WidgetImageView(Context context) {
+        super(context);
+    }
 
     public WidgetImageView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
+    public WidgetImageView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public void setBitmap(Bitmap bitmap) {
+        mBitmap = bitmap;
+        invalidate();
+    }
+
+    public Bitmap getBitmap() {
+        return mBitmap;
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
-        canvas.save();
-        canvas.clipRect(getScrollX() + getPaddingLeft(),
-                getScrollY() + getPaddingTop(),
-                getScrollX() + getRight() - getLeft() - getPaddingRight(),
-                getScrollY() + getBottom() - getTop() - getPaddingBottom());
+        if (mBitmap != null) {
+            updateDstRectF();
+            canvas.drawBitmap(mBitmap, null, mDstRectF, mPaint);
+        }
+    }
 
-        super.onDraw(canvas);
-        canvas.restore();
+    private void updateDstRectF() {
+        if (mBitmap.getWidth() > getWidth()) {
+            float scale = ((float) getWidth()) / mBitmap.getWidth();
+            mDstRectF.set(0, 0, getWidth(), scale * mBitmap.getHeight());
+        } else {
+            mDstRectF.set(
+                    (getWidth() - mBitmap.getWidth()) * 0.5f,
+                    0,
+                    (getWidth() + mBitmap.getWidth()) * 0.5f,
+                    mBitmap.getHeight());
+        }
+    }
+
+    /**
+     * @return the bounds where the image was drawn.
+     */
+    public Rect getBitmapBounds() {
+        updateDstRectF();
+        Rect rect = new Rect();
+        mDstRectF.round(rect);
+        return rect;
     }
 }
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 00fb225..7a7895f 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.support.v7.widget.LinearLayoutManager;
@@ -28,8 +27,8 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
-import android.widget.ImageView;
 import android.widget.Toast;
+
 import com.android.launcher3.BaseContainerView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeleteDropTarget;
@@ -37,10 +36,8 @@
 import com.android.launcher3.DragController;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.Folder;
 import com.android.launcher3.IconCache;
-import com.android.launcher3.Insettable;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
@@ -138,7 +135,7 @@
     //
 
     public View getContentView() {
-        return findViewById(R.id.widgets_content);
+        return mView;
     }
 
     public View getRevealView() {
@@ -222,20 +219,19 @@
 
     private boolean beginDraggingWidget(WidgetCell v) {
         // Get the widget preview as the drag representation
-        ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
+        WidgetImageView image = (WidgetImageView) v.findViewById(R.id.widget_preview);
         PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
 
         // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
         // we abort the drag.
-        if (image.getDrawable() == null) {
+        if (image.getBitmap() == null) {
             return false;
         }
 
         // Compose the drag image
         Bitmap preview;
-        Bitmap outline;
         float scale = 1f;
-        Point previewPadding = null;
+        final Rect bounds = image.getBitmapBounds();
 
         if (createItemInfo instanceof PendingAddWidgetInfo) {
             // This can happen in some weird cases involving multi-touch. We can't start dragging
@@ -244,25 +240,25 @@
             PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo;
             int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true);
 
-            FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable();
+            Bitmap icon = image.getBitmap();
             float minScale = 1.25f;
-            int maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
+            int maxWidth = Math.min((int) (icon.getWidth() * minScale), size[0]);
 
             int[] previewSizeBeforeScale = new int[1];
             preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info,
                     maxWidth, null, previewSizeBeforeScale);
-            // Compare the size of the drag preview to the preview in the AppsCustomize tray
-            int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0],
-                    v.getActualItemWidth());
-            scale = previewWidthInAppsCustomize / (float) preview.getWidth();
 
-            // The bitmap in the AppsCustomize tray is always the the same size, so there
-            // might be extra pixels around the preview itself - this accounts for that
-            if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) {
-                int padding =
-                        (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2;
-                previewPadding = new Point(padding, 0);
+            if (previewSizeBeforeScale[0] < icon.getWidth()) {
+                // The icon has extra padding around it.
+                int padding = (icon.getWidth() - previewSizeBeforeScale[0]) / 2;
+                if (icon.getWidth() > image.getWidth()) {
+                    padding = padding * image.getWidth() / icon.getWidth();
+                }
+
+                bounds.left += padding;
+                bounds.right -= padding;
             }
+            scale = bounds.width() / (float) preview.getWidth();
         } else {
             PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
             Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.activityInfo);
@@ -274,16 +270,12 @@
         boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
                 (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
 
-        // Save the preview for the outline generation, then dim the preview
-        outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(),
-                false);
-
         // Start the drag
         mLauncher.lockScreenOrientation();
-        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha);
+        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, preview, clipAlpha);
         mDragController.startDrag(image, preview, this, createItemInfo,
-                DragController.DRAG_ACTION_COPY, previewPadding, scale);
-        outline.recycle();
+                bounds, DragController.DRAG_ACTION_COPY, scale);
+
         preview.recycle();
         return true;
     }
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index 397d177..3916c00 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -18,9 +18,9 @@
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.os.Build;
 import android.support.v7.widget.RecyclerView;
-import android.content.res.Resources;
 import android.support.v7.widget.RecyclerView.Adapter;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -29,15 +29,16 @@
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.LinearLayout;
+
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DynamicGrid;
-import com.android.launcher3.IconCache;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.R;
 import com.android.launcher3.WidgetPreviewLoader;
+
 import java.util.List;
 
 /**
@@ -56,7 +57,6 @@
     private Context mContext;
     private Launcher mLauncher;
     private LayoutInflater mLayoutInflater;
-    private IconCache mIconCache;
 
     private WidgetsModel mWidgetsModel;
     private WidgetPreviewLoader mWidgetPreviewLoader;
@@ -76,9 +76,7 @@
 
         mIconClickListener = iconClickListener;
         mIconLongClickListener = iconLongClickListener;
-
         mLauncher = launcher;
-        mIconCache = LauncherAppState.getInstance().getIconCache();
 
         setContainerHeight();
     }
@@ -143,7 +141,7 @@
                 LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) infoList.get(i);
                 PendingAddWidgetInfo pawi = new PendingAddWidgetInfo(info, null);
                 widget.setTag(pawi);
-                widget.applyFromAppWidgetProviderInfo(info, -1, mWidgetPreviewLoader);
+                widget.applyFromAppWidgetProviderInfo(info, mWidgetPreviewLoader);
             } else if (infoList.get(i) instanceof ResolveInfo) {
                 ResolveInfo info = (ResolveInfo) infoList.get(i);
                 PendingAddShortcutInfo pasi = new PendingAddShortcutInfo(info.activityInfo);
@@ -185,7 +183,6 @@
         }
     }
 
-    @Override
     public boolean onFailedToRecycleView(WidgetsRowViewHolder holder) {
         // If child views are animating, then the RecyclerView may choose not to recycle the view,
         // causing extraneous onCreateViewHolder() calls.  It is safe in this case to continue
diff --git a/src/com/android/launcher3/widget/WidgetsModel.java b/src/com/android/launcher3/widget/WidgetsModel.java
index 71a7b94..5a920e8 100644
--- a/src/com/android/launcher3/widget/WidgetsModel.java
+++ b/src/com/android/launcher3/widget/WidgetsModel.java
@@ -10,8 +10,9 @@
 import com.android.launcher3.IconCache;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.LauncherModel.WidgetAndShortcutNameComparator;
 import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.model.AppNameComparator;
+import com.android.launcher3.model.WidgetsAndShortcutNameComparator;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -40,12 +41,14 @@
     private RecyclerView.Adapter mAdapter;
 
     private Comparator mWidgetAndShortcutNameComparator;
+    private Comparator mAppNameComparator;
 
     private IconCache mIconCache;
 
     public WidgetsModel(Context context, RecyclerView.Adapter adapter) {
         mAdapter = adapter;
-        mWidgetAndShortcutNameComparator = new WidgetAndShortcutNameComparator(context);
+        mWidgetAndShortcutNameComparator = new WidgetsAndShortcutNameComparator(context);
+        mAppNameComparator = (new AppNameComparator(context)).getAppInfoComparator();
         mIconCache = LauncherAppState.getInstance().getIconCache();
     }
 
@@ -108,7 +111,7 @@
         }
 
         // sort.
-        sortPackageItemInfos();
+        Collections.sort(mPackageItemInfos, mAppNameComparator);
         for (PackageItemInfo p: mPackageItemInfos) {
             Collections.sort(mWidgetsList.get(p), mWidgetAndShortcutNameComparator);
         }
@@ -116,13 +119,4 @@
         // notify.
         mAdapter.notifyDataSetChanged();
     }
-
-    private void sortPackageItemInfos() {
-        Collections.sort(mPackageItemInfos, new Comparator<PackageItemInfo>() {
-            @Override
-            public int compare(PackageItemInfo lhs, PackageItemInfo rhs) {
-                return lhs.title.toString().compareTo(rhs.title.toString());
-            }
-        });
-    }
 }
\ No newline at end of file