Merge "Launcher-side changes to support prediction bar." into ub-launcher3-burnaby
diff --git a/proguard.flags b/proguard.flags
index e2a4b5b..6eb5948 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -65,4 +65,8 @@
 -keep class com.android.launcher3.AppsContainerRecyclerView {
   public void setFastScrollerAlpha(float);
   public float getFastScrollerAlpha();
-}
\ No newline at end of file
+}
+
+-keep class com.android.launcher3.ButtonDropTarget {
+  public int getTextColor();
+}
diff --git a/res/drawable-hdpi/ic_launcher_clear_active_holo.png b/res/drawable-hdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index cdd0052..0000000
--- a/res/drawable-hdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_clear_normal_holo.png b/res/drawable-hdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index 84549ff..0000000
--- a/res/drawable-hdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_active.png b/res/drawable-hdpi/ic_launcher_info_active.png
new file mode 100644
index 0000000..f7a3b68
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_info_active.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_active_holo.png b/res/drawable-hdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index c534e56..0000000
--- a/res/drawable-hdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_normal.png b/res/drawable-hdpi/ic_launcher_info_normal.png
new file mode 100644
index 0000000..780d796
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_info_normal.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_normal_holo.png b/res/drawable-hdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index c9bcd7f..0000000
--- a/res/drawable-hdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_remove_active.png b/res/drawable-hdpi/ic_launcher_remove_active.png
new file mode 100644
index 0000000..e53de0d
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_remove_active.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_remove_normal.png b/res/drawable-hdpi/ic_launcher_remove_normal.png
new file mode 100644
index 0000000..91e19ca
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_remove_normal.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-hdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index 82b1b59..0000000
--- a/res/drawable-hdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-hdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 3fc2e83..0000000
--- a/res/drawable-hdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_uninstall_active.png b/res/drawable-hdpi/ic_launcher_uninstall_active.png
new file mode 100644
index 0000000..22b97ee
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_uninstall_active.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_uninstall_normal.png b/res/drawable-hdpi/ic_launcher_uninstall_normal.png
new file mode 100644
index 0000000..7aea5d0
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_uninstall_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_clear_active_holo.png b/res/drawable-mdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index 2683bea..0000000
--- a/res/drawable-mdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_clear_normal_holo.png b/res/drawable-mdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index 219f3e5..0000000
--- a/res/drawable-mdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_active.png b/res/drawable-mdpi/ic_launcher_info_active.png
new file mode 100644
index 0000000..ea71272
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_info_active.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_active_holo.png b/res/drawable-mdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index f84b4a6..0000000
--- a/res/drawable-mdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_normal.png b/res/drawable-mdpi/ic_launcher_info_normal.png
new file mode 100644
index 0000000..8c60159
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_info_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_normal_holo.png b/res/drawable-mdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index eac578f..0000000
--- a/res/drawable-mdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_remove_active.png b/res/drawable-mdpi/ic_launcher_remove_active.png
new file mode 100644
index 0000000..f36cfdd
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_remove_active.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_remove_normal.png b/res/drawable-mdpi/ic_launcher_remove_normal.png
new file mode 100644
index 0000000..60829b9
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_remove_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-mdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index 0350e55..0000000
--- a/res/drawable-mdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-mdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 799b62f..0000000
--- a/res/drawable-mdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_uninstall_active.png b/res/drawable-mdpi/ic_launcher_uninstall_active.png
new file mode 100644
index 0000000..e4ee911
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_uninstall_active.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_uninstall_normal.png b/res/drawable-mdpi/ic_launcher_uninstall_normal.png
new file mode 100644
index 0000000..aefbc69
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_uninstall_normal.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_clear_active_holo.png b/res/drawable-xhdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index 1a7e53d..0000000
--- a/res/drawable-xhdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_clear_normal_holo.png b/res/drawable-xhdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index d4965d9..0000000
--- a/res/drawable-xhdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_active.png b/res/drawable-xhdpi/ic_launcher_info_active.png
new file mode 100644
index 0000000..b438f9e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_info_active.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_active_holo.png b/res/drawable-xhdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index b8cdbc4..0000000
--- a/res/drawable-xhdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_normal.png b/res/drawable-xhdpi/ic_launcher_info_normal.png
new file mode 100644
index 0000000..5c49816
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_info_normal.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_normal_holo.png b/res/drawable-xhdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index f503fb8..0000000
--- a/res/drawable-xhdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_remove_active.png b/res/drawable-xhdpi/ic_launcher_remove_active.png
new file mode 100644
index 0000000..14ac79d
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_remove_active.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_remove_normal.png b/res/drawable-xhdpi/ic_launcher_remove_normal.png
new file mode 100644
index 0000000..8188805
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_remove_normal.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-xhdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index c155274..0000000
--- a/res/drawable-xhdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-xhdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 2ec7ad9..0000000
--- a/res/drawable-xhdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_uninstall_active.png b/res/drawable-xhdpi/ic_launcher_uninstall_active.png
new file mode 100644
index 0000000..2c19b32
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_uninstall_active.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_uninstall_normal.png b/res/drawable-xhdpi/ic_launcher_uninstall_normal.png
new file mode 100644
index 0000000..a093f28
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_uninstall_normal.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_clear_active_holo.png b/res/drawable-xxhdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index 95cf841..0000000
--- a/res/drawable-xxhdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_clear_normal_holo.png b/res/drawable-xxhdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index b0f5a27..0000000
--- a/res/drawable-xxhdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_active.png b/res/drawable-xxhdpi/ic_launcher_info_active.png
new file mode 100644
index 0000000..d354dd3
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_info_active.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_active_holo.png b/res/drawable-xxhdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index 57f332a..0000000
--- a/res/drawable-xxhdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_normal.png b/res/drawable-xxhdpi/ic_launcher_info_normal.png
new file mode 100644
index 0000000..c270be2
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_info_normal.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_normal_holo.png b/res/drawable-xxhdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index 94f0955..0000000
--- a/res/drawable-xxhdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_remove_active.png b/res/drawable-xxhdpi/ic_launcher_remove_active.png
new file mode 100644
index 0000000..9df4404
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_remove_active.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_remove_normal.png b/res/drawable-xxhdpi/ic_launcher_remove_normal.png
new file mode 100644
index 0000000..5bc8f0c
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_remove_normal.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-xxhdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index 3bb098c..0000000
--- a/res/drawable-xxhdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-xxhdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 550cc5b..0000000
--- a/res/drawable-xxhdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_uninstall_active.png b/res/drawable-xxhdpi/ic_launcher_uninstall_active.png
new file mode 100644
index 0000000..db7d339
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_uninstall_active.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_uninstall_normal.png b/res/drawable-xxhdpi/ic_launcher_uninstall_normal.png
new file mode 100644
index 0000000..4fce55b
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_uninstall_normal.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_info_active.png b/res/drawable-xxxhdpi/ic_launcher_info_active.png
new file mode 100644
index 0000000..162e23d
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_info_active.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_info_normal.png b/res/drawable-xxxhdpi/ic_launcher_info_normal.png
new file mode 100644
index 0000000..270e15d
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_info_normal.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_remove_active.png b/res/drawable-xxxhdpi/ic_launcher_remove_active.png
new file mode 100644
index 0000000..c0b8ea2
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_remove_active.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_remove_normal.png b/res/drawable-xxxhdpi/ic_launcher_remove_normal.png
new file mode 100644
index 0000000..ed96c55
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_remove_normal.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_uninstall_active.png b/res/drawable-xxxhdpi/ic_launcher_uninstall_active.png
new file mode 100644
index 0000000..75896f3
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_uninstall_active.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_uninstall_normal.png b/res/drawable-xxxhdpi/ic_launcher_uninstall_normal.png
new file mode 100644
index 0000000..61490b9
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_uninstall_normal.png
Binary files differ
diff --git a/res/drawable/info_target_selector.xml b/res/drawable/info_target_selector.xml
index f3a7016..51caece 100644
--- a/res/drawable/info_target_selector.xml
+++ b/res/drawable/info_target_selector.xml
@@ -19,6 +19,6 @@
 -->
 
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_launcher_info_normal_holo"  />
-    <item android:drawable="@drawable/ic_launcher_info_active_holo"  />
+    <item android:drawable="@drawable/ic_launcher_info_normal"  />
+    <item android:drawable="@drawable/ic_launcher_info_active"  />
 </transition>
diff --git a/res/drawable/remove_target_selector.xml b/res/drawable/remove_target_selector.xml
index 5e071fb..9025e8a 100644
--- a/res/drawable/remove_target_selector.xml
+++ b/res/drawable/remove_target_selector.xml
@@ -19,6 +19,6 @@
 -->
 
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_launcher_clear_normal_holo"  />
-    <item android:drawable="@drawable/ic_launcher_clear_active_holo"  />
+    <item android:drawable="@drawable/ic_launcher_remove_normal"  />
+    <item android:drawable="@drawable/ic_launcher_remove_active"  />
 </transition>
diff --git a/res/drawable/uninstall_target_selector.xml b/res/drawable/uninstall_target_selector.xml
index 229942e..175cc20 100644
--- a/res/drawable/uninstall_target_selector.xml
+++ b/res/drawable/uninstall_target_selector.xml
@@ -19,6 +19,6 @@
 -->
 
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_launcher_trashcan_normal_holo"  />
-    <item android:drawable="@drawable/ic_launcher_trashcan_active_holo"  />
+    <item android:drawable="@drawable/ic_launcher_uninstall_normal"  />
+    <item android:drawable="@drawable/ic_launcher_uninstall_active"  />
 </transition>
diff --git a/res/layout/add_list_item.xml b/res/layout/add_list_item.xml
deleted file mode 100644
index e937d7b..0000000
--- a/res/layout/add_list_item.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:textAppearance="?android:attr/textAppearanceLarge"
-    android:gravity="center_vertical"
-    android:drawablePadding="14dip"
-    android:paddingLeft="15dip"
-    android:paddingRight="15dip" />
diff --git a/res/layout/rename_folder.xml b/res/layout/rename_folder.xml
deleted file mode 100644
index 21a335c..0000000
--- a/res/layout/rename_folder.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:padding="20dip"
-    android:orientation="vertical">
-
-    <TextView 
-        android:id="@+id/label"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:text="@string/rename_folder_label"
-        android:gravity="start"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-            
-    <EditText
-        android:id="@+id/folder_name"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:scrollHorizontally="true"
-        android:autoText="false"
-        android:capitalize="none"
-        android:gravity="fill_horizontal"
-        android:maxLength="30"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-</LinearLayout>
diff --git a/res/layout/search_drop_target_bar.xml b/res/layout/search_drop_target_bar.xml
index fe18edc..69f42bb 100644
--- a/res/layout/search_drop_target_bar.xml
+++ b/res/layout/search_drop_target_bar.xml
@@ -17,8 +17,7 @@
 <com.android.launcher3.SearchDropTargetBar xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:focusable="false"
-    android:orientation="horizontal" >
+    android:focusable="false" >
 
     <!-- Drag specific targets container -->
 
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 64ddea1..ab23b84 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -17,13 +17,11 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="@dimen/widget_preview_container_width"
-    android:layout_height="wrap_content"
+    android:layout_height="@dimen/widget_cell_height"
     android:layout_weight="1"
-    android:layout_marginTop="@dimen/widget_preview_padding_top"
-    android:layout_marginLeft="8dp"
-    android:layout_marginBottom="8dp"
+    android:layout_marginRight="@dimen/widget_row_divider"
     android:orientation="vertical"
-    android:background="@color/bubble_dark_background"
+    android:background="@color/widgets_cell_color"
     android:focusable="true">
 
     <LinearLayout
@@ -46,7 +44,7 @@
             android:ellipsize="end"
             android:fadingEdge="horizontal"
 
-            android:textColor="#FFFFFFFF"
+            android:textColor="@color/widgets_view_item_text_color"
             android:textSize="16sp"
             android:textAlignment="viewStart"
             android:fontFamily="sans-serif-condensed"
@@ -63,7 +61,7 @@
             android:layout_marginLeft="5dp"
             android:layout_weight="0"
             android:gravity="start"
-            android:textColor="#FFFFFFFF"
+            android:textColor="@color/widgets_view_item_text_color"
             android:textSize="16sp"
             android:textAlignment="viewStart"
             android:fontFamily="sans-serif-condensed"
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index f94d023..12f6401 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -20,7 +20,6 @@
     android:layout_height="wrap_content"
     android:orientation="vertical"
     android:focusable="true"
-    android:background="@drawable/focusable_view_bg"
     android:descendantFocusability="afterDescendants">
 
     <!-- Section info -->
@@ -29,24 +28,23 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         android:focusable="true"
-        android:background="@drawable/focusable_view_bg"
         android:descendantFocusability="afterDescendants">
         <ImageView
             android:id="@+id/section_image"
-            android:layout_width="@dimen/widget_section_height"
             android:layout_height="@dimen/widget_section_height"
-            android:paddingLeft="@dimen/widget_section_icon_padding"
-            android:paddingRight="@dimen/widget_section_icon_padding"
-            android:paddingTop="@dimen/widget_section_icon_padding"
-            android:paddingBottom="@dimen/widget_section_icon_padding"
+            android:layout_width="@dimen/widget_section_icon_width"
+            android:paddingLeft="@dimen/widget_section_icon_horizontal_padding"
+            android:paddingRight="@dimen/widget_section_icon_horizontal_padding"
+            android:paddingTop="@dimen/widget_section_icon_vertical_padding"
+            android:paddingBottom="@dimen/widget_section_icon_vertical_padding"
             android:background="@color/widget_text_panel"
         />
         <TextView
             android:id="@+id/section"
             android:layout_width="match_parent"
             android:layout_height="@dimen/widget_section_height"
-            android:paddingLeft="16dp"
-            android:paddingRight="16dp"
+            android:paddingEnd="@dimen/widget_preview_label_horizontal_padding"
+            android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
             android:singleLine="true"
             android:ellipsize="end"
             android:gravity="start|center_vertical"
@@ -57,31 +55,24 @@
     </LinearLayout>
 
     <!--  Widget list -->
-    <RelativeLayout 
+    <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="end"
+        android:background="@color/widgets_cell_color"
         >
-        <!-- TODO(hyunyoungs): replace the indicator with actual assets. -->
-        <FrameLayout
-            android:id="@+id/scrollable_indicator"
-            android:layout_gravity="center_vertical"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:background="@drawable/ic_pageindicator_default"
-            android:visibility="invisible"
-            />
         <HorizontalScrollView
             android:id="@+id/widgets_scroll_container"
             android:layout_width="match_parent"
             android:layout_height="@dimen/widget_cell_height"
-            android:paddingLeft="40dp"
+            android:layout_marginLeft="@dimen/widget_row_padding"
             android:scrollbars="none" >
             <LinearLayout
                 android:id="@+id/widgets_cell_list"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:orientation="horizontal" />
+                android:orientation="horizontal"
+                android:background="@color/widget_text_panel"/>
         </HorizontalScrollView>
     </RelativeLayout>
 </LinearLayout>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 3a06bd9..0c3714b 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -20,8 +20,9 @@
 <resources>
     <!-- The color tints to apply to the text and drag view when hovering
          over the delete target or the info target -->
-    <color name="delete_target_hover_tint">#DAFF0000</color>
-    <color name="info_target_hover_tint">#DA0099CC</color>
+    <color name="delete_target_hover_tint">#DAC1C1C1</color>
+    <color name="uninstall_target_hover_tint">#DAF0592B</color>
+    <color name="info_target_hover_tint">#DA009688</color>
     <color name="cling_scrim_background">#80000000</color>
 
     <color name="bubble_dark_background">#20000000</color>
@@ -41,5 +42,7 @@
     <color name="apps_view_section_text_color">#009688</color>
 
     <!-- Widgetss view -->
-    <color name="widgets_view_section_text_color">#009688</color>
+    <color name="widgets_view_section_text_color">#FFFFFF</color>
+    <color name="widgets_view_item_text_color">#C4C4C4</color>
+    <color name="widgets_cell_color">#263238</color>
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 47394a1..7ce4059 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -55,9 +55,6 @@
     <integer name="config_appsCustomizeDragSlopeThreshold">150</integer>
 
 <!-- Workspace -->
-    <!-- The transition duration for the background of the drop targets -->
-    <integer name="config_dropTargetBgTransitionDuration">0</integer>
-
     <!-- The duration (in ms) of the fade animation on the object outlines, used when
          we are dragging objects around on the home screen. -->
     <integer name="config_dragOutlineFadeTime">900</integer>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index da11082..a57ae89 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -86,12 +86,16 @@
     <dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
     <dimen name="widget_preview_horizontal_padding">8dp</dimen>
 
-    <dimen name="widget_section_height">52dp</dimen>
-    <dimen name="widget_section_icon_padding">8dp</dimen>
+    <dimen name="widget_section_height">56dp</dimen>
+    <dimen name="widget_section_icon_width">72dp</dimen>
+    <dimen name="widget_section_icon_vertical_padding">8dp</dimen>
+    <dimen name="widget_section_icon_horizontal_padding">16dp</dimen>
 
     <!-- Equation: widget_preview_size + 2 * widget_preview_padding_horizontal -->
     <dimen name="widget_preview_container_width">136dp</dimen>
     <dimen name="widget_cell_height">150dp</dimen>
+    <dimen name="widget_row_padding">8dp</dimen>
+    <dimen name="widget_row_divider">1dp</dimen>
 
     <!-- Padding applied to shortcut previews -->
     <dimen name="shortcut_preview_padding_left">0dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bfe7e36..a5a681a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -34,8 +34,6 @@
     <string name="application_name">Launcher3</string>
     <!-- Accessibility-facing application name -->
     <string name="home">Home</string>
-    <!-- Name for all applications running as this uid. -->
-    <string name="uid_name">Android Core Apps</string>
     <!-- Default folder name -->
     <string name="folder_name"></string>
     <!-- Work folder name -->
@@ -48,10 +46,6 @@
     <string name="safemode_shortcut_error">Downloaded app disabled in Safe mode</string>
     <!-- SafeMode widget error string -->
     <string name="safemode_widget_error">Widgets disabled in Safe mode</string>
-    <!--  Labels for the tabs in the customize drawer -->
-    <string name="widgets_tab_label">Widgets</string>
-
-    <string name="widget_adder">Widgets</string>
 
     <string name="toggle_weight_watcher">Show Mem</string>
 
@@ -62,75 +56,26 @@
     <!-- There is a special version of this format string for Farsi -->
     <string name="widget_dims_format">%1$d \u00d7 %2$d</string>
 
-    <!-- External-drop widget pick label format string [CHAR_LIMIT=25] -->
-    <string name="external_drop_widget_pick_format" translatable="false">%1$s (%2$d \u00d7 %3$d)</string>
-    <!-- External-drop widget error string.  This is the error that is shown
-         when you drag and item into the homescreen and it is unable to fit,
-         or an error is encountered. [CHAR_LIMIT=50] -->
-    <string name="external_drop_widget_error">Couldn\'t drop item on this Home screen.</string>
-    <!-- External-drop widget pick title.  This is shown as the title of the
-         dialog which allows you to pick which widgets to handle a particular
-         drop if there are multiple choices. [CHAR_LIMIT=35] -->
-    <string name="external_drop_widget_pick_title">Choose widget to create</string>
-
     <!-- Apps view -->
     <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
     <string name="apps_view_search_bar_hint">Search Apps</string>
     <!-- Loading apps text. [CHAR_LIMIT=50] -->
-    <string name="loading_apps_message">Loading Apps...</string>
+    <string name="loading_apps_message">Loading Apps&#8230;</string>
     <!-- No-search-results text. [CHAR_LIMIT=50] -->
     <string name="apps_view_no_search_results">No Apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
 
-    <!-- Folders -->
+    <!-- Drag and drop -->
     <skip />
-    <!-- Label of Folder name field in Rename folder dialog box -->
-    <string name="rename_folder_label">Folder name</string>
-    <!-- Title of dialog box -->
-    <string name="rename_folder_title">Rename folder</string>
-    <!-- Buttons in Rename folder dialog box -->
-    <string name="rename_action">OK</string>
-    <!-- Buttons in Rename folder dialog box -->
-    <string name="cancel_action">Cancel</string>
-    <!-- Label for button to sort folder contents. [CHAR_LIMIT=10] -->
-    <string name="sort_alphabetical">A-Z</string>
-
-    <!-- Shortcuts -->
-    <skip />
-    <!-- Title of dialog box -->
-    <string name="menu_item_add_item">Add to Home screen</string>
-    <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all apps -->
-    <string name="group_applications">Apps</string>
-    <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all shortcut
-s -->
-    <string name="group_shortcuts">Shortcuts</string>
-    <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all widgets/gadgets -->
-    <string name="group_widgets">Widgets</string>
-    <!-- Error message when user has filled all their home screens -->
-    <string name="completely_out_of_space">No more room on your Home screens.</string>
     <!-- Error message when user has filled a home screen -->
     <string name="out_of_space">No more room on this Home screen.</string>
     <!-- Error message when user has filled the hotseat -->
     <string name="hotseat_out_of_space">No more room in the Favorites tray</string>
-    <!-- Error message when user tries to drop an invalid item on the hotseat -->
-    <string name="invalid_hotseat_item">This widget is too large for the Favorites tray</string>
-    <!-- Message displayed when a shortcut is created by an external application -->
-    <string name="shortcut_installed">Shortcut \"<xliff:g id="name" example="Browser">%s</xliff:g>\" created.</string>
-    <!-- Message displayed when an external application attemps to create a shortcut that already exists -->
-    <string name="shortcut_duplicate">Shortcut \"<xliff:g id="name" example="Browser">%s</xliff:g>\" already exists.</string>
-
-    <!-- Title of dialog when user is selecting shortcut to add to homescreen -->
-    <string name="title_select_shortcut">Choose shortcut</string>
-    <!-- Title of dialog when user is selecting an application to add to homescreen -->
-    <string name="title_select_application">Choose app</string>
 
     <!-- All applications label -->
     <string name="all_apps_button_label">Apps</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>
-    <!-- Label for trash icon in All Apps. The icon/widget will become completely unavailable on the
-         device. [CHAR_LIMIT=30]-->
-    <string name="delete_zone_label_all_apps">Uninstall</string>
 
     <!-- Label for delete drop target. [CHAR_LIMIT=20] -->
     <string name="delete_target_label">Remove</string>
@@ -139,35 +84,6 @@
     <!-- Label for the info icon. [CHAR_LIMIT=20] -->
     <string name="info_target_label">App info</string>
 
-    <!-- Accessibility: AllApps button -->
-    <string name="accessibility_all_apps_button">Apps</string>
-    <!-- Accessibility: Delete button -->
-    <string name="accessibility_delete_button">Remove</string>
-
-    <!-- Label for trash icon in All Apps, when an updated system app is selected. The update will
-         be uninstalled. [CHAR_LIMIT=30] -->
-    <string name="delete_zone_label_all_apps_system_app">Uninstall update</string>
-
-    <!-- URL pointing to help text. If empty, no link to help will be created [DO NOT TRANSLATE] -->
-    <string name="help_url" translatable="false"></string>
-
-    <!--  Strings for the contextual action bar (CAB) in All Apps -->
-    <skip />
-    <!-- Describes the button for uninstalling the currently selected application.
-         Text is not displayed, but provided for accessibility. [CHAR_LIMIT=none] -->
-    <string name="cab_menu_delete_app">Uninstall app</string>
-    <!-- Describes the button for getting details/info about currently selected application.
-         Text is not displayed, but provided for accessibility. [CHAR_LIMIT=none] -->
-    <string name="cab_menu_app_info">App details</string>
-    <!-- Appears in the CAB when an app is selected in All Apps or Customize mode. [CHAR_LIMIT=50] -->
-    <string name="cab_app_selection_text">1 app selected</string>
-    <!-- Appears in the CAB when a widget is selected in Customize mode. [CHAR_LIMIT=50] -->
-    <string name="cab_widget_selection_text">1 widget selected</string>
-    <!-- Appears in the CAB when a folder is selected in Customize mode. [CHAR_LIMIT=50] -->
-    <string name="cab_folder_selection_text">1 folder selected</string>
-    <!-- Appears in the CAB when a shortcut is selected in Customize mode. [CHAR_LIMIT=50] -->
-    <string name="cab_shortcut_selection_text">1 shortcut selected</string>
-
     <!-- Permissions: -->
     <skip />
     <!-- Permission short label -->
@@ -198,9 +114,6 @@
     <!-- Text to inform the user that they can't uninstall a system application -->
     <string name="uninstall_system_app_text">This is a system app and can\'t be uninstalled.</string>
 
-    <!-- Title of the Android Dreams (screensaver) module -->
-    <string name="dream_name">Rocket Launcher</string>
-
     <!-- Default folder title -->
     <string name="folder_hint_text">Unnamed Folder</string>
 
@@ -214,22 +127,10 @@
     <string name="default_scroll_format">Page %1$d of %2$d</string>
     <!-- The format string for Workspace page scroll text [CHAR_LIMIT=none] -->
     <string name="workspace_scroll_format">Home screen %1$d of %2$d</string>
-    <!-- The format string for AppsCustomize Apps page scroll text [CHAR_LIMIT=none] -->
-    <string name="apps_customize_apps_scroll_format">Apps page %1$d of %2$d</string>
-    <!-- The format string for AppsCustomize Apps page scroll text [CHAR_LIMIT=none] -->
-    <string name="apps_customize_widgets_scroll_format">Widgets page %1$d of %2$d</string>
 
     <!-- Clings -->
     <!-- The title text for the workspace cling [CHAR_LIMIT=30] -->
     <string name="first_run_cling_title">Welcome</string>
-    <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
-    <string name="first_run_cling_description">Make yourself at home.</string>
-    <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
-    <string name="first_run_cling_custom_content_hint"></string>
-    <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
-    <string name="first_run_cling_search_bar_hint"></string>
-    <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
-    <string name="first_run_cling_create_screens_hint">Create more screens for apps and folders</string>
     <!-- The title text for the migration cling [CHAR_LIMIT=30] -->
     <string name="migration_cling_title">Copy your app icons</string>
     <!-- The description of what migration does [CHAR_LIMIT=70] -->
@@ -238,24 +139,14 @@
     <string name="migration_cling_copy_apps">COPY ICONS</string>
     <!-- The description of the button to use the default launcher layout [CHAR_LIMIT=30] -->
     <string name="migration_cling_use_default">START FRESH</string>
-    <!-- The title text for the workspace cling [CHAR_LIMIT=30] -->
-    <string name="workspace_cling_title">Organize your space</string>
-    <!-- The description of how to use the workspace [CHAR_LIMIT=70] -->
-    <string name="workspace_cling_move_item">Touch &amp; hold background to manage wallpaper, widgets and settings.</string>
     <!-- The title text for workspace longpress action [CHAR_LIMIT=40] -->
     <string name="workspace_cling_longpress_title">Wallpapers, widgets, &amp; settings</string>
     <!-- The description of how to use the workspace [CHAR_LIMIT=70] -->
     <string name="workspace_cling_longpress_description">Touch &amp; hold background to customize</string>
     <!-- The description of the button to dismiss the cling [CHAR_LIMIT=30] -->
     <string name="workspace_cling_longpress_dismiss">GOT IT</string>
-    <!-- The title text for the Folder cling [CHAR_LIMIT=30] -->
-    <string name="folder_cling_title">Here\'s a folder</string>
-    <!-- The description of how to create a folder [CHAR_LIMIT=70] -->
-    <string name="folder_cling_create_folder">To create one like this, touch &amp; hold an app, then move it over another.</string>
     <!-- The text on the button to dismiss a cling [CHAR_LIMIT=30] -->
     <string name="cling_dismiss">OK</string>
-    <!-- Error message on dummy custom cling layout [DO NOT TRANSLATE] -->
-    <string name="dummy_custom_cling_error_message">Error: custom workspace layout passed in but custom cling was not overwritten</string>
 
     <!-- Folder accessibility -->
     <!-- The format string for when a folder is opened, speaks the dimensions -->
@@ -309,10 +200,13 @@
 
 <!-- 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 workspace</string>
+    <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 confirmation for item added to workspace [DO NOT TRANSLATE] -->
-    <string name="item_added_to_workspace">Item added to workspace</string>
+    <string name="item_added_to_workspace">Item added to home screen</string>
 
     <!-- Accessibility confirmation for item removed [DO NOT TRANSLATE] -->
     <string name="item_removed">Item removed</string>
@@ -321,7 +215,13 @@
     <string name="action_move">Move Item</string>
 
     <!-- Accessibility description to move item to empty cell. [DO NOT TRANSLATE] -->
-    <string name="move_to_empty_cell">Move to empty cell <xliff:g id="number" example="1">%1$s</xliff:g>, <xliff:g id="number" example="1">%2$s</xliff:g></string>
+    <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] -->
+    <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] -->
+    <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]-->
     <string name="item_moved">Item moved</string>
@@ -329,6 +229,9 @@
     <!-- Accessibility description to move item into an existing folder. [DO NOT TRANSLATE]-->
     <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]-->
+    <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] -->
     <string name="added_to_folder">Item added to folder</string>
 
diff --git a/src/com/android/launcher3/AlphabeticalAppsList.java b/src/com/android/launcher3/AlphabeticalAppsList.java
index 2ee5a62..c7ee2e9 100644
--- a/src/com/android/launcher3/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/AlphabeticalAppsList.java
@@ -254,7 +254,7 @@
         int length = apps.size();
         for (int i = 0; i < length; ++i) {
             AppInfo info = apps.get(i);
-            if (info.user.equals(info.user)
+            if (info.user.equals(targetInfo.user)
                     && info.intent.getComponent().equals(targetComponent)) {
                 return i;
             }
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index fb49df5..683c511 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -16,14 +16,16 @@
 
 package com.android.launcher3;
 
+import android.animation.ObjectAnimator;
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.TransitionDrawable;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -42,8 +44,6 @@
 
     private static int DRAG_VIEW_DROP_DURATION = 285;
 
-    protected final int mTransitionDuration;
-
     protected Launcher mLauncher;
     private int mBottomDragPadding;
     protected TextView mText;
@@ -58,16 +58,15 @@
     protected ColorStateList mOriginalTextColor;
     protected TransitionDrawable mDrawable;
 
+    private ObjectAnimator mCurrentColorAnim;
+
     public ButtonDropTarget(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
     public ButtonDropTarget(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-
-        Resources r = getResources();
-        mTransitionDuration = r.getInteger(R.integer.config_dropTargetBgTransitionDuration);
-        mBottomDragPadding = r.getDimensionPixelSize(R.dimen.drop_target_drag_padding);
+        mBottomDragPadding = getResources().getDimensionPixelSize(R.dimen.drop_target_drag_padding);
     }
 
     @Override
@@ -118,13 +117,18 @@
     }
 
     @Override
-    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) { }
+    public void onFlingToDelete(DragObject d, PointF vec) { }
 
     @Override
     public final void onDragEnter(DragObject d) {
         d.dragView.setColor(mHoverColor);
-        mDrawable.startTransition(mTransitionDuration);
-        setTextColor(mHoverColor);
+        if (Utilities.isLmpOrAbove()) {
+            mDrawable.startTransition(DragView.COLOR_CHANGE_DURATION);
+            animateTextColor(mHoverColor);
+        } else {
+            mDrawable.startTransition(0);
+            setTextColor(mHoverColor);
+        }
     }
 
     @Override
@@ -133,8 +137,23 @@
     }
 
     protected void resetHoverColor() {
-        mDrawable.resetTransition();
-        setTextColor(mOriginalTextColor);
+        if (Utilities.isLmpOrAbove()) {
+            mDrawable.reverseTransition(DragView.COLOR_CHANGE_DURATION);
+            animateTextColor(mOriginalTextColor.getDefaultColor());
+        } else {
+            mDrawable.resetTransition();
+            setTextColor(mOriginalTextColor);
+        }
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    private void animateTextColor(int targetColor) {
+        if (mCurrentColorAnim != null) {
+            mCurrentColorAnim.cancel();
+        }
+        mCurrentColorAnim = ObjectAnimator.ofArgb(this, "textColor", targetColor);
+        mCurrentColorAnim.setDuration(DragView.COLOR_CHANGE_DURATION);
+        mCurrentColorAnim.start();
     }
 
     @Override
@@ -152,6 +171,10 @@
     public final void onDragStart(DragSource source, Object info, int dragAction) {
         mActive = supportsDrop(source, info);
         mDrawable.resetTransition();
+        if (mCurrentColorAnim != null) {
+            mCurrentColorAnim.cancel();
+            mCurrentColorAnim = null;
+        }
         setTextColor(mOriginalTextColor);
         ((ViewGroup) getParent()).setVisibility(mActive ? View.VISIBLE : View.GONE);
     }
@@ -203,6 +226,9 @@
                 DragLayer.ANIMATION_END_DISAPPEAR, null);
     }
 
+    @Override
+    public void prepareAccessibilityDrop() { }
+
     @Thunk abstract void completeDrop(DragObject d);
 
     @Override
@@ -271,4 +297,8 @@
         LauncherAppState.getInstance().getAccessibilityDelegate()
             .handleAccessibleDrop(this, null, getAccessibilityDropConfirmation());
     }
+
+    public int getTextColor() {
+        return getTextColors().getDefaultColor();
+    }
 }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index f08f25f..65c6702 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -35,11 +35,8 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
-import android.os.Bundle;
 import android.os.Parcelable;
 import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.ExploreByTouchHelper;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -48,12 +45,12 @@
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.Animation;
 import android.view.animation.DecelerateInterpolator;
-import android.view.animation.LayoutAnimationController;
 
 import com.android.launcher3.FolderIcon.FolderRingAnimator;
-import com.android.launcher3.LauncherAccessibilityDelegate.DragType;
+import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
+import com.android.launcher3.accessibility.FolderAccessibilityHelper;
+import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
 
@@ -62,10 +59,12 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Stack;
 
 public class CellLayout extends ViewGroup {
+    public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
+    public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
+
     static final String TAG = "CellLayout";
 
     private Launcher mLauncher;
@@ -121,7 +120,6 @@
 
     // If we're actively dragging something over this screen, mIsDragOverlapping is true
     private boolean mIsDragOverlapping = false;
-    boolean mUseActiveGlowBackground = false;
 
     // These arrays are used to implement the drag visualization on x-large screens.
     // They are used as circular arrays, indexed by mDragOutlineCurrent.
@@ -181,12 +179,8 @@
     private final static Paint sPaint = new Paint();
 
     // Related to accessible drag and drop
-    DragAndDropAccessibilityDelegate mTouchHelper = new DragAndDropAccessibilityDelegate(this);
+    private DragAndDropAccessibilityDelegate mTouchHelper;
     private boolean mUseTouchHelper = false;
-    OnClickListener mOldClickListener = null;
-    OnClickListener mOldWorkspaceListener = null;
-    @Thunk int mDownX = 0;
-    @Thunk int mDownY = 0;
 
     public CellLayout(Context context) {
         this(context, null);
@@ -314,7 +308,7 @@
     }
 
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    public void enableAccessibleDrag(boolean enable) {
+    public void enableAccessibleDrag(boolean enable, int dragType) {
         mUseTouchHelper = enable;
         if (!enable) {
             ViewCompat.setAccessibilityDelegate(this, null);
@@ -322,6 +316,13 @@
             getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
             setOnClickListener(mLauncher);
         } else {
+            if (dragType == WORKSPACE_ACCESSIBILITY_DRAG &&
+                    !(mTouchHelper instanceof WorkspaceAccessibilityHelper)) {
+                mTouchHelper = new WorkspaceAccessibilityHelper(this);
+            } else if (dragType == FOLDER_ACCESSIBILITY_DRAG &&
+                    !(mTouchHelper instanceof FolderAccessibilityHelper)) {
+                mTouchHelper = new FolderAccessibilityHelper(this);
+            }
             ViewCompat.setAccessibilityDelegate(this, mTouchHelper);
             setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
             getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -345,15 +346,6 @@
     }
 
     @Override
-    public boolean dispatchTouchEvent(MotionEvent event) {
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            mDownX = (int) event.getX();
-            mDownY = (int) event.getY();
-        }
-        return super.dispatchTouchEvent(event);
-    }
-
-    @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (mUseTouchHelper ||
                 (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev))) {
@@ -362,252 +354,6 @@
         return false;
     }
 
-    class DragAndDropAccessibilityDelegate extends ExploreByTouchHelper implements OnClickListener {
-        private final Rect mTempRect = new Rect();
-
-        public DragAndDropAccessibilityDelegate(View forView) {
-            super(forView);
-        }
-
-        private int getViewIdAt(float x, float y) {
-            if (x < 0 || y < 0 || x > getMeasuredWidth() || y > getMeasuredHeight()) {
-                return ExploreByTouchHelper.INVALID_ID;
-            }
-
-            // Map coords to cell
-            int cellX = (int) Math.floor(x / (mCellWidth + mWidthGap));
-            int cellY = (int) Math.floor(y / (mCellHeight + mHeightGap));
-
-            // Map cell to id
-            int id = cellX * mCountY + cellY;
-            return id;
-        }
-
-        @Override
-        protected int getVirtualViewAt(float x, float y) {
-            return nearestDropLocation(getViewIdAt(x, y));
-        }
-
-        protected int nearestDropLocation(int id) {
-            int count = mCountX * mCountY;
-            for (int delta = 0; delta < count; delta++) {
-                if (id + delta <= (count - 1)) {
-                    int target = intersectsValidDropTarget(id + delta);
-                    if (target >= 0) {
-                        return target;
-                    }
-                } else if (id - delta >= 0) {
-                    int target = intersectsValidDropTarget(id - delta);
-                    if (target >= 0) {
-                        return target;
-                    }
-                }
-            }
-            return ExploreByTouchHelper.INVALID_ID;
-        }
-
-        /**
-         * Find the virtual view id corresponding to the top left corner of any drop region by which
-         * the passed id is contained. For an icon, this is simply
-         *
-         * @param id the id we're interested examining (ie. does it fit there?)
-         * @return the view id of the top left corner of a valid drop region or -1 if there is no
-         *         such valid region. For the icon, this can just be -1 or id.
-         */
-        protected int intersectsValidDropTarget(int id) {
-            LauncherAccessibilityDelegate delegate =
-                    LauncherAppState.getInstance().getAccessibilityDelegate();
-            if (delegate == null) {
-                return -1;
-            }
-
-            int y = id % mCountY;
-            int x = id / mCountY;
-            LauncherAccessibilityDelegate.DragInfo dragInfo = delegate.getDragInfo();
-
-            if (dragInfo.dragType == DragType.WIDGET) {
-                // For a widget, every cell must be vacant. In addition, we will return any valid
-                // drop target by which the passed id is contained.
-                boolean fits = false;
-
-                // These represent the amount that we can back off if we hit a problem. They
-                // get consumed as we move up and to the right, trying new regions.
-                int spanX = dragInfo.info.spanX;
-                int spanY = dragInfo.info.spanY;
-
-                for (int m = 0; m < spanX; m++) {
-                    for (int n = 0; n < spanY; n++) {
-
-                        fits = true;
-                        int x0 = x - m;
-                        int y0 = y - n;
-
-                        if (x0 < 0 || y0 < 0) continue;
-
-                        for (int i = x0; i < x0 + spanX; i++) {
-                            if (!fits) break;
-                            for (int j = y0; j < y0 + spanY; j++) {
-                                if (i >= mCountX || j >= mCountY || mOccupied[i][j]) {
-                                    fits = false;
-                                    break;
-                                }
-                            }
-                        }
-                        if (fits) {
-                            return x0 * mCountY + y0;
-                        }
-                    }
-                }
-                return -1;
-            } else {
-                // For an icon, we simply check the view directly below
-                View child = getChildAt(x, y);
-                if (child == null || child == dragInfo.item) {
-                    // Empty cell. Good for an icon or folder.
-                    return id;
-                } else if (dragInfo.dragType != DragType.FOLDER) {
-                    // For icons, we can consider cells that have another icon or a folder.
-                    ItemInfo info = (ItemInfo) child.getTag();
-                    if (info instanceof AppInfo || info instanceof FolderInfo ||
-                            info instanceof ShortcutInfo) {
-                        return id;
-                    }
-                }
-                return -1;
-            }
-        }
-
-        @Override
-        protected void getVisibleVirtualViews(List<Integer> virtualViews) {
-            // We create a virtual view for each cell of the grid
-            // The cell ids correspond to cells in reading order.
-            int nCells = mCountX * mCountY;
-
-            for (int i = 0; i < nCells; i++) {
-                if (intersectsValidDropTarget(i) >= 0) {
-                    virtualViews.add(i);
-                }
-            }
-        }
-
-        @Override
-        protected boolean onPerformActionForVirtualView(int viewId, int action, Bundle args) {
-            LauncherAccessibilityDelegate delegate =
-                    LauncherAppState.getInstance().getAccessibilityDelegate();
-            if (delegate == null) {
-                return false;
-            }
-
-            if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
-                String confirmation = getConfirmationForIconDrop(viewId);
-                delegate.handleAccessibleDrop(CellLayout.this, getItemBounds(viewId), confirmation);
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public void onClick(View arg0) {
-            LauncherAccessibilityDelegate delegate =
-                    LauncherAppState.getInstance().getAccessibilityDelegate();
-            if (delegate == null) {
-                return;
-            }
-
-            int viewId = getViewIdAt(mDownX, mDownY);
-
-            String confirmation = getConfirmationForIconDrop(viewId);
-            delegate.handleAccessibleDrop(CellLayout.this, getItemBounds(viewId), confirmation);
-        }
-
-        @Override
-        protected void onPopulateEventForVirtualView(int id, AccessibilityEvent event) {
-            if (id == ExploreByTouchHelper.INVALID_ID) {
-                throw new IllegalArgumentException("Invalid virtual view id");
-            }
-            // We're required to set something here.
-            event.setContentDescription("");
-        }
-
-        @Override
-        protected void onPopulateNodeForVirtualView(int id, AccessibilityNodeInfoCompat node) {
-            if (id == ExploreByTouchHelper.INVALID_ID) {
-                throw new IllegalArgumentException("Invalid virtual view id");
-            }
-
-            node.setContentDescription(getLocationDescriptionForIconDrop(id));
-            node.setBoundsInParent(getItemBounds(id));
-
-            node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
-            node.setClickable(true);
-            node.setFocusable(true);
-        }
-
-        private String getLocationDescriptionForIconDrop(int id) {
-            LauncherAccessibilityDelegate delegate =
-                    LauncherAppState.getInstance().getAccessibilityDelegate();
-            if (delegate == null) {
-                return "";
-            }
-
-            int y = id % mCountY;
-            int x = id / mCountY;
-            LauncherAccessibilityDelegate.DragInfo dragInfo = delegate.getDragInfo();
-
-            Resources res = getContext().getResources();
-            View child = getChildAt(x, y);
-            if (child == null || child == dragInfo.item) {
-                return res.getString(R.string.move_to_empty_cell, x + 1, y + 1);
-            } else {
-                ItemInfo info = (ItemInfo) child.getTag();
-                if (info instanceof AppInfo || info instanceof ShortcutInfo) {
-                    return res.getString(R.string.create_folder_with, info.title);
-                } else if (info instanceof FolderInfo) {
-                    return res.getString(R.string.add_to_folder, info.title);
-                }
-            }
-            return "";
-        }
-
-        private String getConfirmationForIconDrop(int id) {
-            LauncherAccessibilityDelegate delegate =
-                LauncherAppState.getInstance().getAccessibilityDelegate();
-            if (delegate == null) {
-                return "";
-            }
-
-            int y = id % mCountY;
-            int x = id / mCountY;
-            LauncherAccessibilityDelegate.DragInfo dragInfo = delegate.getDragInfo();
-
-            Resources res = getContext().getResources();
-            View child = getChildAt(x, y);
-            if (child == null || child == dragInfo.item) {
-                return res.getString(R.string.item_moved);
-            } else {
-                ItemInfo info = (ItemInfo) child.getTag();
-                if (info instanceof AppInfo || info instanceof ShortcutInfo) {
-                    return res.getString(R.string.folder_created);
-
-                } else if (info instanceof FolderInfo) {
-                    return res.getString(R.string.added_to_folder);
-                }
-            }
-            return "";
-        }
-
-        private Rect getItemBounds(int id) {
-            int cellY = id % mCountY;
-            int cellX = id / mCountY;
-            int x = getPaddingLeft() + (int) (cellX * (mCellWidth + mWidthGap));
-            int y = getPaddingTop() + (int) (cellY * (mCellHeight + mHeightGap));
-
-            Rect bounds = mTempRect;
-            bounds.set(x, y, x + mCellWidth, y + mCellHeight);
-            return bounds;
-        }
-    }
-
     public void enableHardwareLayer(boolean hasLayer) {
         mShortcutsAndWidgets.setLayerType(hasLayer ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, sPaint);
     }
@@ -684,10 +430,6 @@
         }
     }
 
-    void setUseActiveGlowBackground(boolean use) {
-        mUseActiveGlowBackground = use;
-    }
-
     void disableBackground() {
         mDrawBackground = false;
     }
@@ -703,7 +445,6 @@
     void setIsDragOverlapping(boolean isDragOverlapping) {
         if (mIsDragOverlapping != isDragOverlapping) {
             mIsDragOverlapping = isDragOverlapping;
-            setUseActiveGlowBackground(mIsDragOverlapping);
             invalidate();
         }
     }
@@ -722,7 +463,7 @@
         if (mDrawBackground && mBackgroundAlpha > 0.0f) {
             Drawable bg;
 
-            if (mUseActiveGlowBackground) {
+            if (mIsDragOverlapping) {
                 // In the mini case, we draw the active_glow bg *over* the active background
                 bg = mActiveGlowBackground;
             } else {
@@ -905,8 +646,12 @@
         mShortcutsAndWidgets.setIsHotseat(isHotseat);
     }
 
+    public boolean isHotseat() {
+        return mIsHotseat;
+    }
+
     public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
-            boolean markCells, boolean inLayout) {
+            boolean markCells) {
         final LayoutParams lp = params;
 
         // Hotseat icons - remove text
@@ -927,7 +672,7 @@
             if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
 
             child.setId(childId);
-            mShortcutsAndWidgets.addView(child, index, lp, inLayout);
+            mShortcutsAndWidgets.addView(child, index, lp);
 
             if (markCells) markCellsAsOccupiedForView(child);
 
@@ -936,11 +681,6 @@
         return false;
     }
 
-    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
-            boolean markCells) {
-        return addViewToCellLayout(child, index, childId, params, markCells, false);
-    }
-
     @Override
     public void removeAllViews() {
         clearOccupiedCells();
@@ -955,10 +695,6 @@
         }
     }
 
-    public void removeViewWithoutMarkingCells(View view) {
-        mShortcutsAndWidgets.removeView(view);
-    }
-
     @Override
     public void removeView(View view) {
         markCellsAsUnoccupiedForView(view);
@@ -999,7 +735,7 @@
      * @param y Y coordinate of the point
      * @param result Array of 2 ints to hold the x and y coordinate of the cell
      */
-    void pointToCellExact(int x, int y, int[] result) {
+    public void pointToCellExact(int x, int y, int[] result) {
         final int hStartPadding = getPaddingLeft();
         final int vStartPadding = getPaddingTop();
 
@@ -1088,9 +824,7 @@
 
     public float getDistanceFromCell(float x, float y, int[] cell) {
         cellToCenterPoint(cell[0], cell[1], mTmpPoint);
-        float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
-                Math.pow(y - mTmpPoint[1], 2));
-        return distance;
+        return (float) Math.hypot(x - mTmpPoint[0], y - mTmpPoint[1]);
     }
 
     int getCellWidth() {
@@ -1109,28 +843,6 @@
         return mHeightGap;
     }
 
-    Rect getContentRect(Rect r) {
-        if (r == null) {
-            r = new Rect();
-        }
-        int left = getPaddingLeft();
-        int top = getPaddingTop();
-        int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
-        int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
-        r.set(left, top, right, bottom);
-        return r;
-    }
-
-    /** Return a rect that has the cellWidth/cellHeight (left, top), and
-     * widthGap/heightGap (right, bottom) */
-    static void getMetrics(Rect metrics, int paddedMeasureWidth,
-            int paddedMeasureHeight, int countX, int countY) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        metrics.set(grid.calculateCellWidth(paddedMeasureWidth, countX),
-                grid.calculateCellHeight(paddedMeasureHeight, countY), 0, 0);
-    }
-
     public void setFixedSize(int width, int height) {
         mFixedWidth = width;
         mFixedHeight = height;
@@ -1246,7 +958,6 @@
     }
 
     public void setBackgroundAlphaMultiplier(float multiplier) {
-
         if (mBackgroundAlphaMultiplier != multiplier) {
             mBackgroundAlphaMultiplier = multiplier;
             invalidate();
@@ -1360,36 +1071,6 @@
         return false;
     }
 
-    /**
-     * Estimate where the top left cell of the dragged item will land if it is dropped.
-     *
-     * @param originX The X value of the top left corner of the item
-     * @param originY The Y value of the top left corner of the item
-     * @param spanX The number of horizontal cells that the item spans
-     * @param spanY The number of vertical cells that the item spans
-     * @param result The estimated drop cell X and Y.
-     */
-    void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
-        final int countX = mCountX;
-        final int countY = mCountY;
-
-        // pointToCellRounded takes the top left of a cell but will pad that with
-        // cellWidth/2 and cellHeight/2 when finding the matching cell
-        pointToCellRounded(originX, originY, result);
-
-        // If the item isn't fully on this screen, snap to the edges
-        int rightOverhang = result[0] + spanX - countX;
-        if (rightOverhang > 0) {
-            result[0] -= rightOverhang; // Snap to right
-        }
-        result[0] = Math.max(0, result[0]); // Snap to left
-        int bottomOverhang = result[1] + spanY - countY;
-        if (bottomOverhang > 0) {
-            result[1] -= bottomOverhang; // Snap to bottom
-        }
-        result[1] = Math.max(0, result[1]); // Snap to top
-    }
-
     void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
             int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
         final int oldDragCellX = mDragCell[0];
@@ -1473,9 +1154,8 @@
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
-            int[] result) {
-        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
+    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, spanX, spanY, result, null);
     }
 
     /**
@@ -1495,30 +1175,10 @@
      */
     int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
             int spanY, int[] result, int[] resultSpan) {
-        return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
+        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, true,
                 result, resultSpan);
     }
 
-    /**
-     * Find a vacant area that will fit the given bounds nearest the requested
-     * cell location. Uses Euclidean distance to score multiple vacant areas.
-     *
-     * @param pixelX The X location at which you want to search for a vacant area.
-     * @param pixelY The Y location at which you want to search for a vacant area.
-     * @param spanX Horizontal span of the object.
-     * @param spanY Vertical span of the object.
-     * @param ignoreOccupied If true, the result can be an occupied cell
-     * @param result Array in which to place the result, or null (in which case a new array will
-     *        be allocated)
-     * @return The X, Y cell of a vacant area that can contain this object,
-     *         nearest the requested location.
-     */
-    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
-            boolean ignoreOccupied, int[] result) {
-        return findNearestArea(pixelX, pixelY, spanX, spanY,
-                spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
-    }
-
     private final Stack<Rect> mTempRectStack = new Stack<Rect>();
     private void lazyInitTempRectStack() {
         if (mTempRectStack.isEmpty()) {
@@ -1550,12 +1210,9 @@
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
-            View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
-            boolean[][] occupied) {
+    private int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
+            int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
         lazyInitTempRectStack();
-        // mark space take by ignoreView as available (method checks if ignoreView is null)
-        markCellsAsUnoccupiedForView(ignoreView, occupied);
 
         // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
         // to the center of the item, but we are searching based on the top-left cell, so
@@ -1586,7 +1243,7 @@
                     // First, let's see if this thing fits anywhere
                     for (int i = 0; i < minSpanX; i++) {
                         for (int j = 0; j < minSpanY; j++) {
-                            if (occupied[x + i][y + j]) {
+                            if (mOccupied[x + i][y + j]) {
                                 continue inner;
                             }
                         }
@@ -1603,7 +1260,7 @@
                     while (!(hitMaxX && hitMaxY)) {
                         if (incX && !hitMaxX) {
                             for (int j = 0; j < ySize; j++) {
-                                if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
+                                if (x + xSize > countX -1 || mOccupied[x + xSize][y + j]) {
                                     // We can't move out horizontally
                                     hitMaxX = true;
                                 }
@@ -1613,7 +1270,7 @@
                             }
                         } else if (!hitMaxY) {
                             for (int i = 0; i < xSize; i++) {
-                                if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
+                                if (y + ySize > countY - 1 || mOccupied[x + i][y + ySize]) {
                                     // We can't move out vertically
                                     hitMaxY = true;
                                 }
@@ -1646,8 +1303,7 @@
                     }
                 }
                 validRegions.push(currentRect);
-                double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
-                        + Math.pow(cellXY[1] - pixelY, 2));
+                double distance = Math.hypot(cellXY[0] - pixelX,  cellXY[1] - pixelY);
 
                 if ((distance <= bestDistance && !contained) ||
                         currentRect.contains(bestRect)) {
@@ -1662,8 +1318,6 @@
                 }
             }
         }
-        // re-mark space taken by ignoreView as occupied
-        markCellsAsOccupiedForView(ignoreView, occupied);
 
         // Return -1, -1 if no suitable location found
         if (bestDistance == Double.MAX_VALUE) {
@@ -1717,8 +1371,7 @@
                     }
                 }
 
-                float distance = (float)
-                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
+                float distance = (float) Math.hypot(x - cellX, y - cellY);
                 int[] curDirection = mTmpPoint;
                 computeDirectionVector(x - cellX, y - cellY, curDirection);
                 // The direction score is just the dot product of the two candidate direction
@@ -2334,7 +1987,7 @@
         }
     }
 
-    ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
+    private ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
             int spanX, int spanY, int[] direction, View dragView, boolean decX,
             ItemConfiguration solution) {
         // Copy the current state into the solution. This solution will be manipulated as necessary.
@@ -2623,7 +2276,7 @@
         mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
     }
 
-    public void setUseTempCoords(boolean useTempCoords) {
+    private void setUseTempCoords(boolean useTempCoords) {
         int childCount = mShortcutsAndWidgets.getChildCount();
         for (int i = 0; i < childCount; i++) {
             LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
@@ -2631,11 +2284,11 @@
         }
     }
 
-    ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
+    private ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
             int spanX, int spanY, View dragView, ItemConfiguration solution) {
         int[] result = new int[2];
         int[] resultSpan = new int[2];
-        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
+        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result,
                 resultSpan);
         if (result[0] >= 0 && result[1] >= 0) {
             copyCurrentStateToSolution(solution, false);
@@ -2952,45 +2605,6 @@
     }
 
     /**
-     * Find a vacant area that will fit the given bounds nearest the requested
-     * cell location. Uses Euclidean distance to score multiple vacant areas.
-     *
-     * @param pixelX The X location at which you want to search for a vacant area.
-     * @param pixelY The Y location at which you want to search for a vacant area.
-     * @param spanX Horizontal span of the object.
-     * @param spanY Vertical span of the object.
-     * @param ignoreView Considers space occupied by this view as unoccupied
-     * @param result Previously returned value to possibly recycle.
-     * @return The X, Y cell of a vacant area that can contain this object,
-     *         nearest the requested location.
-     */
-    int[] findNearestVacantArea(
-            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
-        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
-    }
-
-    /**
-     * Find a vacant area that will fit the given bounds nearest the requested
-     * cell location. Uses Euclidean distance to score multiple vacant areas.
-     *
-     * @param pixelX The X location at which you want to search for a vacant area.
-     * @param pixelY The Y location at which you want to search for a vacant area.
-     * @param minSpanX The minimum horizontal span required
-     * @param minSpanY The minimum vertical span required
-     * @param spanX Horizontal span of the object.
-     * @param spanY Vertical span of the object.
-     * @param ignoreView Considers space occupied by this view as unoccupied
-     * @param result Previously returned value to possibly recycle.
-     * @return The X, Y cell of a vacant area that can contain this object,
-     *         nearest the requested location.
-     */
-    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
-            int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
-        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
-                result, resultSpan, mOccupied);
-    }
-
-    /**
      * Find a starting cell position that will fit the given bounds nearest the requested
      * cell location. Uses Euclidean distance to score multiple vacant areas.
      *
@@ -3003,9 +2617,8 @@
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    int[] findNearestArea(
-            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
-        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
+    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+        return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, false, result, null);
     }
 
     boolean existsEmptyCell() {
@@ -3026,103 +2639,32 @@
      * @return True if a vacant cell of the specified dimension was found, false otherwise.
      */
     public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
-        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
-    }
-
-    /**
-     * Like above, but ignores any cells occupied by the item "ignoreView"
-     *
-     * @param cellXY The array that will contain the position of a vacant cell if such a cell
-     *               can be found.
-     * @param spanX The horizontal span of the cell we want to find.
-     * @param spanY The vertical span of the cell we want to find.
-     * @param ignoreView The home screen item we should treat as not occupying any space
-     * @return
-     */
-    boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
-        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
-                ignoreView, mOccupied);
-    }
-
-    /**
-     * Like above, but if intersectX and intersectY are not -1, then this method will try to
-     * return coordinates for rectangles that contain the cell [intersectX, intersectY]
-     *
-     * @param spanX The horizontal span of the cell we want to find.
-     * @param spanY The vertical span of the cell we want to find.
-     * @param ignoreView The home screen item we should treat as not occupying any space
-     * @param intersectX The X coordinate of the cell that we should try to overlap
-     * @param intersectX The Y coordinate of the cell that we should try to overlap
-     *
-     * @return True if a vacant cell of the specified dimension was found, false otherwise.
-     */
-    boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
-            int intersectX, int intersectY) {
-        return findCellForSpanThatIntersectsIgnoring(
-                cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
-    }
-
-    /**
-     * The superset of the above two methods
-     */
-    boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
-            int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
-        // mark space take by ignoreView as available (method checks if ignoreView is null)
-        markCellsAsUnoccupiedForView(ignoreView, occupied);
-
         boolean foundCell = false;
-        while (true) {
-            int startX = 0;
-            if (intersectX >= 0) {
-                startX = Math.max(startX, intersectX - (spanX - 1));
-            }
-            int endX = mCountX - (spanX - 1);
-            if (intersectX >= 0) {
-                endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
-            }
-            int startY = 0;
-            if (intersectY >= 0) {
-                startY = Math.max(startY, intersectY - (spanY - 1));
-            }
-            int endY = mCountY - (spanY - 1);
-            if (intersectY >= 0) {
-                endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
-            }
+        final int endX = mCountX - (spanX - 1);
+        final int endY = mCountY - (spanY - 1);
 
-            for (int y = startY; y < endY && !foundCell; y++) {
-                inner:
-                for (int x = startX; x < endX; x++) {
-                    for (int i = 0; i < spanX; i++) {
-                        for (int j = 0; j < spanY; j++) {
-                            if (occupied[x + i][y + j]) {
-                                // small optimization: we can skip to after the column we just found
-                                // an occupied cell
-                                x += i;
-                                continue inner;
-                            }
+        for (int y = 0; y < endY && !foundCell; y++) {
+            inner:
+            for (int x = 0; x < endX; x++) {
+                for (int i = 0; i < spanX; i++) {
+                    for (int j = 0; j < spanY; j++) {
+                        if (mOccupied[x + i][y + j]) {
+                            // small optimization: we can skip to after the column we just found
+                            // an occupied cell
+                            x += i;
+                            continue inner;
                         }
                     }
-                    if (cellXY != null) {
-                        cellXY[0] = x;
-                        cellXY[1] = y;
-                    }
-                    foundCell = true;
-                    break;
                 }
-            }
-            if (intersectX == -1 && intersectY == -1) {
+                if (cellXY != null) {
+                    cellXY[0] = x;
+                    cellXY[1] = y;
+                }
+                foundCell = true;
                 break;
-            } else {
-                // if we failed to find anything, try again but without any requirements of
-                // intersecting
-                intersectX = -1;
-                intersectY = -1;
-                continue;
             }
         }
 
-        // re-mark space taken by ignoreView as occupied
-        markCellsAsOccupiedForView(ignoreView, occupied);
         return foundCell;
     }
 
@@ -3232,13 +2774,6 @@
         return result;
     }
 
-    public int[] cellSpansToSize(int hSpans, int vSpans) {
-        int[] size = new int[2];
-        size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
-        size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
-        return size;
-    }
-
     /**
      * Calculate the grid spans needed to fit given item
      */
@@ -3262,44 +2797,6 @@
         info.spanY = spans[1];
     }
 
-    /**
-     * Find the first vacant cell, if there is one.
-     *
-     * @param vacant Holds the x and y coordinate of the vacant cell
-     * @param spanX Horizontal cell span.
-     * @param spanY Vertical cell span.
-     *
-     * @return True if a vacant cell was found
-     */
-    public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
-
-        return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
-    }
-
-    static boolean findVacantCell(int[] vacant, int spanX, int spanY,
-            int xCount, int yCount, boolean[][] occupied) {
-
-        for (int y = 0; (y + spanY) <= yCount; y++) {
-            for (int x = 0; (x + spanX) <= xCount; x++) {
-                boolean available = !occupied[x][y];
-out:            for (int i = x; i < x + spanX; i++) {
-                    for (int j = y; j < y + spanY; j++) {
-                        available = available && !occupied[i][j];
-                        if (!available) break out;
-                    }
-                }
-
-                if (available) {
-                    vacant[0] = x;
-                    vacant[1] = y;
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
     private void clearOccupiedCells() {
         for (int x = 0; x < mCountX; x++) {
             for (int y = 0; y < mCountY; y++) {
@@ -3308,27 +2805,16 @@
         }
     }
 
-    public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
-        markCellsAsUnoccupiedForView(view);
-        markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
-    }
-
     public void markCellsAsOccupiedForView(View view) {
-        markCellsAsOccupiedForView(view, mOccupied);
-    }
-    public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
         if (view == null || view.getParent() != mShortcutsAndWidgets) return;
         LayoutParams lp = (LayoutParams) view.getLayoutParams();
-        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
+        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, true);
     }
 
     public void markCellsAsUnoccupiedForView(View view) {
-        markCellsAsUnoccupiedForView(view, mOccupied);
-    }
-    public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
         if (view == null || view.getParent() != mShortcutsAndWidgets) return;
         LayoutParams lp = (LayoutParams) view.getLayoutParams();
-        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
+        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, false);
     }
 
     private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
@@ -3374,17 +2860,6 @@
         return new CellLayout.LayoutParams(p);
     }
 
-    public static class CellLayoutAnimationController extends LayoutAnimationController {
-        public CellLayoutAnimationController(Animation animation, float delay) {
-            super(animation, delay);
-        }
-
-        @Override
-        protected long getDelayForView(View view) {
-            return (int) (Math.random() * 150);
-        }
-    }
-
     public static class LayoutParams extends ViewGroup.MarginLayoutParams {
         /**
          * Horizontal location of the item in the grid.
@@ -3572,4 +3047,8 @@
     public boolean lastDownOnOccupiedCell() {
         return mLastDownOnOccupiedCell;
     }
+
+    public boolean findVacantCell(int spanX, int spanY, int[] outXY) {
+        return Utilities.findVacantCell(outXY, spanX, spanY, mCountX, mCountY, mOccupied);
+    }
 }
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index e741b97..08186f5 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -17,30 +17,18 @@
 package com.android.launcher3;
 
 import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
 import android.graphics.PointF;
-import android.graphics.Rect;
 import android.os.AsyncTask;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
 
+import com.android.launcher3.util.FlingAnimation;
 import com.android.launcher3.util.Thunk;
-import com.android.launcher3.widget.WidgetsContainerView;
 
 public class DeleteDropTarget extends ButtonDropTarget {
 
-    private static int FLING_DELETE_ANIMATION_DURATION = 350;
-    private static float FLING_TO_DELETE_FRICTION = 0.035f;
-    private static int MODE_FLING_DELETE_TO_TRASH = 0;
-    private static int MODE_FLING_DELETE_ALONG_VECTOR = 1;
-
-    private final int mFlingDeleteMode = MODE_FLING_DELETE_ALONG_VECTOR;
-
     public DeleteDropTarget(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -119,146 +107,19 @@
         return true;
     }
 
-    /**
-     * Creates an animation from the current drag view to the delete trash icon.
-     */
-    private AnimatorUpdateListener createFlingToTrashAnimatorListener(final DragLayer dragLayer,
-            DragObject d, PointF vel, ViewConfiguration config) {
-
-        int width = mDrawable.getIntrinsicWidth();
-        int height = mDrawable.getIntrinsicHeight();
-        final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
-                width, height);
-        final Rect from = new Rect();
-        dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-
-        // Calculate how far along the velocity vector we should put the intermediate point on
-        // the bezier curve
-        float velocity = Math.abs(vel.length());
-        float vp = Math.min(1f, velocity / (config.getScaledMaximumFlingVelocity() / 2f));
-        int offsetY = (int) (-from.top * vp);
-        int offsetX = (int) (offsetY / (vel.y / vel.x));
-        final float y2 = from.top + offsetY;                        // intermediate t/l
-        final float x2 = from.left + offsetX;
-        final float x1 = from.left;                                 // drag view t/l
-        final float y1 = from.top;
-        final float x3 = to.left;                                   // delete target t/l
-        final float y3 = to.top;
-
-        final TimeInterpolator scaleAlphaInterpolator = new TimeInterpolator() {
-            @Override
-            public float getInterpolation(float t) {
-                return t * t * t * t * t * t * t * t;
-            }
-        };
-        return new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final DragView dragView = (DragView) dragLayer.getAnimatedView();
-                float t = ((Float) animation.getAnimatedValue()).floatValue();
-                float tp = scaleAlphaInterpolator.getInterpolation(t);
-                float initialScale = dragView.getInitialScale();
-                float finalAlpha = 0.5f;
-                float scale = dragView.getScaleX();
-                float x1o = ((1f - scale) * dragView.getMeasuredWidth()) / 2f;
-                float y1o = ((1f - scale) * dragView.getMeasuredHeight()) / 2f;
-                float x = (1f - t) * (1f - t) * (x1 - x1o) + 2 * (1f - t) * t * (x2 - x1o) +
-                        (t * t) * x3;
-                float y = (1f - t) * (1f - t) * (y1 - y1o) + 2 * (1f - t) * t * (y2 - x1o) +
-                        (t * t) * y3;
-
-                dragView.setTranslationX(x);
-                dragView.setTranslationY(y);
-                dragView.setScaleX(initialScale * (1f - tp));
-                dragView.setScaleY(initialScale * (1f - tp));
-                dragView.setAlpha(finalAlpha + (1f - finalAlpha) * (1f - tp));
-            }
-        };
-    }
-
-    /**
-     * Creates an animation from the current drag view along its current velocity vector.
-     * For this animation, the alpha runs for a fixed duration and we update the position
-     * progressively.
-     */
-    private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener {
-        private DragLayer mDragLayer;
-        private PointF mVelocity;
-        private Rect mFrom;
-        private long mPrevTime;
-        private boolean mHasOffsetForScale;
-        private float mFriction;
-
-        private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
-
-        public FlingAlongVectorAnimatorUpdateListener(DragLayer dragLayer, PointF vel, Rect from,
-                long startTime, float friction) {
-            mDragLayer = dragLayer;
-            mVelocity = vel;
-            mFrom = from;
-            mPrevTime = startTime;
-            mFriction = 1f - (dragLayer.getResources().getDisplayMetrics().density * friction);
-        }
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            final DragView dragView = (DragView) mDragLayer.getAnimatedView();
-            float t = ((Float) animation.getAnimatedValue()).floatValue();
-            long curTime = AnimationUtils.currentAnimationTimeMillis();
-
-            if (!mHasOffsetForScale) {
-                mHasOffsetForScale = true;
-                float scale = dragView.getScaleX();
-                float xOffset = ((scale - 1f) * dragView.getMeasuredWidth()) / 2f;
-                float yOffset = ((scale - 1f) * dragView.getMeasuredHeight()) / 2f;
-
-                mFrom.left += xOffset;
-                mFrom.top += yOffset;
-            }
-
-            mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f);
-            mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f);
-
-            dragView.setTranslationX(mFrom.left);
-            dragView.setTranslationY(mFrom.top);
-            dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
-
-            mVelocity.x *= mFriction;
-            mVelocity.y *= mFriction;
-            mPrevTime = curTime;
-        }
-    };
-    private AnimatorUpdateListener createFlingAlongVectorAnimatorListener(final DragLayer dragLayer,
-            DragObject d, PointF vel, final long startTime, final int duration,
-            ViewConfiguration config) {
-        final Rect from = new Rect();
-        dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-
-        return new FlingAlongVectorAnimatorUpdateListener(dragLayer, vel, from, startTime,
-                FLING_TO_DELETE_FRICTION);
-    }
-
-    public void onFlingToDelete(final DragObject d, int x, int y, PointF vel) {
-        final boolean isWidgets = d.dragSource instanceof WidgetsContainerView;
-        final boolean isAllapps = d.dragSource instanceof AppsContainerView;
-
+    @Override
+    public void onFlingToDelete(final DragObject d, PointF vel) {
         // Don't highlight the icon as it's animating
         d.dragView.setColor(0);
         d.dragView.updateInitialScaleToCurrentScale();
-        // Don't highlight the target if we are flinging from AllApps
-        if (isWidgets || isAllapps) {
-            resetHoverColor();
-        }
 
-        if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) {
-            // Defer animating out the drop target if we are animating to it
-            mSearchDropTargetBar.deferOnDragEnd();
-            mSearchDropTargetBar.finishAnimations();
-        }
-
-        final ViewConfiguration config = ViewConfiguration.get(mLauncher);
         final DragLayer dragLayer = mLauncher.getDragLayer();
-        final int duration = FLING_DELETE_ANIMATION_DURATION;
+        FlingAnimation fling = new FlingAnimation(d, vel,
+                getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
+                        mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()),
+                        dragLayer);
+
+        final int duration = fling.getDuration();
         final long startTime = AnimationUtils.currentAnimationTimeMillis();
 
         // NOTE: Because it takes time for the first frame of animation to actually be
@@ -282,27 +143,17 @@
                 return Math.min(1f, mOffset + t);
             }
         };
-        AnimatorUpdateListener updateCb = null;
-        if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) {
-            updateCb = createFlingToTrashAnimatorListener(dragLayer, d, vel, config);
-        } else if (mFlingDeleteMode == MODE_FLING_DELETE_ALONG_VECTOR) {
-            updateCb = createFlingAlongVectorAnimatorListener(dragLayer, d, vel, startTime,
-                    duration, config);
-        }
 
         Runnable onAnimationEndRunnable = new Runnable() {
             @Override
             public void run() {
-                // If we are dragging from AllApps, then we allow AppsCustomizePagedView to clean up
-                // itself, otherwise, complete the drop to initiate the deletion process
-                if (!isWidgets || !isAllapps) {
-                    mLauncher.exitSpringLoadedDragMode();
-                    completeDrop(d);
-                }
+                mLauncher.exitSpringLoadedDragMode();
+                completeDrop(d);
                 mLauncher.getDragController().onDeferredEndFling(d);
             }
         };
-        dragLayer.animateView(d.dragView, updateCb, duration, tInterpolator, onAnimationEndRunnable,
+
+        dragLayer.animateView(d.dragView, fling, duration, tInterpolator, onAnimationEndRunnable,
                 DragLayer.ANIMATION_END_DISAPPEAR, null);
     }
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 22fb6a0..deb8075 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -460,8 +460,7 @@
     }
 
     @Thunk float dist(PointF p0, PointF p1) {
-        return (float) Math.sqrt((p1.x - p0.x)*(p1.x-p0.x) +
-                (p1.y-p0.y)*(p1.y-p0.y));
+        return (float) Math.hypot(p1.x - p0.x, p1.y - p0.y);
     }
 
     private float weight(PointF a, PointF b,
@@ -734,7 +733,6 @@
 
     public void layout(Launcher launcher) {
         FrameLayout.LayoutParams lp;
-        Resources res = launcher.getResources();
         boolean hasVerticalBarLayout = isVerticalBarLayout();
 
         // Layout the search bar space
@@ -742,17 +740,22 @@
         lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
         if (hasVerticalBarLayout) {
             // Vertical search bar space
-            lp.gravity = Gravity.TOP | Gravity.LEFT;
+            lp.gravity = Gravity.LEFT;
             lp.width = searchBarSpaceHeightPx;
-            lp.height = LayoutParams.WRAP_CONTENT;
 
             LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
             targets.setOrientation(LinearLayout.VERTICAL);
+            FrameLayout.LayoutParams targetsLp = (FrameLayout.LayoutParams) targets.getLayoutParams();
+            targetsLp.gravity = Gravity.TOP;
+            targetsLp.height = LayoutParams.WRAP_CONTENT;
+
         } else {
             // Horizontal search bar space
-            lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
-            lp.width = searchBarSpaceWidthPx;
+            lp.gravity = Gravity.TOP;
             lp.height = searchBarSpaceHeightPx;
+
+            LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
+            targets.getLayoutParams().width = searchBarSpaceWidthPx;
         }
         searchBar.setLayoutParams(lp);
 
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index 1968868..5fea9d8 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -513,8 +513,7 @@
         checkTouchMove(dropTarget);
 
         // Check if we are hovering over the scroll areas
-        mDistanceSinceScroll +=
-            Math.sqrt(Math.pow(mLastTouch[0] - x, 2) + Math.pow(mLastTouch[1] - y, 2));
+        mDistanceSinceScroll += Math.hypot(mLastTouch[0] - x, mLastTouch[1] - y);
         mLastTouch[0] = x;
         mLastTouch[1] = y;
         checkScrollState(x, y);
@@ -659,6 +658,7 @@
         mDragObject.y = coordinates[1];
         checkTouchMove(dropTarget);
 
+        dropTarget.prepareAccessibilityDrop();
         // Perform the drop
         drop(location[0], location[1]);
         endDrag();
@@ -710,8 +710,7 @@
         mDragObject.dragComplete = true;
         mFlingToDeleteDropTarget.onDragExit(mDragObject);
         if (mFlingToDeleteDropTarget.acceptDrop(mDragObject)) {
-            mFlingToDeleteDropTarget.onFlingToDelete(mDragObject, mDragObject.x, mDragObject.y,
-                    vel);
+            mFlingToDeleteDropTarget.onFlingToDelete(mDragObject, vel);
             accepted = true;
         }
         mDragObject.dragSource.onDropCompleted((View) mFlingToDeleteDropTarget, mDragObject, true,
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index ab2e094..91f97fa 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -657,8 +657,7 @@
             final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
 
         // Calculate the duration of the animation based on the object's distance
-        final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
-                Math.pow(to.top - from.top, 2));
+        final float dist = (float) Math.hypot(to.left - from.left, to.top - from.top);
         final Resources res = getResources();
         final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
 
diff --git a/src/com/android/launcher3/DragView.java b/src/com/android/launcher3/DragView.java
index b1a6266..a4b6704 100644
--- a/src/com/android/launcher3/DragView.java
+++ b/src/com/android/launcher3/DragView.java
@@ -16,22 +16,30 @@
 
 package com.android.launcher3;
 
+import android.animation.FloatArrayEvaluator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
+import android.os.Build;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
 
 import com.android.launcher3.util.Thunk;
 
+import java.util.Arrays;
+
 public class DragView extends View {
+    public static int COLOR_CHANGE_DURATION = 200;
+
     @Thunk static float sDragAlpha = 1f;
 
     private Bitmap mBitmap;
@@ -54,6 +62,9 @@
     // size.  This is ignored for non-icons.
     private float mIntrinsicIconScale = 1f;
 
+    private float[] mCurrentFilter;
+    private ValueAnimator mFilterAnimator;
+
     /**
      * Construct the drag view.
      * <p>
@@ -229,11 +240,50 @@
             mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
         }
         if (color != 0) {
-            mPaint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
+            ColorMatrix m1 = new ColorMatrix();
+            m1.setSaturation(0);
+
+            ColorMatrix m2 = new ColorMatrix();
+            m2.setScale(Color.red(color) / 255f, Color.green(color) / 255f,
+                    Color.blue(color) / 255f, Color.alpha(color) / 255f);
+            m1.postConcat(m2);
+
+            if (Utilities.isLmpOrAbove()) {
+                animateFilterTo(m1.getArray());
+            } else {
+                mPaint.setColorFilter(new ColorMatrixColorFilter(m1));
+                invalidate();
+            }
         } else {
-            mPaint.setColorFilter(null);
+            if (!Utilities.isLmpOrAbove() || mCurrentFilter == null) {
+                mPaint.setColorFilter(null);
+                invalidate();
+            } else {
+                animateFilterTo(new ColorMatrix().getArray());
+            }
         }
-        invalidate();
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    private void animateFilterTo(float[] targetFilter) {
+        float[] oldFilter = mCurrentFilter == null ? new ColorMatrix().getArray() : mCurrentFilter;
+        mCurrentFilter = Arrays.copyOf(oldFilter, oldFilter.length);
+
+        if (mFilterAnimator != null) {
+            mFilterAnimator.cancel();
+        }
+        mFilterAnimator = ValueAnimator.ofObject(new FloatArrayEvaluator(mCurrentFilter),
+                oldFilter, targetFilter);
+        mFilterAnimator.setDuration(COLOR_CHANGE_DURATION);
+        mFilterAnimator.addUpdateListener(new AnimatorUpdateListener() {
+
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mPaint.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
+                invalidate();
+            }
+        });
+        mFilterAnimator.start();
     }
 
     public boolean hasDrawn() {
@@ -301,4 +351,3 @@
         }
     }
 }
-
diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java
index c5cca3b..a3828c1 100644
--- a/src/com/android/launcher3/DropTarget.java
+++ b/src/com/android/launcher3/DropTarget.java
@@ -29,7 +29,7 @@
 
     public static final String TAG = "DropTarget";
 
-    class DragObject {
+    public static class DragObject {
         public int x = -1;
         public int y = -1;
 
@@ -164,7 +164,7 @@
      * of onDrop().  (This is only called on objects that are set as the DragController's
      * fling-to-delete target.
      */
-    void onFlingToDelete(DragObject dragObject, int x, int y, PointF vec);
+    void onFlingToDelete(DragObject dragObject, PointF vec);
 
     /**
      * Check if a drop action can occur at, or near, the requested location.
@@ -183,6 +183,8 @@
      */
     boolean acceptDrop(DragObject dragObject);
 
+    void prepareAccessibilityDrop();
+
     // These methods are implemented in Views
     void getHitRectRelativeToDragLayer(Rect outRect);
     void getLocationInDragLayer(int[] loc);
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index dff47c2..a282805 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -49,8 +49,10 @@
 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.util.Thunk;
@@ -63,7 +65,7 @@
  */
 public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
         View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
-        View.OnFocusChangeListener, DragListener, UninstallSource {
+        View.OnFocusChangeListener, DragListener, UninstallSource, AccessibilityDragSource {
     private static final String TAG = "Launcher.Folder";
 
     /**
@@ -83,12 +85,6 @@
     public static final int SCROLL_HINT_DURATION = DragController.SCROLL_DELAY;
 
     /**
-     * Time in milliseconds for which an icon sticks to the target position
-     * in case of a sorted folder.
-     */
-    private static final int SORTED_STICKY_REORDER_DELAY = 1500;
-
-    /**
      * Fraction of icon width which behave as scroll region.
      */
     private static final float ICON_OVERSCROLL_WIDTH_FACTOR = 0.45f;
@@ -243,7 +239,10 @@
     public boolean onLongClick(View v) {
         // Return if global dragging is not enabled
         if (!mLauncher.isDraggingEnabled()) return true;
+        return beginDrag(v, false);
+    }
 
+    private boolean beginDrag(View v, boolean accessible) {
         Object tag = v.getTag();
         if (tag instanceof ShortcutInfo) {
             ShortcutInfo item = (ShortcutInfo) tag;
@@ -251,7 +250,7 @@
                 return false;
             }
 
-            mLauncher.getWorkspace().beginDragShared(v, new Point(), this, false);
+            mLauncher.getWorkspace().beginDragShared(v, new Point(), this, accessible);
 
             mCurrentDragInfo = item;
             mEmptyCellRank = item.rank;
@@ -265,6 +264,20 @@
         return true;
     }
 
+    @Override
+    public void startDrag(CellInfo cellInfo, boolean accessible) {
+        beginDrag(cellInfo.cell, accessible);
+    }
+
+    @Override
+    public void enableAccessibleDrag(boolean enable) {
+        mLauncher.getSearchBar().enableAccessibleDrag(enable);
+        for (int i = 0; i < mContent.getChildCount(); i++) {
+            mContent.getPageAt(i).enableAccessibleDrag(enable, CellLayout.FOLDER_ACCESSIBILITY_DRAG);
+        }
+        mLauncher.getWorkspace().setAddNewPageOnDrag(!enable);
+    }
+
     public boolean isEditingName() {
         return mIsEditingName;
     }
@@ -417,7 +430,7 @@
         if (!(getParent() instanceof DragLayer)) return;
 
         mContent.completePendingPageChanges();
-        if (!(mDragInProgress && mContent.mIsSorted)) {
+        if (!mDragInProgress) {
             // Open on the first page.
             mContent.snapToPageImmediately(0);
         }
@@ -459,7 +472,7 @@
 
             int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX());
             int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
-            float radius = (float) Math.sqrt(rx * rx + ry * ry);
+            float radius = (float) Math.hypot(rx, ry);
             AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
             Animator reveal = LauncherAnimUtils.createCircularReveal(this, (int) getPivotX(),
                     (int) getPivotY(), 0, radius);
@@ -533,12 +546,6 @@
         mIsExternalDrag = true;
         mDragInProgress = true;
 
-        if (mContent.mIsSorted) {
-            mScrollPauseAlarm.setOnAlarmListener(null);
-            mScrollPauseAlarm.cancelAlarm();
-            mScrollPauseAlarm.setAlarm(SORTED_STICKY_REORDER_DELAY);
-        }
-
         // Since this folder opened by another controller, it might not get onDrop or
         // onDropComplete. Perform cleanup once drag-n-drop ends.
         mDragController.addDragListener(this);
@@ -697,9 +704,15 @@
         if (mInfo.opened) {
             mLauncher.closeFolder();
             mRearrangeOnClose = true;
+        } else if (mState == STATE_ANIMATING) {
+            mRearrangeOnClose = true;
         } else {
             rearrangeChildren();
+            clearDragInfo();
         }
+    }
+
+    private void clearDragInfo() {
         mCurrentDragInfo = null;
         mCurrentDragView = null;
         mSuppressOnAdd = false;
@@ -723,6 +736,18 @@
         }
     }
 
+    /**
+     * When performing an accessibility drop, onDrop is sent immediately after onDragEnter. So we
+     * need to complete all transient states based on timers.
+     */
+    @Override
+    public void prepareAccessibilityDrop() {
+        if (mReorderAlarm.alarmPending()) {
+            mReorderAlarm.cancelAlarm();
+            mReorderAlarmListener.onAlarm(mReorderAlarm);
+        }
+    }
+
     public void onDropCompleted(final View target, final DragObject d,
             final boolean isFlingToDelete, final boolean success) {
         if (mDeferDropAfterUninstall) {
@@ -816,7 +841,8 @@
         return true;
     }
 
-    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
+    @Override
+    public void onFlingToDelete(DragObject d, PointF vec) {
         // Do nothing
     }
 
@@ -1018,6 +1044,7 @@
             }
         }
         mSuppressFolderDeletion = false;
+        clearDragInfo();
     }
 
     @Thunk void replaceFolderWithFinalItem() {
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 3f08f43..a07a3dc 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -20,23 +20,16 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.OvershootInterpolator;
-import android.widget.Switch;
 
 import com.android.launcher3.FocusHelper.PagedFolderKeyEventListener;
 import com.android.launcher3.PageIndicator.PageMarkerResources;
 import com.android.launcher3.Workspace.ItemOperator;
 import com.android.launcher3.util.Thunk;
 
-import java.text.Collator;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -47,17 +40,10 @@
 
     private static final boolean ALLOW_FOLDER_SCROLL = true;
 
-    // To enable this flag, user_folder.xml needs to be modified to add sort button.
-    private static final boolean ALLOW_ITEM_SORTING = false;
-
     private static final int REORDER_ANIMATION_DURATION = 230;
     private static final int START_VIEW_REORDER_DELAY = 30;
     private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
 
-    private static final int SPAN_TO_PAGE_DURATION = 350;
-    private static final int SORT_ANIM_HIDE_DURATION = 130;
-    private static final int SORT_ANIM_SHOW_DURATION = 160;
-
     /**
      * Fraction of the width to scroll when showing the next page hint.
      */
@@ -87,13 +73,8 @@
     private FocusIndicatorView mFocusIndicatorView;
     private PagedFolderKeyEventListener mKeyListener;
 
-    private View mSortButton;
-    private Switch mSortSwitch;
     private View mPageIndicator;
 
-    private boolean mSortOperationPending;
-    boolean mIsSorted;
-
     public FolderPagedView(Context context, AttributeSet attrs) {
         super(context, attrs);
         LauncherAppState app = LauncherAppState.getInstance();
@@ -114,6 +95,7 @@
         mIconCache = app.getIconCache();
 
         rtlLayout = getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
     }
 
     public void setFolder(Folder folder) {
@@ -121,132 +103,6 @@
         mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
         mKeyListener = new PagedFolderKeyEventListener(folder);
         mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
-
-        if (ALLOW_ITEM_SORTING) {
-            // Initialize {@link #mSortSwitch} and {@link #mSortButton}.
-        }
-    }
-
-    /**
-     * Called when sort button is clicked.
-     */
-    private void onSortClicked() {
-        if (mSortOperationPending) {
-            return;
-        }
-        if (mIsSorted) {
-            setIsSorted(false, true);
-        } else {
-            mSortOperationPending = true;
-            doSort();
-        }
-    }
-
-    private void setIsSorted(boolean isSorted, boolean saveChanges) {
-        mIsSorted = isSorted;
-        if (ALLOW_ITEM_SORTING) {
-            mSortSwitch.setChecked(isSorted);
-            mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted,
-                    saveChanges ? mFolder.mLauncher : null);
-        }
-    }
-
-    /**
-     * Sorts the contents of the folder and animates the icons on the first page to reflect
-     * the changes.
-     * Steps:
-     *      1. Scroll to first page
-     *      2. Sort all icons in one go
-     *      3. Re-apply the old IconInfos on the first page (so that there is no instant change)
-     *      4. Animate each view individually to reflect the new icon.
-     */
-    private void doSort() {
-        if (!mSortOperationPending) {
-            return;
-        }
-        if (getNextPage() != 0) {
-            snapToPage(0, SPAN_TO_PAGE_DURATION, new DecelerateInterpolator());
-            return;
-        }
-
-        mSortOperationPending = false;
-        ShortcutInfo[][] oldItems = new ShortcutInfo[mGridCountX][mGridCountY];
-        CellLayout currentPage = getCurrentCellLayout();
-        for (int x = 0; x < mGridCountX; x++) {
-            for (int y = 0; y < mGridCountY; y++) {
-                View v = currentPage.getChildAt(x, y);
-                if (v != null) {
-                    oldItems[x][y] = (ShortcutInfo) v.getTag();
-                }
-            }
-        }
-
-        ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
-        Collections.sort(views, new ViewComparator());
-        arrangeChildren(views, views.size());
-
-        int delay = 0;
-        float delayAmount = START_VIEW_REORDER_DELAY;
-        final Interpolator hideInterpolator = new DecelerateInterpolator(2);
-        final Interpolator showInterpolator = new OvershootInterpolator(0.8f);
-
-        currentPage = getCurrentCellLayout();
-        for (int x = 0; x < mGridCountX; x++) {
-            for (int y = 0; y < mGridCountY; y++) {
-                final BubbleTextView v = (BubbleTextView) currentPage.getChildAt(x, y);
-                if (v != null) {
-                    final ShortcutInfo info = (ShortcutInfo) v.getTag();
-                    final Runnable clearPending = new Runnable() {
-
-                        @Override
-                        public void run() {
-                            mPendingAnimations.remove(v);
-                            v.setScaleX(1);
-                            v.setScaleY(1);
-                        }
-                    };
-                    if (oldItems[x][y] == null) {
-                        v.setScaleX(0);
-                        v.setScaleY(0);
-                        v.animate().setDuration(SORT_ANIM_SHOW_DURATION)
-                            .setStartDelay(SORT_ANIM_HIDE_DURATION + delay)
-                            .scaleX(1).scaleY(1).setInterpolator(showInterpolator)
-                            .withEndAction(clearPending);
-                        mPendingAnimations.put(v, clearPending);
-                    } else {
-                        // Apply the old iconInfo so that there is no sudden change.
-                        v.applyFromShortcutInfo(oldItems[x][y], mIconCache, false);
-                        v.animate().setStartDelay(delay).setDuration(SORT_ANIM_HIDE_DURATION)
-                            .scaleX(0).scaleY(0)
-                            .setInterpolator(hideInterpolator)
-                            .withEndAction(new Runnable() {
-
-                                @Override
-                                public void run() {
-                                    // Apply the new iconInfo as part of the animation.
-                                    v.applyFromShortcutInfo(info, mIconCache, false);
-                                    v.animate().scaleX(1).scaleY(1)
-                                        .setDuration(SORT_ANIM_SHOW_DURATION).setStartDelay(0)
-                                        .setInterpolator(showInterpolator)
-                                        .withEndAction(clearPending);
-                                }
-                       });
-                       mPendingAnimations.put(v, new Runnable() {
-
-                           @Override
-                           public void run() {
-                               clearPending.run();
-                               v.applyFromShortcutInfo(info, mIconCache, false);
-                           }
-                        });
-                    }
-                    delay += delayAmount;
-                    delayAmount *= VIEW_REORDER_DELAY_FACTOR;
-                }
-            }
-        }
-
-        setIsSorted(true, true);
     }
 
     /**
@@ -295,7 +151,6 @@
      * @return list of items that could not be bound, probably because we hit the max size limit.
      */
     public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
-        mIsSorted = ALLOW_ITEM_SORTING && mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED);
         ArrayList<View> icons = new ArrayList<View>();
         ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
 
@@ -317,20 +172,6 @@
     public int allocateRankForNewItem(ShortcutInfo info) {
         int rank = getItemCount();
         ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
-        if (ALLOW_ITEM_SORTING && mIsSorted) {
-            View tmp = new View(getContext());
-            tmp.setTag(info);
-            int index = Collections.binarySearch(views, tmp, new ViewComparator());
-            if (index < 0) {
-                rank = -index - 1;
-            } else {
-                // Item with same name already exists.
-                // We will just insert it before that item.
-                rank = index;
-            }
-
-        }
-
         views.add(rank, null);
         arrangeChildren(views, views.size(), false);
         setCurrentPage(rank / mMaxItemsPerPage);
@@ -397,6 +238,7 @@
         CellLayout page = new CellLayout(getContext());
         page.setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
         page.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
+        page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
         page.setInvertIfRtl(true);
         page.setGridSize(mGridCountX, mGridCountY);
 
@@ -447,10 +289,6 @@
         int position = 0;
         int newX, newY, rank;
 
-        boolean isSorted = mIsSorted;
-
-        ViewComparator comparator = new ViewComparator();
-        View lastView = null;
         rank = 0;
         for (int i = 0; i < itemCount; i++) {
             View v = list.size() > i ? list.get(i) : null;
@@ -465,10 +303,6 @@
             }
 
             if (v != null) {
-                if (lastView != null) {
-                    isSorted &= comparator.compare(lastView, v) <= 0;
-                }
-
                 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
                 newX = position % mGridCountX;
                 newY = position / mGridCountX;
@@ -488,7 +322,6 @@
                         v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
             }
 
-            lastView = v;
             rank ++;
             position++;
         }
@@ -506,23 +339,10 @@
         setEnableOverscroll(getPageCount() > 1);
 
         // Update footer
-        if (ALLOW_ITEM_SORTING) {
-            setIsSorted(isSorted, saveChanges);
-            if (getPageCount() > 1) {
-                mPageIndicator.setVisibility(View.VISIBLE);
-                mSortButton.setVisibility(View.VISIBLE);
-                mFolder.mFolderName.setGravity(rtlLayout ? Gravity.RIGHT : Gravity.LEFT);
-            } else {
-                mPageIndicator.setVisibility(View.GONE);
-                mSortButton.setVisibility(View.GONE);
-                mFolder.mFolderName.setGravity(Gravity.CENTER_HORIZONTAL);
-            }
-        } else {
-            int indicatorVisibility = mPageIndicator.getVisibility();
-            mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
-            if (indicatorVisibility != mPageIndicator.getVisibility()) {
-                mFolder.updateFooterHeight();
-            }
+        int indicatorVisibility = mPageIndicator.getVisibility();
+        mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
+        if (indicatorVisibility != mPageIndicator.getVisibility()) {
+            mFolder.updateFooterHeight();
         }
     }
 
@@ -559,7 +379,7 @@
     public int findNearestArea(int pixelX, int pixelY) {
         int pageIndex = getNextPage();
         CellLayout page = getPageAt(pageIndex);
-        page.findNearestArea(pixelX, pixelY, 1, 1, null, false, sTempPosArray);
+        page.findNearestArea(pixelX, pixelY, 1, 1, sTempPosArray);
         if (mFolder.isLayoutRtl()) {
             sTempPosArray[0] = page.getCountX() - sTempPosArray[0] - 1;
         }
@@ -630,17 +450,6 @@
         if (mFolder != null) {
             mFolder.updateTextViewFocus();
         }
-        if (ALLOW_ITEM_SORTING && mSortOperationPending && getNextPage() == 0) {
-            post(new Runnable() {
-
-                @Override
-                public void run() {
-                    if (mSortOperationPending) {
-                        doSort();
-                    }
-                }
-            });
-        }
     }
 
     /**
@@ -829,14 +638,4 @@
             }
         }
     }
-
-    private static class ViewComparator implements Comparator<View> {
-        private final Collator mCollator = Collator.getInstance();
-
-        @Override
-        public int compare(View lhs, View rhs) {
-            return mCollator.compare( ((ShortcutInfo) lhs.getTag()).title.toString(),
-                    ((ShortcutInfo) rhs.getTag()).title.toString());
-        }
-    }
 }
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 27dda64..23bcc85 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -146,10 +146,13 @@
             return;
         }
 
-        if (DBG) Log.d(TAG, "Got INSTALL_SHORTCUT: " + data.toUri(0));
         PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context);
-        info = convertToLauncherActivityIfPossible(info);
+        if (info.launchIntent == null || info.label == null) {
+            if (DBG) Log.e(TAG, "Invalid install shortcut intent");
+            return;
+        }
 
+        info = convertToLauncherActivityIfPossible(info);
         queuePendingShortcutInfo(info, context);
     }
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index a6752dd..4533089 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1688,9 +1688,6 @@
                 mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
                         LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE
                                 | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS);
-            } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)
-                    || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
-                getModel().forceReload();
             }
         }
     };
@@ -1704,8 +1701,6 @@
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(Intent.ACTION_USER_PRESENT);
         // For handling managed profiles
-        filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
-        filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
         if (ENABLE_DEBUG_INTENTS) {
             filter.addAction(DebugIntents.DELETE_DATABASE);
             filter.addAction(DebugIntents.MIGRATE_DATABASE);
@@ -3591,9 +3586,9 @@
         text.clear();
         // Populate event with a fake title based on the current state.
         if (mState == State.APPS) {
-            text.add("Apps");
+            text.add(getString(R.string.all_apps_button_label));
         } else if (mState == State.WIDGETS) {
-            text.add("Widgets");
+            text.add(getString(R.string.widget_button_text));
         } else {
             text.add(getString(R.string.all_apps_home_button_label));
         }
@@ -3629,14 +3624,13 @@
      * in onResume.
      *
      * This needs to be called from incoming places where resources might have been loaded
-     * while we are paused.  That is becaues the Configuration might be wrong
-     * when we're not running, and if it comes back to what it was when we
-     * were paused, we are not restarted.
+     * while the activity is paused. That is because the Configuration (e.g., rotation)  might be
+     * wrong when we're not running, and if the activity comes back to what the configuration was
+     * when we were paused, activity is not restarted.
      *
      * Implementation of the method from LauncherModel.Callbacks.
      *
-     * @return true if we are currently paused.  The caller might be able to
-     * skip some work in that case since we will come back again.
+     * @return {@code true} if we are currently paused. The caller might be able to skip some work
      */
     private boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
         if (mPaused) {
@@ -3747,19 +3741,6 @@
         }
     }
 
-    @Override
-    public void bindAddPendingItem(final PendingAddItemInfo info, final long container,
-            final long screenId, final int[] cell, final int spanX, final int spanY) {
-        showWorkspace(true, new Runnable() {
-
-            @Override
-            public void run() {
-                mWorkspace.snapToPage(mWorkspace.getPageIndexForScreenId(screenId));
-                addPendingItem(info, container, screenId, cell, spanX, spanY);
-            }
-        });
-    }
-
     private boolean shouldShowWeightWatcher() {
         String spKey = LauncherAppState.getSharedPreferencesKey();
         SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
@@ -4193,10 +4174,6 @@
         if (mAppsView != null) {
             mAppsView.setApps(apps);
         }
-        if (mWidgetsView != null) {
-            mWidgetsView.addWidgets(LauncherModel.getSortedWidgetsAndShortcuts(this, false),
-                    getPackageManager());
-        }
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.bindAllApplications(apps);
         }
@@ -4332,26 +4309,23 @@
         }
     }
 
-    /**
-     * A number of packages were updated.
-     */
     @Thunk ArrayList<Object> mWidgetsAndShortcuts;
     private Runnable mBindPackagesUpdatedRunnable = new Runnable() {
             public void run() {
-                bindPackagesUpdated(mWidgetsAndShortcuts);
-                mWidgetsAndShortcuts = null;
+                bindAllPackages(mWidgetsAndShortcuts);
             }
         };
 
-    public void bindPackagesUpdated(final ArrayList<Object> widgetsAndShortcuts) {
+    @Override
+    public void bindAllPackages(final ArrayList<Object> widgetsAndShortcuts) {
         if (waitUntilResume(mBindPackagesUpdatedRunnable, true)) {
             mWidgetsAndShortcuts = widgetsAndShortcuts;
             return;
         }
 
-        if (mWidgetsView != null) {
-            mWidgetsView.addWidgets(LauncherModel.getSortedWidgetsAndShortcuts(this, false),
-                    getPackageManager());
+        if (mWidgetsView != null && widgetsAndShortcuts != null) {
+            mWidgetsView.addWidgets(widgetsAndShortcuts, getPackageManager());
+            mWidgetsAndShortcuts = null;
         }
     }
 
diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
index a60e160..a527db4 100644
--- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
@@ -5,13 +5,13 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.text.TextUtils;
+import android.util.Log;
 import android.util.SparseArray;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
-import com.android.launcher3.LauncherModel.ScreenPosProvider;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
@@ -19,30 +19,32 @@
 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
 
-    public static final int REMOVE = R.id.action_remove;
-    public static final int INFO = R.id.action_info;
-    public static final int UNINSTALL = R.id.action_uninstall;
-    public static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace;
-    public static final int MOVE = R.id.action_move;
+    private static final String TAG = "LauncherAccessibilityDelegate";
 
-    enum DragType {
+    private static final int REMOVE = R.id.action_remove;
+    private static final int INFO = R.id.action_info;
+    private static final int UNINSTALL = R.id.action_uninstall;
+    private static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace;
+    private static final int MOVE = R.id.action_move;
+
+    public enum DragType {
         ICON,
         FOLDER,
         WIDGET
     }
 
     public static class DragInfo {
-        DragType dragType;
-        ItemInfo info;
-        View item;
+        public DragType dragType;
+        public ItemInfo info;
+        public View item;
     }
 
-    private DragInfo mDragInfo = null;
-
-    private final SparseArray<AccessibilityAction> mActions =
-            new SparseArray<AccessibilityAction>();
+    private final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
     @Thunk final Launcher mLauncher;
 
+    private DragInfo mDragInfo = null;
+    private AccessibilityDragSource mDragSource = null;
+
     public LauncherAccessibilityDelegate(Launcher launcher) {
         mLauncher = launcher;
 
@@ -56,7 +58,6 @@
                 launcher.getText(R.string.action_add_to_workspace)));
         mActions.put(MOVE, new AccessibilityAction(MOVE,
                 launcher.getText(R.string.action_move)));
-
     }
 
     @Override
@@ -93,7 +94,7 @@
         return super.performAccessibilityAction(host, action, args);
     }
 
-    public boolean performAction(View host, ItemInfo item, int action) {
+    public boolean performAction(View host, final ItemInfo item, int action) {
         if (action == REMOVE) {
             if (DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host)) {
                 announceConfirmation(R.string.item_removed);
@@ -108,32 +109,32 @@
         } else if (action == MOVE) {
             beginAccessibleDrag(host, item);
         } else if (action == ADD_TO_WORKSPACE) {
-            final int preferredPage = mLauncher.getWorkspace().getCurrentPage();
-            final ScreenPosProvider screenProvider = new ScreenPosProvider() {
+            final int[] coordinates = new int[2];
+            final long screenId = findSpaceOnWorkspace(item, coordinates);
+            mLauncher.showWorkspace(true, new Runnable() {
 
                 @Override
-                public int getScreenIndex(ArrayList<Long> screenIDs) {
-                    return preferredPage;
-                }
-            };
-            if (item instanceof AppInfo) {
-                final ArrayList<ItemInfo> addShortcuts = new ArrayList<ItemInfo>();
-                addShortcuts.add(((AppInfo) item).makeShortcut());
-                mLauncher.showWorkspace(true, new Runnable() {
-                    @Override
-                    public void run() {
-                        mLauncher.getModel().addAndBindAddedWorkspaceItems(
-                                mLauncher, addShortcuts, screenProvider, 0, true);
-                        announceConfirmation(R.string.item_added_to_workspace);
+                public void run() {
+                    if (item instanceof AppInfo) {
+                        ShortcutInfo info = ((AppInfo) item).makeShortcut();
+                        LauncherModel.addItemToDatabase(mLauncher, info,
+                                LauncherSettings.Favorites.CONTAINER_DESKTOP,
+                                screenId, coordinates[0], coordinates[1]);
+
+                        ArrayList<ItemInfo> itemList = new ArrayList<>();
+                        itemList.add(info);
+                        mLauncher.bindItems(itemList, 0, itemList.size(), true);
+                    } else if (item instanceof PendingAddItemInfo) {
+                        PendingAddItemInfo info = (PendingAddItemInfo) item;
+                        Workspace workspace = mLauncher.getWorkspace();
+                        workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
+                        mLauncher.addPendingItem(info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
+                                screenId, coordinates, info.spanX, info.spanY);
                     }
-                });
-                return true;
-            } else if (item instanceof PendingAddItemInfo) {
-                mLauncher.getModel().addAndBindPendingItem(
-                        mLauncher, (PendingAddItemInfo) item, screenProvider, 0);
-                announceConfirmation(R.string.item_added_to_workspace);
-                return true;
-            }
+                    announceConfirmation(R.string.item_added_to_workspace);
+                }
+            });
+            return true;
         }
         return false;
     }
@@ -197,10 +198,23 @@
 
         Rect pos = new Rect();
         mLauncher.getDragLayer().getDescendantRectRelativeToSelf(item, pos);
-
         mLauncher.getDragController().prepareAccessibleDrag(pos.centerX(), pos.centerY());
-        mLauncher.getWorkspace().enableAccessibleDrag(true);
-        mLauncher.getWorkspace().startDrag(cellInfo, true);
+
+        Workspace workspace = mLauncher.getWorkspace();
+
+        Folder folder = workspace.getOpenFolder();
+        if (folder != null) {
+            if (folder.getItemsInReadingOrder().contains(item)) {
+                mDragSource = folder;
+            } else {
+                mLauncher.closeFolder();
+            }
+        }
+        if (mDragSource == null) {
+            mDragSource = workspace;
+        }
+        mDragSource.enableAccessibleDrag(true);
+        mDragSource.startDrag(cellInfo, true);
     }
 
     public boolean onBackPressed() {
@@ -218,6 +232,52 @@
 
     private void endAccessibleDrag() {
         mDragInfo = null;
-        mLauncher.getWorkspace().enableAccessibleDrag(false);
+        if (mDragSource != null) {
+            mDragSource.enableAccessibleDrag(false);
+            mDragSource = null;
+        }
+    }
+
+    public static interface AccessibilityDragSource {
+        void startDrag(CellLayout.CellInfo cellInfo, boolean accessible);
+
+        void enableAccessibleDrag(boolean enable);
+    }
+
+    /**
+     * Find empty space on the workspace and returns the screenId.
+     */
+    private long findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) {
+        Workspace workspace = mLauncher.getWorkspace();
+        ArrayList<Long> workspaceScreens = workspace.getScreenOrder();
+        long screenId;
+
+        // First check if there is space on the current screen.
+        int screenIndex = workspace.getCurrentPage();
+        screenId = workspaceScreens.get(screenIndex);
+        CellLayout layout = (CellLayout) workspace.getPageAt(screenIndex);
+
+        boolean found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY);
+        screenIndex = workspace.hasCustomContent() ? 1 : 0;
+        while (!found && screenIndex < workspaceScreens.size()) {
+            screenId = workspaceScreens.get(screenIndex);
+            layout = (CellLayout) workspace.getPageAt(screenIndex);
+            found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY);
+            screenIndex++;
+        }
+
+        if (found) {
+            return screenId;
+        }
+
+        workspace.addExtraEmptyScreen();
+        screenId = workspace.commitExtraEmptyScreen();
+        layout = workspace.getScreenWithId(screenId);
+        found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY);
+
+        if (!found) {
+            Log.wtf(TAG, "Not enough space on an empty screen");
+        }
+        return screenId;
     }
 }
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 7f31e49..d51df32 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -112,6 +112,10 @@
         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
         filter.addAction(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
+        // For handling managed profiles
+        filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
+        filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
+
         sContext.registerReceiver(mModel, filter);
     }
 
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index 064f436..92bbb40 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -88,11 +88,6 @@
     /** widgets contain previews, which are very large, dribble them out */
     private static final int MAX_WIDGETS_PER_PASS = 5;
 
-    private static final int IMAGE_COMPRESSION_QUALITY = 75;
-
-    private static final Bitmap.CompressFormat IMAGE_FORMAT =
-            android.graphics.Bitmap.CompressFormat.PNG;
-
     private static final String[] FAVORITE_PROJECTION = {
         Favorites._ID,                     // 0
         Favorites.MODIFIED,                // 1
@@ -969,10 +964,7 @@
     private Resource packIcon(int dpi, Bitmap icon) {
         Resource res = new Resource();
         res.dpi = dpi;
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        if (icon.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) {
-            res.data = os.toByteArray();
-        }
+        res.data = Utilities.flattenBitmap(icon);
         return res;
     }
 
@@ -990,20 +982,14 @@
             widget.icon = new Resource();
             Drawable fullResIcon = iconCache.getFullResIcon(provider.getPackageName(), info.icon);
             Bitmap icon = Utilities.createIconBitmap(fullResIcon, mContext);
-            ByteArrayOutputStream os = new ByteArrayOutputStream();
-            if (icon.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) {
-                widget.icon.data = os.toByteArray();
-                widget.icon.dpi = dpi;
-            }
+            widget.icon.data = Utilities.flattenBitmap(icon);
+            widget.icon.dpi = dpi;
         }
         if (info.previewImage != 0) {
             widget.preview = new Resource();
             Bitmap preview = previewLoader.generateWidgetPreview(info, previewWidth, null);
-            ByteArrayOutputStream os = new ByteArrayOutputStream();
-            if (preview.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) {
-                widget.preview.data = os.toByteArray();
-                widget.preview.dpi = dpi;
-            }
+            widget.preview.data = Utilities.flattenBitmap(preview);
+            widget.preview.dpi = dpi;
         }
         return widget;
     }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index d5dce51..7fdd523 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -35,7 +35,6 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.Bitmap;
-import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Environment;
@@ -198,23 +197,17 @@
         public void bindRestoreItemsChange(HashSet<ItemInfo> updates);
         public void bindComponentsRemoved(ArrayList<String> packageNames,
                         ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);
-        public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
+        public void bindAllPackages(ArrayList<Object> widgetsAndShortcuts);
         public void bindSearchablesChanged();
         public boolean isAllAppsButtonRank(int rank);
         public void onPageBoundSynchronously(int page);
         public void dumpLogsToLocalData();
-        public void bindAddPendingItem(PendingAddItemInfo info, long container, long screenId,
-                int[] cell, int spanX, int spanY);
     }
 
     public interface ItemInfoFilter {
         public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);
     }
 
-    public interface ScreenPosProvider {
-        int getScreenIndex(ArrayList<Long> screenIDs);
-    }
-
     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
         Context context = app.getContext();
 
@@ -406,19 +399,7 @@
         runOnWorkerThread(r);
     }
 
-    public void addAndBindAddedWorkspaceItems(final Context context,
-            final ArrayList<ItemInfo> workspaceApps) {
-        addAndBindAddedWorkspaceItems(context, workspaceApps,
-                new ScreenPosProvider() {
-
-                    @Override
-                    public int getScreenIndex(ArrayList<Long> screenIDs) {
-                        return screenIDs.isEmpty() ? 0 : 1;
-                    }
-                }, 1, false);
-    }
-
-    private static boolean findNextAvailableIconSpaceInScreen(ArrayList<Rect> occupiedPos,
+    private static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> occupiedPos,
             int[] xy, int spanX, int spanY) {
         LauncherAppState app = LauncherAppState.getInstance();
         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
@@ -426,15 +407,17 @@
         final int yCount = (int) grid.numRows;
         boolean[][] occupied = new boolean[xCount][yCount];
         if (occupiedPos != null) {
-            for (Rect r : occupiedPos) {
-                for (int x = r.left; 0 <= x && x < r.right && x < xCount; x++) {
-                    for (int y = r.top; 0 <= y && y < r.bottom && y < yCount; y++) {
+            for (ItemInfo r : occupiedPos) {
+                int right = r.cellX + r.spanX;
+                int bottom = r.cellY + r.spanY;
+                for (int x = r.cellX; 0 <= x && x < right && x < xCount; x++) {
+                    for (int y = r.cellY; 0 <= y && y < bottom && y < yCount; y++) {
                         occupied[x][y] = true;
                     }
                 }
             }
         }
-        return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);
+        return Utilities.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);
     }
 
     /**
@@ -443,53 +426,24 @@
      */
     @Thunk static Pair<Long, int[]> findSpaceForItem(
             Context context,
-            ScreenPosProvider preferredScreen,
-            int fallbackStartScreen,
             ArrayList<Long> workspaceScreens,
             ArrayList<Long> addedWorkspaceScreensFinal,
             int spanX, int spanY) {
-        // Load position of items which are on the desktop. We can't use sBgItemsIdMap because
-        // loadWorkspace() may not have been called.
-        final ContentResolver cr = context.getContentResolver();
-        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
-                new String[] {
-                    LauncherSettings.Favorites.SCREEN,
-                    LauncherSettings.Favorites.CELLX,
-                    LauncherSettings.Favorites.CELLY,
-                    LauncherSettings.Favorites.SPANX,
-                    LauncherSettings.Favorites.SPANY,
-                    LauncherSettings.Favorites.CONTAINER
-                 },
-                 "container=?",
-                 new String[] { Integer.toString(LauncherSettings.Favorites.CONTAINER_DESKTOP) },
-                 null);
+        LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();
 
-        final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
-        final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
-        final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
-        final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
-        final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
-        LongSparseArray<ArrayList<Rect>> screenItems = new LongSparseArray<ArrayList<Rect>>();
-        try {
-            while (c.moveToNext()) {
-                Rect rect = new Rect();
-                rect.left = c.getInt(cellXIndex);
-                rect.top = c.getInt(cellYIndex);
-                rect.right = rect.left + Math.max(1, c.getInt(spanXIndex));
-                rect.bottom = rect.top + Math.max(1, c.getInt(spanYIndex));
-
-                long screenId = c.getInt(screenIndex);
-                ArrayList<Rect> items = screenItems.get(screenId);
-                if (items == null) {
-                    items = new ArrayList<Rect>();
-                    screenItems.put(screenId, items);
+        // Use sBgItemsIdMap as all the items are already loaded.
+        // TODO: Throw exception is above condition is not met.
+        synchronized (sBgLock) {
+            for (ItemInfo info : sBgItemsIdMap) {
+                if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+                    ArrayList<ItemInfo> items = screenItems.get(info.screenId);
+                    if (items == null) {
+                        items = new ArrayList<>();
+                        screenItems.put(info.screenId, items);
+                    }
+                    items.add(info);
                 }
-                items.add(rect);
             }
-        } catch (Exception e) {
-            screenItems.clear();
-        } finally {
-            c.close();
         }
 
         // Find appropriate space for the item.
@@ -499,7 +453,7 @@
 
         int screenCount = workspaceScreens.size();
         // First check the preferred screen.
-        int preferredScreenIndex = preferredScreen.getScreenIndex(workspaceScreens);
+        int preferredScreenIndex = workspaceScreens.isEmpty() ? 0 : 1;
         if (preferredScreenIndex < screenCount) {
             screenId = workspaceScreens.get(preferredScreenIndex);
             found = findNextAvailableIconSpaceInScreen(
@@ -507,8 +461,8 @@
         }
 
         if (!found) {
-            // Search on any of the screens.
-            for (int screen = fallbackStartScreen; screen < screenCount; screen++) {
+            // Search on any of the screens starting from the first screen.
+            for (int screen = 1; screen < screenCount; screen++) {
                 screenId = workspaceScreens.get(screen);
                 if (findNextAvailableIconSpaceInScreen(
                         screenItems.get(screenId), cordinates, spanX, spanY)) {
@@ -538,59 +492,9 @@
 
     /**
      * Adds the provided items to the workspace.
-     * @param preferredScreen the screen where we should try to add the app first
-     * @param fallbackStartScreen the screen to start search for empty space if
-     * preferredScreen is not available.
-     */
-    public void addAndBindPendingItem(
-            final Context context,
-            final PendingAddItemInfo addInfo,
-            final ScreenPosProvider preferredScreen,
-            final int fallbackStartScreen) {
-        final Callbacks callbacks = getCallback();
-        // Process the newly added applications and add them to the database first
-        Runnable r = new Runnable() {
-            public void run() {
-                final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();
-                ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);
-
-                // Find appropriate space for the item.
-                Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,
-                        fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,
-                        addInfo.spanX,
-                        addInfo.spanY);
-                final long screenId = coords.first;
-                final int[] cordinates = coords.second;
-
-                // Update the workspace screens
-                updateWorkspaceScreenOrder(context, workspaceScreens);
-                runOnMainThread(new Runnable() {
-                    public void run() {
-                        Callbacks cb = getCallback();
-                        if (callbacks == cb && cb != null) {
-                            cb.bindAddScreens(addedWorkspaceScreensFinal);
-                            cb.bindAddPendingItem(addInfo,
-                                    LauncherSettings.Favorites.CONTAINER_DESKTOP,
-                                    screenId, cordinates, addInfo.spanX, addInfo.spanY);
-                        }
-                    }
-                });
-            }
-        };
-        runOnWorkerThread(r);
-    }
-
-    /**
-     * Adds the provided items to the workspace.
-     * @param preferredScreen the screen where we should try to add the app first
-     * @param fallbackStartScreen the screen to start search for empty space if
-     * preferredScreen is not available.
      */
     public void addAndBindAddedWorkspaceItems(final Context context,
-            final ArrayList<ItemInfo> workspaceApps,
-            final ScreenPosProvider preferredScreen,
-            final int fallbackStartScreen,
-            final boolean allowDuplicate) {
+            final ArrayList<ItemInfo> workspaceApps) {
         final Callbacks callbacks = getCallback();
         if (workspaceApps.isEmpty()) {
             return;
@@ -607,7 +511,7 @@
                 ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);
                 synchronized(sBgLock) {
                     for (ItemInfo item : workspaceApps) {
-                        if (!allowDuplicate && item instanceof ShortcutInfo) {
+                        if (item instanceof ShortcutInfo) {
                             // Short-circuit this logic if the icon exists somewhere on the workspace
                             if (shortcutExists(context, item.getIntent(), item.user)) {
                                 continue;
@@ -615,8 +519,8 @@
                         }
 
                         // Find appropriate space for the item.
-                        Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,
-                                fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,
+                        Pair<Long, int[]> coords = findSpaceForItem(context,
+                                workspaceScreens, addedWorkspaceScreensFinal,
                                 1, 1);
                         long screenId = coords.first;
                         int[] cordinates = coords.second;
@@ -977,22 +881,22 @@
      * TODO: Throw exception is above condition is not met.
      */
     @Thunk static boolean shortcutExists(Context context, Intent intent, UserHandleCompat user) {
-        final Intent intentWithPkg, intentWithoutPkg;
+        final String intentWithPkg, intentWithoutPkg;
         final String packageName;
         if (intent.getComponent() != null) {
             // If component is not null, an intent with null package will produce
             // the same result and should also be a match.
             packageName = intent.getComponent().getPackageName();
             if (intent.getPackage() != null) {
-                intentWithPkg = intent;
-                intentWithoutPkg = new Intent(intent).setPackage(null);
+                intentWithPkg = intent.toUri(0);
+                intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0);
             } else {
-                intentWithPkg = new Intent(intent).setPackage(packageName);
-                intentWithoutPkg = intent;
+                intentWithPkg = new Intent(intent).setPackage(packageName).toUri(0);
+                intentWithoutPkg = intent.toUri(0);
             }
         } else {
-            intentWithPkg = intent;
-            intentWithoutPkg = intent;
+            intentWithPkg = intent.toUri(0);
+            intentWithoutPkg = intent.toUri(0);
             packageName = intent.getPackage();
         }
 
@@ -1000,9 +904,11 @@
             for (ItemInfo item : sBgItemsIdMap) {
                 if (item instanceof ShortcutInfo) {
                     ShortcutInfo info = (ShortcutInfo) item;
-                    if (intentWithPkg.equals(info.getIntent())
-                            || intentWithoutPkg.equals(info.getIntent())) {
-                        return true;
+                    if (info.getIntent() != null && info.user.equals(user)) {
+                        String s = info.getIntent().toUri(0);
+                        if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) {
+                            return true;
+                        }
                     }
                 }
             }
@@ -1373,6 +1279,9 @@
             if (callbacks != null) {
                 callbacks.bindSearchablesChanged();
             }
+        } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)
+                || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
+            forceReload();
         }
     }
 
@@ -1690,9 +1599,6 @@
                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
                 loadAndBindAllApps();
 
-                // Remove entries for packages which changed while the launcher was dead.
-                LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews();
-
                 // Restore the default thread priority after we are done loading items
                 synchronized (mLock) {
                     android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
@@ -2961,6 +2867,7 @@
                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                     if (callbacks != null) {
                         callbacks.bindAllApplications(added);
+                        loadAndBindWidgetsAndShortcuts(mContext,callbacks);
                         if (DEBUG_LOADERS) {
                             Log.d(TAG, "bound " + added.size() + " apps in "
                                 + (SystemClock.uptimeMillis() - bindTime) + "ms");
@@ -3376,29 +3283,33 @@
         runOnWorkerThread(new Runnable(){
             @Override
             public void run() {
-                final ArrayList<Object> list =
-                        getSortedWidgetsAndShortcuts(context, true /* refresh */);
+                final ArrayList<Object> list = getWidgetsAndShortcuts(context, true /* refresh */);
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
                         Callbacks cb = getCallback();
                         if (callbacks == cb && cb != null) {
-                            callbacks.bindPackagesUpdated(list);
+                            callbacks.bindAllPackages(list);
                         }
                     }
                 });
+                // update the Widget entries inside DB on the worker thread.
+                LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(list);
             }
         });
     }
 
-    // Returns a list of ResolveInfos/AppWidgetInfos in sorted order
-    public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context, boolean refresh) {
+    /**
+     *  Returns a list of ResolveInfos/AppWidgetInfos.
+     *
+     *  @see #loadAndBindWidgetsAndShortcuts
+     */
+    private ArrayList<Object> getWidgetsAndShortcuts(Context context, boolean refresh) {
         PackageManager packageManager = context.getPackageManager();
         final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
         widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh));
         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
         widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));
-        Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));
         return widgetsAndShortcuts;
     }
 
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 1effe1e..51f84bf 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -258,7 +258,7 @@
             // Setup the reveal view animation
             int width = revealView.getMeasuredWidth();
             int height = revealView.getMeasuredHeight();
-            float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
+            float revealRadius = (float) Math.hypot(width / 2, height / 2);
             revealView.setVisibility(View.VISIBLE);
             revealView.setAlpha(0f);
             revealView.setTranslationY(0f);
@@ -563,7 +563,7 @@
             if (fromView.getVisibility() == View.VISIBLE) {
                 int width = revealView.getMeasuredWidth();
                 int height = revealView.getMeasuredHeight();
-                float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
+                float revealRadius = (float) Math.hypot(width / 2, height / 2);
                 revealView.setVisibility(View.VISIBLE);
                 revealView.setAlpha(1f);
                 revealView.setTranslationY(0);
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 15b6176..56c8b39 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -76,14 +76,6 @@
         return null;
     }
 
-    public void addView(View child, int index, LayoutParams params, boolean inLayout) {
-        if (!inLayout) {
-            addView(child, index, params);
-        } else {
-            addViewInLayout(child, index, params, false);
-        }
-    }
-
     @Override
     protected void dispatchDraw(Canvas canvas) {
         @SuppressWarnings("all") // suppress dead code warning
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 4c52d7e..c351135 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -26,7 +26,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         // Get the hover color
-        mHoverColor = getResources().getColor(R.color.delete_target_hover_tint);
+        mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
 
         setDrawable(R.drawable.uninstall_target_selector);
     }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 22677c8..2dbf078 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -583,4 +583,37 @@
             return lhs.rank - rhs.rank;
         }
     };
+
+    /**
+     * Find the first vacant cell, if there is one.
+     *
+     * @param vacant Holds the x and y coordinate of the vacant cell
+     * @param spanX Horizontal cell span.
+     * @param spanY Vertical cell span.
+     *
+     * @return true if a vacant cell was found
+     */
+    public static boolean findVacantCell(int[] vacant, int spanX, int spanY,
+            int xCount, int yCount, boolean[][] occupied) {
+
+        for (int y = 0; (y + spanY) <= yCount; y++) {
+            for (int x = 0; (x + spanX) <= xCount; x++) {
+                boolean available = !occupied[x][y];
+                out:            for (int i = x; i < x + spanX; i++) {
+                    for (int j = y; j < y + spanY; j++) {
+                        available = available && !occupied[i][j];
+                        if (!available) break out;
+                    }
+                }
+
+                if (available) {
+                    vacant[0] = x;
+                    vacant[1] = y;
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 5c3ed92..93bfeaf 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
+import android.os.Process;
 import android.util.Log;
 import android.util.LongSparseArray;
 
@@ -34,7 +35,9 @@
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.widget.WidgetCell;
 
-import java.lang.ref.WeakReference;
+import junit.framework.Assert;
+
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -51,8 +54,13 @@
     private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f;
 
     private final HashMap<String, long[]> mPackageVersions = new HashMap<>();
-    private final HashMap<WidgetCacheKey, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<>();
-    private Set<Bitmap> mUnusedBitmaps = Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>());
+
+    /**
+     * Weak reference objects, do not prevent their referents from being made finalizable,
+     * finalized, and then reclaimed.
+     */
+    private Set<Bitmap> mUnusedBitmaps =
+            Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>());
 
     private final Context mContext;
     private final IconCache mIconCache;
@@ -84,18 +92,9 @@
         String size = previewWidth + "x" + previewHeight;
         WidgetCacheKey key = getObjectKey(o, size);
 
-        // Check if we have the preview loaded or not.
-        synchronized (mLoadedPreviews) {
-            WeakReference<Bitmap> ref = mLoadedPreviews.get(key);
-            if (ref != null && ref.get() != null) {
-                immediateResult[0] = ref.get();
-                return new PreviewLoadRequest(null, key);
-            }
-        }
-
         PreviewLoadTask task = new PreviewLoadTask(key, o, previewWidth, previewHeight, caller);
         task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-        return new PreviewLoadRequest(task, key);
+        return new PreviewLoadRequest(task);
     }
 
     /**
@@ -192,22 +191,6 @@
             mPackageVersions.remove(packageName);
         }
 
-        synchronized (mLoadedPreviews) {
-            Set<WidgetCacheKey> keysToRemove = new HashSet<>();
-            for (WidgetCacheKey key : mLoadedPreviews.keySet()) {
-                if (key.componentName.getPackageName().equals(packageName) && key.user.equals(user)) {
-                    keysToRemove.add(key);
-                }
-            }
-
-            for (WidgetCacheKey key : keysToRemove) {
-                WeakReference<Bitmap> req = mLoadedPreviews.remove(key);
-                if (req != null && req.get() != null) {
-                    mUnusedBitmaps.add(req.get());
-                }
-            }
-        }
-
         try {
             mDb.getWritableDatabase().delete(CacheDb.TABLE_NAME,
                     CacheDb.COLUMN_PACKAGE + " = ? AND " + CacheDb.COLUMN_USER + " = ?",
@@ -223,11 +206,14 @@
      *   2. Any preview for an absent package is removed
      * This ensures that we remove entries for packages which changed while the launcher was dead.
      */
-    public void removeObsoletePreviews() {
+    public void removeObsoletePreviews(ArrayList<Object> list) {
+        // This method should always be called from the worker thread.
+        Assert.assertTrue(LauncherModel.sWorkerThread.getThreadId() == Process.myTid());
+
         LongSparseArray<UserHandleCompat> userIdCache = new LongSparseArray<>();
         LongSparseArray<HashSet<String>> validPackages = new LongSparseArray<>();
 
-        for (Object obj : LauncherModel.getSortedWidgetsAndShortcuts(mContext, false)) {
+        for (Object obj : list) {
             final UserHandleCompat user;
             final String pkg;
             if (obj instanceof ResolveInfo) {
@@ -549,26 +535,25 @@
     public class PreviewLoadRequest {
 
         private final PreviewLoadTask mTask;
-        private final WidgetCacheKey mKey;
 
-        public PreviewLoadRequest(PreviewLoadTask task, WidgetCacheKey key) {
+        public PreviewLoadRequest(PreviewLoadTask task) {
             mTask = task;
-            mKey = key;
         }
 
-        public void cancel(boolean recycleImage) {
+        public void cleanup() {
             if (mTask != null) {
                 mTask.cancel(true);
             }
 
-            if (recycleImage) {
-                synchronized(mLoadedPreviews) {
-                    WeakReference<Bitmap> result = mLoadedPreviews.remove(mKey);
-                    if (result != null && result.get() != null) {
-                        mUnusedBitmaps.add(result.get());
-                    }
-                }
+            if (mTask.mBitmap == null) {
+                return;
             }
+
+            // The preview is no longer bound to any view, move it to {@link WeakReference} list.
+            synchronized(mUnusedBitmaps) {
+                mUnusedBitmaps.add(mTask.mBitmap);
+            }
+            mTask.mBitmap = null;
         }
     }
 
@@ -579,6 +564,7 @@
         private final int mPreviewHeight;
         private final int mPreviewWidth;
         private final WidgetCell mCaller;
+        private Bitmap mBitmap;
 
         PreviewLoadTask(WidgetCacheKey key, Object info, int previewWidth,
                 int previewHeight, WidgetCell caller) {
@@ -597,7 +583,6 @@
         protected Bitmap doInBackground(Void... params) {
             Bitmap unusedBitmap = null;
 
-            // TODO(hyunyoungs): Figure out why this path causes concurrency issue.
             synchronized (mUnusedBitmaps) {
                 // Check if we can use a bitmap
                 for (Bitmap candidate : mUnusedBitmaps) {
@@ -638,10 +623,7 @@
 
         @Override
         protected void onPostExecute(Bitmap result) {
-            synchronized(mLoadedPreviews) {
-                mLoadedPreviews.put(mKey, new WeakReference<Bitmap>(result));
-            }
-
+            mBitmap = result;
             mCaller.applyPreview(result);
         }
     }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 9acdcae..e7a41e0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -60,6 +60,7 @@
 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.compat.UserHandleCompat;
@@ -82,7 +83,7 @@
 public class Workspace extends SmoothPagedView
         implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
         DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,
-        Insettable, UninstallSource {
+        Insettable, UninstallSource, AccessibilityDragSource {
     private static final String TAG = "Launcher.Workspace";
 
     private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
@@ -125,6 +126,7 @@
 
     @Thunk Runnable mRemoveEmptyScreenRunnable;
     @Thunk boolean mDeferRemoveExtraEmptyScreen = false;
+    @Thunk boolean mAddNewPageOnDrag = true;
 
     /**
      * CellInfo for the cell that is currently being dragged
@@ -390,7 +392,7 @@
         post(new Runnable() {
             @Override
             public void run() {
-                if (mIsDragOccuring) {
+                if (mIsDragOccuring && mAddNewPageOnDrag) {
                     mDeferRemoveExtraEmptyScreen = false;
                     addExtraEmptyScreenOnDrag();
                 }
@@ -398,6 +400,9 @@
         });
     }
 
+    public void setAddNewPageOnDrag(boolean addPage) {
+        mAddNewPageOnDrag = addPage;
+    }
 
     public void deferRemoveExtraEmptyScreen() {
         mDeferRemoveExtraEmptyScreen = true;
@@ -562,7 +567,7 @@
         LauncherAccessibilityDelegate delegate =
                 LauncherAppState.getInstance().getAccessibilityDelegate();
         if (delegate != null && delegate.isInAccessibleDrag()) {
-            newScreen.enableAccessibleDrag(true);
+            newScreen.enableAccessibleDrag(true, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
         }
         return screenId;
     }
@@ -1601,10 +1606,11 @@
     }
 
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    @Override
     public void enableAccessibleDrag(boolean enable) {
         for (int i = 0; i < getChildCount(); i++) {
             CellLayout child = (CellLayout) getChildAt(i);
-            child.enableAccessibleDrag(enable);
+            child.enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
         }
 
         if (enable) {
@@ -1615,7 +1621,8 @@
             setOnClickListener(mLauncher);
         }
         mLauncher.getSearchBar().enableAccessibleDrag(enable);
-        mLauncher.getHotseat().getLayout().enableAccessibleDrag(enable);
+        mLauncher.getHotseat().getLayout()
+            .enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
     }
 
     public boolean hasCustomContent() {
@@ -2253,6 +2260,7 @@
         startDrag(cellInfo, false);
     }
 
+    @Override
     public void startDrag(CellLayout.CellInfo cellInfo, boolean accessible) {
         View child = cellInfo.cell;
 
@@ -2616,6 +2624,9 @@
         return false;
     }
 
+    @Override
+    public void prepareAccessibilityDrop() { }
+
     public void onDrop(final DragObject d) {
         mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
         CellLayout dropTargetLayout = mDropToLayout;
@@ -3897,7 +3908,7 @@
     }
 
     @Override
-    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
+    public void onFlingToDelete(DragObject d, PointF vec) {
         // Do nothing
     }
 
diff --git a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
new file mode 100644
index 0000000..0f17241
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
@@ -0,0 +1,137 @@
+/*
+ * 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.accessibility;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.widget.ExploreByTouchHelper;
+import android.view.View;
+import android.view.View.OnClickListener;
+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;
+
+import java.util.List;
+
+/**
+ * Helper class to make drag-and-drop in a {@link CellLayout} accessible.
+ */
+public abstract class DragAndDropAccessibilityDelegate extends ExploreByTouchHelper
+        implements OnClickListener {
+    protected static final int INVALID_POSITION = -1;
+
+    private static final int[] sTempArray = new int[2];
+
+    protected final CellLayout mView;
+    protected final Context mContext;
+    protected final LauncherAccessibilityDelegate mDelegate;
+
+    private final Rect mTempRect = new Rect();
+
+    public DragAndDropAccessibilityDelegate(CellLayout forView) {
+        super(forView);
+        mView = forView;
+        mContext = mView.getContext();
+        mDelegate = LauncherAppState.getInstance().getAccessibilityDelegate();
+    }
+
+    @Override
+    protected int getVirtualViewAt(float x, float y) {
+        if (x < 0 || y < 0 || x > mView.getMeasuredWidth() || y > mView.getMeasuredHeight()) {
+            return INVALID_ID;
+        }
+        mView.pointToCellExact((int) x, (int) y, sTempArray);
+
+        // Map cell to id
+        int id = sTempArray[0] + sTempArray[1] * mView.getCountX();
+        return intersectsValidDropTarget(id);
+    }
+
+    /**
+     * @return the view id of the top left corner of a valid drop region or
+     * {@link #INVALID_POSITION} if there is no such valid region.
+     */
+    protected abstract int intersectsValidDropTarget(int id);
+
+    @Override
+    protected void getVisibleVirtualViews(List<Integer> virtualViews) {
+        // We create a virtual view for each cell of the grid
+        // The cell ids correspond to cells in reading order.
+        int nCells = mView.getCountX() * mView.getCountY();
+
+        for (int i = 0; i < nCells; i++) {
+            if (intersectsValidDropTarget(i) == i) {
+                virtualViews.add(i);
+            }
+        }
+    }
+
+    @Override
+    protected boolean onPerformActionForVirtualView(int viewId, int action, Bundle args) {
+        if (action == AccessibilityNodeInfoCompat.ACTION_CLICK && viewId != INVALID_ID) {
+            String confirmation = getConfirmationForIconDrop(viewId);
+            mDelegate.handleAccessibleDrop(mView, getItemBounds(viewId), confirmation);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onClick(View v) {
+        onPerformActionForVirtualView(getFocusedVirtualView(),
+                AccessibilityNodeInfoCompat.ACTION_CLICK, null);
+    }
+
+    @Override
+    protected void onPopulateEventForVirtualView(int id, AccessibilityEvent event) {
+        if (id == INVALID_ID) {
+            throw new IllegalArgumentException("Invalid virtual view id");
+        }
+        event.setContentDescription(mContext.getString(R.string.action_move_here));
+    }
+
+    @Override
+    protected void onPopulateNodeForVirtualView(int id, AccessibilityNodeInfoCompat node) {
+        if (id == INVALID_ID) {
+            throw new IllegalArgumentException("Invalid virtual view id");
+        }
+
+        node.setContentDescription(getLocationDescriptionForIconDrop(id));
+        node.setBoundsInParent(getItemBounds(id));
+
+        node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
+        node.setClickable(true);
+        node.setFocusable(true);
+    }
+
+    protected abstract String getLocationDescriptionForIconDrop(int id);
+
+    protected abstract String getConfirmationForIconDrop(int id);
+
+    private Rect getItemBounds(int id) {
+        int cellX = id % mView.getCountX();
+        int cellY = id / mView.getCountX();
+        LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+        mView.cellToRect(cellX, cellY, dragInfo.info.spanX, dragInfo.info.spanY, mTempRect);
+        return mTempRect;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/accessibility/FolderAccessibilityHelper.java b/src/com/android/launcher3/accessibility/FolderAccessibilityHelper.java
new file mode 100644
index 0000000..fc105b4
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/FolderAccessibilityHelper.java
@@ -0,0 +1,50 @@
+/*
+ * 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.accessibility;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.FolderPagedView;
+import com.android.launcher3.R;
+
+/**
+ * Implementation of {@link DragAndDropAccessibilityDelegate} to support DnD in a folder.
+ */
+public class FolderAccessibilityHelper extends DragAndDropAccessibilityDelegate {
+    private final int mStartPosition;
+
+    public FolderAccessibilityHelper(CellLayout layout) {
+        super(layout);
+        FolderPagedView parent = (FolderPagedView) layout.getParent();
+
+        int index = parent.indexOfChild(layout);
+        mStartPosition = 1 + index * layout.getCountX() * layout.getCountY();
+    }
+    @Override
+    protected int intersectsValidDropTarget(int id) {
+        return id;
+    }
+
+    @Override
+    protected String getLocationDescriptionForIconDrop(int id) {
+        return mContext.getString(R.string.move_to_position, id + mStartPosition);
+    }
+
+    @Override
+    protected String getConfirmationForIconDrop(int id) {
+        return mContext.getString(R.string.item_moved);
+    }
+}
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
new file mode 100644
index 0000000..42e9e3c
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -0,0 +1,167 @@
+/*
+ * 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.accessibility;
+
+import android.text.TextUtils;
+import android.view.View;
+
+import com.android.launcher3.AppInfo;
+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.R;
+import com.android.launcher3.ShortcutInfo;
+
+/**
+ * Implementation of {@link DragAndDropAccessibilityDelegate} to support DnD on workspace.
+ */
+public class WorkspaceAccessibilityHelper extends DragAndDropAccessibilityDelegate {
+
+    public WorkspaceAccessibilityHelper(CellLayout layout) {
+        super(layout);
+    }
+
+    /**
+     * Find the virtual view id corresponding to the top left corner of any drop region by which
+     * the passed id is contained. For an icon, this is simply
+     */
+    @Override
+    protected int intersectsValidDropTarget(int id) {
+        int mCountX = mView.getCountX();
+        int mCountY = mView.getCountY();
+
+        int x = id % mCountX;
+        int y = id / mCountX;
+        LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+
+        if (dragInfo.dragType == DragType.WIDGET && mView.isHotseat()) {
+            return INVALID_POSITION;
+        }
+
+        if (dragInfo.dragType == DragType.WIDGET) {
+            // For a widget, every cell must be vacant. In addition, we will return any valid
+            // drop target by which the passed id is contained.
+            boolean fits = false;
+
+            // These represent the amount that we can back off if we hit a problem. They
+            // get consumed as we move up and to the right, trying new regions.
+            int spanX = dragInfo.info.spanX;
+            int spanY = dragInfo.info.spanY;
+
+            for (int m = 0; m < spanX; m++) {
+                for (int n = 0; n < spanY; n++) {
+
+                    fits = true;
+                    int x0 = x - m;
+                    int y0 = y - n;
+
+                    if (x0 < 0 || y0 < 0) continue;
+
+                    for (int i = x0; i < x0 + spanX; i++) {
+                        if (!fits) break;
+                        for (int j = y0; j < y0 + spanY; j++) {
+                            if (i >= mCountX || j >= mCountY || mView.isOccupied(i, j)) {
+                                fits = false;
+                                break;
+                            }
+                        }
+                    }
+                    if (fits) {
+                        return x0 + mCountX * y0;
+                    }
+                }
+            }
+            return INVALID_POSITION;
+        } else {
+            // For an icon, we simply check the view directly below
+            View child = mView.getChildAt(x, y);
+            if (child == null || child == dragInfo.item) {
+                // Empty cell. Good for an icon or folder.
+                return id;
+            } else if (dragInfo.dragType != DragType.FOLDER) {
+                // For icons, we can consider cells that have another icon or a folder.
+                ItemInfo info = (ItemInfo) child.getTag();
+                if (info instanceof AppInfo || info instanceof FolderInfo ||
+                        info instanceof ShortcutInfo) {
+                    return id;
+                }
+            }
+            return INVALID_POSITION;
+        }
+    }
+
+    @Override
+    protected String getConfirmationForIconDrop(int id) {
+        int x = id % mView.getCountX();
+        int y = id / mView.getCountX();
+        LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+
+        View child = mView.getChildAt(x, y);
+        if (child == null || child == dragInfo.item) {
+            return mContext.getString(R.string.item_moved);
+        } else {
+            ItemInfo info = (ItemInfo) child.getTag();
+            if (info instanceof AppInfo || info instanceof ShortcutInfo) {
+                return mContext.getString(R.string.folder_created);
+
+            } else if (info instanceof FolderInfo) {
+                return mContext.getString(R.string.added_to_folder);
+            }
+        }
+        return "";
+    }
+
+    @Override
+    protected String getLocationDescriptionForIconDrop(int id) {
+        int x = id % mView.getCountX();
+        int y = id / mView.getCountX();
+        LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+
+        View child = mView.getChildAt(x, y);
+        if (child == null || child == dragInfo.item) {
+            if (mView.isHotseat()) {
+                return mContext.getString(R.string.move_to_hotseat_position, id + 1);
+            } else {
+                return mContext.getString(R.string.move_to_empty_cell, y + 1, x + 1);
+            }
+        } else {
+            ItemInfo info = (ItemInfo) child.getTag();
+            if (info instanceof ShortcutInfo) {
+                return mContext.getString(R.string.create_folder_with, info.title);
+            } else if (info instanceof FolderInfo) {
+                if (TextUtils.isEmpty(info.title.toString().trim())) {
+                    // Find the first item in the folder.
+                    FolderInfo folder = (FolderInfo) info;
+                    ShortcutInfo firstItem = null;
+                    for (ShortcutInfo shortcut : folder.contents) {
+                        if (firstItem == null || firstItem.rank > shortcut.rank) {
+                            firstItem = shortcut;
+                        }
+                    }
+
+                    if (firstItem != null) {
+                        return mContext.getString(R.string.add_to_folder_with_app, firstItem.title);
+                    }
+                }
+                return mContext.getString(R.string.add_to_folder, info.title);
+            }
+        }
+        return "";
+    }
+}
diff --git a/src/com/android/launcher3/util/FlingAnimation.java b/src/com/android/launcher3/util/FlingAnimation.java
new file mode 100644
index 0000000..55c5d7d
--- /dev/null
+++ b/src/com/android/launcher3/util/FlingAnimation.java
@@ -0,0 +1,104 @@
+package com.android.launcher3.util;
+
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.launcher3.DragLayer;
+import com.android.launcher3.DragView;
+import com.android.launcher3.DropTarget.DragObject;
+
+public class FlingAnimation implements AnimatorUpdateListener {
+
+    /**
+     * Maximum acceleration in one dimension (pixels per milliseconds)
+     */
+    private static final float MAX_ACCELERATION = 0.5f;
+    private static final int DRAG_END_DELAY = 300;
+
+    protected final DragObject mDragObject;
+    protected final Rect mIconRect;
+    protected final DragLayer mDragLayer;
+    protected final Rect mFrom;
+    protected final int mDuration;
+    protected final float mUX, mUY;
+    protected final float mAnimationTimeFraction;
+    protected final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
+
+    protected float mAX, mAY;
+
+    /**
+     * @param vel initial fling velocity in pixels per second.
+     */
+    public FlingAnimation(DragObject d, PointF vel, Rect iconRect, DragLayer dragLayer) {
+        mDragObject = d;
+        mUX = vel.x / 1000;
+        mUY = vel.y / 1000;
+        mIconRect = iconRect;
+
+        mDragLayer = dragLayer;
+        mFrom = new Rect();
+        dragLayer.getViewRectRelativeToSelf(d.dragView, mFrom);
+
+        float scale = d.dragView.getScaleX();
+        float xOffset = ((scale - 1f) * d.dragView.getMeasuredWidth()) / 2f;
+        float yOffset = ((scale - 1f) * d.dragView.getMeasuredHeight()) / 2f;
+        mFrom.left += xOffset;
+        mFrom.right -= xOffset;
+        mFrom.top += yOffset;
+        mFrom.bottom -= yOffset;
+
+        mDuration = initDuration();
+        mAnimationTimeFraction = ((float) mDuration) / (mDuration + DRAG_END_DELAY);
+    }
+
+    /**
+     * The fling animation is based on the following system
+     *   - Apply a constant force in the y direction to causing the fling to decelerate.
+     *   - The animation runs for the time taken by the object to go out of the screen.
+     *   - Calculate a constant acceleration in x direction such that the object reaches
+     *     {@link #mIconRect} in the given time.
+     */
+    protected int initDuration() {
+        float sY = -mFrom.bottom;
+
+        float d = mUY * mUY + 2 * sY * MAX_ACCELERATION;
+        if (d >= 0) {
+            // sY can be reached under the MAX_ACCELERATION. Use MAX_ACCELERATION for y direction.
+            mAY = MAX_ACCELERATION;
+        } else {
+            // sY is not reachable, decrease the acceleration so that sY is almost reached.
+            d = 0;
+            mAY = mUY * mUY / (2 * -sY);
+        }
+        double t = (-mUY - Math.sqrt(d)) / mAY;
+
+        float sX = -mFrom.exactCenterX() + mIconRect.exactCenterX();
+
+        // Find horizontal acceleration such that: u*t + a*t*t/2 = s
+        mAX = (float) ((sX - t * mUX) * 2 / (t * t));
+        return (int) Math.round(t);
+    }
+
+    public final int getDuration() {
+        return mDuration + DRAG_END_DELAY;
+    }
+
+    @Override
+    public void onAnimationUpdate(ValueAnimator animation) {
+        float t = animation.getAnimatedFraction();
+        if (t > mAnimationTimeFraction) {
+            t = 1;
+        } else {
+            t = t / mAnimationTimeFraction;
+        }
+        final DragView dragView = (DragView) mDragLayer.getAnimatedView();
+        final float time = t * mDuration;
+        dragView.setTranslationX(time * mUX + mFrom.left + mAX * time * time / 2);
+        dragView.setTranslationY(time * mUY + mFrom.top + mAY * time * time / 2);
+        dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 0bc7333..2df170e 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -48,7 +48,7 @@
     private static final String TAG = "WidgetCell";
     private static final boolean DEBUG = false;
 
-    private static final int FADE_IN_DURATION_MS = 70;
+    private static final int FADE_IN_DURATION_MS = 90;
     private int mPresetPreviewSize;
 
     private ImageView mWidgetImage;
@@ -94,16 +94,25 @@
         mOriginalImagePadding.right = mWidgetImage.getPaddingRight();
         mOriginalImagePadding.bottom = mWidgetImage.getPaddingBottom();
 
-        // Ensure we are using the right text size
-        DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
         mWidgetName = ((TextView) findViewById(R.id.widget_name));
         mWidgetDims = ((TextView) findViewById(R.id.widget_dims));
     }
 
-    public void reset() {
+    /**
+     * Called to clear the view and free attached resources. (e.g., {@link Bitmap}
+     */
+    public void clear() {
+        if (DEBUG) {
+            Log.d(TAG, "reset called on:" + mWidgetName.getText());
+        }
         mWidgetImage.setImageDrawable(null);
         mWidgetName.setText(null);
         mWidgetDims.setText(null);
+
+        if (mActiveRequest != null) {
+            mActiveRequest.cleanup();
+            mActiveRequest = null;
+        }
     }
 
     /**
@@ -140,16 +149,6 @@
         mWidgetPreviewLoader = loader;
     }
 
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        deletePreview(false);
-
-        if (DEBUG) {
-            Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
-        }
-    }
-
     public int[] getPreviewSize() {
         int[] maxSize = new int[2];
         maxSize[0] = mPresetPreviewSize;
@@ -219,16 +218,6 @@
         return Math.min(size[0], info.spanX * cellWidth);
     }
 
-
-    private void deletePreview(boolean recycleImage) {
-        mWidgetImage.setImageDrawable(null);
-
-        if (mActiveRequest != null) {
-            mActiveRequest.cancel(recycleImage);
-            mActiveRequest = null;
-        }
-    }
-
     /**
      * Helper method to get the string info of the tag.
      */
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 27a3ea1..22e29f3 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -24,9 +24,9 @@
 import android.graphics.drawable.Drawable;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.State;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -61,11 +61,11 @@
     private static final String TAG = "WidgetsContainerView";
     private static final boolean DEBUG = false;
 
-    /* {@link RecyclerView} will keep following # of views in cache, before recycling. */
-    private static final int WIDGET_CACHE_SIZE = 2;
-
     private static final int SPRING_MODE_DELAY_MS = 150;
 
+    /* Coefficient multiplied to the screen height for preloading widgets. */
+    private static final int PRELOAD_SCREEN_HEIGHT_MULTIPLE = 1;
+
     /* Global instances that are used inside this container. */
     private Launcher mLauncher;
     private DragController mDragController;
@@ -118,9 +118,15 @@
         }
         mView = (RecyclerView) findViewById(R.id.widgets_list_view);
         mView.setAdapter(mAdapter);
-        mView.setLayoutManager(new LinearLayoutManager(getContext()));
-        mView.setItemViewCacheSize(WIDGET_CACHE_SIZE);
 
+        // This extends the layout space so that preloading happen for the {@link RecyclerView}
+        mView.setLayoutManager(new LinearLayoutManager(getContext()) {
+            @Override
+            protected int getExtraLayoutSpace(State state) {
+                return super.getExtraLayoutSpace(state)
+                        + WidgetsContainerView.this.getHeight() * PRELOAD_SCREEN_HEIGHT_MULTIPLE;
+            }
+        });
         mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
                 getPaddingBottom());
     }
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index f6ab21e..a7728a1 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -120,14 +120,15 @@
             mIconCache.getTitleAndIconForApp(infoOut.packageName,
                     UserHandleCompat.myUserHandle(), false /* useLowResIcon */, infoOut);
         }
-        ((TextView) holder.getContent().findViewById(R.id.section)).setText(infoOut.title);
+
+        TextView tv = ((TextView) holder.getContent().findViewById(R.id.section));
+        tv.setText(infoOut.title);
         ImageView iv = (ImageView) holder.getContent().findViewById(R.id.section_image);
         iv.setImageBitmap(infoOut.iconBitmap);
 
         // Bind the view in the widget horizontal tray region.
         for (int i=0; i < infoList.size(); i++) {
             WidgetCell widget = (WidgetCell) row.getChildAt(i);
-            widget.reset();
             if (getWidgetPreviewLoader() == null) {
                 return;
             }
@@ -150,7 +151,7 @@
     @Override
     public WidgetsRowViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         if (DEBUG) {
-            Log.v(TAG, String.format("\nonCreateViewHolder, [widget#=%d]", viewType));
+            Log.v(TAG, "\nonCreateViewHolder");
         }
 
         ViewGroup container = (ViewGroup) mLayoutInflater.inflate(
@@ -159,6 +160,16 @@
     }
 
     @Override
+    public void onViewRecycled(WidgetsRowViewHolder holder) {
+        ViewGroup row = ((ViewGroup) holder.getContent().findViewById(R.id.widgets_cell_list));
+
+        for (int i = 0; i < row.getChildCount(); i++) {
+            WidgetCell widget = (WidgetCell) row.getChildAt(i);
+            widget.clear();
+        }
+    }
+
+    @Override
     public long getItemId(int pos) {
         return pos;
     }
diff --git a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
index 99a192c..249559a 100644
--- a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
+++ b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
@@ -25,7 +25,7 @@
 
     ViewGroup mContent;
 
-   public WidgetsRowViewHolder(ViewGroup v) {
+    public WidgetsRowViewHolder(ViewGroup v) {
         super(v);
         mContent = v;
     }