Merge "Replacing overview panel icons with vector drawables" into ub-launcher3-calgary
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index eb7ea0c..3a3a28d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -49,7 +49,16 @@
     <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
     <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />
 
-    <application>
+    <application
+        android:backupAgent="com.android.launcher3.LauncherBackupAgent"
+        android:fullBackupOnly="true"
+        android:fullBackupContent="@xml/backupscheme"
+        android:hardwareAccelerated="true"
+        android:icon="@mipmap/ic_launcher_home"
+        android:label="@string/app_name"
+        android:largeHeap="@bool/config_largeHeap"
+        android:restoreAnyVersion="true"
+        android:supportsRtl="true" >
 
         <!--
         Main launcher activity. When extending only change the name, and keep all the
diff --git a/res/drawable/focusable_view_bg.xml b/res/drawable/focusable_view_bg.xml
deleted file mode 100644
index e156513..0000000
--- a/res/drawable/focusable_view_bg.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2011 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_focused="true">
-        <shape android:shape="rectangle">
-            <solid android:color="@color/focused_background" />
-        </shape>
-    </item>
-
-</selector>
\ No newline at end of file
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 3a361e2..d193e2f 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -30,11 +30,6 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
-        <com.android.launcher3.FocusIndicatorView
-            android:id="@+id/focus_indicator"
-            android:layout_width="52dp"
-            android:layout_height="52dp" />
-
         <!-- The workspace contains 5 screens of cells -->
         <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
@@ -51,12 +46,8 @@
             android:layout_gravity="right" />
 
         <include
-            android:id="@+id/app_info_drop_target_bar"
-            layout="@layout/drop_target_bar_vert_info" />
-
-        <include
-            android:id="@+id/search_drop_target_bar"
-            layout="@layout/drop_target_bar_vert_search" />
+            android:id="@+id/drop_target_bar"
+            layout="@layout/drop_target_bar_vert" />
 
         <include layout="@layout/overview_panel"
             android:id="@+id/overview_panel"
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 4576e4d..527ed54 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -31,11 +31,6 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
-        <com.android.launcher3.FocusIndicatorView
-            android:id="@+id/focus_indicator"
-            android:layout_width="52dp"
-            android:layout_height="52dp" />
-
         <!-- The workspace contains 5 screens of cells -->
         <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
@@ -60,15 +55,11 @@
         <com.android.launcher3.pageindicators.PageIndicatorLine
             android:id="@+id/page_indicator"
             android:layout_width="match_parent"
-            android:layout_height="1dp" />
+            android:layout_height="@dimen/dynamic_grid_page_indicator_height" />
 
         <include
-            android:id="@+id/app_info_drop_target_bar"
-            layout="@layout/drop_target_bar_horz_info" />
-
-        <include
-            android:id="@+id/search_drop_target_bar"
-            layout="@layout/drop_target_bar_horz_search" />
+            android:id="@+id/drop_target_bar"
+            layout="@layout/drop_target_bar_horz" />
 
         <include layout="@layout/widgets_view"
             android:id="@+id/widgets_view"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 0f755d8..184e688 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -30,11 +30,6 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
-        <com.android.launcher3.FocusIndicatorView
-            android:id="@+id/focus_indicator"
-            android:layout_width="52dp"
-            android:layout_height="52dp" />
-
         <!-- The workspace contains 5 screens of cells -->
         <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
@@ -51,12 +46,8 @@
             android:layout_height="match_parent" />
 
         <include
-            android:id="@+id/app_info_drop_target_bar"
-            layout="@layout/drop_target_bar_horz_info" />
-
-        <include
-            android:id="@+id/search_drop_target_bar"
-            layout="@layout/drop_target_bar_horz_search" />
+            android:id="@+id/drop_target_bar"
+            layout="@layout/drop_target_bar_horz" />
 
         <include layout="@layout/overview_panel"
             android:id="@+id/overview_panel"
@@ -67,7 +58,7 @@
         <com.android.launcher3.pageindicators.PageIndicatorLine
             android:id="@+id/page_indicator"
             android:layout_width="match_parent"
-            android:layout_height="1dp" />
+            android:layout_height="@dimen/dynamic_grid_page_indicator_height" />
 
         <include layout="@layout/widgets_view"
             android:id="@+id/widgets_view"
diff --git a/res/layout/all_apps_icon.xml b/res/layout/all_apps_icon.xml
index bb95c5f..3836fed 100644
--- a/res/layout/all_apps_icon.xml
+++ b/res/layout/all_apps_icon.xml
@@ -24,6 +24,5 @@
     android:paddingTop="@dimen/all_apps_icon_top_bottom_padding"
     android:paddingBottom="@dimen/all_apps_icon_top_bottom_padding"
     android:focusable="true"
-    android:background="@drawable/focusable_view_bg"
     launcher:iconDisplay="all_apps" />
 
diff --git a/res/layout/all_apps_prediction_bar_icon.xml b/res/layout/all_apps_prediction_bar_icon.xml
index f15aeaf..295b0b7 100644
--- a/res/layout/all_apps_prediction_bar_icon.xml
+++ b/res/layout/all_apps_prediction_bar_icon.xml
@@ -24,6 +24,5 @@
     android:paddingTop="@dimen/all_apps_prediction_icon_top_padding"
     android:paddingBottom="@dimen/all_apps_prediction_icon_bottom_padding"
     android:focusable="true"
-    android:background="@drawable/focusable_view_bg"
     launcher:iconDisplay="all_apps" />
 
diff --git a/res/layout/all_apps_search_market.xml b/res/layout/all_apps_search_market.xml
index ef5e76c..4bdca99 100644
--- a/res/layout/all_apps_search_market.xml
+++ b/res/layout/all_apps_search_market.xml
@@ -24,6 +24,7 @@
     android:fontFamily="sans-serif-medium"
     android:textSize="14sp"
     android:textColor="@color/launcher_accent_color"
+    android:text="@string/all_apps_search_market_message"
     android:textAllCaps="true"
     android:focusable="true"
     android:background="?android:selectableItemBackground" />
diff --git a/res/layout/drop_target_bar_horz.xml b/res/layout/drop_target_bar_horz.xml
new file mode 100644
index 0000000..ee22d1e
--- /dev/null
+++ b/res/layout/drop_target_bar_horz.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.DropTargetBar
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/dynamic_grid_drop_target_size"
+    android:layout_gravity="center_horizontal|top"
+    android:focusable="false">
+
+    <FrameLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1" >
+
+        <!-- Delete target -->
+
+        <com.android.launcher3.DeleteDropTarget
+            launcher:hideParentOnDisable="true"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:id="@+id/delete_target_text"
+            style="@style/DropTargetButton"
+            android:text="@string/remove_drop_target_label" />
+    </FrameLayout>
+
+    <FrameLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1" >
+
+        <!-- App Info -->
+
+        <com.android.launcher3.InfoDropTarget
+            launcher:hideParentOnDisable="true"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:id="@+id/info_target_text"
+            style="@style/DropTargetButton"
+            android:text="@string/app_info_drop_target_label" />
+    </FrameLayout>
+
+    <FrameLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1" >
+
+        <!-- Uninstall target -->
+
+        <com.android.launcher3.UninstallDropTarget
+            launcher:hideParentOnDisable="true"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:id="@+id/uninstall_target_text"
+            style="@style/DropTargetButton"
+            android:text="@string/uninstall_drop_target_label" />
+    </FrameLayout>
+
+</com.android.launcher3.DropTargetBar>
\ No newline at end of file
diff --git a/res/layout/drop_target_bar_horz_info.xml b/res/layout/drop_target_bar_horz_info.xml
deleted file mode 100644
index 92a9b22..0000000
--- a/res/layout/drop_target_bar_horz_info.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 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.
--->
-<com.android.launcher3.AppInfoDropTargetBar xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="48dp"
-    android:layout_gravity="center_horizontal|bottom"
-    android:focusable="false" >
-
-    <FrameLayout
-        android:id="@+id/drag_target_bar"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <!-- Info target -->
-
-        <com.android.launcher3.InfoDropTarget
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_gravity="center"
-            android:gravity="center"
-            android:id="@+id/info_target_text"
-            style="@style/DropTargetButton"
-            android:text="@string/app_info_drop_target_label" />
-    </FrameLayout>
-</com.android.launcher3.AppInfoDropTargetBar>
\ No newline at end of file
diff --git a/res/layout/drop_target_bar_horz_search.xml b/res/layout/drop_target_bar_horz_search.xml
deleted file mode 100644
index 7997801..0000000
--- a/res/layout/drop_target_bar_horz_search.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.launcher3.SearchDropTargetBar xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="center_horizontal|top"
-    android:focusable="false">
-
-    <!-- Drag specific targets container -->
-
-    <LinearLayout
-        android:id="@+id/drag_target_bar"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="center" >
-
-        <FrameLayout
-            android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_weight="1" >
-
-            <!-- Delete target -->
-
-            <com.android.launcher3.DeleteDropTarget
-                launcher:hideParentOnDisable="true"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:layout_gravity="center"
-                android:gravity="center"
-                android:id="@+id/delete_target_text"
-                style="@style/DropTargetButton"
-                android:text="@string/remove_drop_target_label" />
-        </FrameLayout>
-
-        <FrameLayout
-            android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_weight="1" >
-
-            <!-- Uninstall target -->
-
-            <com.android.launcher3.UninstallDropTarget
-                launcher:hideParentOnDisable="true"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:layout_gravity="center"
-                android:gravity="center"
-                android:id="@+id/uninstall_target_text"
-                style="@style/DropTargetButton"
-                android:text="@string/uninstall_drop_target_label" />
-        </FrameLayout>
-    </LinearLayout>
-
-</com.android.launcher3.SearchDropTargetBar>
\ No newline at end of file
diff --git a/res/layout/drop_target_bar_vert.xml b/res/layout/drop_target_bar_vert.xml
new file mode 100644
index 0000000..10b1d7c
--- /dev/null
+++ b/res/layout/drop_target_bar_vert.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 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.
+-->
+<com.android.launcher3.DropTargetBar
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/dynamic_grid_drop_target_size"
+    android:orientation="vertical"
+    android:layout_height="match_parent"
+    android:layout_gravity="left"
+    android:focusable="false"
+    android:paddingTop="@dimen/vert_drop_target_vertical_gap" >
+
+    <!-- Delete target -->
+    <com.android.launcher3.DeleteDropTarget
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/dynamic_grid_drop_target_size"
+        android:gravity="center"
+        android:paddingLeft="@dimen/vert_drop_target_horizontal_gap"
+        android:paddingRight="@dimen/vert_drop_target_horizontal_gap"
+        android:id="@+id/delete_target_text"
+        android:textColor="@android:color/white" />
+
+    <!-- Uninstall target -->
+    <com.android.launcher3.UninstallDropTarget
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/dynamic_grid_drop_target_size"
+        android:gravity="center"
+        android:paddingLeft="@dimen/vert_drop_target_horizontal_gap"
+        android:paddingRight="@dimen/vert_drop_target_horizontal_gap"
+        android:id="@+id/uninstall_target_text"
+        android:textColor="@android:color/white"
+        android:layout_marginTop="@dimen/vert_drop_target_vertical_gap"/>
+
+    <Space
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <!-- App Info -->
+    <com.android.launcher3.InfoDropTarget
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/dynamic_grid_drop_target_size"
+        android:gravity="center"
+        android:paddingLeft="@dimen/vert_drop_target_horizontal_gap"
+        android:paddingRight="@dimen/vert_drop_target_horizontal_gap"
+        android:id="@+id/info_target_text"
+        android:textColor="@android:color/white"
+        android:layout_marginBottom="64dp"/>
+
+</com.android.launcher3.DropTargetBar>
\ No newline at end of file
diff --git a/res/layout/drop_target_bar_vert_info.xml b/res/layout/drop_target_bar_vert_info.xml
deleted file mode 100644
index da33d1a..0000000
--- a/res/layout/drop_target_bar_vert_info.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 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.
--->
-<com.android.launcher3.AppInfoDropTargetBar xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="48dp"
-    android:layout_height="match_parent"
-    android:focusable="false" >
-
-    <FrameLayout
-        android:id="@+id/drag_target_bar"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <!-- Info target -->
-        <com.android.launcher3.InfoDropTarget
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:layout_gravity="center_horizontal|bottom"
-            android:gravity="center"
-            android:paddingLeft="14dp"
-            android:paddingRight="14dp"
-            android:textColor="@android:color/white"
-            android:id="@+id/info_target_text" />
-    </FrameLayout>
-
-</com.android.launcher3.AppInfoDropTargetBar>
\ No newline at end of file
diff --git a/res/layout/drop_target_bar_vert_search.xml b/res/layout/drop_target_bar_vert_search.xml
deleted file mode 100644
index d5e41df..0000000
--- a/res/layout/drop_target_bar_vert_search.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.launcher3.SearchDropTargetBar xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="48dp"
-    android:layout_height="match_parent"
-    android:focusable="false">
-
-    <!-- Drag specific targets container -->
-
-    <LinearLayout
-        android:id="@+id/drag_target_bar"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        android:layout_gravity="center"
-        android:paddingTop="20dp">
-
-        <!-- Delete target -->
-        <com.android.launcher3.DeleteDropTarget
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:gravity="center"
-            android:paddingLeft="14dp"
-            android:paddingRight="14dp"
-            android:id="@+id/delete_target_text"
-            android:textColor="@android:color/white"
-            android:layout_marginBottom="10dp" />
-
-        <!-- Uninstall target -->
-        <com.android.launcher3.UninstallDropTarget
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:layout_gravity="center"
-            android:gravity="center"
-            android:paddingLeft="14dp"
-            android:paddingRight="14dp"
-            android:id="@+id/uninstall_target_text"
-            android:textColor="@android:color/white"
-            android:layout_marginTop="10dp"/>
-    </LinearLayout>
-
-</com.android.launcher3.SearchDropTargetBar>
\ No newline at end of file
diff --git a/res/layout/qsb_container.xml b/res/layout/qsb_container.xml
new file mode 100644
index 0000000..55c7390
--- /dev/null
+++ b/res/layout/qsb_container.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 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.
+-->
+<com.android.launcher3.QsbContainerView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/qsb_container"
+        android:padding="0dp" >
+
+    <fragment
+        android:name="com.android.launcher3.QsbContainerView$QsbFragment"
+        android:layout_width="match_parent"
+        android:tag="qsb_view"
+        android:layout_height="match_parent"/>
+</com.android.launcher3.QsbContainerView>
\ No newline at end of file
diff --git a/res/layout/qsb_default_view.xml b/res/layout/qsb_default_view.xml
new file mode 100644
index 0000000..82bdea5
--- /dev/null
+++ b/res/layout/qsb_default_view.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:layout_margin="16dp"
+        android:layout_gravity="center_vertical"
+        android:background="@drawable/quantum_panel_shape"
+        android:elevation="2dp"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="0dp"
+            android:id="@+id/btn_qsb_search"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center_vertical"
+            android:paddingStart="16dp"
+            android:text="@string/abandoned_search"
+            android:textColor="@color/quantum_panel_text_color"
+            android:textAppearance="?android:textAppearanceMedium"
+            android:clickable="true"
+            android:background="?android:attr/selectableItemBackground" />
+        <ImageView
+            android:layout_width="48dp"
+            android:id="@+id/btn_qsb_setup"
+            android:clickable="true"
+            android:visibility="gone"
+            android:layout_height="match_parent"
+            android:src="@drawable/ic_setting"
+            android:tint="@color/quantum_panel_text_color"
+            android:contentDescription="@string/gadget_setup_text"
+            android:padding="8dp"
+            android:background="?android:attr/selectableItemBackground" />
+    </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index 8a1b7d0..d950750 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -22,27 +22,14 @@
     android:elevation="5dp"
     android:orientation="vertical" >
 
-    <FrameLayout
-        android:id="@+id/folder_content_wrapper"
+    <com.android.launcher3.folder.FolderPagedView
+        android:id="@+id/folder_content"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" >
-
-        <!-- Actual size of the indicator doesn't matter as it is scaled to match the view size -->
-
-        <com.android.launcher3.FocusIndicatorView
-            android:id="@+id/focus_indicator"
-            android:layout_width="20dp"
-            android:layout_height="20dp" />
-
-        <com.android.launcher3.folder.FolderPagedView
-            android:id="@+id/folder_content"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:paddingLeft="4dp"
-            android:paddingRight="4dp"
-            android:paddingTop="8dp"
-            launcher:pageIndicator="@+id/folder_page_indicator" />
-    </FrameLayout>
+        android:layout_height="match_parent"
+        android:paddingLeft="4dp"
+        android:paddingRight="4dp"
+        android:paddingTop="8dp"
+        launcher:pageIndicator="@+id/folder_page_indicator" />
 
     <LinearLayout
         android:id="@+id/folder_footer"
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index de1316e..bb6bd76 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -22,27 +22,14 @@
     android:elevation="5dp"
     android:orientation="vertical" >
 
-    <FrameLayout
-        android:id="@+id/folder_content_wrapper"
+    <com.android.launcher3.folder.FolderPagedView
+        android:id="@+id/folder_content"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" >
-
-        <!-- Actual size of the indicator doesn't matter as it is scaled to match the view size -->
-
-        <com.android.launcher3.FocusIndicatorView
-            android:id="@+id/focus_indicator"
-            android:layout_width="20dp"
-            android:layout_height="20dp" />
-
-        <com.android.launcher3.folder.FolderPagedView
-            android:id="@+id/folder_content"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:paddingLeft="8dp"
-            android:paddingRight="8dp"
-            android:paddingTop="8dp"
-            launcher:pageIndicator="@+id/folder_page_indicator" />
-    </FrameLayout>
+        android:layout_height="match_parent"
+        android:paddingLeft="8dp"
+        android:paddingRight="8dp"
+        android:paddingTop="8dp"
+        launcher:pageIndicator="@+id/folder_page_indicator" />
 
     <LinearLayout
         android:id="@+id/folder_footer"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index ed5ad77..e25fd4e 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Deursoek programme …"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Laai tans programme …"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Geen programme gevind wat met \"<xliff:g id="QUERY">%1$s</xliff:g>\" ooreenstem nie"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Gaan na <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Niks meer spasie op die tuisskerm nie."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Geen plek meer in die Gunstelinge-laai nie"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Programme"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index c8070f0..40b1694 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"መተግበሪያዎችን ይፈልጉ…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"መተግበሪያዎችን በመጫን ላይ..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"ከ«<xliff:g id="QUERY">%1$s</xliff:g>» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"ወደ <xliff:g id="QUERY">%1$s</xliff:g> ሂድ"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"በዚህ መነሻ ማያ ገጽ ላይ ምንም ቦታ የለም።"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"በተወዳጆች መሣቢያ ውስጥ ተጨማሪ ቦታ የለም"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"መተግበሪያዎች"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index e059d26..f555ee1 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"البحث في التطبيقات…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"جارٍ تحميل التطبيقات…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"لم يتم العثور على أية تطبيقات تتطابق مع \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"الانتقال إلى <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"ليس هناك مساحة أخرى في هذه الشاشة الرئيسية."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"لا يوجد المزيد من الحقول في علبة المفضلة"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"التطبيقات"</string>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
index 239d718..cf109b4 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az-rAZ/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Tətbiqləri Axtarın..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Tətbiqlər endirilir..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" sorğusuna uyğun Tətbiqlər tapılmadı"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> daxil olun"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Bu Əsas ekranda boş yer yoxdur."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritlər-də yer yoxdur"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Tətbiqlər"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index a09d457..b2c072f 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Търсене в приложенията…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Приложенията се зареждат…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Няма намерени приложения, съответстващи на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Отваряне на <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"На този начален екран няма повече място."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Няма повече място в областта с любимите"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Приложения"</string>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index a584f17..271d739 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"অ্যাপ্লিকেশানগুলি অনুসন্ধান করুন..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"অ্যাপ্লিকেশানগুলি লোড হচ্ছে..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" এর সাথে মেলে এমন কোনো অ্যাপ্লিকেশান পাওয়া যায়নি"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> এ যান"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"এই হোম স্ক্রীনে আর কোনো জায়গা নেই৷"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"পছন্দসই ট্রে-তে আর কোনো জায়গা নেই"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"অ্যাপ্লিকেশানগুলি"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 8027031..1704459 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Cerca a les aplicacions…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"S\'estan carregant les aplicacions..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No s\'ha trobat cap aplicació que coincideixi amb <xliff:g id="QUERY">%1$s</xliff:g>"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Vés a <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Ja no queda espai en aquesta pantalla d\'inici."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No hi ha més espai a la safata Preferits."</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicacions"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index a047c39..9a7459d 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Hledat v aplikacích…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Načítání aplikací…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Dotazu „<xliff:g id="QUERY">%1$s</xliff:g>“ neodpovídají žádné aplikace"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Přejít na <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Na této ploše již není místo."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Na panelu Oblíbené položky již není místo."</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikace"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index c24c159..811a802 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Søg i Apps…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Indlæser apps…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Der blev ikke fundet nogen apps, som matcher \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Gå til <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Der er ikke mere plads på denne startskærm."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Der er ikke mere plads i bakken Foretrukne"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 4633adb..a87ccd8 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Apps suchen…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Apps werden geladen..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Keine Apps für \"<xliff:g id="QUERY">%1$s</xliff:g>\" gefunden"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Gehe zu <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Auf diesem Startbildschirm ist kein Platz mehr vorhanden."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ablage \"Favoriten\" ist voll."</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index fd8f1f8..f2081e7 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Αναζήτηση εφαρμογών…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Φόρτωση εφαρμογών…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Δεν βρέθηκαν εφαρμογές για το ερώτημα \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Μετάβαση σε <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Δεν υπάρχει χώρος σε αυτήν την αρχική οθόνη."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Δεν υπάρχει επιπλέον χώρος στην περιοχή Αγαπημένα"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Εφαρμογές"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 23882b1..781ddee 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Search Apps…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Go to <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
@@ -59,7 +60,7 @@
     <string name="migration_cling_description" msgid="2752413805582227644">"Import icons and folders from your old Home screens?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPY ICONS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START AFRESH"</string>
-    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets, &amp; settings"</string>
+    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets &amp; settings"</string>
     <string name="workspace_cling_longpress_description" msgid="6569028007301925917">"Tap &amp; hold background to customise"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"GOT IT"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder opened, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 23882b1..781ddee 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Search Apps…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Go to <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
@@ -59,7 +60,7 @@
     <string name="migration_cling_description" msgid="2752413805582227644">"Import icons and folders from your old Home screens?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPY ICONS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START AFRESH"</string>
-    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets, &amp; settings"</string>
+    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets &amp; settings"</string>
     <string name="workspace_cling_longpress_description" msgid="6569028007301925917">"Tap &amp; hold background to customise"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"GOT IT"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder opened, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 23882b1..781ddee 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Search Apps…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Go to <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
@@ -59,7 +60,7 @@
     <string name="migration_cling_description" msgid="2752413805582227644">"Import icons and folders from your old Home screens?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPY ICONS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START AFRESH"</string>
-    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets, &amp; settings"</string>
+    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets &amp; settings"</string>
     <string name="workspace_cling_longpress_description" msgid="6569028007301925917">"Tap &amp; hold background to customise"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"GOT IT"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder opened, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 0061f66..fd32a19 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Buscar apps…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicaciones…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No hay aplicaciones que coincidan con <xliff:g id="QUERY">%1$s</xliff:g>."</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Ir a <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"No hay más espacio en esta pantalla principal."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"La bandeja de favoritos está llena."</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicaciones"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 1169f44..8e5d07f 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Buscar aplicaciones…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicaciones…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No se han encontrado aplicaciones que contengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Ir a <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"No queda espacio en la pantalla de inicio."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"La bandeja de favoritos está completa"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicaciones"</string>
@@ -76,10 +77,10 @@
     <string name="allow_rotation_desc" msgid="7635719920854330492">"Al girar el dispositivo"</string>
     <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"La configuración de pantalla actual no permite girar la pantalla"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string>
-    <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string>
+    <string name="abandoned_clean_this" msgid="7610119707847920412">"Quitar"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicación no está instalada"</string>
-    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"La aplicación de este icono no está instalada. Puedes eliminar el icono o buscar la aplicación e instalarla manualmente."</string>
+    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"La aplicación de este icono no está instalada. Puedes quitar el icono o buscar la aplicación e instalarla manualmente."</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Descargando <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="PROGRESS">%2$s</xliff:g> completado)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Esperando para instalar <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Añadir a la pantalla de inicio"</string>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
index 3fb031a..00f960d 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et-rEE/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Otsimine rakendustest …"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Rakenduste laadimine ..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Päringule „<xliff:g id="QUERY">%1$s</xliff:g>” ei vastanud ükski rakendus"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Mine: <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Sellel avaekraanil pole enam ruumi."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Salves Lemmikud pole rohkem ruumi"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Rakendused"</string>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index 6688ed4..e410597 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Bilatu aplikazioetan…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Aplikazioak kargatzen…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ez da aurkitu \"<xliff:g id="QUERY">%1$s</xliff:g>\" bilaketarekin bat datorren aplikaziorik"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Joan hona: <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Hasierako pantaila honetan ez dago toki gehiago."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ez dago toki gehiago Gogokoak erretiluan"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikazioak"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 720bb31..747da84 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"جستجوی برنامه‌ها…‏‏"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"در حال بارگیری برنامه‌ها..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"هیچ برنامه‌ای مطابق با «<xliff:g id="QUERY">%1$s</xliff:g>» پیدا نشد"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"رفتن به <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"فضای بیشتری در این صفحه اصلی موجود نیست."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"فضای بیشتری در سینی موارد دلخواه وجود ندارد"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"برنامه‌ها"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index ac14d86..c97d7b1 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Hae sovelluksia…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Ladataan sovelluksia…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"”<xliff:g id="QUERY">%1$s</xliff:g>” ei palauttanut sovelluksia."</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Siirry: <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Tässä aloitusruudussa ei ole enää tilaa."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Suosikit-valikossa ei ole enää tilaa"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Sovellukset"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index c87169f..265e636 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Rechercher des applications..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Chargement des applications en cours..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Aucune application trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Aller à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Pas d\'espace libre sur l\'écran d\'accueil."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Il n\'y a plus d\'espace dans la zone des favoris"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Applications"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 192a025..af19699 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Rechercher des applications…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Chargement des applications en cours…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Aucune application ne correspond à la requête \"<xliff:g id="QUERY">%1$s</xliff:g>\"."</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Accéder à <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Pas d\'espace libre sur cet écran d\'accueil."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Plus d\'espace disponible dans la zone de favoris."</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Applications"</string>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index 6ddef28..115497a 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Buscar aplicacións..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicacións..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Non se atoparon aplicacións que coincidan con \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Ir a <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Non hai máis espazo nesta pantalla de inicio."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Non hai máis espazo na bandexa de favoritos"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicacións"</string>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index fbe3efe..ef37318 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"ઍપ્લિકેશનોમાં શોધો…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ઍપ્લિકેશનો લોડ કરી રહ્યું છે…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> પર જાઓ"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"આ હોમ સ્ક્રીન પર વધુ જગ્યા નથી."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"મનપસંદ ટ્રે પર વધુ જગ્યા નથી"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ઍપ્લિકેશનો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 695a1e6..742cd90 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"ऐप्स खोजें…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ऐप्स लोड हो रहे हैं..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" से मिलान करने वाला कोई ऐप नहीं मिला"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> पर जाएं"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"इस होम स्‍क्रीन पर स्थान शेष नहीं है."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"पसंदीदा ट्रे में और स्थान नहीं है"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ऐप्लिकेशन"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 61b365f..027c926 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Pretraživanje aplikacija…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Učitavanje aplikacija…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nema aplikacija podudarnih s upitom \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Idite na <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Na ovom početnom zaslonu više nema mjesta."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora na traci Favoriti"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikacije"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index f558fb6..783a367 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Alkalmazások keresése…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Alkalmazások betöltése…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Egy alkalmazás sem található a(z) „<xliff:g id="QUERY">%1$s</xliff:g>” lekérdezésre."</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Keresse fel ezt: <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Nincs több hely ezen a kezdőképernyőn."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nincs több hely a Kedvencek tálcán"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Alkalmazások"</string>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index 1f2de4c..8d57e59 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Հավելվածների որոնում…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Հավելվածների բեռնում…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"«<xliff:g id="QUERY">%1$s</xliff:g>» հարցմանը համապատասխանող հավելվածներ չեն գտնվել"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Գնալ <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Այլևս տեղ չկա այս հիմնական էկրանին:"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ընտրյալների ցուցակում այլևս ազատ տեղ չկա"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Ծրագրեր"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 50aa03d..3faefb7 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Telusuri Aplikasi..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Memuat Aplikasi..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Tidak ditemukan Aplikasi yang cocok dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Buka <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Tidak ada ruang lagi pada layar Utama ini."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Tidak ada ruang tersisa di baki Favorit"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikasi"</string>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
index c2f3396..42cb440 100644
--- a/res/values-is-rIS/strings.xml
+++ b/res/values-is-rIS/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Leita í forritum…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Hleður forrit…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ekki fundust forrit sem samsvara „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Fara í <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Ekki meira pláss á þessum heimaskjá."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ekki meira pláss í bakka fyrir uppáhald"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Forrit"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 467094f..b651bc8 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Ricerca app…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Caricamento di app…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nessuna app trovata corrispondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Vai a <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Spazio nella schermata Home esaurito."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Spazio esaurito nella barra dei Preferiti"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"App"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 14d0aa6..44bcd87 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"חיפוש אפליקציות..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"טוען אפליקציות…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"לא נמצאו אפליקציות התואמות ל-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"עבור אל <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"אין עוד מקום במסך דף הבית הזה."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"אין עוד מקום במגש המועדפים"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"אפליקציות"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index e86e56f..e70770c 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"アプリを検索…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"アプリを読み込んでいます…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"「<xliff:g id="QUERY">%1$s</xliff:g>」に一致するアプリは見つかりませんでした"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g>にアクセス"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"このホーム画面に空きスペースがありません。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"お気に入りトレイに空きスペースがありません"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"アプリ"</string>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index 682cc12..b531a56 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"აპების ძიება…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"აპები იტვირთება..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"„<xliff:g id="QUERY">%1$s</xliff:g>“-ის თანხვედრი აპები არ მოიძებნა"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"გადადი <xliff:g id="QUERY">%1$s</xliff:g>-ში"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"ამ მთავარ ეკრანზე ადგილი აღარ არის."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"რჩეულების თაროზე ადგილი არ არის"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"აპები"</string>
@@ -59,7 +60,7 @@
     <string name="migration_cling_description" msgid="2752413805582227644">"გსურთ, ძველი მთავარი ეკრანიდან ხატულების და საქაღ. იმპორტი?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ხატულების კოპირება"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"სტანდარტული განლაგება"</string>
-    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"ფონები, ვიჯეტები, &amp; პარამეტრები"</string>
+    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"ფონები, ვიჯეტები &amp; პარამეტრები"</string>
     <string name="workspace_cling_longpress_description" msgid="6569028007301925917">"მოსარგებად, ხანგრძლივად შეეხეთ ფონს."</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"გასაგებია"</string>
     <string name="folder_opened" msgid="94695026776264709">"საქაღალდე გახსნილია, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
index 3fa3d80..7c9aaee 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk-rKZ/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Қолданбаларды іздеу…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Қолданбалар жүктелуде…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"«<xliff:g id="QUERY">%1$s</xliff:g>» сұрауына сәйкес келетін қолданбалар жоқ"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> сұрауына өту"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Бұл Негізгі экранда орын қалмады."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Қалаулылар науасында орын қалмады"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Қолданбалар"</string>
@@ -69,7 +70,7 @@
     <string name="folder_renamed" msgid="1794088362165669656">"Қалта атауы <xliff:g id="NAME">%1$s</xliff:g> болып өзгертілді"</string>
     <string name="folder_name_format" msgid="6629239338071103179">"Қалта: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Виджеттер"</string>
-    <string name="wallpaper_button_text" msgid="8404103075899945851">"Артқы фондар"</string>
+    <string name="wallpaper_button_text" msgid="8404103075899945851">"Тұсқағаздар"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Параметрлер"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Әкімші өшірді"</string>
     <string name="allow_rotation_title" msgid="3132336367556833843">"Негізгі экранды айналдыруды рұқсат ету"</string>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
index 4cd6856..dc9b606 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km-rKH/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"ស្វែងរកកម្មវិធី…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"កំពុងដំណើរការកម្មវិធី..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"គ្មានកម្មវិធីដែលត្រូវជាមួយ \"<xliff:g id="QUERY">%1$s</xliff:g>\" ទេ"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"ចូលទៅកាន់ <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"គ្មាន​បន្ទប់​នៅ​លើ​អេក្រង់​ដើម​នេះ​ទៀត​ទេ។"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"គ្មាន​បន្ទប់​​ក្នុង​ថាស​និយម​ប្រើ"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"កម្មវិធី"</string>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index dcd64ec..5d6ec41 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"ಅಪ್ಲಿಕೇಷನ್‌ಗಳನ್ನು ಹುಡುಕಿ..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> ಗೆ ಹೋಗಿ"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಹೆಚ್ಚು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ಮೆಚ್ಚಿನವುಗಳ ಟ್ರೇನಲ್ಲಿ ಹೆಚ್ಚಿನ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 572c62d..5fd20e2 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"앱 검색..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"앱 로드 중..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\'<xliff:g id="QUERY">%1$s</xliff:g>\'와(과) 일치하는 앱이 없습니다."</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g>(으)로 이동"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"홈 화면에 더 이상 공간이 없습니다."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"즐겨찾기 트레이에 더 이상 공간이 없습니다."</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"앱"</string>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
index 2edd170..8fce8c8 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky-rKG/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Колдонмолорду издөө…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Колдонмолор жүктөлүүдө…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" дал келген колдонмолор табылган жок"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> сурамына өтүңүз"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Бул Үй экранында бош орун жок."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Тандамалдар тайпасында орун калган жок"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Колдонмолор"</string>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
index 228bd90..24e6096 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo-rLA/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"ຄົ້ນຫາແອັບ"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"​ກຳ​ລັງ​ໂຫລດ​ແອັບ..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"ບໍ່​ພົບ​ແອັບ​ໃດ​ທີ່​ກົງ​ກັນ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"ໄປ​ທີ່ <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"ບໍ່ມີຫ້ອງເຫຼືອໃນໜ້າຈໍຫຼັກນີ້."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ບໍ່ມີບ່ອນຫວ່າງໃນຖາດສຳລັບເກັບສິ່ງທີ່ໃຊ້ເປັນປະຈຳ"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ແອັບຯ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 3796c26..f48f569 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Ieškoti programų..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Įkeliamos programos..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nerasta jokių užklausą „<xliff:g id="QUERY">%1$s</xliff:g>“ atitinkančių programų"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Eiti į <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Šiame pagrindiniame ekrane vietos nebėra."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Mėgstamiausių dėkle nebėra vietos"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Programos"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index c592d3b..7aaab86 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Meklēt lietotnes…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Notiek lietotņu ielāde…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Vaicājumam “<xliff:g id="QUERY">%1$s</xliff:g>” neatbilda neviena lietotne."</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Doties uz: <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Šajā sākuma ekrānā vairs nav vietas."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Izlases joslā vairs nav vietas."</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Lietotnes"</string>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
index a691bce..d7c67f2 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Пребарувај апликации…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Се вчитуваат апликации…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Не се најдени апликации што одговараат на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Оди на <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Нема повеќе простор на овој екран на почетната страница."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Нема повеќе простор на лентата „Омилени“"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Апликации"</string>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index 5cfff55..94dd5b5 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"ആപ്പ്‌സ് തിരയുക…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ആപ്പ്‌സ് ലോഡുചെയ്യുന്നു..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പ്‌സൊന്നും കണ്ടെത്തിയില്ല"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> എന്നതിലേക്ക് പോവുക"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"ഈ ഹോം സ്‌ക്രീനിൽ ഒഴിവൊന്നുമില്ല."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"പ്രിയപ്പെട്ടവയുടെ ട്രേയിൽ ഒഴിവൊന്നുമില്ല"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"അപ്ലിക്കേഷനുകൾ"</string>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
index a47fcfc..35d522c 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn-rMN/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Апп хайх..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Аппликейшныг ачаалж байна..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"-д нийцэх апп олдсонгүй"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> руу очих"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Энэ Нүүр дэлгэц зайгүй."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"\"Дуртай\" трей дээр өөр зай байхгүй байна"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Апп"</string>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index c14a5d2..1598e52 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"अॅप्स शोधा..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"अॅप्स लोड करीत आहे..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> वर जा"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"या मुख्य स्क्रीनवर आणखी जागा नाही."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"आवडीच्या ट्रे मध्ये आणखी जागा नाही"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"अॅप्स"</string>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index 9bb4ea0..e9c4eac 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Cari Apl..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Memuatkan Apl…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Tiada Apl yang ditemui sepadan dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Pergi ke <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Tiada lagi ruang pada skrin Laman Utama ini."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Tiada ruang dalam dulang Kegemaran lagi"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apl"</string>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index b9ca0ea..53786a7 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -32,10 +32,11 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"အက်ပ်များကို ရှာဖွေပါ…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"App များ ရယူနေစဉ်..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" နှင့်ကိုက်ညီသည့် အပ်ဖ်များမတွေ့ပါ"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g>ကို သွားပါ"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"ဤပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"အနှစ်သက်ဆုံးများ ထားရာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
-    <string name="all_apps_button_label" msgid="9110807029020582876">"အပ်ပလီကေးရှင်းများ"</string>
+    <string name="all_apps_button_label" msgid="9110807029020582876">"အက်ပ်များ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ပင်မစာမျက်နှာ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ဖယ်ရှားမည်"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ဖယ်ထုတ်မည်"</string>
@@ -59,18 +60,18 @@
     <string name="migration_cling_description" msgid="2752413805582227644">"ပင်မစာမျက်နှာအဟောင်းမှ ပုံညွှန်းများ နှင့် အကန့်များကို ယူလာပါမလား"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPY ICONS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START FRESH"</string>
-    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"နောက်ခံများ၊ ဝီဂျက်များ&amp; ဆက်တင်များ"</string>
+    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"နောက်ခံများ၊ ဝိဂျက်များ&amp; ဆက်တင်များ"</string>
     <string name="workspace_cling_longpress_description" msgid="6569028007301925917">"စိတ်တိုင်းကျပြုပြင်ရန် နောက်ခံတို့၍ &amp; ဖိထားပါ"</string>
-    <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ရပြီ"</string>
+    <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ရပါပြီ"</string>
     <string name="folder_opened" msgid="94695026776264709">"ဖွင့်ထားသောအကန့်, <xliff:g id="WIDTH">%1$d</xliff:g> နှင့် <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"ဖိုင်တွဲကို ပိတ်ရန် တို့ပါ"</string>
     <string name="folder_tap_to_rename" msgid="4017685068016979677">"အမည်ပြောင်းခြင်းကို သိမ်းဆည်းရန် တို့ပါ"</string>
     <string name="folder_closed" msgid="4100806530910930934">"ပိတ်ထားသောအကန့်"</string>
     <string name="folder_renamed" msgid="1794088362165669656">"ပြောင်းလဲလိုက်သော အကန့်အမည် <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_name_format" msgid="6629239338071103179">"အကန့်အမည်: <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="widget_button_text" msgid="2880537293434387943">"ဝဒ်ဂျက်များ"</string>
+    <string name="widget_button_text" msgid="2880537293434387943">"ဝိဂျက်များ"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"နောက်ခံများ"</string>
-    <string name="settings_button_text" msgid="8119458837558863227">"အပြင်အဆင်များ"</string>
+    <string name="settings_button_text" msgid="8119458837558863227">"ဆက်တင်များ"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"သင့်စီမံခန့်ခွဲသူက ပိတ်လိုက်ပါသည်"</string>
     <string name="allow_rotation_title" msgid="3132336367556833843">"ပင်မစာမျက်နှာကို လှည့်ခွင့်ပြုပါ"</string>
     <string name="allow_rotation_desc" msgid="7635719920854330492">"စက်ပစ္စည်းကို လှည့်ထားသည့်အခါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index e5bd1c1..5a0c2b5 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Søk i apper"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Laster inn apper …"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Fant ingen apper som samsvarer med «<xliff:g id="QUERY">%1$s</xliff:g>»"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Gå til <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Denne startsiden er full."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritter-skuffen er full"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apper"</string>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index 169f3de..22d994e 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"अनुप्रयोगहरू खोज्नुहोस्..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"अनुप्रयोगहरू लोड गरिँदै..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" सँग मिल्दो कुनै अनुप्रयोगहरू फेला परेनन्"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> मा जानुहोस्"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"यो गृह स्क्रिनमा कुनै थप ठाउँ छैन।"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"मनपर्ने ट्रे अब कुनै ठाँउ छैन"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"अनुप्रयोगहरू"</string>
@@ -59,7 +60,7 @@
     <string name="migration_cling_description" msgid="2752413805582227644">"आफ्नो पुरानो गृह स्क्रीनबाट अाईकन र फोल्डरहरू आयात गर्नुहोस्?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ICONS प्रतिलिप गर्नुहोस्"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START FRESH"</string>
-    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"वालपेपरहरू, विजेट; सेटिङहरू"</string>
+    <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"वालपेपर, विजेट तथा सेटिङहरू"</string>
     <string name="workspace_cling_longpress_description" msgid="6569028007301925917">"अनुकूलन गर्नका लागि पृष्ठभूमिलाई ट्याप गरी थिचिरहनुहोस्"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"बुँझें"</string>
     <string name="folder_opened" msgid="94695026776264709">"फोल्डर खुल्यो <xliff:g id="WIDTH">%1$d</xliff:g> बाट <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index a546a85..b2f48a0 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Apps zoeken…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Apps laden…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Er zijn geen apps gevonden die overeenkomen met \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Ga naar <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Er is geen ruimte meer op dit startscherm."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Geen ruimte meer in het vak \'Favorieten\'"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
index 47bb556..4ab6b9b 100644
--- a/res/values-pa-rIN/strings.xml
+++ b/res/values-pa-rIN/strings.xml
@@ -30,9 +30,10 @@
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ਡਬਲ-ਟੈਪ &amp; ਇੱਕ ਵਿਜੇਟ ਚੁਣਨ ਲਈ ਹੋਲਡ ਕਰੋ ਅਤੇ ਕਸਟਮ ਕਿਰਿਆਵਾਂ ਵਰਤੋ।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"ਐਪਾਂ ਖੋਜੋ…"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"ਐਪਸ ਲੋਡ ਕਰ ਰਿਹਾ ਹੈ..."</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"ਐਪਾਂ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ਨਾਲ ਮਿਲਦੀਆਂ ਕੋਈ ਵੀ ਐਪਾਂ ਨਹੀਂ ਮਿਲੀਆਂ"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> ਤੇ ਜਾਓ"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"ਇਸ ਹੋਮ ਸਕ੍ਰੀਨ ਲਈ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ ਹੈ।"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ਮਨਪਸੰਦ ਟ੍ਰੇ ਵਿੱਚ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ।"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ਐਪਾਂ"</string>
@@ -40,12 +41,12 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ਹਟਾਓ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ਸਥਾਪਨਾ ਰੱਦ ਕਰੋ"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ਐਪ ਜਾਣਕਾਰੀ"</string>
-    <string name="permlab_install_shortcut" msgid="5632423390354674437">"ਸ਼ੌਰਟਕਟ ਇੰਸਟੌਲ ਕਰੋ"</string>
-    <string name="permdesc_install_shortcut" msgid="923466509822011139">"ਇੱਕ ਐਪ ਨੂੰ ਉਪਭੋਗਤਾ ਦੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਸ਼ੌਰਟਕਟ ਜੋੜਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
-    <string name="permlab_read_settings" msgid="1941457408239617576">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ੌਰਟਕਟ ਪੜ੍ਹੋ"</string>
-    <string name="permdesc_read_settings" msgid="5833423719057558387">"ਐਪ ਨੂੰ ਹੋਮ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ੌਰਟਕਟ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
-    <string name="permlab_write_settings" msgid="3574213698004620587">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ੌਰਟਕਟ ਲਿਖੋ"</string>
-    <string name="permdesc_write_settings" msgid="5440712911516509985">"ਐਪ ਨੂੰ ਹੋਮ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ੌਰਟਕਟ ਬਦਲਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
+    <string name="permlab_install_shortcut" msgid="5632423390354674437">"ਸ਼ਾਰਟਕੱਟ ਇੰਸਟੌਲ ਕਰੋ"</string>
+    <string name="permdesc_install_shortcut" msgid="923466509822011139">"ਇੱਕ ਐਪ ਨੂੰ ਉਪਭੋਗਤਾ ਦੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਸ਼ਾਰਟਕੱਟ ਜੋੜਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
+    <string name="permlab_read_settings" msgid="1941457408239617576">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਪੜ੍ਹੋ"</string>
+    <string name="permdesc_read_settings" msgid="5833423719057558387">"ਐਪ ਨੂੰ ਹੋਮ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
+    <string name="permlab_write_settings" msgid="3574213698004620587">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਲਿਖੋ"</string>
+    <string name="permdesc_write_settings" msgid="5440712911516509985">"ਐਪ ਨੂੰ ਹੋਮ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਬਦਲਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਫੋਨ ਕਾਲਾਂ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਹੈ"</string>
     <string name="gadget_error_text" msgid="6081085226050792095">"ਵਿਜੇਟ ਲੋਡ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"ਸਥਾਪਤ ਕਰੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 54d7780..92063e1 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Szukaj w aplikacjach…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Wczytuję aplikacje…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nie znaleziono aplikacji pasujących do zapytania „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Otwórz <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Brak miejsca na tym ekranie głównym."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Brak miejsca w Ulubionych"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikacje"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index dddf2dc..29d6c94 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Pesquisar aplicações..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"A carregar aplicações..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Não foram encontradas aplic. que correspondam a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Aceder a <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Sem espaço suficiente neste Ecrã principal."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Não existe mais espaço no tabuleiro de Favoritos"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicações"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index f821b21..69a60e1 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Pesquisar apps..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Carregando apps…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nenhum app encontrado que corresponda a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Ir para <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Não há mais espaço na tela inicial."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Sem espaço na bandeja de favoritos"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 6be7727..cfe631f 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Căutați aplicații…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Se încarcă aplicațiile..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nu s-a găsit nicio aplicație pentru „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Accesați <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Nu mai este loc pe acest Ecran de pornire."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Spațiu epuizat în bara Preferate"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicații"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 9349c0b..a9fe949 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Поиск приложений"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Загрузка…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"По запросу \"<xliff:g id="QUERY">%1$s</xliff:g>\" ничего не найдено"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"На этом экране все занято"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"В разделе \"Избранное\" больше нет места"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Приложения"</string>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index d13ae32..41e4d9a 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"යෙදුම් සොයන්න..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"යෙදුම් පූරණය වෙමින්…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" සමග ගැළපෙන යෙදුම් හමු නොවිණි"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> වෙත යන්න"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"මෙම මුල් පිටු තිරය මත තවත් අවසර නැත."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ප්‍රියතම දෑ ඇති තැටියේ තවත් ඉඩ නොමැත"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"යෙදුම්"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 4f92d1e..d0dcf27 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -29,10 +29,11 @@
     <string name="long_press_widget_to_add" msgid="5154837155685183344">"Miniaplikáciu pridáte klepnutím a podržaním."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Miniaplikáciu pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Vyhľadávanie v aplikáciách…"</string>
+    <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Hľadať aplikácie…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Načítavajú sa aplikácie..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nenašli sa žiadne aplikácie zodpovedajúce dopytu <xliff:g id="QUERY">%1$s</xliff:g>"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Prejsť na dopyt <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Na tejto ploche už nie je miesto"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Na paneli Obľúbené položky už nie je miesto"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikácie"</string>
@@ -60,7 +61,7 @@
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"SKOPÍROVAŤ IKONY"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ZAČAŤ ODZNOVA"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Tapety, miniaplikácie a nastavenia"</string>
-    <string name="workspace_cling_longpress_description" msgid="6569028007301925917">"Pozadie prispôsobíte klepnutím a podržaním"</string>
+    <string name="workspace_cling_longpress_description" msgid="6569028007301925917">"Pozadie môžete prispôsobiť jeho pridržaním"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"DOBRE"</string>
     <string name="folder_opened" msgid="94695026776264709">"Otvorený priečinok, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Priečinok zavriete klepnutím"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 27412db..5d396e4 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Iskanje po aplikacijah …"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Nalaganje aplikacij …"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ni aplikacij, ki bi ustrezale poizvedbi »<xliff:g id="QUERY">%1$s</xliff:g>«"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Odpri storitev <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Na tem začetnem zaslonu ni več prostora."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"V vrstici za priljubljene ni več prostora"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikacije"</string>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
index 4ee58f0..2627691 100644
--- a/res/values-sq-rAL/strings.xml
+++ b/res/values-sq-rAL/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Kërko për aplikacione..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Po ngarkon aplikacionet..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nuk u gjet asnjë aplikacion që përputhet me \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Shko te <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Nuk ka më hapësirë në këtë ekran bazë."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nuk ka më hapësirë në tabakanë \"Të preferuarat\""</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikacionet"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index c174ace..c4154f5 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Претражите апликације..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Апликације се учитавају..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Није пронађена ниједна апликација за „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Иди на апликацију <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Нема више простора на овом почетном екрану."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Нема више простора на траци Омиљено"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Апликације"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 3019603..7f5af4b 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Sök efter appar …"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Läser in appar …"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Det gick inte att hitta några appar som matchar <xliff:g id="QUERY">%1$s</xliff:g>"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Gå till <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Det finns inte plats för mer på den här startskärmen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritfältet är fullt"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Appar"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 5b2eb27..291e52d 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Tafuta Programu..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Inapakia Programu..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Haikupata programu zinazolingana na \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Nenda kwenye <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Hakuna nafasi katika skrini hii ya Mwanzo."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Hakuna nafasi zaidi katika treya ya Vipendeleo"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Programu"</string>
@@ -62,7 +63,7 @@
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"NAKILI IKONI"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ANZA UPYA"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Mandhari, wijeti na mipangilio"</string>
-    <string name="workspace_cling_longpress_description" msgid="6569028007301925917">"Gusa na ushikilie mandhari ili uweke mapendeleo"</string>
+    <string name="workspace_cling_longpress_description" msgid="6569028007301925917">"Gusa na ushikilie mandhari ili ubadilishe upendavyo"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"NIMEELEWA"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folda imefunguliwa, <xliff:g id="WIDTH">%1$d</xliff:g> kwa <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Gonga ili ufunge folda"</string>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index 6bb0a10..495f9d1 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"பயன்பாடுகளில் தேடுக…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"பயன்பாடுகளை ஏற்றுகிறது..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g>க்குச் செல்லவும்"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"முகப்புத் திரையில் இடமில்லை."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"பிடித்தவை ட்ரேயில் இடமில்லை"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"பயன்பாடுகள்"</string>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index 82a772e..2757d4a 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"అనువర్తనాల్లో శోధించండి…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"అనువర్తనాలను లోడ్ చేస్తోంది…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"కి సరిపోలే అనువర్తనాలేవీ కనుగొనబడలేదు"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g>కి వెళ్లు"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"ఈ హోమ్ స్క్రీన్‌లో ఖాళీ లేదు."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ఇష్టమైనవి ట్రేలో ఖాళీ లేదు"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"అనువర్తనాలు"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index e22ebf1..3fa6211 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"ค้นหาแอป…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"กำลังโหลดแอป…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"ไม่พบแอปที่ตรงกับ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"ไปที่ <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"ไม่มีที่ว่างในหน้าจอหลักนี้"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ไม่มีพื้นที่เหลือในถาดรายการโปรด"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"แอป"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index ed0206e..dd7adea 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Maghanap ng Mga App…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Nilo-load ang Mga App…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Walang nakitang Mga App na tumutugma sa \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Pumunta sa <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Wala nang lugar sa Home screen na ito."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Wala nang lugar sa tray ng Mga Paborito"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 94c38d9..40ac473 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Uygulamalarda Ara…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Uygulamalar Yükleniyor…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ile eşleşen uygulama bulunamadı"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> uygulamasına git"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Bu Ana ekranda yer kalmadı."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoriler tepsisinde başka yer kalmadı"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Uygulamalar"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 1fc74b6..497d71e 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Пошук додатків…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Завантаження додатків…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Немає додатків для запиту \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Перейти в додаток <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"На цьому головному екрані більше немає місця."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"В області \"Вибране\" немає місця"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Додатки"</string>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
index c6e6cfc..6bc601d 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur-rPK/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"ایپس تلاش کریں…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ایپس لوڈ ہو رہی ہیں…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" سے مماثل کوئی ایپس نہیں ملیں"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g> پر جائیں"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"اس ہوم اسکرین پر مزید کوئی گنجائش نہیں ہے۔"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"پسندیدہ ٹرے میں مزید کوئی گنجائش نہیں ہے"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ایپس"</string>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index 859ff12..80e3460 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Ilovalar ichidan qidirish…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Ilovalar yuklanmoqda…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"“<xliff:g id="QUERY">%1$s</xliff:g>” so‘rovi bo‘yicha hech narsa topilmadi"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"<xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Uy ekranida bitta ham xona yo‘q."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ajratilganlarda birorta ham xona yo‘q"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Ilovalar"</string>
@@ -73,7 +74,7 @@
     <string name="settings_button_text" msgid="8119458837558863227">"Sozlamalar"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administrator tomonidan o‘chirilgan"</string>
     <string name="allow_rotation_title" msgid="3132336367556833843">"Asosiy ekranni aylantirishga ruxsat berish"</string>
-    <string name="allow_rotation_desc" msgid="7635719920854330492">"Qurilma aylanganda"</string>
+    <string name="allow_rotation_desc" msgid="7635719920854330492">"Qurilma burilganda"</string>
     <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Ekran sozlamalariga ko‘ra uni aylantirib bo‘lmaydi"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Noma’lum"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"O‘chirish"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 5da05a1..baf2cad 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Tìm kiếm ứng dụng..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Đang tải ứng dụng..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Không tìm thấy ứng dụng nào phù hợp với \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Chuyển tới <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Không còn chỗ trên Màn hình chính này."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Không còn chỗ trong khay Mục yêu thích"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Ứng dụng"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 8f269ed..d784b47 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"搜索应用…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"正在加载应用…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"未找到与“<xliff:g id="QUERY">%1$s</xliff:g>”相符的应用"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"转到 <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"此主屏幕上已没有空间。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"收藏栏已满"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"应用"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index a8bd7bb..0440648 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"搜尋應用程式…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"正在載入應用程式…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"無法找到與「<xliff:g id="QUERY">%1$s</xliff:g>」相符的應用程式"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"前往 <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"主畫面已無空間。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"我的收藏寄存區沒有足夠空間"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"應用程式"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 6d66f18..c9bb47f 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"搜尋應用程式…"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"正在載入應用程式…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"找不到符合「<xliff:g id="QUERY">%1$s</xliff:g>」的應用程式"</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"前往 <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"這個主螢幕已無空間。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"「我的最愛」匣已無可用空間"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"應用程式"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 2184831..bacf2b8 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -32,7 +32,8 @@
     <string name="all_apps_search_bar_hint" msgid="6705987535534678581">"Sesha izinhlelo zokusebenza..."</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Ilayisha izinhlelo zokusebenza..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Azikho izinhlelo zokusebenza ezitholakele ezifana ne-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
-    <string name="all_apps_search_market_message" msgid="5470761048755751471">"Hamba ku-<xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <!-- no translation found for all_apps_search_market_message (1366263386197059176) -->
+    <skip />
     <string name="out_of_space" msgid="4691004494942118364">"Asisekho isikhala kulesi sikrini Sasekhaya."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Asisekho isikhala kwitreyi lezintandokazi"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Izinhlelo zokusebenza"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 6f41a4b..64868f2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -17,19 +17,7 @@
 <resources>
 <!-- Dynamic Grid -->
     <dimen name="dynamic_grid_edge_margin">6dp</dimen>
-    <dimen name="dynamic_grid_search_bar_height">48dp</dimen>
-    <!-- We want 46dp extra for the tall search bar. -->
-    <dimen name="dynamic_grid_search_bar_height_tall">94dp</dimen>
-    <dimen name="qsb_internal_padding_top">8dp</dimen>
-    <dimen name="qsb_internal_padding_bottom">8dp</dimen>
-    <dimen name="dynamic_grid_search_bar_extra_top_padding">0dp</dimen>
-    <!-- Reduce the space between the status bar and the search bar when the search bar is tall -->
-    <dimen name="dynamic_grid_search_bar_negative_top_padding_short">-4dp</dimen>
-    <dimen name="dynamic_grid_search_bar_bottom_padding">4dp</dimen>
-    <!-- Reduce the padding between the search bar and workspace when the search bar is tall -->
-    <dimen name="dynamic_grid_search_bar_bottom_negative_padding_short">-6dp</dimen>
-    <dimen name="dynamic_grid_search_bar_bottom_padding_tablet">16dp</dimen>
-    <dimen name="dynamic_grid_page_indicator_height">20dp</dimen>
+    <dimen name="dynamic_grid_page_indicator_height">1dp</dimen>
     <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
     <dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
     <dimen name="dynamic_grid_overview_min_icon_zone_height">80dp</dimen>
@@ -37,6 +25,15 @@
     <dimen name="dynamic_grid_overview_bar_item_width">80dp</dimen>
     <dimen name="dynamic_grid_overview_bar_spacer_width">20dp</dimen>
 
+    <dimen name="dynamic_grid_workspace_top_padding">12dp</dimen>
+    <!-- Minimum space between workspace and hotseat in spring loaded mode -->
+    <dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
+
+<!-- Drop target bar -->
+    <dimen name="dynamic_grid_drop_target_size">48dp</dimen>
+    <dimen name="vert_drop_target_vertical_gap">20dp</dimen>
+    <dimen name="vert_drop_target_horizontal_gap">14dp</dimen>
+
 <!-- App Widget resize frame -->
     <dimen name="default_widget_padding">8dp</dimen>
     <dimen name="widget_handle_margin">13dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e675a92..9f011e5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -52,9 +52,8 @@
     <string name="all_apps_loading_message">Loading Apps&#8230;</string>
     <!-- No-search-results text. [CHAR_LIMIT=50] -->
     <string name="all_apps_no_search_results">No Apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
-    <!-- Search market text.  This is a format string where the first argument is the name of the activity
-         handling the search.  The format string does not need to handle both of these arguments. [CHAR_LIMIT=50] -->
-    <string name="all_apps_search_market_message">Go to <xliff:g id="query" example="Play Store">%1$s</xliff:g></string>
+    <!-- Label for the button which allows the user to get app search results. [CHAR_LIMIT=50] -->
+    <string name="all_apps_search_market_message">Search for more apps</string>
 
     <!-- Drag and drop -->
     <skip />
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index 28fd268..e0694f3 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -66,6 +66,7 @@
         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
     }
 
+    @Override
     public Intent getIntent() {
         return intent;
     }
diff --git a/src/com/android/launcher3/AppInfoDropTargetBar.java b/src/com/android/launcher3/AppInfoDropTargetBar.java
deleted file mode 100644
index e06f941..0000000
--- a/src/com/android/launcher3/AppInfoDropTargetBar.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import com.android.launcher3.dragndrop.DragController;
-
-public class AppInfoDropTargetBar extends BaseDropTargetBar {
-    private ButtonDropTarget mAppInfoDropTarget;
-
-    public AppInfoDropTargetBar(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public AppInfoDropTargetBar(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        // Get the individual components
-        mAppInfoDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.info_target_text);
-
-        mAppInfoDropTarget.setDropTargetBar(this);
-    }
-
-    @Override
-    public void setup(Launcher launcher, DragController dragController) {
-        dragController.addDragListener(this);
-
-        dragController.addDragListener(mAppInfoDropTarget);
-        dragController.addDropTarget(mAppInfoDropTarget);
-
-        mAppInfoDropTarget.setLauncher(launcher);
-    }
-
-    @Override
-    public void showDropTargets() {
-        animateDropTargetBarToAlpha(1f, DEFAULT_DRAG_FADE_DURATION);
-    }
-
-    @Override
-    public void hideDropTargets() {
-        animateDropTargetBarToAlpha(0f, DEFAULT_DRAG_FADE_DURATION);
-    }
-
-    private void animateDropTargetBarToAlpha(float alpha, int duration) {
-        resetAnimation(duration);
-        if (duration > 0) {
-            animateAlpha(mDropTargetBar, alpha, DEFAULT_INTERPOLATOR);
-            mCurrentAnimation.start();
-        } else {
-            mDropTargetBar.setAlpha(alpha);
-            AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
-        }
-    }
-
-    @Override
-    public void enableAccessibleDrag(boolean enable) {
-        mAppInfoDropTarget.enableAccessibleDrag(enable);
-    }
-}
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
index d0cacd3..a9ef43d 100644
--- a/src/com/android/launcher3/BaseContainerView.java
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -24,6 +24,9 @@
 import android.view.View;
 import android.widget.FrameLayout;
 
+import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.config.FeatureFlags;
+
 /**
  * A base container view, which supports resizing.
  */
@@ -48,7 +51,11 @@
         super(context, attrs, defStyleAttr);
 
         int width = ((Launcher) context).getDeviceProfile().availableWidthPx;
-        mHorizontalPadding = DeviceProfile.getContainerPadding(context, width);
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && (this instanceof AllAppsContainerView)) {
+            mHorizontalPadding = 0;
+        } else {
+            mHorizontalPadding = DeviceProfile.getContainerPadding(context, width);
+        }
 
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.BaseContainerView, defStyleAttr, 0);
diff --git a/src/com/android/launcher3/BaseDropTargetBar.java b/src/com/android/launcher3/BaseDropTargetBar.java
deleted file mode 100644
index 9b38623..0000000
--- a/src/com/android/launcher3/BaseDropTargetBar.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AccelerateInterpolator;
-import android.widget.FrameLayout;
-
-import com.android.launcher3.dragndrop.DragController;
-
-/**
- * Base class for drop target bars (where you can drop apps to do actions such as uninstall).
- */
-public abstract class BaseDropTargetBar extends FrameLayout implements DragController.DragListener {
-    protected static final int DEFAULT_DRAG_FADE_DURATION = 175;
-    protected static final TimeInterpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator();
-
-    protected View mDropTargetBar;
-    protected boolean mAccessibilityEnabled = false;
-
-    protected AnimatorSet mCurrentAnimation;
-    protected boolean mDeferOnDragEnd;
-
-    public BaseDropTargetBar(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public BaseDropTargetBar(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        mDropTargetBar = findViewById(R.id.drag_target_bar);
-
-        // Create the various fade animations
-        mDropTargetBar.setAlpha(0f);
-    }
-
-    /**
-     * Convenience method to animate the alpha of a view.
-     */
-    protected void animateAlpha(View v, float alpha, TimeInterpolator interpolator) {
-        if (Float.compare(v.getAlpha(), alpha) != 0) {
-            ObjectAnimator anim = ObjectAnimator.ofFloat(v, View.ALPHA, alpha);
-            anim.setInterpolator(interpolator);
-            anim.addListener(new ViewVisiblilyUpdateHandler(v));
-            mCurrentAnimation.play(anim);
-        }
-    }
-
-    protected void resetAnimation(int newAnimationDuration) {
-        // Update the accessibility state
-        AccessibilityManager am = (AccessibilityManager)
-                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-        mAccessibilityEnabled = am.isEnabled();
-
-        // Cancel any existing animation
-        if (mCurrentAnimation != null) {
-            mCurrentAnimation.cancel();
-            mCurrentAnimation = null;
-        }
-
-        if (newAnimationDuration > 0) {
-            mCurrentAnimation = new AnimatorSet();
-            mCurrentAnimation.setDuration(newAnimationDuration);
-        }
-    }
-
-    /*
-     * DragController.DragListener implementation
-     */
-    @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
-        showDropTargets();
-    }
-
-    /**
-     * This is called to defer hiding the delete drop target until the drop animation has completed,
-     * instead of hiding immediately when the drag has ended.
-     */
-    protected void deferOnDragEnd() {
-        mDeferOnDragEnd = true;
-    }
-
-    @Override
-    public void onDragEnd() {
-        if (!mDeferOnDragEnd) {
-            hideDropTargets();
-        } else {
-            mDeferOnDragEnd = false;
-        }
-    }
-
-    public abstract void showDropTargets();
-
-    public abstract void hideDropTargets();
-
-    public abstract void enableAccessibleDrag(boolean enable);
-
-    public abstract void setup(Launcher launcher, DragController dragController);
-
-    private class ViewVisiblilyUpdateHandler extends AnimatorListenerAdapter {
-        private final View mView;
-
-        ViewVisiblilyUpdateHandler(View v) {
-            mView = v;
-        }
-
-        @Override
-        public void onAnimationStart(Animator animation) {
-            // Ensure that the view is visible for the animation
-            mView.setVisibility(View.VISIBLE);
-        }
-
-        @Override
-        public void onAnimationEnd(Animator animation){
-            AlphaUpdateListener.updateVisibility(mView, mAccessibilityEnabled);
-        }
-
-    }
-}
diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
index a680169..fd0045e 100644
--- a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
+++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
@@ -27,7 +27,6 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.MotionEvent;
-import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
 
 import com.android.launcher3.util.Thunk;
@@ -293,7 +292,7 @@
     /**
      * Returns whether the specified points are near the scroll bar bounds.
      */
-    private boolean isNearThumb(int x, int y) {
+    public boolean isNearThumb(int x, int y) {
         mTmpRect.set(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth,
                 mThumbOffset.y + mThumbHeight);
         mTmpRect.inset(mTouchInset, mTouchInset);
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 43afbe5..61ac713 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -55,10 +55,10 @@
     private static final int DRAG_VIEW_DROP_DURATION = 285;
 
     private final boolean mHideParentOnDisable;
+    protected final Launcher mLauncher;
 
-    protected Launcher mLauncher;
     private int mBottomDragPadding;
-    protected BaseDropTargetBar mDropTargetBar;
+    protected DropTargetBar mDropTargetBar;
 
     /** Whether this drop target is active for the current drag */
     protected boolean mActive;
@@ -80,6 +80,8 @@
 
     public ButtonDropTarget(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        mLauncher = (Launcher) context;
+
         Resources resources = getResources();
         mBottomDragPadding = resources.getDimensionPixelSize(R.dimen.drop_target_drag_padding);
 
@@ -109,11 +111,7 @@
         }
     }
 
-    public void setLauncher(Launcher launcher) {
-        mLauncher = launcher;
-    }
-
-    public void setDropTargetBar(BaseDropTargetBar dropTargetBar) {
+    public void setDropTargetBar(DropTargetBar dropTargetBar) {
         mDropTargetBar = dropTargetBar;
     }
 
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index e3bb5fa..6755ff7 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -896,14 +896,30 @@
         if (!isFullscreen) {
             left += (int) Math.ceil(getUnusedHorizontalSpace() / 2f);
         }
+        int right = r - l - getPaddingRight();
+        if (!isFullscreen) {
+            right -= (int) Math.ceil(getUnusedHorizontalSpace() / 2f);
+        }
+
         int top = getPaddingTop();
+        int bottom = b - t - getPaddingBottom();
 
         mTouchFeedbackView.layout(left, top,
                 left + mTouchFeedbackView.getMeasuredWidth(),
                 top + mTouchFeedbackView.getMeasuredHeight());
-        mShortcutsAndWidgets.layout(left, top,
-                left + r - l,
-                top + b - t);
+        mShortcutsAndWidgets.layout(left, top, right, bottom);
+
+        // Expand the background drawing bounds by the padding baked into the background drawable
+        mBackground.getPadding(mTempRect);
+        mBackground.setBounds(
+                left - mTempRect.left,
+                top - mTempRect.top,
+                right + mTempRect.right,
+                bottom + mTempRect.bottom);
+    }
+
+    public Rect getBackgroundBounds() {
+        return mBackground.getBounds();
     }
 
     /**
@@ -916,16 +932,6 @@
     }
 
     @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-
-        // Expand the background drawing bounds by the padding baked into the background drawable
-        mBackground.getPadding(mTempRect);
-        mBackground.setBounds(-mTempRect.left, -mTempRect.top,
-                w + mTempRect.right, h + mTempRect.bottom);
-    }
-
-    @Override
     protected void setChildrenDrawingCacheEnabled(boolean enabled) {
         mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled);
     }
@@ -2708,7 +2714,7 @@
 
         /**
          * Indicates whether this item can be reordered. Always true except in the case of the
-         * the AllApps button.
+         * the AllApps button and QSB place holder.
          */
         public boolean canReorder = true;
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 8d11aaa..4a550ed 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -70,7 +70,10 @@
     public final Rect defaultWidgetPadding;
     private final int pageIndicatorHeightPx;
     private final int defaultPageSpacingPx;
+    private final int topWorkspacePadding;
     private float dragViewScale;
+    public float workspaceSpringLoadShrinkFactor;
+    public final int workspaceSpringLoadedBottomSpace;
 
     // Workspace icons
     public int iconSizePx;
@@ -92,8 +95,7 @@
     public int hotseatCellWidthPx;
     public int hotseatCellHeightPx;
     public int hotseatIconSizePx;
-    private int normalHotseatBarHeightPx, shortHotseatBarHeightPx;
-    private int hotseatBarHeightPx; // One of the above.
+    private int hotseatBarHeightPx;
 
     // All apps
     public int allAppsNumCols;
@@ -102,15 +104,8 @@
     public final int allAppsIconSizePx;
     public final float allAppsIconTextSizeSp;
 
-    // QSB
-    private int searchBarWidgetInternalPaddingTop, searchBarWidgetInternalPaddingBottom;
-    private int searchBarTopPaddingPx;
-    private int tallSearchBarNegativeTopPaddingPx, normalSearchBarTopExtraPaddingPx;
-    private int searchBarTopExtraPaddingPx; // One of the above.
-    private int normalSearchBarBottomPaddingPx, tallSearchBarBottomPaddingPx;
-    private int searchBarBottomPaddingPx; // One of the above.
-    private int normalSearchBarSpaceHeightPx, tallSearchBarSpaceHeightPx;
-    private int searchBarSpaceHeightPx; // One of the above.
+    // Drop Target
+    public int dropTargetBarSizePx;
 
     public DeviceProfile(Context context, InvariantDeviceProfile inv,
             Point minSize, Point maxSize,
@@ -140,6 +135,8 @@
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_height);
         defaultPageSpacingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing);
+        topWorkspacePadding =
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_top_padding);
         overviewModeMinIconZoneHeightPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_min_icon_zone_height);
         overviewModeMaxIconZoneHeightPx =
@@ -152,6 +149,9 @@
                 res.getInteger(R.integer.config_dynamic_grid_overview_icon_zone_percentage) / 100f;
         iconDrawablePaddingOriginalPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding);
+        dropTargetBarSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_drop_target_size);
+        workspaceSpringLoadedBottomSpace =
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_min_spring_loaded_space);
 
         // AllApps uses the original non-scaled icon text size
         allAppsIconTextSizeSp = inv.iconTextSize;
@@ -195,7 +195,7 @@
         float usedHeight = (cellHeightPx * inv.numRows);
 
         // We only care about the top and bottom workspace padding, which is not affected by RTL.
-        Rect workspacePadding = getWorkspacePadding(false /* isLayoutRtl */);
+        Rect workspacePadding = getWorkspacePadding();
         int maxHeight = (availableHeightPx - workspacePadding.top - workspacePadding.bottom);
         if (usedHeight > maxHeight) {
             scale = maxHeight / usedHeight;
@@ -211,33 +211,6 @@
         iconDrawablePaddingPx = drawablePadding;
         hotseatIconSizePx = (int) (Utilities.pxFromDp(inv.hotseatIconSize, dm) * scale);
 
-        // Search Bar
-        normalSearchBarSpaceHeightPx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_search_bar_height);
-        tallSearchBarSpaceHeightPx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_search_bar_height_tall);
-        searchBarWidgetInternalPaddingTop = res.getDimensionPixelSize(
-                R.dimen.qsb_internal_padding_top);
-        searchBarWidgetInternalPaddingBottom = res.getDimensionPixelSize(
-                R.dimen.qsb_internal_padding_bottom);
-        normalSearchBarTopExtraPaddingPx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_search_bar_extra_top_padding);
-        tallSearchBarNegativeTopPaddingPx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_search_bar_negative_top_padding_short);
-        if (isTablet && !isVerticalBarLayout()) {
-            searchBarTopPaddingPx = searchBarWidgetInternalPaddingTop;
-            normalSearchBarBottomPaddingPx = searchBarWidgetInternalPaddingBottom +
-                    res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_bottom_padding_tablet);
-            tallSearchBarBottomPaddingPx = normalSearchBarBottomPaddingPx;
-        } else {
-            searchBarTopPaddingPx = searchBarWidgetInternalPaddingTop;
-            normalSearchBarBottomPaddingPx = searchBarWidgetInternalPaddingBottom +
-                    res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_bottom_padding);
-            tallSearchBarBottomPaddingPx = searchBarWidgetInternalPaddingBottom
-                    + res.getDimensionPixelSize(
-                    R.dimen.dynamic_grid_search_bar_bottom_negative_padding_short);
-        }
-
         // Calculate the actual text height
         Paint textPaint = new Paint();
         textPaint.setTextSize(iconTextSizePx);
@@ -249,11 +222,22 @@
         dragViewScale = (iconSizePx + scaleDps) / iconSizePx;
 
         // Hotseat
-        normalHotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx;
-        shortHotseatBarHeightPx = iconSizePx + 2 * edgeMarginPx;
+        hotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx;
         hotseatCellWidthPx = iconSizePx;
         hotseatCellHeightPx = iconSizePx;
 
+        if (!isVerticalBarLayout()) {
+            int expectedWorkspaceHeight = availableHeightPx - hotseatBarHeightPx
+                    - pageIndicatorHeightPx - topWorkspacePadding;
+            float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace;
+            workspaceSpringLoadShrinkFactor = Math.min(
+                    res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f,
+                    1 - (minRequiredHeight / expectedWorkspaceHeight));
+        } else {
+            workspaceSpringLoadShrinkFactor =
+                    res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
+        }
+
         // Folder
         int folderCellPadding = isTablet || isLandscape ? 6 * edgeMarginPx : 3 * edgeMarginPx;
         // Don't let the folder get too close to the edges of the screen.
@@ -281,60 +265,33 @@
         allAppsNumPredictiveCols = numPredictiveAppCols;
     }
 
-    /** Returns the amount of extra space to allocate to the search bar for vertical padding. */
-    private int getSearchBarTotalVerticalPadding() {
-        return searchBarTopPaddingPx + searchBarTopExtraPaddingPx + searchBarBottomPaddingPx;
-    }
-
     /** Returns the width and height of the search bar, ignoring any padding. */
-    public Point getSearchBarDimensForWidgetOpts(Resources res) {
-        Rect searchBarBounds = getSearchBarBounds(Utilities.isRtl(res));
+    public Point getSearchBarDimensForWidgetOpts() {
         if (isVerticalBarLayout()) {
-            return new Point(searchBarBounds.width(), searchBarBounds.height());
-        }
-        int widgetInternalPadding = searchBarWidgetInternalPaddingTop +
-                searchBarWidgetInternalPaddingBottom;
-        return new Point(searchBarBounds.width(), searchBarSpaceHeightPx + widgetInternalPadding);
-    }
-
-    /** Returns the search bar bounds in the current orientation */
-    public Rect getSearchBarBounds(boolean isLayoutRtl) {
-        Rect bounds = new Rect();
-        if (isVerticalBarLayout()) {
-            if (isLayoutRtl) {
-                bounds.set(availableWidthPx - normalSearchBarSpaceHeightPx, edgeMarginPx,
-                        availableWidthPx, availableHeightPx - edgeMarginPx);
-            } else {
-                bounds.set(0, edgeMarginPx, normalSearchBarSpaceHeightPx,
-                        availableHeightPx - edgeMarginPx);
-            }
+            return new Point(dropTargetBarSizePx, availableHeightPx - 2 * edgeMarginPx);
         } else {
-            int boundsBottom = searchBarSpaceHeightPx + getSearchBarTotalVerticalPadding();
+            int gap;
             if (isTablet) {
                 // Pad the left and right of the workspace to ensure consistent spacing
                 // between all icons
                 int width = getCurrentWidth();
                 // XXX: If the icon size changes across orientations, we will have to take
                 //      that into account here too.
-                int gap = (int) ((width - 2 * edgeMarginPx -
-                        (inv.numColumns * cellWidthPx)) / (2 * (inv.numColumns + 1)));
-                bounds.set(edgeMarginPx + gap, 0,
-                        availableWidthPx - (edgeMarginPx + gap), boundsBottom);
+                gap = ((width - 2 * edgeMarginPx
+                        - (inv.numColumns * cellWidthPx)) / (2 * (inv.numColumns + 1)))
+                        + edgeMarginPx;
             } else {
-                bounds.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
-                        0,
-                        availableWidthPx - (desiredWorkspaceLeftRightMarginPx -
-                        defaultWidgetPadding.right), boundsBottom);
+                gap = desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right;
             }
+            return new Point(availableWidthPx - 2 * gap, dropTargetBarSizePx);
         }
-        return bounds;
     }
 
     public Point getCellSize() {
         Point result = new Point();
         // Since we are only concerned with the overall padding, layout direction does
         // not matter.
-        Rect padding = getWorkspacePadding(false /* isLayoutRtl */ );
+        Rect padding = getWorkspacePadding();
         result.x = calculateCellWidth(availableWidthPx - padding.left - padding.right,
                 inv.numColumns);
         result.y = calculateCellHeight(availableHeightPx - padding.top - padding.bottom,
@@ -343,20 +300,13 @@
     }
 
     /** Returns the workspace padding in the specified orientation */
-    public Rect getWorkspacePadding(boolean isLayoutRtl) {
-        Rect searchBarBounds = getSearchBarBounds(isLayoutRtl);
+    public Rect getWorkspacePadding() {
         Rect padding = new Rect();
         if (isVerticalBarLayout()) {
-            // Pad the left and right of the workspace with search/hotseat bar sizes
-            if (isLayoutRtl) {
-                padding.set(normalHotseatBarHeightPx, edgeMarginPx,
-                        searchBarBounds.width(), edgeMarginPx);
-            } else {
-                padding.set(searchBarBounds.width(), edgeMarginPx,
-                        normalHotseatBarHeightPx, edgeMarginPx);
-            }
+            // in case of isVerticalBarLayout, the hotseat is always on the right and the drop
+            // target bar is on the left, independent of the layout direction.
+            padding.set(dropTargetBarSizePx, edgeMarginPx, hotseatBarHeightPx, edgeMarginPx);
         } else {
-            int paddingTop = searchBarBounds.bottom;
             int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
             if (isTablet) {
                 // Pad the left and right of the workspace to ensure consistent spacing
@@ -369,14 +319,14 @@
                         ((inv.numColumns - 1) * gapScale * cellWidthPx)));
                 availablePaddingX = (int) Math.min(availablePaddingX,
                             width * MAX_HORIZONTAL_PADDING_PERCENT);
-                int availablePaddingY = Math.max(0, height - paddingTop - paddingBottom
+                int availablePaddingY = Math.max(0, height - topWorkspacePadding - paddingBottom
                         - (int) (2 * inv.numRows * cellHeightPx));
-                padding.set(availablePaddingX / 2, paddingTop + availablePaddingY / 2,
+                padding.set(availablePaddingX / 2, topWorkspacePadding + availablePaddingY / 2,
                         availablePaddingX / 2, paddingBottom + availablePaddingY / 2);
             } else {
                 // Pad the top and bottom of the workspace with search/hotseat bar sizes
                 padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
-                        paddingTop,
+                        topWorkspacePadding,
                         desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
                         paddingBottom);
             }
@@ -384,7 +334,7 @@
         return padding;
     }
 
-    private int getWorkspacePageSpacing(boolean isLayoutRtl) {
+    private int getWorkspacePageSpacing() {
         if (isVerticalBarLayout() || isLargeTablet) {
             // In landscape mode the page spacing is set to the default.
             return defaultPageSpacingPx;
@@ -392,7 +342,7 @@
             // In portrait, we want the pages spaced such that there is no
             // overhang of the previous / next page into the current page viewport.
             // We assume symmetrical padding in portrait mode.
-            return Math.max(defaultPageSpacingPx, 2 * getWorkspacePadding(isLayoutRtl).left);
+            return Math.max(defaultPageSpacingPx, 2 * getWorkspacePadding().left);
         }
     }
 
@@ -444,50 +394,28 @@
         return visibleChildren;
     }
 
-    // TODO(twickham): b/25154513
-    public void setSearchBarHeight(int searchBarHeight) {
-        if (searchBarHeight == LauncherCallbacks.SEARCH_BAR_HEIGHT_TALL) {
-            hotseatBarHeightPx = shortHotseatBarHeightPx;
-            searchBarSpaceHeightPx = tallSearchBarSpaceHeightPx;
-            searchBarBottomPaddingPx = tallSearchBarBottomPaddingPx;
-            searchBarTopExtraPaddingPx = isPhone ? tallSearchBarNegativeTopPaddingPx
-                    : normalSearchBarTopExtraPaddingPx;
-        } else {
-            hotseatBarHeightPx = normalHotseatBarHeightPx;
-            searchBarSpaceHeightPx = normalSearchBarSpaceHeightPx;
-            searchBarBottomPaddingPx = normalSearchBarBottomPaddingPx;
-            searchBarTopExtraPaddingPx = normalSearchBarTopExtraPaddingPx;
-        }
-    }
-
     public void layout(Launcher launcher) {
         FrameLayout.LayoutParams lp;
         boolean hasVerticalBarLayout = isVerticalBarLayout();
         final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources());
 
         // Layout the search bar space
-        Rect searchBarBounds = getSearchBarBounds(isLayoutRtl);
-        View searchBar = launcher.getSearchDropTargetBar();
+        Point searchBarBounds = getSearchBarDimensForWidgetOpts();
+        View searchBar = launcher.getDropTargetBar();
         lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
-        lp.width = searchBarBounds.width();
-        lp.height = searchBarBounds.height();
-        lp.topMargin = searchBarTopExtraPaddingPx;
+        lp.width = searchBarBounds.x;
+        lp.height = searchBarBounds.y;
+        lp.topMargin = edgeMarginPx;
         searchBar.setLayoutParams(lp);
 
-        // Layout the app info bar space
-        View appInfoBar = launcher.getAppInfoDropTargetBar();
-        lp = (FrameLayout.LayoutParams) appInfoBar.getLayoutParams();
-        lp.bottomMargin = hotseatBarHeightPx;
-        appInfoBar.setLayoutParams(lp);
-
         // Layout the workspace
         PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
         lp = (FrameLayout.LayoutParams) workspace.getLayoutParams();
         lp.gravity = Gravity.CENTER;
-        Rect padding = getWorkspacePadding(isLayoutRtl);
+        Rect padding = getWorkspacePadding();
         workspace.setLayoutParams(lp);
         workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom);
-        workspace.setPageSpacing(getWorkspacePageSpacing(isLayoutRtl));
+        workspace.setPageSpacing(getWorkspacePageSpacing());
 
         // Layout the hotseat
         View hotseat = launcher.findViewById(R.id.hotseat);
@@ -503,7 +431,7 @@
             // Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the
             //                     screen regardless of RTL
             lp.gravity = Gravity.RIGHT;
-            lp.width = normalHotseatBarHeightPx;
+            lp.width = hotseatBarHeightPx;
             lp.height = LayoutParams.MATCH_PARENT;
             hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
         } else if (isTablet) {
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
new file mode 100644
index 0000000..5966af5
--- /dev/null
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewPropertyAnimator;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.AccelerateInterpolator;
+import android.widget.LinearLayout;
+
+import com.android.launcher3.dragndrop.DragController;
+
+/*
+ * The top bar containing various drop targets: Delete/App Info/Uninstall.
+ */
+public class DropTargetBar extends LinearLayout implements DragController.DragListener {
+
+    protected static final int DEFAULT_DRAG_FADE_DURATION = 175;
+    protected static final TimeInterpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator();
+
+    private final Runnable mFadeAnimationEndRunnable = new Runnable() {
+
+        @Override
+        public void run() {
+            AccessibilityManager am = (AccessibilityManager)
+                    getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+            boolean accessibilityEnabled = am.isEnabled();
+            AlphaUpdateListener.updateVisibility(DropTargetBar.this, accessibilityEnabled);
+        }
+    };
+
+    @ViewDebug.ExportedProperty(category = "launcher")
+    protected boolean mDeferOnDragEnd;
+
+    @ViewDebug.ExportedProperty(category = "launcher")
+    protected boolean mVisible = false;
+
+    private ViewPropertyAnimator mCurrentAnimation;
+
+    // Drop targets
+    private ButtonDropTarget mDeleteDropTarget;
+    private ButtonDropTarget mAppInfoDropTarget;
+    private ButtonDropTarget mUninstallDropTarget;
+
+    public DropTargetBar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public DropTargetBar(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        // Get the individual components
+        mDeleteDropTarget = (ButtonDropTarget) findViewById(R.id.delete_target_text);
+        mAppInfoDropTarget = (ButtonDropTarget) findViewById(R.id.info_target_text);
+        mUninstallDropTarget = (ButtonDropTarget) findViewById(R.id.uninstall_target_text);
+
+        mDeleteDropTarget.setDropTargetBar(this);
+        mAppInfoDropTarget.setDropTargetBar(this);
+        mUninstallDropTarget.setDropTargetBar(this);
+
+        // Initialize with hidden state
+        setAlpha(0f);
+    }
+
+    public void setup(DragController dragController) {
+        dragController.addDragListener(this);
+        dragController.setFlingToDeleteDropTarget(mDeleteDropTarget);
+
+        dragController.addDragListener(mDeleteDropTarget);
+        dragController.addDragListener(mAppInfoDropTarget);
+        dragController.addDragListener(mUninstallDropTarget);
+
+        dragController.addDropTarget(mDeleteDropTarget);
+        dragController.addDropTarget(mAppInfoDropTarget);
+        dragController.addDropTarget(mUninstallDropTarget);
+    }
+
+    private void animateToVisibility(boolean isVisible) {
+        if (mVisible != isVisible) {
+            mVisible = isVisible;
+
+            // Cancel any existing animation
+            if (mCurrentAnimation != null) {
+                mCurrentAnimation.cancel();
+                mCurrentAnimation = null;
+            }
+
+            float finalAlpha = mVisible ? 1 : 0;
+            if (Float.compare(getAlpha(), finalAlpha) != 0) {
+                setVisibility(View.VISIBLE);
+                mCurrentAnimation = animate().alpha(finalAlpha)
+                        .setInterpolator(DEFAULT_INTERPOLATOR)
+                        .setDuration(DEFAULT_DRAG_FADE_DURATION)
+                        .withEndAction(mFadeAnimationEndRunnable);
+            }
+
+        }
+    }
+
+    public void enableAccessibleDrag(boolean enable) {
+        mDeleteDropTarget.enableAccessibleDrag(enable);
+        mAppInfoDropTarget.enableAccessibleDrag(enable);
+        mUninstallDropTarget.enableAccessibleDrag(enable);
+    }
+
+    /*
+     * DragController.DragListener implementation
+     */
+    @Override
+    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
+        animateToVisibility(true);
+    }
+
+    /**
+     * This is called to defer hiding the delete drop target until the drop animation has completed,
+     * instead of hiding immediately when the drag has ended.
+     */
+    protected void deferOnDragEnd() {
+        mDeferOnDragEnd = true;
+    }
+
+    @Override
+    public void onDragEnd() {
+        if (!mDeferOnDragEnd) {
+            animateToVisibility(false);
+        } else {
+            mDeferOnDragEnd = false;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index f99c08a..0b9e4ac 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -356,7 +356,7 @@
         CellLayout iconLayout = (CellLayout) parent.getParent();
         final Workspace workspace = (Workspace) iconLayout.getParent();
         final ViewGroup dragLayer = (ViewGroup) workspace.getParent();
-        final ViewGroup tabs = (ViewGroup) dragLayer.findViewById(R.id.search_drop_target_bar);
+        final ViewGroup tabs = (ViewGroup) dragLayer.findViewById(R.id.drop_target_bar);
         final Hotseat hotseat = (Hotseat) dragLayer.findViewById(R.id.hotseat);
 
         final ItemInfo itemInfo = (ItemInfo) v.getTag();
diff --git a/src/com/android/launcher3/FocusIndicatorView.java b/src/com/android/launcher3/FocusIndicatorView.java
deleted file mode 100644
index a835d99..0000000
--- a/src/com/android/launcher3/FocusIndicatorView.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.animation.Animator;
-import android.animation.PropertyValuesHolder;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.util.Pair;
-import android.view.View;
-
-import com.android.launcher3.util.Thunk;
-
-public class FocusIndicatorView extends View implements View.OnFocusChangeListener {
-
-    // It can be any number >0. The view is resized using scaleX and scaleY.
-    static final int DEFAULT_LAYOUT_SIZE = 100;
-
-    private static final float MIN_VISIBLE_ALPHA = 0.2f;
-    private static final long ANIM_DURATION = 150;
-
-    private final int[] mIndicatorPos = new int[2];
-    private final int[] mTargetViewPos = new int[2];
-
-    private Animator mCurrentAnimation;
-    private ViewAnimState mTargetState;
-
-    private View mLastFocusedView;
-    private boolean mInitiated;
-    private final OnFocusChangeListener mHideIndicatorOnFocusListener;
-
-    private Pair<View, Boolean> mPendingCall;
-
-    public FocusIndicatorView(Context context) {
-        this(context, null);
-    }
-
-    public FocusIndicatorView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        setAlpha(0);
-        setBackgroundColor(getResources().getColor(R.color.focused_background));
-
-        mHideIndicatorOnFocusListener = new OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                if (hasFocus) {
-                    endCurrentAnimation();
-                    setAlpha(0);
-                }
-            }
-        };
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-
-        // Redraw if it is already showing. This avoids a bug where the height changes by a small
-        // amount on connecting/disconnecting a bluetooth keyboard.
-        if (mLastFocusedView != null) {
-            mPendingCall = Pair.create(mLastFocusedView, Boolean.TRUE);
-            invalidate();
-        }
-    }
-
-    /**
-     * Sets the alpha of this FocusIndicatorView to 0 when a view with this listener receives focus.
-     */
-    public View.OnFocusChangeListener getHideIndicatorOnFocusListener() {
-        return mHideIndicatorOnFocusListener;
-    }
-
-    @Override
-    public void onFocusChange(View v, boolean hasFocus) {
-        mPendingCall = null;
-        if (!mInitiated && (getWidth() == 0)) {
-            // View not yet laid out. Wait until the view is ready to be drawn, so that be can
-            // get the location on screen.
-            mPendingCall = Pair.create(v, hasFocus);
-            invalidate();
-            return;
-        }
-
-        if (!mInitiated) {
-            // The parent view should always the a parent of the target view.
-            computeLocationRelativeToParent(this, (View) getParent(), mIndicatorPos);
-            mInitiated = true;
-        }
-
-        if (hasFocus) {
-            int indicatorWidth = getWidth();
-            int indicatorHeight = getHeight();
-
-            endCurrentAnimation();
-            ViewAnimState nextState = new ViewAnimState();
-            nextState.scaleX = v.getScaleX() * v.getWidth() / indicatorWidth;
-            nextState.scaleY = v.getScaleY() * v.getHeight() / indicatorHeight;
-
-            computeLocationRelativeToParent(v, (View) getParent(), mTargetViewPos);
-            nextState.x = mTargetViewPos[0] - mIndicatorPos[0] - (1 - nextState.scaleX) * indicatorWidth / 2;
-            nextState.y = mTargetViewPos[1] - mIndicatorPos[1] - (1 - nextState.scaleY) * indicatorHeight / 2;
-
-            if (getAlpha() > MIN_VISIBLE_ALPHA) {
-                mTargetState = nextState;
-                mCurrentAnimation = new LauncherViewPropertyAnimator(this)
-                        .alpha(1)
-                        .translationX(mTargetState.x)
-                        .translationY(mTargetState.y)
-                        .scaleX(mTargetState.scaleX)
-                        .scaleY(mTargetState.scaleY);
-            } else {
-                applyState(nextState);
-                mCurrentAnimation = LauncherAnimUtils.ofPropertyValuesHolder(this,
-                        PropertyValuesHolder.ofFloat(View.ALPHA, 1));
-            }
-            mLastFocusedView = v;
-        } else {
-            if (mLastFocusedView == v) {
-                mLastFocusedView = null;
-                endCurrentAnimation();
-                mCurrentAnimation = LauncherAnimUtils.ofPropertyValuesHolder(this,
-                        PropertyValuesHolder.ofFloat(View.ALPHA, 0));
-            }
-        }
-        if (mCurrentAnimation != null) {
-            mCurrentAnimation.setDuration(ANIM_DURATION).start();
-        }
-    }
-
-    private void endCurrentAnimation() {
-        if (mCurrentAnimation != null) {
-            mCurrentAnimation.cancel();
-            mCurrentAnimation = null;
-        }
-        if (mTargetState != null) {
-            applyState(mTargetState);
-            mTargetState = null;
-        }
-    }
-
-    private void applyState(ViewAnimState state) {
-        setTranslationX(state.x);
-        setTranslationY(state.y);
-        setScaleX(state.scaleX);
-        setScaleY(state.scaleY);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mPendingCall != null) {
-            onFocusChange(mPendingCall.first, mPendingCall.second);
-        }
-    }
-
-    /**
-     * Computes the location of a view relative to {@param parent}, off-setting
-     * any shift due to page view scroll.
-     * @param pos an array of two integers in which to hold the coordinates
-     */
-    private static void computeLocationRelativeToParent(View v, View parent, int[] pos) {
-        pos[0] = pos[1] = 0;
-        computeLocationRelativeToParentHelper(v, parent, pos);
-
-        // If a view is scaled, its position will also shift accordingly. For optimization, only
-        // consider this for the last node.
-        pos[0] += (1 - v.getScaleX()) * v.getWidth() / 2;
-        pos[1] += (1 - v.getScaleY()) * v.getHeight() / 2;
-    }
-
-    private static void computeLocationRelativeToParentHelper(View child,
-            View commonParent, int[] shift) {
-        View parent = (View) child.getParent();
-        shift[0] += child.getLeft();
-        shift[1] += child.getTop();
-        if (parent instanceof PagedView) {
-            PagedView page = (PagedView) parent;
-            shift[0] -= page.getScrollForPage(page.indexOfChild(child));
-        }
-
-        if (parent != commonParent) {
-            computeLocationRelativeToParentHelper(parent, commonParent, shift);
-        }
-    }
-
-    @Thunk static final class ViewAnimState {
-        float x, y, scaleX, scaleY;
-    }
-}
diff --git a/src/com/android/launcher3/InsettableFrameLayout.java b/src/com/android/launcher3/InsettableFrameLayout.java
index f4bfa45..61edc0f 100644
--- a/src/com/android/launcher3/InsettableFrameLayout.java
+++ b/src/com/android/launcher3/InsettableFrameLayout.java
@@ -9,6 +9,9 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.config.FeatureFlags;
+
 public class InsettableFrameLayout extends FrameLayout implements
     ViewGroup.OnHierarchyChangeListener, Insettable {
 
@@ -31,6 +34,9 @@
             lp.rightMargin += (newInsets.right - oldInsets.right);
             lp.bottomMargin += (newInsets.bottom - oldInsets.bottom);
         }
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && child instanceof AllAppsContainerView) {
+            lp.setMargins(0, 0, 0, lp.bottomMargin);
+        }
         child.setLayoutParams(lp);
     }
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 13e451a..a504250 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -45,20 +45,16 @@
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
@@ -95,7 +91,9 @@
 import android.widget.Toast;
 
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.allapps.DefaultAppSearchController;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.LauncherActivityInfoCompat;
@@ -110,14 +108,14 @@
 import com.android.launcher3.dynamicui.ExtractedColors;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.keyboard.ViewGroupFocusHelper;
+import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.logging.LoggerUtils;
 import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.model.WidgetsModel;
-import com.android.launcher3.pageindicators.PageIndicator;
 import com.android.launcher3.pageindicators.PageIndicatorLine;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.TestingUtils;
 import com.android.launcher3.util.Thunk;
@@ -183,6 +181,9 @@
     static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
             "com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
 
+    public static final String ACTION_APPWIDGET_HOST_RESET =
+            "com.android.launcher3.intent.ACTION_APPWIDGET_HOST_RESET";
+
     // Type: int
     private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
     // Type: int
@@ -197,9 +198,6 @@
     static final String INTRO_SCREEN_DISMISSED = "launcher.intro_screen_dismissed";
     static final String FIRST_RUN_ACTIVITY_DISPLAYED = "launcher.first_run_activity_displayed";
 
-    private static final String QSB_WIDGET_ID = "qsb_widget_id";
-    private static final String QSB_WIDGET_PROVIDER = "qsb_widget_provider";
-
     /** The different states that Launcher can be in. */
     enum State { NONE, WORKSPACE, WORKSPACE_SPRING_LOADED, APPS, APPS_SPRING_LOADED,
         WIDGETS, WIDGETS_SPRING_LOADED }
@@ -219,8 +217,19 @@
     private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
     @Thunk static int NEW_APPS_ANIMATION_DELAY = 500;
 
-    private final BroadcastReceiver mCloseSystemDialogsReceiver
-            = new CloseSystemDialogsIntentReceiver();
+    private final BroadcastReceiver mUiBroadcastReceiver = new BroadcastReceiver() {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                closeSystemDialogs();
+            } else if (ACTION_APPWIDGET_HOST_RESET.equals(intent.getAction())) {
+                if (mAppWidgetHost != null) {
+                    mAppWidgetHost.startListening();
+                }
+            }
+        }
+    };
 
     @Thunk Workspace mWorkspace;
     private View mLauncherView;
@@ -245,18 +254,16 @@
     private View mAllAppsButton;
     private View mWidgetsButton;
 
-    private SearchDropTargetBar mSearchDropTargetBar;
-    private AppInfoDropTargetBar mAppInfoDropTargetBar;
+    private DropTargetBar mDropTargetBar;
 
     // Main container view for the all apps screen.
     @Thunk AllAppsContainerView mAppsView;
+    AllAppsTransitionController mAllAppsController;
 
     // Main container view and the model for the widget tray screen.
     @Thunk WidgetsContainerView mWidgetsView;
     @Thunk WidgetsModel mWidgetsModel;
 
-    private AppWidgetHostView mQsb;
-
     private Bundle mSavedState;
     // We set the state in both onCreate and then onNewIntent in some cases, which causes both
     // scroll issues (because the workspace may not have been measured yet) and extra work.
@@ -358,7 +365,7 @@
 
     private UserEventDispatcher mUserEventDispatcher;
 
-    public FocusIndicatorView mFocusHandler;
+    public ViewGroupFocusHelper mFocusHandler;
     private boolean mRotationEnabled = false;
 
     @Thunk void setOrientation() {
@@ -409,7 +416,8 @@
         mIconCache = app.getIconCache();
 
         mDragController = new DragController(this);
-        mStateTransitionAnimation = new LauncherStateTransitionAnimation(this);
+        mAllAppsController = new AllAppsTransitionController(this);
+        mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, mAllAppsController);
 
         mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
 
@@ -428,8 +436,6 @@
 
         setContentView(R.layout.launcher);
 
-        app.getInvariantDeviceProfile().landscapeProfile.setSearchBarHeight(getSearchBarHeight());
-        app.getInvariantDeviceProfile().portraitProfile.setSearchBarHeight(getSearchBarHeight());
         setupViews();
         mDeviceProfile.layout(this);
         mExtractedColors = new ExtractedColors();
@@ -464,7 +470,8 @@
         Selection.setSelection(mDefaultKeySsb, 0);
 
         IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        registerReceiver(mCloseSystemDialogsReceiver, filter);
+        filter.addAction(ACTION_APPWIDGET_HOST_RESET);
+        registerReceiver(mUiBroadcastReceiver, filter);
 
         mRotationEnabled = getResources().getBoolean(R.bool.allow_rotation);
         // In case we are on a device with locked rotation, we should look at preferences to check
@@ -739,10 +746,6 @@
             } else if (resultCode == RESULT_OK) {
                 addAppWidgetImpl(appWidgetId, mPendingAddInfo, null,
                         mPendingAddWidgetInfo, ON_ACTIVITY_RESULT_ANIMATION_DELAY);
-
-                // When the user has granted permission to bind widgets, we should check to see if
-                // we can inflate the default search bar widget.
-                getOrCreateQsbBar();
             }
             return;
         } else if (requestCode == REQUEST_PICK_WALLPAPER) {
@@ -879,7 +882,7 @@
             sPendingAddItem = null;
             if (grantResults.length > 0
                     && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
-                startActivity(v, intent, null);
+                startActivitySafely(v, intent, null);
             } else {
                 // TODO: Show a snack bar with link to settings
                 Toast.makeText(this, getString(R.string.msg_no_phone_permission,
@@ -1056,7 +1059,6 @@
         if (!isWorkspaceLoading()) {
             getWorkspace().reinflateWidgetsIfNecessary();
         }
-        reinflateQSBIfNecessary();
 
         if (DEBUG_RESUME_TIME) {
             Log.d(TAG, "Time spent in onResume: " + (System.currentTimeMillis() - startTime));
@@ -1339,11 +1341,10 @@
      * Finds all the views we need and configure them properly.
      */
     private void setupViews() {
-        final DragController dragController = mDragController;
-
         mLauncherView = findViewById(R.id.launcher);
-        mFocusHandler = (FocusIndicatorView) findViewById(R.id.focus_indicator);
         mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
+        mFocusHandler = mDragLayer.getFocusIndicatorHelper();
+
         mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
         mPageIndicator = (PageIndicatorLine) mDragLayer.findViewById(R.id.page_indicator);
 
@@ -1353,7 +1354,8 @@
         mWorkspaceBackgroundDrawable = getResources().getDrawable(R.drawable.workspace_bg);
 
         // Setup the drag layer
-        mDragLayer.setup(this, dragController);
+
+        mDragLayer.setup(this, mDragController, mAllAppsController);
 
         // Setup the hotseat
         mHotseat = (Hotseat) findViewById(R.id.hotseat);
@@ -1367,15 +1369,12 @@
         // Setup the workspace
         mWorkspace.setHapticFeedbackEnabled(false);
         mWorkspace.setOnLongClickListener(this);
-        mWorkspace.setup(dragController);
-        dragController.addDragListener(mWorkspace);
+        mWorkspace.setup(mDragController);
+        mWorkspace.bindAndInitFirstWorkspaceScreen(null /* recycled qsb */);
+        mDragController.addDragListener(mWorkspace);
 
         // Get the search/delete/uninstall bar
-        mSearchDropTargetBar = (SearchDropTargetBar)
-                mDragLayer.findViewById(R.id.search_drop_target_bar);
-        // Get the app info bar
-        mAppInfoDropTargetBar = (AppInfoDropTargetBar)
-                mDragLayer.findViewById(R.id.app_info_drop_target_bar);
+        mDropTargetBar = (DropTargetBar) mDragLayer.findViewById(R.id.drop_target_bar);
 
         // Setup Apps and Widgets
         mAppsView = (AllAppsContainerView) findViewById(R.id.apps_view);
@@ -1387,17 +1386,11 @@
         }
 
         // Setup the drag controller (drop targets have to be added in reverse order in priority)
-        dragController.setDragScoller(mWorkspace);
-        dragController.setScrollView(mDragLayer);
-        dragController.setMoveTarget(mWorkspace);
-        dragController.addDropTarget(mWorkspace);
-        if (mSearchDropTargetBar != null) {
-            mSearchDropTargetBar.setup(this, dragController);
-            mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
-        }
-        if (mAppInfoDropTargetBar != null) {
-            mAppInfoDropTargetBar.setup(this, dragController);
-        }
+        mDragController.setDragScoller(mWorkspace);
+        mDragController.setScrollView(mDragLayer);
+        mDragController.setMoveTarget(mWorkspace);
+        mDragController.addDropTarget(mWorkspace);
+        mDropTargetBar.setup(mDragController);
 
         if (TestingUtils.MEMORY_DUMP_ENABLED) {
             TestingUtils.addWeightWatcher(this);
@@ -1806,12 +1799,8 @@
         return mOverviewPanel;
     }
 
-    public SearchDropTargetBar getSearchDropTargetBar() {
-        return mSearchDropTargetBar;
-    }
-
-    public AppInfoDropTargetBar getAppInfoDropTargetBar() {
-        return mAppInfoDropTargetBar;
+    public DropTargetBar getDropTargetBar() {
+        return mDropTargetBar;
     }
 
     public LauncherAppWidgetHost getAppWidgetHost() {
@@ -1940,6 +1929,7 @@
         if (mWorkspace.getChildCount() > 0) {
             outState.putInt(RUNTIME_STATE_CURRENT_SCREEN,
                     mWorkspace.getCurrentPageOffsetFromCustomContent());
+
         }
         super.onSaveInstanceState(outState);
 
@@ -1999,7 +1989,7 @@
         ((AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE))
                 .removeAccessibilityStateChangeListener(this);
 
-        unregisterReceiver(mCloseSystemDialogsReceiver);
+        unregisterReceiver(mUiBroadcastReceiver);
 
         LauncherAnimUtils.onDestroyActivity();
 
@@ -2052,10 +2042,9 @@
             appSearchData = new Bundle();
             appSearchData.putString("source", "launcher-search");
         }
-        Rect sourceBounds = new Rect();
-        if (mSearchDropTargetBar != null) {
-            sourceBounds = mSearchDropTargetBar.getSearchBarBounds();
-        }
+
+        // TODO send proper bounds.
+        Rect sourceBounds = null;
 
         boolean clearTextImmediately = startSearch(initialQuery, selectInitialQuery,
                 appSearchData, sourceBounds);
@@ -2465,19 +2454,6 @@
     }
 
     /**
-     * Re-listen when widget host is reset.
-     */
-    @Override
-    public void onAppWidgetHostReset() {
-        if (mAppWidgetHost != null) {
-            mAppWidgetHost.startListening();
-        }
-
-        // Recreate the QSB, as the widget has been reset.
-        bindSearchProviderChanged();
-    }
-
-    /**
      * Launches the intent referred by the clicked shortcut.
      *
      * @param v The view representing the clicked shortcut.
@@ -2679,26 +2655,13 @@
         startAppShortcutOrInfoActivity(v);
     }
 
-    @Thunk void startAppShortcutOrInfoActivity(View v) {
-        Object tag = v.getTag();
-        final ShortcutInfo shortcut;
-        final Intent intent;
-        if (tag instanceof ShortcutInfo) {
-            shortcut = (ShortcutInfo) tag;
-            intent = shortcut.intent;
-            int[] pos = new int[2];
-            v.getLocationOnScreen(pos);
-            intent.setSourceBounds(new Rect(pos[0], pos[1],
-                    pos[0] + v.getWidth(), pos[1] + v.getHeight()));
-
-        } else if (tag instanceof AppInfo) {
-            shortcut = null;
-            intent = ((AppInfo) tag).intent;
-        } else {
-            throw new IllegalArgumentException("Input must be a Shortcut or AppInfo");
+    private void startAppShortcutOrInfoActivity(View v) {
+        ItemInfo item = (ItemInfo) v.getTag();
+        Intent intent = item.getIntent();
+        if (intent == null) {
+            throw new IllegalArgumentException("Input must have a valid intent");
         }
-
-        boolean success = startActivitySafely(v, intent, tag);
+        boolean success = startActivitySafely(v, intent, item);
         getUserEventDispatcher().logAppLaunch(v, intent);
 
         if (success && v instanceof BubbleTextView) {
@@ -2838,102 +2801,109 @@
         }
     }
 
-    private boolean startActivity(View v, Intent intent, Object tag) {
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+    private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
         try {
-            // Only launch using the new animation if the shortcut has not opted out (this is a
-            // private contract between launcher and may be ignored in the future).
-            boolean useLaunchAnimation = (v != null) &&
-                    !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
-            LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this);
-            UserManagerCompat userManager = UserManagerCompat.getInstance(this);
-
-            UserHandleCompat user = null;
-            if (intent.hasExtra(AppInfo.EXTRA_PROFILE)) {
-                long serialNumber = intent.getLongExtra(AppInfo.EXTRA_PROFILE, -1);
-                user = userManager.getUserForSerialNumber(serialNumber);
-            }
-
-            Bundle optsBundle = null;
-            if (useLaunchAnimation) {
-                ActivityOptions opts = null;
-                if (Utilities.ATLEAST_MARSHMALLOW) {
-                    int left = 0, top = 0;
-                    int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
-                    if (v instanceof TextView) {
-                        // Launch from center of icon, not entire view
-                        Drawable icon = Workspace.getTextViewIcon((TextView) v);
-                        if (icon != null) {
-                            Rect bounds = icon.getBounds();
-                            left = (width - bounds.width()) / 2;
-                            top = v.getPaddingTop();
-                            width = bounds.width();
-                            height = bounds.height();
-                        }
-                    }
-                    opts = ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
-                } else if (!Utilities.ATLEAST_LOLLIPOP) {
-                    // Below L, we use a scale up animation
-                    opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
-                                    v.getMeasuredWidth(), v.getMeasuredHeight());
-                } else if (Utilities.ATLEAST_LOLLIPOP_MR1) {
-                    // On L devices, we use the device default slide-up transition.
-                    // On L MR1 devices, we a custom version of the slide-up transition which
-                    // doesn't have the delay present in the device default.
-                    opts = ActivityOptions.makeCustomAnimation(this,
-                            R.anim.task_open_enter, R.anim.no_anim);
-                }
-                optsBundle = opts != null ? opts.toBundle() : null;
-            }
-
-            if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
+            StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
+            try {
+                // Temporarily disable deathPenalty on all default checks. For eg, shortcuts
+                // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
+                // is enabled by default on NYC.
+                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
+                        .penaltyLog().build());
                 // Could be launching some bookkeeping activity
                 startActivity(intent, optsBundle);
-            } else {
-                // TODO Component can be null when shortcuts are supported for secondary user
-                launcherApps.startActivityForProfile(intent.getComponent(), user,
-                        intent.getSourceBounds(), optsBundle);
+            } finally {
+                StrictMode.setVmPolicy(oldPolicy);
             }
-            return true;
         } catch (SecurityException e) {
-            if (Utilities.ATLEAST_MARSHMALLOW && tag instanceof ItemInfo) {
-                // Due to legacy reasons, direct call shortcuts require Launchers to have the
-                // corresponding permission. Show the appropriate permission prompt if that
-                // is the case.
-                if (intent.getComponent() == null
-                        && Intent.ACTION_CALL.equals(intent.getAction())
-                        && checkSelfPermission(Manifest.permission.CALL_PHONE) !=
-                            PackageManager.PERMISSION_GRANTED) {
-                    // TODO: Rename sPendingAddItem to a generic name.
-                    sPendingAddItem = preparePendingAddArgs(REQUEST_PERMISSION_CALL_PHONE, intent,
-                            0, (ItemInfo) tag);
-                    requestPermissions(new String[]{Manifest.permission.CALL_PHONE},
-                            REQUEST_PERMISSION_CALL_PHONE);
-                    return false;
-                }
+            // Due to legacy reasons, direct call shortcuts require Launchers to have the
+            // corresponding permission. Show the appropriate permission prompt if that
+            // is the case.
+            if (intent.getComponent() == null
+                    && Intent.ACTION_CALL.equals(intent.getAction())
+                    && checkSelfPermission(Manifest.permission.CALL_PHONE) !=
+                    PackageManager.PERMISSION_GRANTED) {
+                // TODO: Rename sPendingAddItem to a generic name.
+                sPendingAddItem = preparePendingAddArgs(REQUEST_PERMISSION_CALL_PHONE, intent,
+                        0, info);
+                requestPermissions(new String[]{Manifest.permission.CALL_PHONE},
+                        REQUEST_PERMISSION_CALL_PHONE);
+            } else {
+                // No idea why this was thrown.
+                throw e;
             }
-            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
-            Log.e(TAG, "Launcher does not have the permission to launch " + intent +
-                    ". Make sure to create a MAIN intent-filter for the corresponding activity " +
-                    "or use the exported attribute for this activity. "
-                    + "tag="+ tag + " intent=" + intent, e);
         }
-        return false;
     }
 
-    public boolean startActivitySafely(View v, Intent intent, Object tag) {
-        boolean success = false;
+    private Bundle getActivityLaunchOptions(View v) {
+        if (Utilities.ATLEAST_MARSHMALLOW) {
+            int left = 0, top = 0;
+            int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
+            if (v instanceof TextView) {
+                // Launch from center of icon, not entire view
+                Drawable icon = Workspace.getTextViewIcon((TextView) v);
+                if (icon != null) {
+                    Rect bounds = icon.getBounds();
+                    left = (width - bounds.width()) / 2;
+                    top = v.getPaddingTop();
+                    width = bounds.width();
+                    height = bounds.height();
+                }
+            }
+            return ActivityOptions.makeClipRevealAnimation(v, left, top, width, height).toBundle();
+        } else if (Utilities.ATLEAST_LOLLIPOP_MR1) {
+            // On L devices, we use the device default slide-up transition.
+            // On L MR1 devices, we use a custom version of the slide-up transition which
+            // doesn't have the delay present in the device default.
+            return ActivityOptions.makeCustomAnimation(
+                    this, R.anim.task_open_enter, R.anim.no_anim).toBundle();
+        }
+        return null;
+    }
+
+    public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
         if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
             Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
             return false;
         }
-        try {
-            success = startActivity(v, intent, tag);
-        } catch (ActivityNotFoundException e) {
-            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
-            Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
+        // Only launch using the new animation if the shortcut has not opted out (this is a
+        // private contract between launcher and may be ignored in the future).
+        boolean useLaunchAnimation = (v != null) &&
+                !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
+        Bundle optsBundle = useLaunchAnimation ? getActivityLaunchOptions(v) : null;
+
+        UserHandleCompat user = null;
+        if (intent.hasExtra(AppInfo.EXTRA_PROFILE)) {
+            long serialNumber = intent.getLongExtra(AppInfo.EXTRA_PROFILE, -1);
+            user = UserManagerCompat.getInstance(this).getUserForSerialNumber(serialNumber);
         }
-        return success;
+
+        // Prepare intent
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (v != null) {
+            int[] pos = new int[2];
+            v.getLocationOnScreen(pos);
+            intent.setSourceBounds(
+                    new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight()));
+        }
+        try {
+            if (Utilities.ATLEAST_MARSHMALLOW &&
+                    item != null && item.itemType == Favorites.ITEM_TYPE_SHORTCUT) {
+                // Shortcuts need some special checks due to legacy reasons.
+                startShortcutIntentSafely(intent, optsBundle, item);
+            } else if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
+                // Could be launching some bookkeeping activity
+                startActivity(intent, optsBundle);
+            } else {
+                LauncherAppsCompat.getInstance(this).startActivityForProfile(
+                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
+            }
+            return true;
+        } catch (ActivityNotFoundException|SecurityException e) {
+            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
+        }
+        return false;
     }
 
     /**
@@ -3167,6 +3137,8 @@
                     mWorkspace.startReordering(v);
                 } else {
                     showOverviewMode(true);
+                    mHotseat.requestDisallowInterceptTouchEvent(true);
+
                 }
             } else {
                 final boolean isAllAppsButton = inHotseat && isAllAppsButtonRank(
@@ -3322,7 +3294,7 @@
     /**
      * Shows the apps view.
      */
-    void showAppsView(boolean animated, boolean resetListToTop, boolean updatePredictedApps,
+    public void showAppsView(boolean animated, boolean resetListToTop, boolean updatePredictedApps,
             boolean focusSearchBar) {
         if (resetListToTop) {
             mAppsView.scrollToTop();
@@ -3497,105 +3469,6 @@
         return (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch());
     }
 
-    public View getOrCreateQsbBar() {
-        if (launcherCallbacksProvidesSearch()) {
-            return mLauncherCallbacks.getQsbBar();
-        }
-
-        if (mQsb == null) {
-            AppWidgetProviderInfo searchProvider = Utilities.getSearchWidgetProvider(this);
-            if (searchProvider == null) {
-                return null;
-            }
-
-            Bundle opts = new Bundle();
-            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
-                    AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
-
-            // Determine the min and max dimensions of the widget.
-            LauncherAppState app = LauncherAppState.getInstance();
-            DeviceProfile portraitProfile = app.getInvariantDeviceProfile().portraitProfile;
-            DeviceProfile landscapeProfile = app.getInvariantDeviceProfile().landscapeProfile;
-            float density = getResources().getDisplayMetrics().density;
-            Point searchDimens = portraitProfile.getSearchBarDimensForWidgetOpts(getResources());
-            int maxHeight = (int) (searchDimens.y / density);
-            int minHeight = maxHeight;
-            int maxWidth = (int) (searchDimens.x / density);
-            int minWidth = maxWidth;
-            if (!landscapeProfile.isVerticalBarLayout()) {
-                searchDimens = landscapeProfile.getSearchBarDimensForWidgetOpts(getResources());
-                maxHeight = (int) Math.max(maxHeight, searchDimens.y / density);
-                minHeight = (int) Math.min(minHeight, searchDimens.y / density);
-                maxWidth = (int) Math.max(maxWidth, searchDimens.x / density);
-                minWidth = (int) Math.min(minWidth, searchDimens.x / density);
-            }
-            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight);
-            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, minHeight);
-            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, maxWidth);
-            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, minWidth);
-            if (LOGD) {
-                Log.d(TAG, "QSB widget options: maxHeight=" + maxHeight + " minHeight=" + minHeight
-                        + " maxWidth=" + maxWidth + " minWidth=" + minWidth);
-            }
-
-            if (mLauncherCallbacks != null) {
-                opts.putAll(mLauncherCallbacks.getAdditionalSearchWidgetOptions());
-            }
-
-            int widgetId = mSharedPrefs.getInt(QSB_WIDGET_ID, -1);
-            AppWidgetProviderInfo widgetInfo = mAppWidgetManager.getAppWidgetInfo(widgetId);
-            if (!searchProvider.provider.flattenToString().equals(
-                    mSharedPrefs.getString(QSB_WIDGET_PROVIDER, null))
-                    || (widgetInfo == null)
-                    || !widgetInfo.provider.equals(searchProvider.provider)) {
-                // A valid widget is not already bound.
-                if (widgetId > -1) {
-                    mAppWidgetHost.deleteAppWidgetId(widgetId);
-                    widgetId = -1;
-                }
-
-                // Try to bind a new widget
-                widgetId = mAppWidgetHost.allocateAppWidgetId();
-
-                if (!AppWidgetManagerCompat.getInstance(this)
-                        .bindAppWidgetIdIfAllowed(widgetId, searchProvider, opts)) {
-                    mAppWidgetHost.deleteAppWidgetId(widgetId);
-                    widgetId = -1;
-                }
-
-                mSharedPrefs.edit()
-                    .putInt(QSB_WIDGET_ID, widgetId)
-                    .putString(QSB_WIDGET_PROVIDER, searchProvider.provider.flattenToString())
-                    .apply();
-            }
-
-            mAppWidgetHost.setQsbWidgetId(widgetId);
-            if (widgetId != -1) {
-                mQsb = mAppWidgetHost.createView(this, widgetId, searchProvider);
-                mQsb.setId(R.id.qsb_widget);
-                if (!Utilities.containsAll(
-                        AppWidgetManager.getInstance(this).getAppWidgetOptions(widgetId), opts)) {
-                    // Launcher should not be updating the options often.
-                    FileLog.d(TAG, "Options for QSB were not same");
-                    mQsb.updateAppWidgetOptions(opts);
-                }
-                mQsb.setPadding(0, 0, 0, 0);
-                mSearchDropTargetBar.addView(mQsb);
-                mSearchDropTargetBar.setQsbSearchBar(mQsb);
-            }
-        }
-        return mQsb;
-    }
-
-    private void reinflateQSBIfNecessary() {
-        if (mQsb instanceof LauncherAppWidgetHostView &&
-                ((LauncherAppWidgetHostView) mQsb).isReinflateRequired()) {
-            mSearchDropTargetBar.removeView(mQsb);
-            mQsb = null;
-            mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
-        }
-    }
-
     @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
         final boolean result = super.dispatchPopulateAccessibilityEvent(event);
@@ -3615,16 +3488,6 @@
     }
 
     /**
-     * Receives notifications when system dialogs are to be closed.
-     */
-    @Thunk class CloseSystemDialogsIntentReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            closeSystemDialogs();
-        }
-    }
-
-    /**
      * If the activity is currently paused, signal that we need to run the passed Runnable
      * in onResume.
      *
@@ -3729,12 +3592,13 @@
 
     @Override
     public void bindScreens(ArrayList<Long> orderedScreenIds) {
-        bindAddScreens(orderedScreenIds);
-
-        // If there are no screens, we need to have an empty screen
-        if (orderedScreenIds.size() == 0) {
-            mWorkspace.addExtraEmptyScreen();
+        // Make sure the first screen is always at the start.
+        if (orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != 0) {
+            orderedScreenIds.remove(Workspace.FIRST_SCREEN_ID);
+            orderedScreenIds.add(0, Workspace.FIRST_SCREEN_ID);
+            mModel.updateWorkspaceScreenOrder(this, orderedScreenIds);
         }
+        bindAddScreens(orderedScreenIds);
 
         // Create the custom content page (this call updates mDefaultScreen which calls
         // setCurrentPage() so ensure that all pages are added before calling this).
@@ -3744,11 +3608,14 @@
         }
     }
 
-    @Override
-    public void bindAddScreens(ArrayList<Long> orderedScreenIds) {
+    private void bindAddScreens(ArrayList<Long> orderedScreenIds) {
         int count = orderedScreenIds.size();
         for (int i = 0; i < count; i++) {
-            mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(orderedScreenIds.get(i));
+            long screenId = orderedScreenIds.get(i);
+            if (screenId != Workspace.FIRST_SCREEN_ID) {
+                // No need to bind the first screen, as its always bound.
+                mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(screenId);
+            }
         }
     }
 
@@ -3827,24 +3694,6 @@
                 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                     ShortcutInfo info = (ShortcutInfo) item;
                     view = createShortcut(info);
-
-                    /*
-                     * TODO: FIX collision case
-                     */
-                    if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
-                        CellLayout cl = mWorkspace.getScreenWithId(item.screenId);
-                        if (cl != null && cl.isOccupied(item.cellX, item.cellY)) {
-                            View v = cl.getChildAt(item.cellX, item.cellY);
-                            Object tag = v.getTag();
-                            String desc = "Collision while binding workspace item: " + item
-                                    + ". Collides with " + tag;
-                            if (ProviderConfig.IS_DOGFOOD_BUILD) {
-                                throw (new RuntimeException(desc));
-                            } else {
-                                Log.d(TAG, desc);
-                            }
-                        }
-                    }
                     break;
                 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                     view = FolderIcon.fromXml(R.layout.folder_icon, this,
@@ -3855,6 +3704,25 @@
                     throw new RuntimeException("Invalid Item Type");
             }
 
+             /*
+             * Remove colliding items.
+             */
+            if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+                CellLayout cl = mWorkspace.getScreenWithId(item.screenId);
+                if (cl != null && cl.isOccupied(item.cellX, item.cellY)) {
+                    View v = cl.getChildAt(item.cellX, item.cellY);
+                    Object tag = v.getTag();
+                    String desc = "Collision while binding workspace item: " + item
+                            + ". Collides with " + tag;
+                    if (ProviderConfig.IS_DOGFOOD_BUILD) {
+                        throw (new RuntimeException(desc));
+                    } else {
+                        Log.d(TAG, desc);
+                        LauncherModel.deleteItemFromDatabase(this, item);
+                        continue;
+                    }
+                }
+            }
             workspace.addInScreenFromBind(view, item.container, item.screenId, item.cellX,
                     item.cellY, 1, 1);
             if (animateIcons) {
@@ -4142,11 +4010,6 @@
         return mDeviceProfile.isVerticalBarLayout();
     }
 
-    /** Returns the search bar bounds in pixels. */
-    protected Rect getSearchBarBounds() {
-        return mDeviceProfile.getSearchBarBounds(Utilities.isRtl(getResources()));
-    }
-
     public int getSearchBarHeight() {
         if (mLauncherCallbacks != null) {
             return mLauncherCallbacks.getSearchBarHeight();
@@ -4154,17 +4017,6 @@
         return LauncherCallbacks.SEARCH_BAR_HEIGHT_NORMAL;
     }
 
-    public void bindSearchProviderChanged() {
-        if (mSearchDropTargetBar == null) {
-            return;
-        }
-        if (mQsb != null) {
-            mSearchDropTargetBar.removeView(mQsb);
-            mQsb = null;
-        }
-        mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
-    }
-
     /**
      * A runnable that we can dequeue and re-enqueue when all applications are bound (to prevent
      * multiple calls to bind the same list.)
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 9d889e0..ae3abbf 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -105,7 +105,6 @@
         // Register intent receivers
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_LOCALE_CHANGED);
-        filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
         // For handling managed profiles
         filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
         filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 8c23ff3..3bb7381 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -37,7 +37,6 @@
 
     private final ArrayList<Runnable> mProviderChangeListeners = new ArrayList<Runnable>();
 
-    private int mQsbWidgetId = -1;
     private Launcher mLauncher;
 
     public LauncherAppWidgetHost(Launcher launcher, int hostId) {
@@ -45,23 +44,9 @@
         mLauncher = launcher;
     }
 
-    public void setQsbWidgetId(int widgetId) {
-        mQsbWidgetId = widgetId;
-    }
-
     @Override
     protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
-        if (appWidgetId == mQsbWidgetId) {
-            return new LauncherAppWidgetHostView(context) {
-
-                @Override
-                protected View getErrorView() {
-                    // For the QSB, show an empty view instead of an error view.
-                    return new View(getContext());
-                }
-            };
-        }
         return new LauncherAppWidgetHostView(context);
     }
 
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index 28557d0..53d9c04 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -54,6 +54,8 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mChildrenFocused;
 
+    protected int mErrorViewId = R.layout.appwidget_error;
+
     public LauncherAppWidgetHostView(Context context) {
         super(context);
         mContext = context;
@@ -68,7 +70,7 @@
 
     @Override
     protected View getErrorView() {
-        return mInflater.inflate(R.layout.appwidget_error, this, false);
+        return mInflater.inflate(mErrorViewId, this, false);
     }
 
     public void updateLastInflationOrientation() {
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index 4c8fedf..99210fd 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -72,7 +72,7 @@
      */
     int appWidgetId = NO_ID;
 
-    ComponentName providerName;
+    public ComponentName providerName;
 
     /**
      * Indicates the restore status of the widget.
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index 28d8052..f245cd3 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -63,9 +63,8 @@
         LauncherAppState app = LauncherAppState.getInstance();
         InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
 
-        // We only care out the cell size, which is independent of the the layout direction.
-        Rect paddingLand = idp.landscapeProfile.getWorkspacePadding(false /* isLayoutRtl */);
-        Rect paddingPort = idp.portraitProfile.getWorkspacePadding(false /* isLayoutRtl */);
+        Rect paddingLand = idp.landscapeProfile.getWorkspacePadding();
+        Rect paddingPort = idp.portraitProfile.getWorkspacePadding();
 
         // Always assume we're working with the smallest span to make sure we
         // reserve enough space in both orientations.
diff --git a/src/com/android/launcher3/LauncherBackupAgent.java b/src/com/android/launcher3/LauncherBackupAgent.java
index b2f5c57..b3e73f7 100644
--- a/src/com/android/launcher3/LauncherBackupAgent.java
+++ b/src/com/android/launcher3/LauncherBackupAgent.java
@@ -3,24 +3,12 @@
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
 import android.os.ParcelFileDescriptor;
 
-import com.android.launcher3.LauncherProvider.DatabaseHelper;
-import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.logging.FileLog;
-
-import java.io.InvalidObjectException;
+import com.android.launcher3.provider.RestoreDbTask;
 
 public class LauncherBackupAgent extends BackupAgent {
 
-    private static final String TAG = "LauncherBackupAgent";
-
-    private static final String INFO_COLUMN_NAME = "name";
-    private static final String INFO_COLUMN_DEFAULT_VALUE = "dflt_value";
-
     @Override
     public void onRestore(
             BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) {
@@ -35,99 +23,6 @@
 
     @Override
     public void onRestoreFinished() {
-        DatabaseHelper helper = new DatabaseHelper(this, null, LauncherFiles.LAUNCHER_DB);
-
-        if (!sanitizeDBSafely(helper)) {
-            helper.createEmptyDB(helper.getWritableDatabase());
-        }
-
-        try {
-            // Flush all logs before the process is killed.
-            FileLog.flushAll(null);
-        } catch (Exception e) { }
-    }
-
-    private boolean sanitizeDBSafely(DatabaseHelper helper) {
-        SQLiteDatabase db = helper.getWritableDatabase();
-        db.beginTransaction();
-        try {
-            sanitizeDB(helper, db);
-            db.setTransactionSuccessful();
-            return true;
-        } catch (Exception e) {
-            FileLog.e(TAG, "Failed to verify db", e);
-            return false;
-        } finally {
-            db.endTransaction();
-        }
-    }
-
-    /**
-     * Makes the following changes in the provider DB.
-     *   1. Removes all entries belonging to a managed profile as managed profiles
-     *      cannot be restored.
-     *   2. Marks all entries as restored. The flags are updated during first load or as
-     *      the restored apps get installed.
-     *   3. If the user serial for primary profile is different than that of the previous device,
-     *      update the entries to the new profile id.
-     */
-    private void sanitizeDB(DatabaseHelper helper, SQLiteDatabase db) throws Exception {
-        long oldProfileId = getDefaultProfileId(db);
-        // Delete all entries which do not belong to the main user
-        int itemsDeleted = db.delete(
-                Favorites.TABLE_NAME, "profileId != ?", new String[]{Long.toString(oldProfileId)});
-        if (itemsDeleted > 0) {
-            FileLog.d(TAG, itemsDeleted + " items belonging to a managed profile, were deleted");
-        }
-
-        // Mark all items as restored.
-        ContentValues values = new ContentValues();
-        values.put(Favorites.RESTORED, 1);
-        db.update(Favorites.TABLE_NAME, values, null, null);
-
-        // Mark widgets with appropriate restore flag
-        values.put(Favorites.RESTORED,
-                LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
-                LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY |
-                LauncherAppWidgetInfo.FLAG_UI_NOT_READY);
-        db.update(Favorites.TABLE_NAME, values, "itemType = ?",
-                new String[]{Integer.toString(Favorites.ITEM_TYPE_APPWIDGET)});
-
-        long myProfileId = helper.getDefaultUserSerial();
-        if (Utilities.longCompare(oldProfileId, myProfileId) != 0) {
-            FileLog.d(TAG, "Changing primary user id from " + oldProfileId + " to " + myProfileId);
-            migrateProfileId(db, myProfileId);
-        }
-    }
-
-    /**
-     * Updates profile id of all entries and changes the default value for the column.
-     */
-    protected void migrateProfileId(SQLiteDatabase db, long newProfileId) {
-        // Update existing entries.
-        ContentValues values = new ContentValues();
-        values.put(Favorites.PROFILE_ID, newProfileId);
-        db.update(Favorites.TABLE_NAME, values, null, null);
-
-        // Change default value of the column.
-        db.execSQL("ALTER TABLE favorites RENAME TO favorites_old;");
-        Favorites.addTableToDb(db, newProfileId, false);
-        db.execSQL("INSERT INTO favorites SELECT * FROM favorites_old;");
-        db.execSQL("DROP TABLE favorites_old;");
-    }
-
-    /**
-     * Returns the profile id for used in the favorites table of the provided db.
-     */
-    protected long getDefaultProfileId(SQLiteDatabase db) throws Exception {
-        try (Cursor c = db.rawQuery("PRAGMA table_info (favorites)", null)){
-            int nameIndex = c.getColumnIndex(INFO_COLUMN_NAME);
-            while (c.moveToNext()) {
-                if (Favorites.PROFILE_ID.equals(c.getString(nameIndex))) {
-                    return c.getLong(c.getColumnIndex(INFO_COLUMN_DEFAULT_VALUE));
-                }
-            }
-            throw new InvalidObjectException("Table does not have a profile id column");
-        }
+        RestoreDbTask.setPending(this, true);
     }
 }
diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java
index c44969f..f0e9593 100644
--- a/src/com/android/launcher3/LauncherClings.java
+++ b/src/com/android/launcher3/LauncherClings.java
@@ -38,7 +38,7 @@
 
 import com.android.launcher3.util.Thunk;
 
-class LauncherClings implements OnClickListener, OnKeyListener {
+public class LauncherClings implements OnClickListener, OnKeyListener {
     private static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed";
 
     private static final String TAG_CROP_TOP_AND_SIDES = "crop_bg_top_and_sides";
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 649f42d..557a91a 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3;
 
-import android.app.SearchManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -177,7 +176,6 @@
         public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,
                               boolean forceAnimateIcons);
         public void bindScreens(ArrayList<Long> orderedScreenIds);
-        public void bindAddScreens(ArrayList<Long> orderedScreenIds);
         public void finishBindingItems();
         public void bindAppWidget(LauncherAppWidgetInfo info);
         public void bindAllApplications(ArrayList<AppInfo> apps);
@@ -196,7 +194,6 @@
         public void bindAppInfosRemoved(ArrayList<AppInfo> appInfos);
         public void notifyWidgetProvidersChanged();
         public void bindWidgetsModel(WidgetsModel model);
-        public void bindSearchProviderChanged();
         public boolean isAllAppsButtonRank(int rank);
         public void onPageBoundSynchronously(int page);
         public void executeOnNextDraw(ViewOnDrawExecutor executor);
@@ -1139,11 +1136,6 @@
         if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
             // If we have changed locale we need to clear out the labels in all apps/workspace.
             forceReload();
-        } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action)) {
-            Callbacks callbacks = getCallback();
-            if (callbacks != null) {
-                callbacks.bindSearchProviderChanged();
-            }
         } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)
                 || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
             UserManagerCompat.getInstance(context).enableAndResetCache();
@@ -1528,7 +1520,12 @@
             }
 
             if (!occupied.containsKey(item.screenId)) {
-                occupied.put(item.screenId, new GridOccupancy(countX + 1, countY + 1));
+                GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
+                if (item.screenId == Workspace.FIRST_SCREEN_ID) {
+                    // Mark the first row as occupied in order to account for the QSB.
+                    screen.markCells(0, 0, countX + 1, 1, true);
+                }
+                occupied.put(item.screenId, screen);
             }
             final GridOccupancy occupancy = occupied.get(item.screenId);
 
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 11d61d0..dfb8ba2 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -46,7 +46,6 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.UserManager;
-import android.provider.BaseColumns;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
@@ -58,6 +57,7 @@
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.dynamicui.ExtractionUtils;
+import com.android.launcher3.provider.RestoreDbTask;
 import com.android.launcher3.util.ManagedProfileHeuristic;
 import com.android.launcher3.util.NoLocaleSqliteContext;
 import com.android.launcher3.util.Preconditions;
@@ -117,6 +117,15 @@
     protected synchronized void createDbIfNotExists() {
         if (mOpenHelper == null) {
             mOpenHelper = new DatabaseHelper(getContext(), mListenerHandler);
+
+            if (RestoreDbTask.isPending(getContext())) {
+                if (!RestoreDbTask.performRestore(mOpenHelper)) {
+                    mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
+                }
+                // Set is pending to false irrespective of the result, so that it doesn't get
+                // executed again.
+                RestoreDbTask.setPending(getContext(), false);
+            }
         }
     }
 
@@ -611,8 +620,11 @@
             // Database was just created, so wipe any previous widgets
             if (mWidgetHostResetHandler != null) {
                 new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID).deleteHost();
-                mWidgetHostResetHandler.sendEmptyMessage(
-                        ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET);
+                mWidgetHostResetHandler.sendMessage(Message.obtain(
+                        mWidgetHostResetHandler,
+                        ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET,
+                        mContext
+                ));
             }
 
             // Set the flag for empty DB
@@ -623,7 +635,7 @@
                     mContext);
         }
 
-        protected long getDefaultUserSerial() {
+        public long getDefaultUserSerial() {
             return UserManagerCompat.getInstance(mContext).getSerialNumberForUser(
                     UserHandleCompat.myUserHandle());
         }
@@ -1100,7 +1112,11 @@
                         mListener.onExtractedColorsChanged();
                         break;
                     case MSG_APP_WIDGET_HOST_RESET:
-                        mListener.onAppWidgetHostReset();
+                        Context context = (Context) msg.obj;
+                        if (context != null) {
+                            context.sendBroadcast(new Intent(Launcher.ACTION_APPWIDGET_HOST_RESET)
+                                    .setPackage(context.getPackageName()));
+                        }
                         break;
                 }
             }
diff --git a/src/com/android/launcher3/LauncherProviderChangeListener.java b/src/com/android/launcher3/LauncherProviderChangeListener.java
index 524befc..5998dad 100644
--- a/src/com/android/launcher3/LauncherProviderChangeListener.java
+++ b/src/com/android/launcher3/LauncherProviderChangeListener.java
@@ -10,6 +10,4 @@
     public void onLauncherProviderChange();
 
     public void onExtractedColorsChanged();
-
-    public void onAppWidgetHostReset();
 }
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 17a5424..d62c629 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -33,6 +33,8 @@
 import android.view.animation.DecelerateInterpolator;
 
 import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.UiThreadCircularReveal;
 import com.android.launcher3.widget.WidgetsContainerView;
@@ -82,6 +84,17 @@
  */
 public class LauncherStateTransitionAnimation {
 
+    /**
+     * animation used for all apps and widget tray when
+     *{@link FeatureFlags#LAUNCHER3_ALL_APPS_PULL_UP} is {@code false}
+     */
+    public static final int CIRCULAR_REVEAL = 0;
+    /**
+     * animation used for all apps and not widget tray when
+     *{@link FeatureFlags#LAUNCHER3_ALL_APPS_PULL_UP} is {@code true}
+     */
+    public static final int PULLUP = 1;
+
     private static final float FINAL_REVEAL_ALPHA_FOR_WIDGETS = 0.3f;
 
     /**
@@ -113,9 +126,11 @@
 
     @Thunk Launcher mLauncher;
     @Thunk AnimatorSet mCurrentAnimation;
+    AllAppsTransitionController mAllAppsController;
 
-    public LauncherStateTransitionAnimation(Launcher l) {
+    public LauncherStateTransitionAnimation(Launcher l, AllAppsTransitionController allAppsController) {
         mLauncher = l;
+        mAllAppsController = allAppsController;
     }
 
     /**
@@ -154,9 +169,13 @@
                 }
             }
         };
+        int animType = CIRCULAR_REVEAL;
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
+            animType = PULLUP;
+        }
         // Only animate the search bar if animating from spring loaded mode back to all apps
         mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState,
-                Workspace.State.NORMAL_HIDDEN, buttonView, toView, animated, cb);
+                Workspace.State.NORMAL_HIDDEN, buttonView, toView, animated, animType, cb);
     }
 
     /**
@@ -167,7 +186,7 @@
         final WidgetsContainerView toView = mLauncher.getWidgetsView();
         final View buttonView = mLauncher.getWidgetsButton();
         mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState,
-                Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, animated,
+                Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, animated, CIRCULAR_REVEAL,
                 new PrivateTransitionCallbacks(FINAL_REVEAL_ALPHA_FOR_WIDGETS){
                     @Override
                     void onTransitionComplete() {
@@ -189,8 +208,12 @@
         }
 
         if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED) {
+            int animType = CIRCULAR_REVEAL;
+            if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
+                animType = PULLUP;
+            }
             startAnimationToWorkspaceFromAllApps(fromWorkspaceState, toWorkspaceState,
-                    animated, onCompleteRunnable);
+                    animated, animType, onCompleteRunnable);
         } else if (fromState == Launcher.State.WIDGETS ||
                 fromState == Launcher.State.WIDGETS_SPRING_LOADED) {
             startAnimationToWorkspaceFromWidgets(fromWorkspaceState, toWorkspaceState,
@@ -208,7 +231,7 @@
     private AnimatorSet startAnimationToOverlay(
             final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState,
             final View buttonView, final BaseContainerView toView,
-            final boolean animated, final PrivateTransitionCallbacks pCb) {
+            final boolean animated, int animType, final PrivateTransitionCallbacks pCb) {
         final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
         final Resources res = mLauncher.getResources();
         final boolean material = Utilities.ATLEAST_LOLLIPOP;
@@ -225,12 +248,37 @@
         // Cancel the current animation
         cancelAnimation();
 
-        playCommonTransitionAnimations(toWorkspaceState, fromView, toView,
-                animated, initialized, animation, revealDuration, layerViews);
-
         final View contentView = toView.getContentView();
 
-        if (animated && initialized) {
+        if (!animated || !initialized) {
+            playCommonTransitionAnimations(toWorkspaceState, fromView, toView,
+                    animated, initialized, animation, revealDuration, layerViews);
+
+            toView.setTranslationX(0.0f);
+            toView.setTranslationY(0.0f);
+            toView.setScaleX(1.0f);
+            toView.setScaleY(1.0f);
+            toView.setAlpha(1.0f);
+            toView.setVisibility(View.VISIBLE);
+            toView.bringToFront();
+
+            // Show the content view
+            contentView.setVisibility(View.VISIBLE);
+
+            dispatchOnLauncherTransitionPrepare(fromView, animated, false);
+            dispatchOnLauncherTransitionStart(fromView, animated, false);
+            dispatchOnLauncherTransitionEnd(fromView, animated, false);
+            dispatchOnLauncherTransitionPrepare(toView, animated, false);
+            dispatchOnLauncherTransitionStart(toView, animated, false);
+            dispatchOnLauncherTransitionEnd(toView, animated, false);
+            pCb.onTransitionComplete();
+
+            return null;
+        }
+        if (animType == CIRCULAR_REVEAL) {
+            playCommonTransitionAnimations(toWorkspaceState, fromView, toView,
+                    animated, initialized, animation, revealDuration, layerViews);
+
             // Setup the reveal view animation
             final View revealView = toView.getRevealView();
 
@@ -366,27 +414,41 @@
             toView.post(startAnimRunnable);
 
             return animation;
-        } else {
-            toView.setTranslationX(0.0f);
-            toView.setTranslationY(0.0f);
-            toView.setScaleX(1.0f);
-            toView.setScaleY(1.0f);
-            toView.setVisibility(View.VISIBLE);
-            toView.bringToFront();
-
-            // Show the content view
-            contentView.setVisibility(View.VISIBLE);
+        } else if (animType == PULLUP) {
+            animation.addListener(new AnimatorListenerAdapter() {
+                  @Override
+                  public void onAnimationEnd(Animator animation) {
+                      dispatchOnLauncherTransitionEnd(fromView, animated, false);
+                      dispatchOnLauncherTransitionEnd(toView, animated, false);
+                      cleanupAnimation();
+                      pCb.onTransitionComplete();
+                  }
+            });
+            mAllAppsController.animateToAllApps(animation, revealDuration);
+            playCommonTransitionAnimations(toWorkspaceState, fromView, toView,
+                    animated, initialized, animation, revealDuration, layerViews);
 
             dispatchOnLauncherTransitionPrepare(fromView, animated, false);
-            dispatchOnLauncherTransitionStart(fromView, animated, false);
-            dispatchOnLauncherTransitionEnd(fromView, animated, false);
             dispatchOnLauncherTransitionPrepare(toView, animated, false);
-            dispatchOnLauncherTransitionStart(toView, animated, false);
-            dispatchOnLauncherTransitionEnd(toView, animated, false);
-            pCb.onTransitionComplete();
 
-            return null;
+            final AnimatorSet stateAnimation = animation;
+            final Runnable startAnimRunnable = new Runnable() {
+                public void run() {
+                    // Check that mCurrentAnimation hasn't changed while
+                    // we waited for a layout/draw pass
+                    if (mCurrentAnimation != stateAnimation)
+                        return;
+                    dispatchOnLauncherTransitionStart(fromView, animated, false);
+                    dispatchOnLauncherTransitionStart(toView, animated, false);
+
+                    toView.requestFocus();
+                    stateAnimation.start();
+                }
+            };
+            toView.post(startAnimRunnable);
+            return animation;
         }
+        return null;
     }
 
     /**
@@ -401,12 +463,6 @@
         Animator workspaceAnim = mLauncher.startWorkspaceStateChangeAnimation(toWorkspaceState,
                 animated, layerViews);
 
-        // Animate the search bar
-        final SearchDropTargetBar.State toSearchBarState =
-                toWorkspaceState.searchDropTargetBarState;
-        mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState,
-                animated ? revealDuration : 0, animation);
-
         if (animated && initialized) {
             // Play the workspace animation
             if (workspaceAnim != null) {
@@ -439,7 +495,7 @@
      * Starts an animation to the workspace from the apps view.
      */
     private void startAnimationToWorkspaceFromAllApps(final Workspace.State fromWorkspaceState,
-            final Workspace.State toWorkspaceState, final boolean animated, 
+            final Workspace.State toWorkspaceState, final boolean animated, int type,
             final Runnable onCompleteRunnable) {
         AllAppsContainerView appsView = mLauncher.getAppsView();
         // No alpha anim from all apps
@@ -476,7 +532,7 @@
         // Only animate the search bar if animating to spring loaded mode from all apps
         mCurrentAnimation = startAnimationToWorkspaceFromOverlay(fromWorkspaceState, toWorkspaceState,
                 mLauncher.getAllAppsButton(), appsView,
-                animated, onCompleteRunnable, cb);
+                animated, type, onCompleteRunnable, cb);
     }
 
     /**
@@ -506,7 +562,7 @@
         mCurrentAnimation = startAnimationToWorkspaceFromOverlay(
                 fromWorkspaceState, toWorkspaceState,
                 mLauncher.getWidgetsButton(), widgetsView,
-                animated, onCompleteRunnable, cb);
+                animated, CIRCULAR_REVEAL, onCompleteRunnable, cb);
     }
 
     /**
@@ -598,7 +654,7 @@
     private AnimatorSet startAnimationToWorkspaceFromOverlay(
             final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState,
             final View buttonView, final BaseContainerView fromView,
-            final boolean animated, final Runnable onCompleteRunnable,
+            final boolean animated, int animType, final Runnable onCompleteRunnable,
             final PrivateTransitionCallbacks pCb) {
         final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
         final Resources res = mLauncher.getResources();
@@ -619,10 +675,31 @@
 
         boolean multiplePagesVisible = toWorkspaceState.hasMultipleVisiblePages;
 
-        playCommonTransitionAnimations(toWorkspaceState, fromView, toView,
-                animated, initialized, animation, revealDuration, layerViews);
+        if (!animated || !initialized) {
+            playCommonTransitionAnimations(toWorkspaceState, fromView, toView,
+                    animated, initialized, animation, revealDuration, layerViews);
+            if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
+                mAllAppsController.finishPullDown();
+            }
+            fromView.setVisibility(View.GONE);
+            dispatchOnLauncherTransitionPrepare(fromView, animated, multiplePagesVisible);
+            dispatchOnLauncherTransitionStart(fromView, animated, true);
+            dispatchOnLauncherTransitionEnd(fromView, animated, true);
+            dispatchOnLauncherTransitionPrepare(toView, animated, multiplePagesVisible);
+            dispatchOnLauncherTransitionStart(toView, animated, true);
+            dispatchOnLauncherTransitionEnd(toView, animated, true);
+            pCb.onTransitionComplete();
 
-        if (animated && initialized) {
+            // Run any queued runnables
+            if (onCompleteRunnable != null) {
+                onCompleteRunnable.run();
+            }
+
+            return null;
+        }
+        if (animType == CIRCULAR_REVEAL) {
+            playCommonTransitionAnimations(toWorkspaceState, fromView, toView,
+                    animated, initialized, animation, revealDuration, layerViews);
             final View revealView = fromView.getRevealView();
             final View contentView = fromView.getContentView();
 
@@ -791,23 +868,61 @@
             fromView.post(startAnimRunnable);
 
             return animation;
-        } else /* if (!(animated && initialized)) */ {
-            fromView.setVisibility(View.GONE);
-            dispatchOnLauncherTransitionPrepare(fromView, animated, multiplePagesVisible);
-            dispatchOnLauncherTransitionStart(fromView, animated, true);
-            dispatchOnLauncherTransitionEnd(fromView, animated, true);
-            dispatchOnLauncherTransitionPrepare(toView, animated, multiplePagesVisible);
-            dispatchOnLauncherTransitionStart(toView, animated, true);
-            dispatchOnLauncherTransitionEnd(toView, animated, true);
-            pCb.onTransitionComplete();
+        } else if (animType == PULLUP) {
+            animation.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    dispatchOnLauncherTransitionEnd(fromView, animated, false);
+                    dispatchOnLauncherTransitionEnd(toView, animated, false);
+                    cleanupAnimation();
+                    pCb.onTransitionComplete();
+                }
 
-            // Run any queued runnables
-            if (onCompleteRunnable != null) {
-                onCompleteRunnable.run();
-            }
+            });
+            mAllAppsController.animateToWorkspace(animation, revealDuration);
+            playCommonTransitionAnimations(toWorkspaceState, fromView, toView,
+                    animated, initialized, animation, revealDuration, layerViews);
 
-            return null;
+            // Dispatch the prepare transition signal
+            dispatchOnLauncherTransitionPrepare(fromView, animated, false);
+            dispatchOnLauncherTransitionPrepare(toView, animated, false);
+
+            animation.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    dispatchOnLauncherTransitionEnd(fromView, animated, true);
+                    dispatchOnLauncherTransitionEnd(toView, animated, true);
+
+                    // Run any queued runnables
+                    if (onCompleteRunnable != null) {
+                        onCompleteRunnable.run();
+                    }
+
+                    // This can hold unnecessary references to views.
+                    cleanupAnimation();
+                    pCb.onTransitionComplete();
+                }
+            });
+
+            final AnimatorSet stateAnimation = animation;
+            final Runnable startAnimRunnable = new Runnable() {
+                public void run() {
+                    // Check that mCurrentAnimation hasn't changed while
+                    // we waited for a layout/draw pass
+                    if (mCurrentAnimation != stateAnimation)
+                        return;
+                    dispatchOnLauncherTransitionStart(fromView, animated, false);
+                    dispatchOnLauncherTransitionStart(toView, animated, false);
+
+                    // Focus the new view
+                    toView.requestFocus();
+                    stateAnimation.start();
+                }
+            };
+            fromView.post(startAnimRunnable);
+            return animation;
         }
+        return null;
     }
 
     /**
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index fdca9f2..9266793 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -647,6 +647,9 @@
     public static class LayoutParams extends ViewGroup.LayoutParams {
         public boolean isFullScreenPage = false;
 
+        // If true, the start edge of the page snaps to the start edge of the viewport.
+        public boolean matchStartEdge = false;
+
         /**
          * {@inheritDoc}
          */
@@ -778,6 +781,10 @@
 
                     childWidth = getViewportWidth() - horizontalPadding
                             - mInsets.left - mInsets.right;
+
+                    if (lp.matchStartEdge) {
+                        childWidth += getPaddingStart();
+                    }
                     childHeight = getViewportHeight() - verticalPadding
                             - mInsets.top - mInsets.bottom;
                     mNormalChildHeight = childHeight;
@@ -827,7 +834,8 @@
         LayoutParams lp = (LayoutParams) getChildAt(startIndex).getLayoutParams();
         LayoutParams nextLp;
 
-        int childLeft = offsetX + (lp.isFullScreenPage ? 0 : getPaddingLeft());
+        int childLeft = offsetX +
+                ((lp.isFullScreenPage || (!mIsRtl && lp.matchStartEdge)) ? 0 : getPaddingLeft());
         if (mPageScrolls == null || childCount != mChildCountOnLastLayout) {
             mPageScrolls = new int[childCount];
         }
@@ -851,7 +859,8 @@
                 child.layout(childLeft, childTop,
                         childLeft + child.getMeasuredWidth(), childTop + childHeight);
 
-                int scrollOffsetLeft = lp.isFullScreenPage ? 0 : getPaddingLeft();
+                int scrollOffsetLeft = (lp.isFullScreenPage || (!mIsRtl & lp.matchStartEdge)) ?
+                        0 : getPaddingLeft();
                 mPageScrolls[i] = childLeft - scrollOffsetLeft - offsetX;
 
                 int pageGap = mPageSpacing;
@@ -1653,7 +1662,8 @@
                 if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);
 
                 final int pageUnderPointIndex = getNearestHoverOverPageIndex();
-                if (pageUnderPointIndex > -1 && pageUnderPointIndex != indexOfChild(mDragView)) {
+                // Do not allow any page to be moved to 0th position.
+                if (pageUnderPointIndex > 0 && pageUnderPointIndex != indexOfChild(mDragView)) {
                     mTempVisiblePagesRange[0] = 0;
                     mTempVisiblePagesRange[1] = getPageCount() - 1;
                     getFreeScrollPageRange(mTempVisiblePagesRange);
@@ -1961,7 +1971,7 @@
         snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
     }
 
-    private static class ScrollInterpolator implements Interpolator {
+    public static class ScrollInterpolator implements Interpolator {
         public ScrollInterpolator() {
         }
 
@@ -2171,7 +2181,8 @@
     public boolean startReordering(View v) {
         int dragViewIndex = indexOfChild(v);
 
-        if (mTouchState != TOUCH_STATE_REST || dragViewIndex == -1) return false;
+        // Do not allow the first page to be moved around
+        if (mTouchState != TOUCH_STATE_REST || dragViewIndex <= 0) return false;
 
         mTempVisiblePagesRange[0] = 0;
         mTempVisiblePagesRange[1] = getPageCount() - 1;
diff --git a/src/com/android/launcher3/PinchAnimationManager.java b/src/com/android/launcher3/PinchAnimationManager.java
index c8c8fa4..c1c2519 100644
--- a/src/com/android/launcher3/PinchAnimationManager.java
+++ b/src/com/android/launcher3/PinchAnimationManager.java
@@ -150,12 +150,10 @@
                 animateOverviewPanelButtons(goingTowards == OVERVIEW);
             } else if (startState == NORMAL) {
                 animateHotseatAndPageIndicator(goingTowards == NORMAL);
-                animateQsb(goingTowards == NORMAL);
             }
         } else if (threshold == PinchThresholdManager.THRESHOLD_TWO) {
             if (startState == OVERVIEW) {
                 animateHotseatAndPageIndicator(goingTowards == NORMAL);
-                animateQsb(goingTowards == NORMAL);
                 animateScrim(goingTowards == OVERVIEW);
             } else if (startState == NORMAL) {
                 animateOverviewPanelButtons(goingTowards == OVERVIEW);
@@ -198,12 +196,6 @@
         }
     }
 
-    private void animateQsb(boolean show) {
-        SearchDropTargetBar.State searchBarState = show ? SearchDropTargetBar.State.SEARCH_BAR
-                : SearchDropTargetBar.State.INVISIBLE;
-        mLauncher.getSearchDropTargetBar().animateToState(searchBarState, THRESHOLD_ANIM_DURATION);
-    }
-
     private void animateOverviewPanelButtons(boolean show) {
         animateShowHideView(INDEX_OVERVIEW_PANEL_BUTTONS, mLauncher.getOverviewPanel(), show);
     }
diff --git a/src/com/android/launcher3/PinchToOverviewListener.java b/src/com/android/launcher3/PinchToOverviewListener.java
index 0c8568e..6ee96fc 100644
--- a/src/com/android/launcher3/PinchToOverviewListener.java
+++ b/src/com/android/launcher3/PinchToOverviewListener.java
@@ -21,6 +21,8 @@
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 
+import com.android.launcher3.util.TouchController;
+
 /**
  * Detects pinches and animates the Workspace to/from overview mode.
  *
@@ -30,7 +32,8 @@
  * @see PinchThresholdManager
  * @see PinchAnimationManager
  */
-public class PinchToOverviewListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
+public class PinchToOverviewListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
+        implements TouchController {
     private static final float OVERVIEW_PROGRESS = 0f;
     private static final float WORKSPACE_PROGRESS = 1f;
     /**
@@ -63,15 +66,16 @@
         return mPinchStarted;
     }
 
-    public void onTouchEvent(MotionEvent ev) {
+    public boolean onTouchEvent(MotionEvent ev) {
         if (mPinchStarted) {
             if (ev.getPointerCount() > 2) {
                 // Using more than two fingers causes weird behavior, so just cancel the pinch.
                 cancelPinch(mPreviousProgress, -1);
             } else {
-                mPinchDetector.onTouchEvent(ev);
+                return mPinchDetector.onTouchEvent(ev);
             }
         }
+        return false;
     }
 
     @Override
diff --git a/src/com/android/launcher3/QsbContainerView.java b/src/com/android/launcher3/QsbContainerView.java
new file mode 100644
index 0000000..7d939a0
--- /dev/null
+++ b/src/com/android/launcher3/QsbContainerView.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.SearchManager;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+
+/**
+ * A frame layout which contains a QSB. This internally uses fragment to bind the view, which
+ * allows it to contain the logic for {@link Fragment#startActivityForResult(Intent, int)}.
+ */
+public class QsbContainerView extends FrameLayout {
+
+    public QsbContainerView(Context context) {
+        super(context);
+    }
+
+    public QsbContainerView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public QsbContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    public void setPadding(int left, int top, int right, int bottom) {
+        super.setPadding(0, 0, 0, 0);
+    }
+
+    /**
+     * A fragment to display the QSB.
+     */
+    public static class QsbFragment extends Fragment implements View.OnClickListener {
+
+        private static final int REQUEST_BIND_QSB = 1;
+        private static final String QSB_WIDGET_ID = "qsb_widget_id";
+
+        private static int sSavedWidgetId = -1;
+
+        private AppWidgetProviderInfo mWidgetInfo;
+        private LauncherAppWidgetHostView mQsb;
+
+        private BroadcastReceiver mRebindReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                rebindFragment();
+            }
+        };
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+
+            IntentFilter filter = new IntentFilter(Launcher.ACTION_APPWIDGET_HOST_RESET);
+            filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
+            getActivity().registerReceiver(mRebindReceiver, filter);
+        }
+
+        private FrameLayout mWrapper;
+
+        @Override
+        public View onCreateView(
+                LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+            if (savedInstanceState != null) {
+                sSavedWidgetId = savedInstanceState.getInt(QSB_WIDGET_ID, -1);
+            }
+            mWrapper = new FrameLayout(getActivity());
+            mWrapper.addView(createQsb(inflater, mWrapper));
+            return mWrapper;
+        }
+
+        private View createQsb(LayoutInflater inflater, ViewGroup container) {
+            Launcher launcher = (Launcher) getActivity();
+            mWidgetInfo = getSearchWidgetProvider(launcher);
+            if (mWidgetInfo == null) {
+                // There is no search provider, just show the default widget.
+                return getDefaultView(inflater, container, false);
+            }
+
+            SharedPreferences prefs = Utilities.getPrefs(launcher);
+            AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(launcher);
+            LauncherAppWidgetHost widgetHost = launcher.getAppWidgetHost();
+            InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();
+
+            Bundle opts = new Bundle();
+            Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(launcher, idp.numColumns, 1, null);
+            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left);
+            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, size.top);
+            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, size.right);
+            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, size.bottom);
+
+            int widgetId = prefs.getInt(QSB_WIDGET_ID, -1);
+            AppWidgetProviderInfo widgetInfo = widgetManager.getAppWidgetInfo(widgetId);
+            boolean isWidgetBound = (widgetInfo != null) &&
+                    widgetInfo.provider.equals(mWidgetInfo.provider);
+
+            if (!isWidgetBound) {
+                // widgetId is already bound and its not the correct provider.
+                // Delete the widget id.
+                if (widgetId > -1) {
+                    widgetHost.deleteAppWidgetId(widgetId);
+                    widgetId = -1;
+                }
+
+                widgetId = widgetHost.allocateAppWidgetId();
+                isWidgetBound = widgetManager.bindAppWidgetIdIfAllowed(widgetId, mWidgetInfo, opts);
+                if (!isWidgetBound) {
+                    widgetHost.deleteAppWidgetId(widgetId);
+                    widgetId = -1;
+                }
+            }
+
+            if (isWidgetBound) {
+                mQsb = (LauncherAppWidgetHostView)
+                        widgetHost.createView(launcher, widgetId, mWidgetInfo);
+                mQsb.setId(R.id.qsb_widget);
+                mQsb.mErrorViewId = R.layout.qsb_default_view;
+
+                if (!Utilities.containsAll(AppWidgetManager.getInstance(launcher)
+                        .getAppWidgetOptions(widgetId), opts)) {
+                    mQsb.updateAppWidgetOptions(opts);
+                }
+                mQsb.setPadding(0, 0, 0, 0);
+                return mQsb;
+            }
+
+            // Return a default widget with setup icon.
+            return getDefaultView(inflater, container, true);
+        }
+
+        @Override
+        public void onClick(View view) {
+            if (view.getId() == R.id.btn_qsb_search) {
+                getActivity().startSearch("", false, null, true);
+            } else if (view.getId() == R.id.btn_qsb_setup) {
+                // Allocate a new widget id for QSB
+                sSavedWidgetId = ((Launcher) getActivity())
+                        .getAppWidgetHost().allocateAppWidgetId();
+                // Start intent for bind the widget
+                Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
+                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, sSavedWidgetId);
+                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, mWidgetInfo.provider);
+                startActivityForResult(intent, REQUEST_BIND_QSB);
+            }
+        }
+
+        @Override
+        public void onSaveInstanceState(Bundle outState) {
+            super.onSaveInstanceState(outState);
+            outState.putInt(QSB_WIDGET_ID, sSavedWidgetId);
+        }
+
+        @Override
+        public void onActivityResult(int requestCode, int resultCode, Intent data) {
+            if (requestCode == REQUEST_BIND_QSB) {
+                if (resultCode == Activity.RESULT_OK) {
+                    int widgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+                            sSavedWidgetId);
+                    Utilities.getPrefs(getActivity()).edit().putInt(QSB_WIDGET_ID, widgetId).apply();
+                    sSavedWidgetId = -1;
+                    rebindFragment();
+                } else if (sSavedWidgetId != -1) {
+                    ((Launcher) getActivity()).getAppWidgetHost().deleteAppWidgetId(sSavedWidgetId);
+                    sSavedWidgetId = -1;
+                }
+            }
+        }
+
+        @Override
+        public void onResume() {
+            super.onResume();
+            if (mQsb != null && mQsb.isReinflateRequired()) {
+                rebindFragment();
+            }
+        }
+
+        @Override
+        public void onDestroy() {
+            getActivity().unregisterReceiver(mRebindReceiver);
+            super.onDestroy();
+        }
+
+        private void rebindFragment() {
+            if (mWrapper != null && getActivity() != null) {
+                mWrapper.removeAllViews();
+                mWrapper.addView(createQsb(getActivity().getLayoutInflater(), mWrapper));
+            }
+        }
+
+        private View getDefaultView(LayoutInflater inflater, ViewGroup parent, boolean showSetup) {
+            View v = inflater.inflate(R.layout.qsb_default_view, parent, false);
+            if (showSetup) {
+                View setupButton = v.findViewById(R.id.btn_qsb_setup);
+                setupButton.setVisibility(View.VISIBLE);
+                setupButton.setOnClickListener(this);
+            }
+            v.findViewById(R.id.btn_qsb_search).setOnClickListener(this);
+            return v;
+        }
+    }
+
+    /**
+     * Returns a widget with category {@link AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}
+     * provided by the same package which is set to be global search activity.
+     * If widgetCategory is not supported, or no such widget is found, returns the first widget
+     * provided by the package.
+     */
+    public static AppWidgetProviderInfo getSearchWidgetProvider(Context context) {
+        SearchManager searchManager =
+                (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
+        ComponentName searchComponent = searchManager.getGlobalSearchActivity();
+        if (searchComponent == null) return null;
+        String providerPkg = searchComponent.getPackageName();
+
+        AppWidgetProviderInfo defaultWidgetForSearchPackage = null;
+
+        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
+        for (AppWidgetProviderInfo info : appWidgetManager.getInstalledProviders()) {
+            if (info.provider.getPackageName().equals(providerPkg) && info.configure == null) {
+                if ((info.widgetCategory & AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) != 0) {
+                    return info;
+                } else if (defaultWidgetForSearchPackage == null) {
+                    defaultWidgetForSearchPackage = info;
+                }
+            }
+        }
+        return defaultWidgetForSearchPackage;
+    }
+}
diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java
deleted file mode 100644
index 171dd87..0000000
--- a/src/com/android/launcher3/SearchDropTargetBar.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-
-import com.android.launcher3.dragndrop.DragController;
-import com.android.launcher3.util.Thunk;
-
-/*
- * This bar will manage the transition between the QSB search bar and the delete/uninstall drop
- * targets so that each of the individual ButtonDropTargets don't have to.
- */
-public class SearchDropTargetBar extends BaseDropTargetBar {
-
-    private static final TimeInterpolator MOVE_DOWN_INTERPOLATOR = new DecelerateInterpolator(0.6f);
-    private static final TimeInterpolator MOVE_UP_INTERPOLATOR = new DecelerateInterpolator(1.5f);
-
-    /** The different states that the search bar space can be in. */
-    public enum State {
-        INVISIBLE             (0f, 0f, 0f),
-        INVISIBLE_TRANSLATED  (0f, 0f, -1f),
-        SEARCH_BAR            (1f, 0f, 0f),
-        DROP_TARGET           (0f, 1f, 0f);
-
-        private final float mSearchBarAlpha;
-        private final float mDropTargetBarAlpha;
-        private final float mTranslation;
-
-        State(float sbAlpha, float dtbAlpha, float translation) {
-            mSearchBarAlpha = sbAlpha;
-            mDropTargetBarAlpha = dtbAlpha;
-            mTranslation = translation;
-        }
-
-    }
-
-
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private State mState = State.SEARCH_BAR;
-    @Thunk View mQSB;
-
-    // Drop targets
-    private ButtonDropTarget mDeleteDropTarget;
-    private ButtonDropTarget mUninstallDropTarget;
-
-    public SearchDropTargetBar(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SearchDropTargetBar(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        // Get the individual components
-        mDeleteDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.delete_target_text);
-        mUninstallDropTarget = (ButtonDropTarget) mDropTargetBar
-                .findViewById(R.id.uninstall_target_text);
-
-        mDeleteDropTarget.setDropTargetBar(this);
-        mUninstallDropTarget.setDropTargetBar(this);
-    }
-
-    @Override
-    public void setup(Launcher launcher, DragController dragController) {
-        dragController.addDragListener(this);
-        dragController.setFlingToDeleteDropTarget(mDeleteDropTarget);
-
-        dragController.addDragListener(mDeleteDropTarget);
-        dragController.addDragListener(mUninstallDropTarget);
-
-        dragController.addDropTarget(mDeleteDropTarget);
-        dragController.addDropTarget(mUninstallDropTarget);
-
-        mDeleteDropTarget.setLauncher(launcher);
-        mUninstallDropTarget.setLauncher(launcher);
-    }
-
-    @Override
-    public void showDropTargets() {
-        animateToState(State.DROP_TARGET, DEFAULT_DRAG_FADE_DURATION);
-    }
-
-    @Override
-    public void hideDropTargets() {
-        animateToState(State.SEARCH_BAR, DEFAULT_DRAG_FADE_DURATION);
-    }
-
-    public void setQsbSearchBar(View qsb) {
-        mQSB = qsb;
-    }
-
-    /**
-     * Animates the current search bar state to a new state.  If the {@param duration} is 0, then
-     * the state is applied immediately.
-     */
-    public void animateToState(State newState, int duration) {
-        animateToState(newState, duration, null);
-    }
-
-    public void animateToState(State newState, int duration, AnimatorSet animation) {
-        if (mState != newState) {
-            mState = newState;
-
-            resetAnimation(duration);
-            if (duration > 0) {
-                animateAlpha(mDropTargetBar, mState.mDropTargetBarAlpha, DEFAULT_INTERPOLATOR);
-            } else {
-                mDropTargetBar.setAlpha(mState.mDropTargetBarAlpha);
-                AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
-            }
-
-            if (mQSB != null) {
-                boolean isVertical = ((Launcher) getContext()).getDeviceProfile()
-                        .isVerticalBarLayout();
-                float translation = isVertical ? 0 : mState.mTranslation * getMeasuredHeight();
-
-                if (duration > 0) {
-                    int translationChange = Float.compare(mQSB.getTranslationY(), translation);
-
-                    animateAlpha(mQSB, mState.mSearchBarAlpha,
-                            translationChange == 0 ? DEFAULT_INTERPOLATOR
-                                    : (translationChange < 0 ? MOVE_DOWN_INTERPOLATOR
-                                    : MOVE_UP_INTERPOLATOR));
-
-                    if (translationChange != 0) {
-                        mCurrentAnimation.play(
-                                ObjectAnimator.ofFloat(mQSB, View.TRANSLATION_Y, translation));
-                    }
-                } else {
-                    mQSB.setTranslationY(translation);
-                    mQSB.setAlpha(mState.mSearchBarAlpha);
-                    AlphaUpdateListener.updateVisibility(mQSB, mAccessibilityEnabled);
-                }
-            }
-
-            // Start the final animation
-            if (duration > 0) {
-                if (animation != null) {
-                    animation.play(mCurrentAnimation);
-                } else {
-                    mCurrentAnimation.start();
-                }
-            }
-        }
-    }
-
-    /**
-     * @return the bounds of the QSB search bar.
-     */
-    public Rect getSearchBarBounds() {
-        if (mQSB != null) {
-            final int[] pos = new int[2];
-            mQSB.getLocationOnScreen(pos);
-
-            final Rect rect = new Rect();
-            rect.left = pos[0];
-            rect.top = pos[1];
-            rect.right = pos[0] + mQSB.getWidth();
-            rect.bottom = pos[1] + mQSB.getHeight();
-            return rect;
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public void enableAccessibleDrag(boolean enable) {
-        if (mQSB != null) {
-            mQSB.setVisibility(enable ? View.GONE : View.VISIBLE);
-        }
-        mDeleteDropTarget.enableAccessibleDrag(enable);
-        mUninstallDropTarget.enableAccessibleDrag(enable);
-    }
-}
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index 5ef6dd5..cedeb39 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -59,7 +59,7 @@
                 // Launcher supports rotation by default. No need to show this setting.
                 getPreferenceScreen().removePreference(rotationPref);
             } else {
-                ContentResolver resolver = getContext().getContentResolver();
+                ContentResolver resolver = getActivity().getContentResolver();
                 mRotationLockObserver = new SystemDisplayRotationLockObserver(rotationPref, resolver);
 
                 // Register a content observer to listen for system setting changes while
@@ -70,14 +70,14 @@
 
                 // Initialize the UI once
                 mRotationLockObserver.onChange(true);
-                rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getContext()));
+                rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity()));
             }
         }
 
         @Override
         public void onDestroy() {
             if (mRotationLockObserver != null) {
-                getContext().getContentResolver().unregisterContentObserver(mRotationLockObserver);
+                getActivity().getContentResolver().unregisterContentObserver(mRotationLockObserver);
                 mRotationLockObserver = null;
             }
             super.onDestroy();
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 008dd84..c016aa9 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -18,6 +18,7 @@
 
 import android.app.WallpaperManager;
 import android.content.Context;
+import android.graphics.Paint;
 import android.graphics.Rect;
 import android.view.View;
 import android.view.ViewGroup;
@@ -217,4 +218,11 @@
     protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
         super.setChildrenDrawnWithCacheEnabled(enabled);
     }
+
+    @Override
+    public void setLayerType(int layerType, Paint paint) {
+        // When clip children is disabled do not use hardware layer,
+        // as hardware layer forces clip children.
+        super.setLayerType(getClipChildren() ? layerType : LAYER_TYPE_NONE, paint);
+    }
 }
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 2cc9bb0..d051665 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -144,6 +144,7 @@
         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
     }
 
+    @Override
     public Intent getIntent() {
         return intent;
     }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index c9d8cce..4aaa02f 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -18,10 +18,7 @@
 
 import android.annotation.TargetApi;
 import android.app.Activity;
-import android.app.SearchManager;
 import android.app.WallpaperManager;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
@@ -603,39 +600,6 @@
     }
 
     /**
-     * Returns a widget with category {@link AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}
-     * provided by the same package which is set to be global search activity.
-     * If widgetCategory is not supported, or no such widget is found, returns the first widget
-     * provided by the package.
-     */
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-    public static AppWidgetProviderInfo getSearchWidgetProvider(Context context) {
-        SearchManager searchManager =
-                (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
-        ComponentName searchComponent = searchManager.getGlobalSearchActivity();
-        if (searchComponent == null) return null;
-        String providerPkg = searchComponent.getPackageName();
-
-        AppWidgetProviderInfo defaultWidgetForSearchPackage = null;
-
-        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
-        for (AppWidgetProviderInfo info : appWidgetManager.getInstalledProviders()) {
-            if (info.provider.getPackageName().equals(providerPkg)) {
-                if (ATLEAST_JB_MR1) {
-                    if ((info.widgetCategory & AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) != 0) {
-                        return info;
-                    } else if (defaultWidgetForSearchPackage == null) {
-                        defaultWidgetForSearchPackage = info;
-                    }
-                } else {
-                    return info;
-                }
-            }
-        }
-        return defaultWidgetForSearchPackage;
-    }
-
-    /**
      * Compresses the bitmap to a byte array for serialization.
      */
     public static byte[] flattenBitmap(Bitmap bitmap) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 62c1bc8..85ba57c 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
@@ -44,6 +45,7 @@
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Property;
 import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.View;
@@ -73,7 +75,7 @@
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.logging.UserEventDispatcher;
-import com.android.launcher3.pageindicators.PageIndicator;
+import com.android.launcher3.pageindicators.PageIndicatorLine;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.LongArrayMap;
@@ -109,7 +111,10 @@
     private static final boolean MAP_RECURSE = true;
 
     // The screen id used for the empty screen always present to the right.
-    public final static long EXTRA_EMPTY_SCREEN_ID = -201;
+    public static final long EXTRA_EMPTY_SCREEN_ID = -201;
+    // The is the first screen. It is always present, even if its empty.
+    public static final long FIRST_SCREEN_ID = 0;
+
     private final static long CUSTOM_CONTENT_SCREEN_ID = -301;
 
     private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;
@@ -173,26 +178,22 @@
     private Matrix mTempMatrix = new Matrix();
 
     private SpringLoadedDragController mSpringLoadedDragController;
-    private float mSpringLoadedShrinkFactor;
     private float mOverviewModeShrinkFactor;
 
     // State variable that indicates whether the pages are small (ie when you're
     // in all apps or customize mode)
 
-    enum State {
-        NORMAL          (SearchDropTargetBar.State.SEARCH_BAR, false, false),
-        NORMAL_HIDDEN   (SearchDropTargetBar.State.INVISIBLE_TRANSLATED, false, false),
-        SPRING_LOADED   (SearchDropTargetBar.State.DROP_TARGET, false, true),
-        OVERVIEW        (SearchDropTargetBar.State.INVISIBLE, true, true),
-        OVERVIEW_HIDDEN (SearchDropTargetBar.State.INVISIBLE, true, false);
+    public enum State {
+        NORMAL          (false, false),
+        NORMAL_HIDDEN   (false, false),
+        SPRING_LOADED   (false, true),
+        OVERVIEW        (true, true),
+        OVERVIEW_HIDDEN (true, false);
 
-        public final SearchDropTargetBar.State searchDropTargetBarState;
         public final boolean shouldUpdateWidget;
         public final boolean hasMultipleVisiblePages;
 
-        State(SearchDropTargetBar.State searchBarState, boolean shouldUpdateWidget,
-                boolean hasMultipleVisiblePages) {
-            searchDropTargetBarState = searchBarState;
+        State(boolean shouldUpdateWidget, boolean hasMultipleVisiblePages) {
             this.shouldUpdateWidget = shouldUpdateWidget;
             this.hasMultipleVisiblePages = hasMultipleVisiblePages;
         }
@@ -281,6 +282,7 @@
     private WorkspaceStateTransitionAnimation mStateTransitionAnimation;
 
     private AccessibilityDelegate mPagesAccessibilityDelegate;
+    private OnStateChangeListener mOnStateChangeListener;
 
     /**
      * Used to inflate the Workspace from XML.
@@ -313,9 +315,6 @@
         mWallpaperManager = WallpaperManager.getInstance(context);
 
         mWallpaperOffset = new WallpaperOffsetInterpolator(this);
-
-        mSpringLoadedShrinkFactor =
-                res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
         mOverviewModeShrinkFactor =
                 res.getInteger(R.integer.config_workspaceOverviewShrinkPercentage) / 100f;
 
@@ -341,9 +340,14 @@
         }
     }
 
+    public void setOnStateChangeListener(OnStateChangeListener listener) {
+        mOnStateChangeListener = listener;
+    }
+
     // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each
     // dimension if unsuccessful
     public int[] estimateItemSize(ItemInfo itemInfo, boolean springLoaded) {
+        float shrinkFactor = mLauncher.getDeviceProfile().workspaceSpringLoadShrinkFactor;
         int[] size = new int[2];
         if (getChildCount() > 0) {
             // Use the first non-custom page to estimate the child position
@@ -352,8 +356,8 @@
             size[0] = r.width();
             size[1] = r.height();
             if (springLoaded) {
-                size[0] *= mSpringLoadedShrinkFactor;
-                size[1] *= mSpringLoadedShrinkFactor;
+                size[0] *= shrinkFactor;
+                size[1] *= shrinkFactor;
             }
             return size;
         } else {
@@ -501,6 +505,38 @@
         return mTouchState != TOUCH_STATE_REST;
     }
 
+    /**
+     * Initializes and binds the first page
+     * @param qsb an exisitng qsb to recycle or null.
+     */
+    public void bindAndInitFirstWorkspaceScreen(View qsb) {
+        // Add the first page
+        CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, 0);
+
+        if (!mIsRtl || !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+            // Let the cell layout extend the start padding.
+            ((LayoutParams) firstPage.getLayoutParams()).matchStartEdge = true;
+            firstPage.setPaddingRelative(getPaddingStart(), 0, 0, 0);
+        }
+
+        if (qsb == null) {
+            // Always add a QSB on the first screen.
+            qsb = mLauncher.getLayoutInflater().inflate(R.layout.qsb_container,
+                    firstPage, false);
+        }
+
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) qsb.getLayoutParams();
+        lp.cellX = 0;
+        lp.cellY = 0;
+        lp.cellHSpan = firstPage.getCountX();
+        lp.cellVSpan = 1;
+        lp.canReorder = false;
+
+        if (!firstPage.addViewToCellLayout(qsb, 0, R.id.qsb_container, lp, true)) {
+            Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout");
+        }
+    }
+
     public void removeAllWorkspaceScreens() {
         // Disable all layout transitions before removing all pages to ensure that we don't get the
         // transition animations competing with us changing the scroll when we add pages or the
@@ -513,30 +549,39 @@
             removeCustomContentPage();
         }
 
+        // Recycle the QSB widget
+        View qsb = findViewById(R.id.qsb_container);
+        if (qsb != null) {
+            ((ViewGroup) qsb.getParent()).removeView(qsb);
+        }
+
         // Remove the pages and clear the screen models
         removeAllViews();
         mScreenOrder.clear();
         mWorkspaceScreens.clear();
 
+        // Ensure that the first page is always present
+        bindAndInitFirstWorkspaceScreen(qsb);
+
         // Re-enable the layout transitions
         enableLayoutTransitions();
     }
 
-    public long insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {
+    public void insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {
         // Find the index to insert this view into.  If the empty screen exists, then
         // insert it before that.
         int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);
         if (insertIndex < 0) {
             insertIndex = mScreenOrder.size();
         }
-        return insertNewWorkspaceScreen(screenId, insertIndex);
+        insertNewWorkspaceScreen(screenId, insertIndex);
     }
 
-    public long insertNewWorkspaceScreen(long screenId) {
-        return insertNewWorkspaceScreen(screenId, getChildCount());
+    public void insertNewWorkspaceScreen(long screenId) {
+        insertNewWorkspaceScreen(screenId, getChildCount());
     }
 
-    public long insertNewWorkspaceScreen(long screenId, int insertIndex) {
+    public CellLayout insertNewWorkspaceScreen(long screenId, int insertIndex) {
         if (mWorkspaceScreens.containsKey(screenId)) {
             throw new RuntimeException("Screen id " + screenId + " already exists!");
         }
@@ -558,7 +603,8 @@
         if (delegate != null && delegate.isInAccessibleDrag()) {
             newScreen.enableAccessibleDrag(true, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
         }
-        return screenId;
+
+        return newScreen;
     }
 
     public void createCustomContentContainer() {
@@ -765,6 +811,8 @@
                     if (stripEmptyScreens) {
                         stripEmptyScreens();
                     }
+                    // Update the page indicator to reflect the removed page.
+                    showPageIndicatorAtCurrentScroll();
                 }
             }
         };
@@ -860,7 +908,8 @@
         for (int i = 0; i < total; i++) {
             long id = mWorkspaceScreens.keyAt(i);
             CellLayout cl = mWorkspaceScreens.valueAt(i);
-            if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) {
+            // FIRST_SCREEN_ID can never be removed.
+            if (id > FIRST_SCREEN_ID && cl.getShortcutsAndWidgets().getChildCount() == 0) {
                 removeScreens.add(id);
             }
         }
@@ -1338,19 +1387,52 @@
         // TODO(adamcohen): figure out a final effect here. We may need to recommend
         // different effects based on device performance. On at least one relatively high-end
         // device I've tried, translating the launcher causes things to get quite laggy.
-        setTranslationAndAlpha(mLauncher.getSearchDropTargetBar(), transX, alpha);
-        setTranslationAndAlpha(getPageIndicator(), transX, alpha);
-        setTranslationAndAlpha(getChildAt(getCurrentPage()), transX, alpha);
-        setTranslationAndAlpha(mLauncher.getHotseat(), transX, alpha);
+        setWorkspaceTranslation(TRANSLATION_X, transX, alpha);
+        setHotseatTranslation(TRANSLATION_X, transX, alpha);
+    }
+
+    /**
+     * Moves the workspace UI in the provided direction.
+     * @param direction either {@link #TRANSLATION_X} or {@link #TRANSLATION_Y}
+     * @param translation the amound of shift.
+     * @param alpha the alpha for the workspace page
+     */
+    public void setWorkspaceTranslation(
+            Property<View, Float> direction, float translation, float alpha) {
+        View currentChild = getChildAt(getCurrentPage());
+        if (currentChild != null) {
+            direction.set(currentChild, translation);
+            currentChild.setAlpha(alpha);
+        }
 
         // When the animation finishes, reset all pages, just in case we missed a page.
-        if (transX == 0) {
+        if (Float.compare(translation, 0) == 0) {
             for (int i = getChildCount() - 1; i >= 0; i--) {
-                setTranslationAndAlpha(getChildAt(i), 0, alpha);
+                View child = getChildAt(i);
+                direction.set(child, translation);
+                child.setAlpha(alpha);
             }
         }
     }
 
+    /**
+     * Moves the Hotseat UI in the provided direction.
+     * @param direction either {@link #TRANSLATION_X} or {@link #TRANSLATION_Y}
+     * @param translation the amound of shift.
+     * @param alpha the alpha for the hotseat page
+     */
+    public void setHotseatTranslation(
+            Property<View, Float> direction, float translation, float alpha) {
+        View pageIndicator = getPageIndicator();
+        if (pageIndicator != null) {
+            direction.set(pageIndicator, translation);
+            pageIndicator.setAlpha(alpha);
+        }
+
+        direction.set(mLauncher.getHotseat(), translation);
+        mLauncher.getHotseat().setAlpha(alpha);
+    }
+
     @Override
     protected Matrix getPageShiftMatrix() {
         if (Float.compare(mOverlayTranslation, 0) != 0) {
@@ -1363,13 +1445,6 @@
         return super.getPageShiftMatrix();
     }
 
-    private void setTranslationAndAlpha(View v, float transX, float alpha) {
-        if (v != null) {
-            v.setTranslationX(transX);
-            v.setAlpha(alpha);
-        }
-    }
-
     @Override
     protected void getEdgeVerticalPostion(int[] pos) {
         View child = getChildAt(getPageCount() - 1);
@@ -1494,8 +1569,7 @@
             // Reset our click listener
             setOnClickListener(mLauncher);
         }
-        mLauncher.getSearchDropTargetBar().enableAccessibleDrag(enable);
-        mLauncher.getAppInfoDropTargetBar().enableAccessibleDrag(enable);
+        mLauncher.getDropTargetBar().enableAccessibleDrag(enable);
         mLauncher.getHotseat().getLayout()
             .enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
     }
@@ -1603,8 +1677,6 @@
             if (listener != null) {
                 getPageIndicator().setOnClickListener(listener);
             }
-
-            showPageIndicatorAtCurrentScroll();
         }
 
         // Update wallpaper dimensions if they were changed since last onResume
@@ -1898,7 +1970,7 @@
 
     int getOverviewModeTranslationY() {
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        Rect workspacePadding = grid.getWorkspacePadding(Utilities.isRtl(getResources()));
+        Rect workspacePadding = grid.getWorkspacePadding();
         int overviewButtonBarHeight = grid.getOverviewModeButtonBarHeight();
 
         int scaledHeight = (int) (mOverviewModeShrinkFactor * getNormalChildHeight());
@@ -1911,15 +1983,26 @@
         return -workspaceOffsetTopEdge + overviewOffsetTopEdge;
     }
 
-    int getSpringLoadedTranslationY() {
+    float getSpringLoadedTranslationY() {
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        Rect workspacePadding = grid.getWorkspacePadding(Utilities.isRtl(getResources()));
-        int scaledHeight = (int) (mSpringLoadedShrinkFactor * getNormalChildHeight());
-        int workspaceTop = mInsets.top + workspacePadding.top;
-        int workspaceBottom = getViewportHeight() - mInsets.bottom - workspacePadding.bottom;
-        int workspaceHeight = workspaceBottom - workspaceTop;
-        // Center the spring-loaded pages by translating it up by half of the reduced height.
-        return -(workspaceHeight - scaledHeight) / 2;
+        if (grid.isVerticalBarLayout() || getChildCount() == 0) {
+            return 0;
+        }
+        Rect workspacePadding = grid.getWorkspacePadding();
+
+        float scaledHeight = grid.workspaceSpringLoadShrinkFactor * getNormalChildHeight();
+        float shrunkTop = mInsets.top + grid.dropTargetBarSizePx;
+        float shrunkBottom = getViewportHeight() - mInsets.bottom
+                - workspacePadding.bottom - grid.workspaceSpringLoadedBottomSpace;
+        float totalShrunkSpace = shrunkBottom - shrunkTop;
+
+        float desiredCellTop = shrunkTop + (totalShrunkSpace - scaledHeight) / 2;
+
+        float halfHeight = getHeight() / 2;
+        float myCenter = getTop() + halfHeight;
+        float cellTopFromCenter = halfHeight - getChildAt(0).getTop();
+        float actualCellTop = myCenter - cellTopFromCenter * grid.workspaceSpringLoadShrinkFactor;
+        return (desiredCellTop - actualCellTop) / grid.workspaceSpringLoadShrinkFactor;
     }
 
     float getOverviewModeShrinkFactor() {
@@ -1933,7 +2016,7 @@
     public Animator setStateWithAnimation(State toState, boolean animated,
             HashMap<View, Integer> layerViews) {
         // Create the animation to the new state
-        Animator workspaceAnim =  mStateTransitionAnimation.getAnimationToState(mState,
+        AnimatorSet workspaceAnim =  mStateTransitionAnimation.getAnimationToState(mState,
                 toState, animated, layerViews);
 
         boolean shouldNotifyWidgetChange = !mState.shouldUpdateWidget
@@ -1946,6 +2029,10 @@
             mLauncher.notifyWidgetProvidersChanged();
         }
 
+        if (mOnStateChangeListener != null) {
+            mOnStateChangeListener.prepareStateChange(toState, animated ? workspaceAnim : null);
+        }
+
         return workspaceAnim;
     }
 
@@ -2009,6 +2096,14 @@
 
     @Override
     public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
+        if (mPageIndicator instanceof PageIndicatorLine) {
+            boolean isNewStateSpringLoaded = mState == State.SPRING_LOADED;
+            ((PageIndicatorLine) mPageIndicator).setShouldAutoHide(!isNewStateSpringLoaded);
+            if (isNewStateSpringLoaded) {
+                // Show the page indicator at the same time as the rest of the transition.
+                showPageIndicatorAtCurrentScroll();
+            }
+        }
     }
 
     @Override
@@ -2022,7 +2117,7 @@
         updateChildrenLayersEnabled(false);
         showCustomContentIfNecessary();
         mForceDrawAdjacentPages = false;
-        if (mState == State.NORMAL || mState == State.SPRING_LOADED) {
+        if (mState == State.SPRING_LOADED) {
             showPageIndicatorAtCurrentScroll();
         }
     }
@@ -3938,7 +4033,7 @@
         });
     }
 
-    private View getFirstMatch(final ItemOperator operator) {
+    public View getFirstMatch(final ItemOperator operator) {
         final View[] value = new View[1];
         mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
             @Override
@@ -4351,4 +4446,14 @@
             });
         }
     }
+
+    public interface OnStateChangeListener {
+
+        /**
+         * Called when the workspace state is changing.
+         * @param toState final state
+         * @param targetAnim animation which will be played during the transition or null.
+         */
+        void prepareStateChange(State toState, AnimatorSet targetAnim);
+    }
 }
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index e268640..0f437c1 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -211,8 +211,7 @@
         mOverviewTransitionTime = res.getInteger(R.integer.config_overviewTransitionTime);
         mOverlayTransitionTime = res.getInteger(R.integer.config_overlayTransitionTime);
         mSpringLoadedTransitionTime = mOverlayTransitionTime / 2;
-        mSpringLoadedShrinkFactor =
-                res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100f;
+        mSpringLoadedShrinkFactor = mLauncher.getDeviceProfile().workspaceSpringLoadShrinkFactor;
         mOverviewModeShrinkFactor =
                 res.getInteger(R.integer.config_workspaceOverviewShrinkPercentage) / 100f;
         mWorkspaceScrimAlpha = res.getInteger(R.integer.config_workspaceScrimAlpha) / 100f;
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index aa6e08e..6bf8abf 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -118,7 +118,9 @@
                     info.addAction(mActions.get(RESIZE));
                 }
             }
-        } if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
+        }
+
+        if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
             info.addAction(mActions.get(ADD_TO_WORKSPACE));
         }
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index c9bd02c..a74c4c5 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -18,18 +18,23 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.method.TextKeyListener;
 import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.widget.LinearLayout;
 
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.BaseContainerView;
@@ -40,6 +45,7 @@
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.ExtendedEditText;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
@@ -47,6 +53,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.keyboard.FocusedItemDecorator;
 import com.android.launcher3.util.ComponentKey;
 
 import java.nio.charset.Charset;
@@ -178,9 +185,13 @@
         mApps.setAdapter(mAdapter);
         mLayoutManager = mAdapter.getLayoutManager();
         mItemDecoration = mAdapter.getItemDecoration();
-        mRecyclerViewTopBottomPadding =
-                res.getDimensionPixelSize(R.dimen.all_apps_list_top_bottom_padding);
-
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
+            mRecyclerViewTopBottomPadding = 0;
+            setPadding(0, 0, 0, 0);
+        } else {
+            mRecyclerViewTopBottomPadding =
+                    res.getDimensionPixelSize(R.dimen.all_apps_list_top_bottom_padding);
+        }
         mSearchQueryBuilder = new SpannableStringBuilder();
         Selection.setSelection(mSearchQueryBuilder, 0);
     }
@@ -220,6 +231,13 @@
         mApps.removeApps(apps);
     }
 
+    public void setSearchBarVisible(boolean visible) {
+        if (visible) {
+            mSearchBarController.setVisibility(View.VISIBLE);
+        } else {
+            mSearchBarController.setVisibility(View.INVISIBLE);
+        }
+    }
     /**
      * Sets the search bar that shows above the a-z list.
      */
@@ -240,6 +258,25 @@
     }
 
     /**
+     * Returns whether the view itself will handle the touch event or not.
+     */
+    public boolean shouldContainerScroll(float x, float y) {
+        int[] point = new int[2];
+        point[0] = (int) x;
+        point[1] = (int) y;
+        Utilities.mapCoordInSelfToDescendent(mAppsRecyclerView, this, point);
+
+        // if the MotionEvent is inside the thumb, container should not be pulled down.
+        if (mAppsRecyclerView.getScrollBar().isNearThumb(point[0], point[1])){
+             return false;
+        }
+        // If scroller is at the very top, then it's okay for the container to be pulled down.
+        if (Float.compare(0f, mAppsRecyclerView.getScrollBar().getThumbOffset().y) == 0) {
+            return true;
+        }
+        return false;
+    }
+    /**
      * Focuses the search field and begins an app search.
      */
     public void startAppsSearch() {
@@ -291,6 +328,10 @@
             mAppsRecyclerView.addItemDecoration(mItemDecoration);
         }
 
+        FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mAppsRecyclerView);
+        mAppsRecyclerView.addItemDecoration(focusedItemDecorator);
+        mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
+
         // Precalculate the prediction icon and normal icon sizes
         LayoutInflater layoutInflater = LayoutInflater.from(getContext());
         final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -321,13 +362,33 @@
                 MeasureSpec.getSize(widthMeasureSpec) - mHorizontalPadding,
                 MeasureSpec.getSize(heightMeasureSpec));
 
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+        int availableWidth = (!mContentBounds.isEmpty() ? mContentBounds.width() :
+                MeasureSpec.getSize(widthMeasureSpec))
+                - 2 * mAppsRecyclerView.getMaxScrollbarWidth();
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
+            if (mNumAppsPerRow != grid.inv.numColumns ||
+                    mNumPredictedAppsPerRow != grid.inv.numColumns) {
+                mNumAppsPerRow = grid.inv.numColumns;
+                mNumPredictedAppsPerRow = grid.inv.numColumns;
+
+                mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow);
+                mAdapter.setNumAppsPerRow(mNumAppsPerRow);
+                mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, new FullMergeAlgorithm());
+                if (mNumAppsPerRow > 0) {
+                    int iconSize = availableWidth / mNumAppsPerRow;
+                    int iconSpacing = (iconSize - grid.allAppsIconSizePx) / 2;
+                }
+            }
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
+        }
+
+        // --- remove START when {@code FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP} is enabled. ---
+
         // Update the number of items in the grid before we measure the view
         // TODO: mSectionNamesMargin is currently 0, but also account for it,
         // if it's enabled in the future.
-        int availableWidth = (!mContentBounds.isEmpty() ? mContentBounds.width() :
-                MeasureSpec.getSize(widthMeasureSpec))
-                    - 2 * mAppsRecyclerView.getMaxScrollbarWidth();
-        DeviceProfile grid = mLauncher.getDeviceProfile();
         grid.updateAppsViewNumCols(getResources(), availableWidth);
         if (mNumAppsPerRow != grid.allAppsNumCols ||
                 mNumPredictedAppsPerRow != grid.allAppsNumPredictiveCols) {
@@ -346,6 +407,8 @@
             mAdapter.setNumAppsPerRow(mNumAppsPerRow);
             mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, mergeAlgorithm);
 
+            // TODO: should we not do all this complicated computation but just match the
+            // numAppsPerRow with the workspace?
             if (mNumAppsPerRow > 0) {
                 int iconSize = availableWidth / mNumAppsPerRow;
                 int iconSpacing = (iconSize - grid.allAppsIconSizePx) / 2;
@@ -353,6 +416,7 @@
             }
         }
 
+        // --- remove END when {@code FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP} is enabled. ---
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
@@ -385,6 +449,25 @@
         MarginLayoutParams lp = (MarginLayoutParams) mSearchContainer.getLayoutParams();
         lp.leftMargin = bgPadding.left;
         lp.rightMargin = bgPadding.right;
+
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
+            MarginLayoutParams mlp = (MarginLayoutParams) mAppsRecyclerView.getLayoutParams();
+
+            int navBarHeight = 84; /* replace with mInset.height() in dragLayer */
+            DeviceProfile grid = mLauncher.getDeviceProfile();
+            int height = navBarHeight + grid.hotseatCellHeightPx;
+
+            mlp.topMargin = height;
+            mAppsRecyclerView.setLayoutParams(mlp);
+
+            LinearLayout.LayoutParams llp =
+                    (LinearLayout.LayoutParams) mSearchInput.getLayoutParams();
+            llp.topMargin = navBarHeight;
+            mSearchInput.setLayoutParams(llp);
+
+            lp.height = height;
+            mSearchContainer.setBackground(null);
+        }
         mSearchContainer.setLayoutParams(lp);
     }
 
@@ -437,6 +520,7 @@
         // Return early if this is not initiated from a touch
         if (!v.isInTouchMode()) return false;
         // When we have exited all apps or are in transition, disregard long clicks
+
         if (!mLauncher.isAppsViewVisible() ||
                 mLauncher.getWorkspace().isSwitchingState()) return false;
         // Return if global dragging is not enabled
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 115db9d..c2a319c 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -33,6 +33,7 @@
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnFocusChangeListener;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
@@ -348,15 +349,10 @@
 
     private BindViewCallback mBindViewCallback;
     private AllAppsSearchBarController mSearchController;
+    private OnFocusChangeListener mIconFocusListener;
 
     // The text to show when there are no search results and no market search handler.
     private String mEmptySearchMessage;
-    // The name of the market app which handles searches, to be used in the format str
-    // below when updating the search-market view.  Only needs to be loaded once.
-    private String mMarketAppName;
-    // The text to show when there is a market app which can handle a specific query, updated
-    // each time the search query changes.
-    private String mMarketSearchMessage;
     // The intent to send off to the market app, updated each time the search query changes.
     private Intent mMarketSearchIntent;
 
@@ -402,14 +398,10 @@
 
     public void setSearchController(AllAppsSearchBarController searchController) {
         mSearchController = searchController;
+    }
 
-        // Resolve the market app handling additional searches
-        PackageManager pm = mLauncher.getPackageManager();
-        ResolveInfo marketInfo = pm.resolveActivity(mSearchController.createMarketSearchIntent(""),
-                PackageManager.MATCH_DEFAULT_ONLY);
-        if (marketInfo != null) {
-            mMarketAppName = marketInfo.loadLabel(pm).toString();
-        }
+    public void setIconFocusListener(OnFocusChangeListener focusListener) {
+        mIconFocusListener = focusListener;
     }
 
     /**
@@ -419,11 +411,7 @@
     public void setLastSearchQuery(String query) {
         Resources res = mLauncher.getResources();
         mEmptySearchMessage = res.getString(R.string.all_apps_no_search_results, query);
-        if (mMarketAppName != null) {
-            mMarketSearchMessage = res.getString(R.string.all_apps_search_market_message,
-                    mMarketAppName);
-            mMarketSearchIntent = mSearchController.createMarketSearchIntent(query);
-        }
+        mMarketSearchIntent = mSearchController.createMarketSearchIntent(query);
     }
 
     /**
@@ -461,26 +449,17 @@
         switch (viewType) {
             case SECTION_BREAK_VIEW_TYPE:
                 return new ViewHolder(new View(parent.getContext()));
-            case ICON_VIEW_TYPE: {
-                BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
-                        R.layout.all_apps_icon, parent, false);
-                icon.setOnTouchListener(mTouchListener);
-                icon.setOnClickListener(mIconClickListener);
-                icon.setOnLongClickListener(mIconLongClickListener);
-                icon.setLongPressTimeout(ViewConfiguration.get(parent.getContext())
-                        .getLongPressTimeout());
-                icon.setFocusable(true);
-                return new ViewHolder(icon);
-            }
+            case ICON_VIEW_TYPE:
             case PREDICTION_ICON_VIEW_TYPE: {
                 BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
-                        R.layout.all_apps_prediction_bar_icon, parent, false);
+                        viewType == ICON_VIEW_TYPE ? R.layout.all_apps_icon :
+                                R.layout.all_apps_prediction_bar_icon, parent, false);
                 icon.setOnTouchListener(mTouchListener);
                 icon.setOnClickListener(mIconClickListener);
                 icon.setOnLongClickListener(mIconLongClickListener);
                 icon.setLongPressTimeout(ViewConfiguration.get(parent.getContext())
                         .getLongPressTimeout());
-                icon.setFocusable(true);
+                icon.setOnFocusChangeListener(mIconFocusListener);
                 return new ViewHolder(icon);
             }
             case EMPTY_SEARCH_VIEW_TYPE:
@@ -511,12 +490,16 @@
                 AppInfo info = mApps.getAdapterItems().get(position).appInfo;
                 BubbleTextView icon = (BubbleTextView) holder.mContent;
                 icon.applyFromApplicationInfo(info);
+                icon.setAccessibilityDelegate(
+                        LauncherAppState.getInstance().getAccessibilityDelegate());
                 break;
             }
             case PREDICTION_ICON_VIEW_TYPE: {
                 AppInfo info = mApps.getAdapterItems().get(position).appInfo;
                 BubbleTextView icon = (BubbleTextView) holder.mContent;
                 icon.applyFromApplicationInfo(info);
+                icon.setAccessibilityDelegate(
+                        LauncherAppState.getInstance().getAccessibilityDelegate());
                 break;
             }
             case EMPTY_SEARCH_VIEW_TYPE:
@@ -529,10 +512,8 @@
                 TextView searchView = (TextView) holder.mContent;
                 if (mMarketSearchIntent != null) {
                     searchView.setVisibility(View.VISIBLE);
-                    searchView.setContentDescription(mMarketSearchMessage);
                     searchView.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
                             Gravity.START | Gravity.CENTER_VERTICAL);
-                    searchView.setText(mMarketSearchMessage);
                 } else {
                     searchView.setVisibility(View.GONE);
                 }
diff --git a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
index a4bea8d..ac35932 100644
--- a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
@@ -49,6 +49,9 @@
     protected DefaultAppSearchAlgorithm mSearchAlgorithm;
     protected InputMethodManager mInputMethodManager;
 
+    public void setVisibility(int visibility) {
+        mInput.setVisibility(visibility);
+    }
     /**
      * Sets the references to the apps model and the search result callback.
      */
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
new file mode 100644
index 0000000..7f047d5
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -0,0 +1,375 @@
+package com.android.launcher3.allapps;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.PagedView;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.util.TouchController;
+
+/**
+ * Handles AllApps view transition.
+ * 1) Slides all apps view using direct manipulation
+ * 2) When finger is released, animate to either top or bottom accordingly.
+ *
+ * Algorithm:
+ * If release velocity > THRES1, snap according to the direction of movement.
+ * If release velocity < THRES1, snap according to either top or bottom depending on whether it's
+ *     closer to top or closer to the page indicator.
+ */
+public class AllAppsTransitionController implements TouchController, VerticalPullDetector.Listener {
+
+    private static final String TAG = "AllAppsTrans";
+    private static final boolean DBG = false;
+
+     private final Interpolator mAccelInterpolator = new AccelerateInterpolator(1f);
+
+    private static final float ANIMATION_DURATION = 2000;
+    private static final float FINAL_ALPHA = .65f;
+
+    private AllAppsContainerView mAppsView;
+    private Workspace mWorkspace;
+    private Hotseat mHotseat;
+    private Drawable mHotseatBackground;
+    private float mHotseatAlpha;
+
+    private final Launcher mLauncher;
+    private final VerticalPullDetector mDetector;
+
+    // Animation in this class is controlled by a single variable {@link mProgressTransY}.
+    // Visually, it represents top y coordinate of the all apps container. Using the
+    // {@link mTranslation} as the denominator, this fraction value ranges in [0, 1].
+    private float mProgressTransY;   // numerator
+    private float mTranslation = -1; // denominator
+
+    private static final float RECATCH_REJECTION_FRACTION = .0875f;
+
+    private long mAnimationDuration;
+    private float mCurY;
+
+    private AnimatorSet mCurrentAnimation;
+    private boolean mNoIntercept;
+
+    public AllAppsTransitionController(Launcher launcher) {
+        mLauncher = launcher;
+        mDetector = new VerticalPullDetector(launcher);
+        mDetector.setListener(this);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        init();
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mNoIntercept = false;
+            if (mLauncher.getWorkspace().isInOverviewMode() || mLauncher.isWidgetsViewVisible()) {
+                mNoIntercept = true;
+            } else if (mLauncher.isAllAppsVisible() &&
+                    !mAppsView.shouldContainerScroll(ev.getX(), ev.getY())) {
+                mNoIntercept = true;
+            } else {
+                mDetector.setDetectableScrollConditions(mLauncher.isAllAppsVisible() /* down */,
+                        isInDisallowRecatchTopZone(), isInDisallowRecatchBottomZone());
+            }
+        }
+        if (mNoIntercept) {
+            return false;
+        }
+        mDetector.onTouchEvent(ev);
+        return mDetector.shouldIntercept();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        return mDetector.onTouchEvent(ev);
+    }
+
+    private boolean isInDisallowRecatchTopZone() {
+        return mProgressTransY / mTranslation < RECATCH_REJECTION_FRACTION;
+    }
+
+    private boolean isInDisallowRecatchBottomZone() {
+        return mProgressTransY / mTranslation > 1 - RECATCH_REJECTION_FRACTION;
+    }
+
+    private void init() {
+        if (mAppsView != null) {
+            return;
+        }
+        mAppsView = mLauncher.getAppsView();
+        mHotseat = mLauncher.getHotseat();
+        mWorkspace = mLauncher.getWorkspace();
+
+        if (mHotseatBackground == null) {
+            mHotseatBackground = mHotseat.getBackground();
+            mHotseatAlpha = mHotseatBackground.getAlpha() / 255f;
+        }
+    }
+
+    @Override
+    public void onScrollStart(boolean start) {
+        cancelAnimation();
+        mCurrentAnimation = LauncherAnimUtils.createAnimatorSet();
+        preparePull(start);
+        mCurY = mAppsView.getTranslationY();
+    }
+
+    /**
+     * @param start {@code true} if start of new drag.
+     */
+    public void preparePull(boolean start) {
+        mHotseat.setVisibility(View.VISIBLE);
+        mHotseat.bringToFront();
+        if (start) {
+            if (!mLauncher.isAllAppsVisible()) {
+                mHotseat.setBackground(null);
+                mAppsView.setVisibility(View.VISIBLE);
+                mAppsView.getContentView().setVisibility(View.VISIBLE);
+                mAppsView.getContentView().setBackground(null);
+                mAppsView.getRevealView().setVisibility(View.VISIBLE);
+                mAppsView.getRevealView().setAlpha(mHotseatAlpha);
+                mAppsView.setSearchBarVisible(false);
+
+                if (mTranslation < 0) {
+                    mTranslation = mHotseat.getTop();
+                    setProgress(mTranslation);
+                }
+            } else {
+                // TODO: get rid of this workaround to override state change by workspace transition
+                mWorkspace.onLauncherTransitionPrepare(mLauncher, false, false);
+                View child = ((CellLayout) mWorkspace.getChildAt(mWorkspace.getNextPage()))
+                        .getShortcutsAndWidgets();
+                child.setVisibility(View.VISIBLE);
+                child.setAlpha(1f);
+
+                mAppsView.setSearchBarVisible(false);
+                setLightStatusBar(false);
+            }
+        }
+    }
+
+    private void setLightStatusBar(boolean enable) {
+        int systemUiFlags = mLauncher.getWindow().getDecorView().getSystemUiVisibility();
+        if (enable) {
+            mLauncher.getWindow().getDecorView().setSystemUiVisibility(systemUiFlags
+                    | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+
+        } else {
+            mLauncher.getWindow().getDecorView().setSystemUiVisibility(systemUiFlags
+                    & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+
+        }
+    }
+
+    @Override
+    public boolean onScroll(float displacement, float velocity) {
+        if (mAppsView == null) {
+            return false;   // early termination.
+        }
+        if (0 <= mCurY + displacement && mCurY + displacement < mTranslation) {
+            setProgress(mCurY + displacement);
+        }
+        return true;
+    }
+
+    /**
+     * @param progress y value of the border between hotseat and all apps
+     */
+    public void setProgress(float progress) {
+        mProgressTransY = progress;
+        float alpha = calcAlphaAllApps(progress);
+        float workspaceHotseatAlpha = 1 - alpha;
+
+        mAppsView.getRevealView().setAlpha(Math.min(FINAL_ALPHA, Math.max(mHotseatAlpha, alpha)));
+        mAppsView.getContentView().setAlpha(alpha);
+        mAppsView.setTranslationY(progress);
+        mWorkspace.setWorkspaceTranslation(View.TRANSLATION_Y, -mTranslation + progress,
+                mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
+        mWorkspace.setHotseatTranslation(
+                View.TRANSLATION_Y, -mTranslation + progress, workspaceHotseatAlpha);
+    }
+
+    public float getProgress() {
+        return mProgressTransY;
+    }
+
+    private float calcAlphaAllApps(float progress) {
+        return ((mTranslation - progress)/mTranslation);
+    }
+
+    @Override
+    public void onScrollEnd(float velocity, boolean fling) {
+        if (mAppsView == null) {
+            return; // early termination.
+        }
+
+        if (fling) {
+            if (velocity < 0) {
+                calculateDuration(velocity, mAppsView.getTranslationY());
+                showAppsView(); // Flinging in UP direction
+            } else {
+                calculateDuration(velocity, Math.abs(mTranslation - mAppsView.getTranslationY()));
+                showWorkspace(); // Flinging in DOWN direction
+            }
+            // snap to top or bottom using the release velocity
+        } else {
+            if (mAppsView.getTranslationY() > mTranslation / 2) {
+                calculateDuration(velocity, Math.abs(mTranslation - mAppsView.getTranslationY()));
+                showWorkspace(); // Released in the bottom half
+            } else {
+                calculateDuration(velocity, Math.abs(mAppsView.getTranslationY()));
+                showAppsView(); // Released in the top half
+            }
+        }
+    }
+
+    private void calculateDuration(float velocity, float disp) {
+        // TODO: make these values constants after tuning.
+        float velocityDivisor = Math.max(1.5f, Math.abs(0.25f * velocity));
+        float travelDistance = Math.max(0.2f, disp / mTranslation);
+        mAnimationDuration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance);
+        if (DBG) {
+            Log.d(TAG, String.format("calculateDuration=%d, v=%f, d=%f", mAnimationDuration, velocity, disp));
+        }
+    }
+
+    /**
+     * Depending on the current state of the launcher, either just
+     * 1) animate
+     * 2) animate and do all the state updates.
+     */
+    private void showAppsView() {
+        if (mLauncher.isAllAppsVisible()) {
+            animateToAllApps(mCurrentAnimation, mAnimationDuration);
+            mCurrentAnimation.start();
+        } else {
+            mLauncher.showAppsView(true /* animated */, true /* resetListToTop */,
+                    true /* updatePredictedApps */, false /* focusSearchBar */);
+        }
+    }
+
+    /**
+     * Depending on the current state of the launcher, either just
+     * 1) animate
+     * 2) animate and do all the state updates.
+     */
+    private void showWorkspace() {
+        if (mLauncher.isAllAppsVisible()) {
+            mLauncher.showWorkspace(true /* animated */);
+        } else {
+            animateToWorkspace(mCurrentAnimation, mAnimationDuration);
+            mCurrentAnimation.start();
+        }
+    }
+
+    public void animateToAllApps(AnimatorSet animationOut, long duration) {
+        if ((mAppsView = mLauncher.getAppsView()) == null || animationOut == null){
+            return;
+        }
+        if (mDetector.isRestingState()) {
+            preparePull(true);
+            mAnimationDuration = duration;
+        }
+        mCurY = mAppsView.getTranslationY();
+        final float fromAllAppsTop = mAppsView.getTranslationY();
+        final float toAllAppsTop = 0;
+
+        ObjectAnimator driftAndAlpha = ObjectAnimator.ofFloat(this, "progress",
+                fromAllAppsTop, toAllAppsTop);
+        driftAndAlpha.setDuration(mAnimationDuration);
+        driftAndAlpha.setInterpolator(new PagedView.ScrollInterpolator());
+        animationOut.play(driftAndAlpha);
+
+        animationOut.addListener(new AnimatorListenerAdapter() {
+            boolean canceled = false;
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                canceled = true;
+            }
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (canceled) {
+                    return;
+                } else {
+                    finishPullUp();
+                    cleanUpAnimation();
+                    mDetector.finishedScrolling();
+                }
+            }});
+        mCurrentAnimation = animationOut;
+    }
+
+    private void finishPullUp() {
+        mAppsView.setSearchBarVisible(true);
+        mHotseat.setVisibility(View.INVISIBLE);
+        setProgress(0f);
+        setLightStatusBar(true);
+    }
+
+    public void animateToWorkspace(AnimatorSet animationOut, long duration) {
+        if ((mAppsView = mLauncher.getAppsView()) == null || animationOut == null){
+            return;
+        }
+        if(mDetector.isRestingState()) {
+            preparePull(true);
+            mAnimationDuration = duration;
+        }
+        final float fromAllAppsTop = mAppsView.getTranslationY();
+        final float toAllAppsTop = mTranslation;
+
+        ObjectAnimator driftAndAlpha = ObjectAnimator.ofFloat(this, "progress",
+                fromAllAppsTop, toAllAppsTop);
+        driftAndAlpha.setDuration(mAnimationDuration);
+        driftAndAlpha.setInterpolator(new PagedView.ScrollInterpolator());
+        animationOut.play(driftAndAlpha);
+
+        animationOut.addListener(new AnimatorListenerAdapter() {
+             boolean canceled = false;
+             @Override
+             public void onAnimationCancel(Animator animation) {
+                 canceled = true;
+             }
+
+             @Override
+             public void onAnimationEnd(Animator animation) {
+                 if (canceled) {
+                     return;
+                 } else {
+                     finishPullDown();
+                     cleanUpAnimation();
+                     mDetector.finishedScrolling();
+                 }
+             }});
+        mCurrentAnimation = animationOut;
+    }
+
+    public void finishPullDown() {
+        mAppsView.setVisibility(View.INVISIBLE);
+        mHotseat.setBackground(mHotseatBackground);
+        mHotseat.setVisibility(View.VISIBLE);
+        setProgress(mTranslation);
+        setLightStatusBar(false);
+    }
+
+    private void cancelAnimation() {
+        if (mCurrentAnimation != null) {
+            mCurrentAnimation.cancel();
+            mCurrentAnimation = null;
+        }
+    }
+
+    private void cleanUpAnimation() {
+        mCurrentAnimation = null;
+    }
+}
diff --git a/src/com/android/launcher3/allapps/VerticalPullDetector.java b/src/com/android/launcher3/allapps/VerticalPullDetector.java
new file mode 100644
index 0000000..7df63e0
--- /dev/null
+++ b/src/com/android/launcher3/allapps/VerticalPullDetector.java
@@ -0,0 +1,244 @@
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+/**
+ * One dimensional scroll gesture detector for all apps container pull up interaction.
+ */
+public class VerticalPullDetector {
+
+    private static final String TAG = "ScrollGesture";
+    private static final boolean DBG = false;
+
+    private float mTouchSlop;
+    private boolean mScrollDown; // if false, only scroll up will be reported.
+    private boolean mDisallowRecatchFromTop;
+    private boolean mDisallowRecatchFromBottom;
+
+    /**
+     * The minimum release velocity in pixels per millisecond that triggers fling..
+     */
+    private static final float RELEASE_VELOCITY_PX_MS = 1.0f;
+
+    /**
+     * The time constant used to calculate dampening in the low-pass filter of scroll velocity.
+     * Cutoff frequency is set at 10 Hz.
+     */
+    public static final float SCROLL_VELOCITY_DAMPENING_RC = 1000f / (2f * (float) Math.PI * 10);
+
+    /* Scroll state, this is set to true during dragging and animation. */
+    private State mState = State.NONE;
+    enum State {NONE, DRAG, SCROLLING};
+
+    private void setState(State newState) {
+        if (DBG) {
+            Log.d(TAG, mState + "->" + newState);
+        }
+        mState = newState;
+    }
+
+    public boolean shouldIntercept() {
+        return mState == State.DRAG;
+    }
+
+    public boolean isRestingState() {
+        return mState == State.NONE;
+    }
+
+    private float mDownX;
+    private float mDownY;
+    private float mDownMillis;
+
+    private float mLastY;
+    private float mLastMillis;
+
+    private float mVelocity;
+    private float mLastDisplacement;
+    private float mDisplacementY;
+    private float mDisplacementX;
+
+    /* scroll started during previous animation */
+    private boolean mSubtractSlop = true;
+
+    /* Client of this gesture detector can register a callback. */
+    Listener mListener;
+
+    public void setListener(Listener l) {
+        mListener = l;
+    }
+
+    interface Listener{
+        void onScrollStart(boolean start);
+        boolean onScroll(float displacement, float velocity);
+        void onScrollEnd(float velocity, boolean fling);
+    }
+
+    public VerticalPullDetector(Context context) {
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+    }
+
+    public void setDetectableScrollConditions(boolean scrollDown, boolean disallowRecatchFromTop,
+            boolean disallowRecatchFromBottom) {
+        mScrollDown = scrollDown;
+        mDisallowRecatchFromTop = disallowRecatchFromTop;
+        mDisallowRecatchFromBottom = disallowRecatchFromBottom;
+    }
+
+    private boolean shouldScrollStart() {
+        float deltaY = Math.abs(mDisplacementY);
+        float deltaX = Math.max(Math.abs(mDisplacementX), 1);
+        if (mScrollDown && mDisplacementY > mTouchSlop) {
+            if (deltaY > deltaX) {
+                return true;
+            }
+        }
+        if (!mScrollDown && mDisplacementY < -mTouchSlop) {
+            if (deltaY > deltaX) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean shouldRecatchScrollStart() {
+        if (!mDisallowRecatchFromBottom && !mDisallowRecatchFromTop) {
+            return true;
+        }
+        if (mDisallowRecatchFromTop && mDisplacementY > mTouchSlop) {
+            mDisallowRecatchFromTop = false;
+            return true;
+        }
+        if (mDisallowRecatchFromBottom && mDisplacementY < -mTouchSlop) {
+            mDisallowRecatchFromBottom = false;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean onTouchEvent(MotionEvent ev) {
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mDownMillis = ev.getDownTime();
+                mDownX = ev.getX();
+                mDownY = ev.getY();
+                mLastDisplacement = 0;
+                mVelocity = 0;
+                if (mState == State.SCROLLING && shouldRecatchScrollStart()){
+                    reportScrollStart(true /* recatch */);
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                mDisplacementX = ev.getX() - mDownX;
+                mDisplacementY = ev.getY() - mDownY;
+                mVelocity = computeVelocity(ev, mVelocity);
+
+                if (mState == State.SCROLLING && shouldRecatchScrollStart()){
+                    setState(State.DRAG);
+                    reportScrollStart(true /* recatch */);
+                }
+                if (mState == State.NONE && shouldScrollStart()) {
+                    setState(State.DRAG);
+                    reportScrollStart(false /* recatch */);
+                }
+                if (mState == State.DRAG && mListener != null) {
+                    reportScroll();
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                // These are synthetic events and there is no need to update internal values.
+                if (mState == State.DRAG && mListener != null) {
+                    reportScrollEnd();
+                }
+                break;
+            default:
+                //TODO: add multi finger tracking by tracking active pointer.
+                break;
+        }
+        // Do house keeping.
+        mLastDisplacement = mDisplacementY;
+
+        mLastY = ev.getY();
+        mLastMillis = ev.getEventTime();
+
+        return true;
+    }
+
+    public void finishedScrolling() {
+        setState(State.NONE);
+    }
+
+    private boolean reportScrollStart(boolean recatch) {
+        mListener.onScrollStart(!recatch);
+        mSubtractSlop = !recatch;
+        if (DBG) {
+            Log.d(TAG, "onScrollStart recatch:" + recatch);
+        }
+        return true;
+    }
+
+    private boolean reportScroll() {
+        float delta = mDisplacementY - mLastDisplacement;
+        if (delta != 0) {
+            if (DBG) {
+                Log.d(TAG, String.format("onScroll disp=%.1f, velocity=%.1f",
+                        mDisplacementY, mVelocity));
+            }
+            float subtractDisplacement = 0f;
+            if (mSubtractSlop) {
+                if (mDisplacementY > 0) {
+                    subtractDisplacement = mTouchSlop;
+                } else {
+                    subtractDisplacement = -mTouchSlop;
+                }
+            }
+            return mListener.onScroll(mDisplacementY - subtractDisplacement, mVelocity);
+        }
+        return true;
+    }
+
+    private void reportScrollEnd() {
+        if (DBG) {
+            Log.d(TAG, String.format("onScrolEnd disp=%.1f, velocity=%.1f",
+                    mDisplacementY, mVelocity));
+        }
+        mListener.onScrollEnd(mVelocity, Math.abs(mVelocity) > RELEASE_VELOCITY_PX_MS);
+        setState(State.SCROLLING);
+    }
+    /**
+     * Computes the damped velocity using the two motion events and the previous velocity.
+     */
+    private float computeVelocity(MotionEvent to, float previousVelocity) {
+        float delta = computeDelta(to);
+
+        float deltaTimeMillis = to.getEventTime() - mLastMillis;
+        float velocity = (deltaTimeMillis > 0) ? (delta / deltaTimeMillis) : 0;
+        if (Math.abs(previousVelocity) < 0.001f) {
+            return velocity;
+        }
+
+        float alpha = computeDampeningFactor(deltaTimeMillis);
+        return interpolate(previousVelocity, velocity, alpha);
+    }
+
+    private float computeDelta(MotionEvent to) {
+        return to.getY() - mLastY;
+    }
+
+    /**
+     * Returns a time-dependent dampening factor using delta time.
+     */
+    private static float computeDampeningFactor(float deltaTime) {
+        return deltaTime / (SCROLL_VELOCITY_DAMPENING_RC + deltaTime);
+    }
+
+    /**
+     * Returns the linear interpolation between two values
+     */
+    private static float interpolate(float from, float to, float alpha) {
+        return (1.0f - alpha) * from + alpha * to;
+    }
+}
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index f4470f3..af5ff58 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -46,6 +46,7 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.TouchController;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -53,7 +54,7 @@
 /**
  * Class for initiating a drag within a view or across multiple views.
  */
-public class DragController implements DragDriver.EventListener {
+public class DragController implements DragDriver.EventListener, TouchController {
     private static final String TAG = "Launcher.DragController";
 
     /** Indicates the drag is a move.  */
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 33ce683..765ad64 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -29,7 +29,6 @@
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.DragEvent;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -43,6 +42,7 @@
 import android.widget.TextView;
 
 import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.BaseContainerView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.ItemInfo;
@@ -51,15 +51,19 @@
 import com.android.launcher3.LauncherAppWidgetHostView;
 import com.android.launcher3.PinchToOverviewListener;
 import com.android.launcher3.R;
-import com.android.launcher3.SearchDropTargetBar;
+import com.android.launcher3.DropTargetBar;
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
+import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.TouchController;
 
 import java.util.ArrayList;
 
@@ -108,6 +112,8 @@
 
     // Related to adjacent page hints
     private final Rect mScrollChildPosition = new Rect();
+    private final ViewGroupFocusHelper mFocusIndicatorHelper;
+
     private boolean mInScrollArea;
     private boolean mShowPageHints;
     private Drawable mLeftHoverDrawable;
@@ -117,6 +123,11 @@
 
     // Related to pinch-to-go-to-overview gesture.
     private PinchToOverviewListener mPinchListener = null;
+
+    // Handles all apps pull up interaction
+    private AllAppsTransitionController mAllAppsController;
+
+    private TouchController mActiveController;
     /**
      * Used to create a new DragLayer from XML.
      *
@@ -136,17 +147,24 @@
         mLeftHoverDrawableActive = res.getDrawable(R.drawable.page_hover_left_active);
         mRightHoverDrawableActive = res.getDrawable(R.drawable.page_hover_right_active);
         mIsRtl = Utilities.isRtl(res);
+        mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
     }
 
-    public void setup(Launcher launcher, DragController controller) {
+    public void setup(Launcher launcher, DragController dragController,
+            AllAppsTransitionController allAppsTransitionController) {
         mLauncher = launcher;
-        mDragController = controller;
+        mDragController = dragController;
+        mAllAppsController = allAppsTransitionController;
 
         boolean isAccessibilityEnabled = ((AccessibilityManager) mLauncher.getSystemService(
                 Context.ACCESSIBILITY_SERVICE)).isEnabled();
         onAccessibilityStateChanged(isAccessibilityEnabled);
     }
 
+    public ViewGroupFocusHelper getFocusIndicatorHelper() {
+        return mFocusIndicatorHelper;
+    }
+
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
@@ -173,31 +191,17 @@
 
     private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
         getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect);
-        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
-            return true;
-        }
-        return false;
+        return mHitRect.contains((int) ev.getX(), (int) ev.getY());
     }
 
     private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
         getDescendantRectRelativeToSelf(folder, mHitRect);
-        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
-            return true;
-        }
-        return false;
+        return mHitRect.contains((int) ev.getX(), (int) ev.getY());
     }
 
     private boolean isEventOverDropTargetBar(MotionEvent ev) {
-        getDescendantRectRelativeToSelf(mLauncher.getSearchDropTargetBar(), mHitRect);
-        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
-            return true;
-        }
-
-        getDescendantRectRelativeToSelf(mLauncher.getAppInfoDropTargetBar(), mHitRect);
-        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
-            return true;
-        }
-        return false;
+        getDescendantRectRelativeToSelf(mLauncher.getDropTargetBar(), mHitRect);
+        return mHitRect.contains((int) ev.getX(), (int) ev.getY());
     }
 
     private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
@@ -246,6 +250,7 @@
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         int action = ev.getAction();
 
+
         if (action == MotionEvent.ACTION_DOWN) {
             if (handleTouchDown(ev, true)) {
                 return true;
@@ -258,11 +263,21 @@
         }
         clearAllResizeFrames();
 
-        if (mPinchListener != null && mPinchListener.onInterceptTouchEvent(ev)) {
-            // Stop listening for scrolling etc. (onTouchEvent() handles the rest of the pinch.)
+        if (mDragController.onInterceptTouchEvent(ev)) {
+            mActiveController = mDragController;
             return true;
         }
-        return mDragController.onInterceptTouchEvent(ev);
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && mAllAppsController.onInterceptTouchEvent(ev)) {
+            mActiveController = mAllAppsController;
+            return true;
+        }
+
+        if (mPinchListener != null && mPinchListener.onInterceptTouchEvent(ev)) {
+            // Stop listening for scrolling etc. (onTouchEvent() handles the rest of the pinch.)
+            mActiveController = mPinchListener;
+            return true;
+        }
+        return false;
     }
 
     @Override
@@ -334,7 +349,7 @@
                 return super.onRequestSendAccessibilityEvent(child, event);
             }
 
-            if (isInAccessibleDrag() && child instanceof SearchDropTargetBar) {
+            if (isInAccessibleDrag() && child instanceof DropTargetBar) {
                 return super.onRequestSendAccessibilityEvent(child, event);
             }
             // Skip propagating onRequestSendAccessibilityEvent all for other children
@@ -352,8 +367,7 @@
             childrenForAccessibility.add(currentFolder);
 
             if (isInAccessibleDrag()) {
-                childrenForAccessibility.add(mLauncher.getSearchDropTargetBar());
-                childrenForAccessibility.add(mLauncher.getAppInfoDropTargetBar());
+                childrenForAccessibility.add(mLauncher.getDropTargetBar());
             }
         } else {
             super.addChildrenForAccessibility(childrenForAccessibility);
@@ -375,11 +389,6 @@
         int x = (int) ev.getX();
         int y = (int) ev.getY();
 
-        // This is only reached if a pinch was started from onInterceptTouchEvent();
-        // this continues sending events for it.
-        if (mPinchListener != null) {
-            mPinchListener.onTouchEvent(ev);
-        }
 
         if (action == MotionEvent.ACTION_DOWN) {
             if (handleTouchDown(ev, false)) {
@@ -406,7 +415,10 @@
             }
         }
         if (handled) return true;
-        return mDragController.onTouchEvent(ev);
+        if (mActiveController != null) {
+            return mActiveController.onTouchEvent(ev);
+        }
+        return false;
     }
 
     @Override
@@ -950,13 +962,19 @@
             canvas.save();
             if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) {
                 // Cut a hole in the darkening scrim on the page that should be highlighted, if any.
-                getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
+                float scale = getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
+                Rect backBounds = currCellLayout.getBackgroundBounds();
+                mHighlightRect.left += (int) (backBounds.left * scale);
+                mHighlightRect.top += (int) (backBounds.top * scale);
+                mHighlightRect.right = (int) (mHighlightRect.left + backBounds.width() * scale);
+                mHighlightRect.bottom = (int) (mHighlightRect.top + backBounds.height() * scale);
                 canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE);
             }
             canvas.drawColor((alpha << 24) | SCRIM_COLOR);
             canvas.restore();
         }
 
+        mFocusIndicatorHelper.draw(canvas);
         super.dispatchDraw(canvas);
     }
 
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 6df296e..93238de 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -98,7 +98,7 @@
     private static final String TAG = "Launcher.Folder";
 
     /**
-     * We avoid measuring {@link #mContentWrapper} with a 0 width or height, as this
+     * We avoid measuring {@link #mContent} with a 0 width or height, as this
      * results in CellLayout being measured as UNSPECIFIED, which it does not support.
      */
     private static final int MIN_CONTENT_DIMEN = 5;
@@ -147,7 +147,6 @@
     @Thunk FolderIcon mFolderIcon;
 
     @Thunk FolderPagedView mContent;
-    @Thunk View mContentWrapper;
     public ExtendedEditText mFolderName;
     private PageIndicatorDots mPageIndicator;
 
@@ -226,7 +225,6 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mContentWrapper = findViewById(R.id.folder_content_wrapper);
         mContent = (FolderPagedView) findViewById(R.id.folder_content);
         mContent.setFolder(this);
 
@@ -318,7 +316,7 @@
 
     @Override
     public void enableAccessibleDrag(boolean enable) {
-        mLauncher.getSearchDropTargetBar().enableAccessibleDrag(enable);
+        mLauncher.getDropTargetBar().enableAccessibleDrag(enable);
         for (int i = 0; i < mContent.getChildCount(); i++) {
             mContent.getPageAt(i).enableAccessibleDrag(enable, CellLayout.FOLDER_ACCESSIBILITY_DRAG);
         }
@@ -562,8 +560,8 @@
             reveal.setDuration(mMaterialExpandDuration);
             reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
 
-            mContentWrapper.setAlpha(0f);
-            Animator iconsAlpha = ObjectAnimator.ofFloat(mContentWrapper, "alpha", 0f, 1f);
+            mContent.setAlpha(0f);
+            Animator iconsAlpha = ObjectAnimator.ofFloat(mContent, "alpha", 0f, 1f);
             iconsAlpha.setDuration(mMaterialExpandDuration);
             iconsAlpha.setStartDelay(mMaterialExpandStagger);
             iconsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
@@ -581,12 +579,12 @@
 
             openFolderAnim = anim;
 
-            mContentWrapper.setLayerType(LAYER_TYPE_HARDWARE, null);
+            mContent.setLayerType(LAYER_TYPE_HARDWARE, null);
             mFooter.setLayerType(LAYER_TYPE_HARDWARE, null);
             onCompleteRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    mContentWrapper.setLayerType(LAYER_TYPE_NONE, null);
+                    mContent.setLayerType(LAYER_TYPE_NONE, null);
                     mFooter.setLayerType(LAYER_TYPE_NONE, null);
                 }
             };
@@ -1054,7 +1052,7 @@
         int top = Math.min(Math.max(sTempRect.top, centeredTop),
                 sTempRect.top + sTempRect.height() - height);
 
-        int distFromEdgeOfScreen = grid.getWorkspacePadding(isLayoutRtl()).left + getPaddingLeft();
+        int distFromEdgeOfScreen = grid.getWorkspacePadding().left + getPaddingLeft();
 
         if (grid.isPhone && (grid.availableWidthPx - width) < 4 * distFromEdgeOfScreen) {
             // Center the folder if it is very close to being centered anyway, by virtue of
@@ -1093,7 +1091,7 @@
 
     private int getContentAreaHeight() {
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        Rect workspacePadding = grid.getWorkspacePadding(mContent.mIsRtl);
+        Rect workspacePadding = grid.getWorkspacePadding();
         int maxContentAreaHeight = grid.availableHeightPx -
                 workspacePadding.top - workspacePadding.bottom -
                 mFooterHeight;
@@ -1122,7 +1120,7 @@
         int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(contentHeight, MeasureSpec.EXACTLY);
 
         mContent.setFixedSize(contentWidth, contentHeight);
-        mContentWrapper.measure(contentAreaWidthSpec, contentAreaHeightSpec);
+        mContent.measure(contentAreaWidthSpec, contentAreaHeightSpec);
 
         if (mContent.getChildCount() > 0) {
             int cellIconGap = (mContent.getPageAt(0).getCellWidth()
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index d8b83ad..c56e4e5 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.graphics.Canvas;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Gravity;
@@ -30,7 +31,6 @@
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.FocusHelper.PagedFolderKeyEventListener;
-import com.android.launcher3.FocusIndicatorView;
 import com.android.launcher3.IconCache;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.ItemInfo;
@@ -45,6 +45,7 @@
 import com.android.launcher3.Workspace.ItemOperator;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.pageindicators.PageIndicator;
+import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
@@ -73,6 +74,7 @@
 
     private final LayoutInflater mInflater;
     private final IconCache mIconCache;
+    private final ViewGroupFocusHelper mFocusIndicatorHelper;
 
     @Thunk final HashMap<View, Runnable> mPendingAnimations = new HashMap<>();
 
@@ -90,7 +92,6 @@
     private int mGridCountY;
 
     private Folder mFolder;
-    private FocusIndicatorView mFocusIndicatorView;
     private PagedFolderKeyEventListener mKeyListener;
 
     private PageIndicator mPageIndicator;
@@ -112,11 +113,11 @@
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
 
         setEdgeGlowColor(getResources().getColor(R.color.folder_edge_effect_color));
+        mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
     }
 
     public void setFolder(Folder folder) {
         mFolder = folder;
-        mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
         mKeyListener = new PagedFolderKeyEventListener(folder);
         mPageIndicator = (PageIndicator) folder.findViewById(R.id.folder_page_indicator);
     }
@@ -162,6 +163,12 @@
         }
     }
 
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        mFocusIndicatorHelper.draw(canvas);
+        super.dispatchDraw(canvas);
+    }
+
     /**
      * Binds items to the layout.
      * @return list of items that could not be bound, probably because we hit the max size limit.
@@ -226,7 +233,7 @@
         textView.applyFromShortcutInfo(item, mIconCache);
         textView.setOnClickListener(mFolder);
         textView.setOnLongClickListener(mFolder);
-        textView.setOnFocusChangeListener(mFocusIndicatorView);
+        textView.setOnFocusChangeListener(mFocusIndicatorHelper);
         textView.setOnKeyListener(mKeyListener);
 
         textView.setLayoutParams(new CellLayout.LayoutParams(
diff --git a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
new file mode 100644
index 0000000..7672f5a
--- /dev/null
+++ b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2016 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.keyboard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.RectEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Build.VERSION_CODES;
+import android.util.Property;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+import com.android.launcher3.R;
+
+/**
+ * A helper class to draw background of a focused view.
+ */
+@TargetApi(VERSION_CODES.LOLLIPOP)
+public abstract class FocusIndicatorHelper implements
+        OnFocusChangeListener, AnimatorUpdateListener {
+
+    private static final float MIN_VISIBLE_ALPHA = 0.2f;
+    private static final long ANIM_DURATION = 150;
+
+    public static final Property<FocusIndicatorHelper, Float> ALPHA =
+            new Property<FocusIndicatorHelper, Float>(Float.TYPE, "alpha") {
+                @Override
+                public void set(FocusIndicatorHelper object, Float value) {
+                    object.setAlpha(value);
+                }
+
+                @Override
+                public Float get(FocusIndicatorHelper object) {
+                    return object.mAlpha;
+                }
+            };
+
+    public static final Property<FocusIndicatorHelper, Float> SHIFT =
+            new Property<FocusIndicatorHelper, Float>(
+                    Float.TYPE, "shift") {
+
+                @Override
+                public void set(FocusIndicatorHelper object, Float value) {
+                    object.mShift = value;
+                }
+
+                @Override
+                public Float get(FocusIndicatorHelper object) {
+                    return object.mShift;
+                }
+            };
+
+    private static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
+    private static final Rect sTempRect1 = new Rect();
+    private static final Rect sTempRect2 = new Rect();
+
+    private final View mContainer;
+    private final Paint mPaint;
+    private final int mMaxAlpha;
+
+    private final Rect mDirtyRect = new Rect();
+    private boolean mIsDirty = false;
+
+    private View mLastFocusedView;
+
+    private View mCurrentView;
+    private View mTargetView;
+    /**
+     * The fraction indicating the position of the focusRect between {@link #mCurrentView}
+     * & {@link #mTargetView}
+     */
+    private float mShift;
+
+    private ObjectAnimator mCurrentAnimation;
+    private float mAlpha;
+
+    public FocusIndicatorHelper(View container) {
+        mContainer = container;
+
+        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        int color = container.getResources().getColor(R.color.focused_background);
+        mMaxAlpha = Color.alpha(color);
+        mPaint.setColor(0xFF000000 | color);
+
+        setAlpha(0);
+        mShift = 0;
+    }
+
+    protected void setAlpha(float alpha) {
+        mAlpha = alpha;
+        mPaint.setAlpha((int) (mAlpha * mMaxAlpha));
+    }
+
+    @Override
+    public void onAnimationUpdate(ValueAnimator animation) {
+        invalidateDirty();
+    }
+
+    protected void invalidateDirty() {
+        if (mIsDirty) {
+            mContainer.invalidate(mDirtyRect);
+            mIsDirty = false;
+        }
+
+        Rect newRect = getDrawRect();
+        if (newRect != null) {
+            mContainer.invalidate(newRect);
+        }
+    }
+
+    public void draw(Canvas c) {
+        if (mAlpha > 0) {
+            Rect newRect = getDrawRect();
+            if (newRect != null) {
+                mDirtyRect.set(newRect);
+                c.drawRect(mDirtyRect, mPaint);
+                mIsDirty = true;
+            }
+        }
+    }
+
+    private Rect getDrawRect() {
+        if (mCurrentView != null) {
+            viewToRect(mCurrentView, sTempRect1);
+
+            if (mShift > 0 && mTargetView != null) {
+                viewToRect(mTargetView, sTempRect2);
+                return RECT_EVALUATOR.evaluate(mShift, sTempRect1, sTempRect2);
+            } else {
+                return sTempRect1;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void onFocusChange(View v, boolean hasFocus) {
+        if (hasFocus) {
+            endCurrentAnimation();
+
+            if (mAlpha > MIN_VISIBLE_ALPHA) {
+                mTargetView = v;
+
+                mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
+                        PropertyValuesHolder.ofFloat(ALPHA, 1),
+                        PropertyValuesHolder.ofFloat(SHIFT, 1));
+                mCurrentAnimation.addListener(new ViewSetListener(v, true));
+            } else {
+                setCurrentView(v);
+
+                mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
+                        PropertyValuesHolder.ofFloat(ALPHA, 1));
+            }
+
+            mLastFocusedView = v;
+        } else {
+            if (mLastFocusedView == v) {
+                mLastFocusedView = null;
+                endCurrentAnimation();
+                mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
+                        PropertyValuesHolder.ofFloat(ALPHA, 0));
+                mCurrentAnimation.addListener(new ViewSetListener(null, false));
+            }
+        }
+
+        // invalidate once
+        invalidateDirty();
+
+        mLastFocusedView = hasFocus ? v : null;
+        if (mCurrentAnimation != null) {
+            mCurrentAnimation.addUpdateListener(this);
+            mCurrentAnimation.setDuration(ANIM_DURATION).start();
+        }
+    }
+
+    protected void endCurrentAnimation() {
+        if (mCurrentAnimation != null) {
+            mCurrentAnimation.cancel();
+            mCurrentAnimation = null;
+        }
+    }
+
+    protected void setCurrentView(View v) {
+        mCurrentView = v;
+        mShift = 0;
+        mTargetView = null;
+    }
+
+    /**
+     * Gets the position of {@param v} relative to {@link #mContainer}.
+     */
+    public abstract void viewToRect(View v, Rect outRect);
+
+    private class ViewSetListener extends AnimatorListenerAdapter {
+        private final View mViewToSet;
+        private final boolean mCallOnCancel;
+        private boolean mCalled = false;
+
+        public ViewSetListener(View v, boolean callOnCancel) {
+            mViewToSet = v;
+            mCallOnCancel = callOnCancel;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            if (!mCallOnCancel) {
+                mCalled = true;
+            }
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (!mCalled) {
+                setCurrentView(mViewToSet);
+                mCalled = true;
+            }
+        }
+    }
+}
diff --git a/src/com/android/launcher3/keyboard/FocusedItemDecorator.java b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
new file mode 100644
index 0000000..9c80b0f
--- /dev/null
+++ b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 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.keyboard;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ItemDecoration;
+import android.support.v7.widget.RecyclerView.State;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+/**
+ * {@link ItemDecoration} for drawing and animating focused view background.
+ */
+public class FocusedItemDecorator extends ItemDecoration {
+
+    private FocusIndicatorHelper mHelper;
+
+    public FocusedItemDecorator(View container) {
+        mHelper = new FocusIndicatorHelper(container) {
+
+            @Override
+            public void viewToRect(View v, Rect outRect) {
+                outRect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+            }
+        };
+    }
+
+    public OnFocusChangeListener getFocusListener() {
+        return mHelper;
+    }
+
+    @Override
+    public void onDraw(Canvas c, RecyclerView parent, State state) {
+        mHelper.draw(c);
+    }
+}
diff --git a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
new file mode 100644
index 0000000..bd5c06e
--- /dev/null
+++ b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 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.keyboard;
+
+import android.graphics.Rect;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+import com.android.launcher3.PagedView;
+
+/**
+ * {@link FocusIndicatorHelper} for a generic view group.
+ */
+public class ViewGroupFocusHelper extends FocusIndicatorHelper {
+
+    private final View mContainer;
+
+    public ViewGroupFocusHelper(View container) {
+        super(container);
+        mContainer = container;
+    }
+
+    @Override
+    public void viewToRect(View v, Rect outRect) {
+        outRect.left = 0;
+        outRect.top = 0;
+
+        computeLocationRelativeToContainer(v, outRect);
+
+        // If a view is scaled, its position will also shift accordingly. For optimization, only
+        // consider this for the last node.
+        outRect.left += (1 - v.getScaleX()) * v.getWidth() / 2;
+        outRect.top += (1 - v.getScaleY()) * v.getHeight() / 2;
+
+        outRect.right = outRect.left + (int) (v.getScaleX() * v.getWidth());
+        outRect.bottom = outRect.top + (int) (v.getScaleY() * v.getHeight());
+    }
+
+    private void computeLocationRelativeToContainer(View child, Rect outRect) {
+        View parent = (View) child.getParent();
+        outRect.left += child.getLeft();
+        outRect.top += child.getTop();
+
+        if (parent != mContainer) {
+            if (parent instanceof PagedView) {
+                PagedView page = (PagedView) parent;
+                outRect.left -= page.getScrollForPage(page.indexOfChild(child));
+            }
+
+            computeLocationRelativeToContainer(parent, outRect);
+        }
+    }
+
+    /**
+     * Sets the alpha of this FocusIndicatorHelper to 0 when a view with this listener
+     * receives focus.
+     */
+    public View.OnFocusChangeListener getHideIndicatorOnFocusListener() {
+        return new OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (hasFocus) {
+                    endCurrentAnimation();
+                    setCurrentView(null);
+                    setAlpha(0);
+                    invalidateDirty();
+                }
+            }
+        };
+    }
+}
diff --git a/src/com/android/launcher3/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java
index 68d9b8c..8629e92 100644
--- a/src/com/android/launcher3/logging/FileLog.java
+++ b/src/com/android/launcher3/logging/FileLog.java
@@ -40,6 +40,15 @@
     private static File sLogsDirectory = null;
 
     public static void setDir(File logsDir) {
+        if (ProviderConfig.IS_DOGFOOD_BUILD) {
+            synchronized (DATE_FORMAT) {
+                // If the target directory changes, stop any active thread.
+                if (sHandler != null && !logsDir.equals(sLogsDirectory)) {
+                    ((HandlerThread) sHandler.getLooper().getThread()).quit();
+                    sHandler = null;
+                }
+            }
+        }
         sLogsDirectory = logsDir;
     }
 
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index f900790..dd11bde 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -22,6 +22,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
 import com.android.launcher3.backup.nano.BackupProtos;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.PackageInstallerCompat;
@@ -221,7 +222,7 @@
                 // {@link #mCarryOver}, to prevent an infinite loop. If no item could be removed,
                 // break the loop and abort migration by throwing an exception.
                 OptimalPlacementSolution placement = new OptimalPlacementSolution(
-                        new GridOccupancy(mTrgX, mTrgY), deepCopy(mCarryOver), true);
+                        new GridOccupancy(mTrgX, mTrgY), deepCopy(mCarryOver), 0, true);
                 placement.find();
                 if (placement.finalPlacedItems.size() > 0) {
                     long newScreenId = LauncherSettings.Settings.call(
@@ -262,13 +263,16 @@
      * Migrate a particular screen id.
      * Strategy:
      *   1) For all possible combinations of row and column, pick the one which causes the least
-     *      data loss: {@link #tryRemove(int, int, ArrayList, float[])}
+     *      data loss: {@link #tryRemove(int, int, int, ArrayList, float[])}
      *   2) Maintain a list of all lost items before this screen, and add any new item lost from
      *      this screen to that list as well.
      *   3) If all those items from the above list can be placed on this screen, place them
      *      (otherwise they are placed on a new screen).
      */
     private void migrateScreen(long screenId) {
+        // If we are migrating the first screen, do not touch the first row.
+        int startY = screenId == Workspace.FIRST_SCREEN_ID ? 1 : 0;
+
         ArrayList<DbEntry> items = loadWorkspaceEntries(screenId);
 
         int removedCol = Integer.MAX_VALUE;
@@ -286,10 +290,10 @@
 
         // Try removing all possible combinations
         for (int x = 0; x < mSrcX; x++) {
-            for (int y = 0; y < mSrcY; y++) {
+            for (int y = startY; y < mSrcY; y++) {
                 // Use a deep copy when trying out a particular combination as it can change
                 // the underlying object.
-                ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, deepCopy(items), outLoss);
+                ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, startY, deepCopy(items), outLoss);
 
                 if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1] < moveWt))) {
                     removeWt = outLoss[0];
@@ -338,12 +342,13 @@
         if (!mCarryOver.isEmpty() && removeWt == 0) {
             // No new items were removed in this step. Try placing all the items on this screen.
             GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY);
+            occupied.markCells(0, 0, mTrgX, startY, true);
             for (DbEntry item : finalItems) {
                 occupied.markCells(item, true);
             }
 
             OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied,
-                    deepCopy(mCarryOver), true);
+                    deepCopy(mCarryOver), startY, true);
             placement.find();
             if (placement.lowestWeightLoss == 0) {
                 // All items got placed
@@ -375,9 +380,10 @@
      * @param outLoss array of size 2. The first entry is filled with weight loss, and the second
      * with the overall item movement.
      */
-    private ArrayList<DbEntry> tryRemove(int col, int row, ArrayList<DbEntry> items,
-            float[] outLoss) {
+    private ArrayList<DbEntry> tryRemove(int col, int row, int startY,
+            ArrayList<DbEntry> items, float[] outLoss) {
         GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY);
+        occupied.markCells(0, 0, mTrgX, startY, true);
 
         col = mShouldRemoveX ? col : Integer.MAX_VALUE;
         row = mShouldRemoveY ? row : Integer.MAX_VALUE;
@@ -399,7 +405,8 @@
             }
         }
 
-        OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied, removedItems);
+        OptimalPlacementSolution placement =
+                new OptimalPlacementSolution(occupied, removedItems, startY);
         placement.find();
         finalItems.addAll(placement.finalPlacedItems);
         outLoss[0] = placement.lowestWeightLoss;
@@ -415,19 +422,24 @@
         // linear placement.
         private final boolean ignoreMove;
 
+        // The first row in the grid from where the placement should start.
+        private final int startY;
+
         float lowestWeightLoss = Float.MAX_VALUE;
         float lowestMoveCost = Float.MAX_VALUE;
         ArrayList<DbEntry> finalPlacedItems;
 
-        public OptimalPlacementSolution(GridOccupancy occupied, ArrayList<DbEntry> itemsToPlace) {
-            this(occupied, itemsToPlace, false);
+        public OptimalPlacementSolution(
+                GridOccupancy occupied, ArrayList<DbEntry> itemsToPlace, int startY) {
+            this(occupied, itemsToPlace, startY, false);
         }
 
         public OptimalPlacementSolution(GridOccupancy occupied, ArrayList<DbEntry> itemsToPlace,
-                boolean ignoreMove) {
+                int startY, boolean ignoreMove) {
             this.occupied = occupied;
             this.itemsToPlace = itemsToPlace;
             this.ignoreMove = ignoreMove;
+            this.startY = startY;
 
             // Sort the items such that larger widgets appear first followed by 1x1 items
             Collections.sort(this.itemsToPlace);
@@ -477,7 +489,7 @@
                 int myW = me.spanX;
                 int myH = me.spanY;
 
-                for (int y = 0; y < mTrgY; y++) {
+                for (int y = startY; y < mTrgY; y++) {
                     for (int x = 0; x < mTrgX; x++) {
                         float newMoveCost = moveCost;
                         if (x != myX) {
@@ -547,7 +559,7 @@
                 int newDistance = Integer.MAX_VALUE;
                 int newX = Integer.MAX_VALUE, newY = Integer.MAX_VALUE;
 
-                for (int y = 0; y < mTrgY; y++) {
+                for (int y = startY; y < mTrgY; y++) {
                     for (int x = 0; x < mTrgX; x++) {
                         if (!occupied.cells[x][y]) {
                             int dist = ignoreMove ? 0 :
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 7d84a0c..99af93b 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -24,7 +24,6 @@
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
 import android.graphics.Canvas;
-import android.view.animation.Interpolator;
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
@@ -33,6 +32,7 @@
 import android.util.Property;
 import android.view.View;
 import android.view.ViewOutlineProvider;
+import android.view.animation.Interpolator;
 import android.view.animation.OvershootInterpolator;
 
 import com.android.launcher3.R;
@@ -224,8 +224,14 @@
 
     @Override
     public void setActiveMarker(int activePage) {
-        mActivePage = activePage;
-        invalidate();
+        if (mActivePage != activePage) {
+            mActivePage = activePage;
+
+            // Simulate a scroll change
+            int totalScroll = mNumPages - 1;
+            int currentScroll = mIsRtl ? (totalScroll - mActivePage) : mActivePage;
+            setScroll(currentScroll, totalScroll);
+        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLine.java b/src/com/android/launcher3/pageindicators/PageIndicatorLine.java
index a358e7b..aec708c 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLine.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorLine.java
@@ -14,7 +14,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Property;
-import android.view.View;
 import android.view.ViewConfiguration;
 
 import com.android.launcher3.Utilities;
@@ -28,16 +27,29 @@
 public class PageIndicatorLine extends PageIndicator {
     private static final String TAG = "PageIndicatorLine";
 
-    private static final int LINE_FADE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
+    private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
     private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
     public static final int WHITE_ALPHA = (int) (0.70f * 255);
     public static final int BLACK_ALPHA = (int) (0.65f * 255);
 
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private static final int LINE_ALPHA_ANIMATOR_INDEX = 0;
+    private static final int NUM_PAGES_ANIMATOR_INDEX = 1;
+    private static final int TOTAL_SCROLL_ANIMATOR_INDEX = 2;
 
-    private ValueAnimator mLineAlphaAnimator;
-    private int mAlpha = 0;
-    private float mProgress = 0f;
+    private ValueAnimator[] mAnimators = new ValueAnimator[3];
+
+    private final Handler mDelayedLineFadeHandler = new Handler(Looper.getMainLooper());
+
+    private boolean mShouldAutoHide = true;
+
+    // The alpha of the line when it is showing.
+    private int mActiveAlpha = 0;
+    // The alpha that the line is being animated to or already at (either 0 or mActiveAlpha).
+    private int mToAlpha;
+    // A float value representing the number of pages, to allow for an animation when it changes.
+    private float mNumPagesFloat;
+    private int mCurrentScroll;
+    private int mTotalScroll;
     private Paint mLinePaint;
 
     private static final Property<PageIndicatorLine, Integer> PAINT_ALPHA
@@ -54,6 +66,34 @@
         }
     };
 
+    private static final Property<PageIndicatorLine, Float> NUM_PAGES
+            = new Property<PageIndicatorLine, Float>(Float.class, "num_pages") {
+        @Override
+        public Float get(PageIndicatorLine obj) {
+            return obj.mNumPagesFloat;
+        }
+
+        @Override
+        public void set(PageIndicatorLine obj, Float numPages) {
+            obj.mNumPagesFloat = numPages;
+            obj.invalidate();
+        }
+    };
+
+    private static final Property<PageIndicatorLine, Integer> TOTAL_SCROLL
+            = new Property<PageIndicatorLine, Integer>(Integer.class, "total_scroll") {
+        @Override
+        public Integer get(PageIndicatorLine obj) {
+            return obj.mTotalScroll;
+        }
+
+        @Override
+        public void set(PageIndicatorLine obj, Integer totalScroll) {
+            obj.mTotalScroll = totalScroll;
+            obj.invalidate();
+        }
+    };
+
     private Runnable mHideLineRunnable = new Runnable() {
         @Override
         public void run() {
@@ -77,13 +117,15 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        if (mNumPages == 0) {
+        if (mTotalScroll == 0 || mNumPagesFloat == 0) {
             return;
         }
 
+        // Compute and draw line rect.
+        float progress = Utilities.boundToRange(((float) mCurrentScroll) / mTotalScroll, 0f, 1f);
         int availableWidth = canvas.getWidth();
-        int lineWidth = availableWidth / mNumPages;
-        int lineLeft = (int) (mProgress * (availableWidth - lineWidth));
+        int lineWidth = (int) (availableWidth / mNumPagesFloat);
+        int lineLeft = (int) (progress * (availableWidth - lineWidth));
         int lineRight = lineLeft + lineWidth;
         canvas.drawRect(lineLeft, 0, lineRight, canvas.getHeight(), mLinePaint);
     }
@@ -93,13 +135,25 @@
         if (getAlpha() == 0) {
             return;
         }
-        animateLineToAlpha(mAlpha);
-        mProgress = Utilities.boundToRange(((float) currentScroll) / totalScroll, 0f, 1f);;
-        invalidate();
+        animateLineToAlpha(mActiveAlpha);
 
-        // Hide after a brief period.
-        mHandler.removeCallbacksAndMessages(null);
-        mHandler.postDelayed(mHideLineRunnable, LINE_FADE_DELAY);
+        mCurrentScroll = currentScroll;
+        if (mTotalScroll == 0) {
+            mTotalScroll = totalScroll;
+        } else if (mTotalScroll != totalScroll) {
+            animateToTotalScroll(totalScroll);
+        } else {
+            invalidate();
+        }
+
+        if (mShouldAutoHide) {
+            hideAfterDelay();
+        }
+    }
+
+    private void hideAfterDelay() {
+        mDelayedLineFadeHandler.removeCallbacksAndMessages(null);
+        mDelayedLineFadeHandler.postDelayed(mHideLineRunnable, LINE_FADE_DELAY);
     }
 
     @Override
@@ -108,7 +162,18 @@
 
     @Override
     protected void onPageCountChanged() {
-        invalidate();
+        if (Float.compare(mNumPages, mNumPagesFloat) != 0) {
+            animateToNumPages(mNumPages);
+        }
+    }
+
+    public void setShouldAutoHide(boolean shouldAutoHide) {
+        mShouldAutoHide = shouldAutoHide;
+        if (shouldAutoHide && mLinePaint.getAlpha() > 0) {
+            hideAfterDelay();
+        } else if (!shouldAutoHide) {
+            mDelayedLineFadeHandler.removeCallbacksAndMessages(null);
+        }
     }
 
     /**
@@ -122,9 +187,9 @@
         if (color != Color.TRANSPARENT) {
             color = ColorUtils.setAlphaComponent(color, 255);
             if (color == Color.BLACK) {
-                mAlpha = BLACK_ALPHA;
+                mActiveAlpha = BLACK_ALPHA;
             } else if (color == Color.WHITE) {
-                mAlpha = WHITE_ALPHA;
+                mActiveAlpha = WHITE_ALPHA;
             } else {
                 Log.e(TAG, "Setting workspace page indicators to an unsupported color: #"
                         + Integer.toHexString(color));
@@ -135,22 +200,44 @@
     }
 
     private void animateLineToAlpha(int alpha) {
-        if (mLineAlphaAnimator != null) {
-            // An animation is already running, so ignore the new animation request unless we are
-            // trying to hide the line, in which case we always allow the animation.
-            if (alpha != 0) {
-                return;
-            }
-            mLineAlphaAnimator.cancel();
+        if (alpha == mToAlpha) {
+            // Ignore the new animation if it is going to the same alpha as the current animation.
+            return;
         }
-        mLineAlphaAnimator = ObjectAnimator.ofInt(this, PAINT_ALPHA, alpha);
-        mLineAlphaAnimator.addListener(new AnimatorListenerAdapter() {
+        mToAlpha = alpha;
+        setupAndRunAnimation(ObjectAnimator.ofInt(this, PAINT_ALPHA, alpha),
+                LINE_ALPHA_ANIMATOR_INDEX);
+    }
+
+    private void animateToNumPages(int numPages) {
+        setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numPages),
+                NUM_PAGES_ANIMATOR_INDEX);
+    }
+
+    private void animateToTotalScroll(int totalScroll) {
+        setupAndRunAnimation(ObjectAnimator.ofInt(this, TOTAL_SCROLL, totalScroll),
+                TOTAL_SCROLL_ANIMATOR_INDEX);
+    }
+
+    /**
+     * Starts the given animator and stores it in the provided index in {@link #mAnimators} until
+     * the animation ends.
+     *
+     * If an animator is already at the index (i.e. it is already playing), it is canceled and
+     * replaced with the new animator.
+     */
+    private void setupAndRunAnimation(ValueAnimator animator, final int animatorIndex) {
+        if (mAnimators[animatorIndex] != null) {
+            mAnimators[animatorIndex].cancel();
+        }
+        mAnimators[animatorIndex] = animator;
+        mAnimators[animatorIndex].addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                mLineAlphaAnimator = null;
+                mAnimators[animatorIndex] = null;
             }
         });
-        mLineAlphaAnimator.setDuration(LINE_FADE_DURATION);
-        mLineAlphaAnimator.start();
+        mAnimators[animatorIndex].setDuration(LINE_ANIMATE_DURATION);
+        mAnimators[animatorIndex].start();
     }
 }
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
new file mode 100644
index 0000000..9d8b6b3
--- /dev/null
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2016 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.provider;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherProvider.DatabaseHelper;
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.logging.FileLog;
+
+import java.io.InvalidObjectException;
+
+/**
+ * Utility class to update DB schema after it has been restored.
+ *
+ * This task is executed when Launcher starts for the first time and not immediately after restore.
+ * This helps keep the model consistent if the launcher updates between restore and first startup.
+ */
+public class RestoreDbTask {
+
+    private static final String TAG = "RestoreDbTask";
+    private static final String RESTORE_TASK_PENDING = "restore_task_pending";
+
+    private static final String INFO_COLUMN_NAME = "name";
+    private static final String INFO_COLUMN_DEFAULT_VALUE = "dflt_value";
+
+    public static boolean performRestore(DatabaseHelper helper) {
+        SQLiteDatabase db = helper.getWritableDatabase();
+        db.beginTransaction();
+        try {
+            new RestoreDbTask().sanitizeDB(helper, db);
+            db.setTransactionSuccessful();
+            return true;
+        } catch (Exception e) {
+            FileLog.e(TAG, "Failed to verify db", e);
+            return false;
+        } finally {
+            db.endTransaction();
+        }
+    }
+
+    /**
+     * Makes the following changes in the provider DB.
+     *   1. Removes all entries belonging to a managed profile as managed profiles
+     *      cannot be restored.
+     *   2. Marks all entries as restored. The flags are updated during first load or as
+     *      the restored apps get installed.
+     *   3. If the user serial for primary profile is different than that of the previous device,
+     *      update the entries to the new profile id.
+     */
+    private void sanitizeDB(DatabaseHelper helper, SQLiteDatabase db) throws Exception {
+        long oldProfileId = getDefaultProfileId(db);
+        // Delete all entries which do not belong to the main user
+        int itemsDeleted = db.delete(
+                Favorites.TABLE_NAME, "profileId != ?", new String[]{Long.toString(oldProfileId)});
+        if (itemsDeleted > 0) {
+            FileLog.d(TAG, itemsDeleted + " items belonging to a managed profile, were deleted");
+        }
+
+        // Mark all items as restored.
+        ContentValues values = new ContentValues();
+        values.put(Favorites.RESTORED, 1);
+        db.update(Favorites.TABLE_NAME, values, null, null);
+
+        // Mark widgets with appropriate restore flag
+        values.put(Favorites.RESTORED,
+                LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
+                        LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY |
+                        LauncherAppWidgetInfo.FLAG_UI_NOT_READY);
+        db.update(Favorites.TABLE_NAME, values, "itemType = ?",
+                new String[]{Integer.toString(Favorites.ITEM_TYPE_APPWIDGET)});
+
+        long myProfileId = helper.getDefaultUserSerial();
+        if (Utilities.longCompare(oldProfileId, myProfileId) != 0) {
+            FileLog.d(TAG, "Changing primary user id from " + oldProfileId + " to " + myProfileId);
+            migrateProfileId(db, myProfileId);
+        }
+    }
+
+    /**
+     * Updates profile id of all entries and changes the default value for the column.
+     */
+    protected void migrateProfileId(SQLiteDatabase db, long newProfileId) {
+        // Update existing entries.
+        ContentValues values = new ContentValues();
+        values.put(Favorites.PROFILE_ID, newProfileId);
+        db.update(Favorites.TABLE_NAME, values, null, null);
+
+        // Change default value of the column.
+        db.execSQL("ALTER TABLE favorites RENAME TO favorites_old;");
+        Favorites.addTableToDb(db, newProfileId, false);
+        db.execSQL("INSERT INTO favorites SELECT * FROM favorites_old;");
+        db.execSQL("DROP TABLE favorites_old;");
+    }
+
+    /**
+     * Returns the profile id used in the favorites table of the provided db.
+     */
+    protected long getDefaultProfileId(SQLiteDatabase db) throws Exception {
+        try (Cursor c = db.rawQuery("PRAGMA table_info (favorites)", null)){
+            int nameIndex = c.getColumnIndex(INFO_COLUMN_NAME);
+            while (c.moveToNext()) {
+                if (Favorites.PROFILE_ID.equals(c.getString(nameIndex))) {
+                    return c.getLong(c.getColumnIndex(INFO_COLUMN_DEFAULT_VALUE));
+                }
+            }
+            throw new InvalidObjectException("Table does not have a profile id column");
+        }
+    }
+
+    public static boolean isPending(Context context) {
+        return Utilities.getPrefs(context).getBoolean(RESTORE_TASK_PENDING, false);
+    }
+
+    public static void setPending(Context context, boolean isPending) {
+        Utilities.getPrefs(context).edit().putBoolean(RESTORE_TASK_PENDING, isPending).commit();
+    }
+}
diff --git a/src/com/android/launcher3/util/GridOccupancy.java b/src/com/android/launcher3/util/GridOccupancy.java
index 3f5f0b4..6a10b0a 100644
--- a/src/com/android/launcher3/util/GridOccupancy.java
+++ b/src/com/android/launcher3/util/GridOccupancy.java
@@ -77,7 +77,7 @@
     public void markCells(int cellX, int cellY, int spanX, int spanY, boolean value) {
         if (cellX < 0 || cellY < 0) return;
         for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
-            for (int y = cellY; y < cellY + spanY && y < mCountX; y++) {
+            for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
                 cells[x][y] = value;
             }
         }
diff --git a/src/com/android/launcher3/util/TouchController.java b/src/com/android/launcher3/util/TouchController.java
new file mode 100644
index 0000000..d1409c8
--- /dev/null
+++ b/src/com/android/launcher3/util/TouchController.java
@@ -0,0 +1,8 @@
+package com.android.launcher3.util;
+
+import android.view.MotionEvent;
+
+public interface TouchController {
+    boolean onTouchEvent(MotionEvent ev);
+    boolean onInterceptTouchEvent(MotionEvent ev);
+}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 9ec0340..3ad03ae 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -207,4 +207,9 @@
         }
         return "";
     }
+
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return WidgetCell.class.getName();
+    }
 }
diff --git a/src_config/com/android/launcher3/config/FeatureFlags.java b/src_config/com/android/launcher3/config/FeatureFlags.java
index 34c6663..2b9e6ce 100644
--- a/src_config/com/android/launcher3/config/FeatureFlags.java
+++ b/src_config/com/android/launcher3/config/FeatureFlags.java
@@ -29,4 +29,5 @@
     public static boolean LAUNCHER3_LEGACY_FOLDER_ICON = false;
     public static boolean LAUNCHER3_USE_SYSTEM_DRAG_DRIVER = false;
     public static boolean LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW = false;
+    public static boolean LAUNCHER3_ALL_APPS_PULL_UP = true;
 }
diff --git a/tests/src/com/android/launcher3/BindWidgetTest.java b/tests/src/com/android/launcher3/BindWidgetTest.java
index 34b1174..5c5069f 100644
--- a/tests/src/com/android/launcher3/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/BindWidgetTest.java
@@ -1,38 +1,30 @@
 package com.android.launcher3;
 
 import android.annotation.TargetApi;
-import android.app.SearchManager;
 import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
-import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiSelector;
-import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.PackageInstallerCompat;
+import com.android.launcher3.ui.LauncherInstrumentationTestCase;
 import com.android.launcher3.util.ManagedProfileHeuristic;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
 import com.android.launcher3.widget.WidgetHostViewLoader;
 
-import java.io.FileInputStream;
 import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Tests for bind widget flow.
@@ -41,12 +33,8 @@
  */
 @LargeTest
 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class BindWidgetTest extends InstrumentationTestCase {
+public class BindWidgetTest extends LauncherInstrumentationTestCase {
 
-    private static final long DEFAULT_TIMEOUT = 6000;
-
-    private UiDevice mDevice;
-    private Context mTargetContext;
     private ContentResolver mResolver;
     private AppWidgetManagerCompat mWidgetManager;
 
@@ -59,23 +47,9 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        mDevice = UiDevice.getInstance(getInstrumentation());
-        mTargetContext = getInstrumentation().getTargetContext();
         mResolver = mTargetContext.getContentResolver();
         mWidgetManager = AppWidgetManagerCompat.getInstance(mTargetContext);
-
-        // Check bind widget permission
-        String pkg = mTargetContext.getPackageName();
-        if (mTargetContext.getPackageManager().checkPermission(
-                pkg, android.Manifest.permission.BIND_APPWIDGET)
-                != PackageManager.PERMISSION_GRANTED) {
-            ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
-                    "appwidget grantbind --package " + pkg);
-            // Read the input stream fully.
-            FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
-            while (fis.read() != -1);
-            fis.close();
-        }
+        grantWidgetPermission();
 
         // Clear all existing data
         LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
@@ -231,10 +205,13 @@
      */
     private void setupAndVerifyContents(
             LauncherAppWidgetInfo item, Class<?> widgetClass, String desc) {
-        // Add new screen
-        long screenId = LauncherSettings.Settings.call(
-                mResolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
-                .getLong(LauncherSettings.Settings.EXTRA_VALUE);
+        long screenId = Workspace.FIRST_SCREEN_ID;
+        // Update the screen id counter for the provider.
+        LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID);
+
+        if (screenId > Workspace.FIRST_SCREEN_ID) {
+            screenId = Workspace.FIRST_SCREEN_ID;
+        }
         ContentValues v = new ContentValues();
         v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
         v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, 0);
@@ -264,61 +241,14 @@
             throw new IllegalArgumentException(t);
         }
         // Launch the home activity
-        getInstrumentation().getContext().startActivity(new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME)
-                .setPackage(mTargetContext.getPackageName())
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
-
+        startLauncher();
         // Verify UI
         UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
                 .className(widgetClass);
         if (desc != null) {
             selector = selector.description(desc);
         }
-        assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_TIMEOUT));
-    }
-
-    /**
-     * Finds a widget provider which can fit on the home screen.
-     * @param hasConfigureScreen if true, a provider with a config screen is returned.
-     */
-    private LauncherAppWidgetProviderInfo findWidgetProvider(final boolean hasConfigureScreen) {
-        LauncherAppWidgetProviderInfo info = getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
-            @Override
-            public LauncherAppWidgetProviderInfo call() throws Exception {
-                InvariantDeviceProfile idv =
-                        LauncherAppState.getInstance().getInvariantDeviceProfile();
-
-                ComponentName searchComponent = ((SearchManager) mTargetContext
-                        .getSystemService(Context.SEARCH_SERVICE)).getGlobalSearchActivity();
-                String searchPackage = searchComponent == null
-                        ? null : searchComponent.getPackageName();
-
-                for (AppWidgetProviderInfo info :
-                        AppWidgetManagerCompat.getInstance(mTargetContext).getAllProviders()) {
-                    if ((info.configure != null) ^ hasConfigureScreen) {
-                        continue;
-                    }
-                    // Exclude the widgets in search package, as Launcher already binds them in
-                    // QSB, so they can cause conflicts.
-                    if (info.provider.getPackageName().equals(searchPackage)) {
-                        continue;
-                    }
-                    LauncherAppWidgetProviderInfo widgetInfo = LauncherAppWidgetProviderInfo
-                            .fromProviderInfo(mTargetContext, info);
-                    if (widgetInfo.minSpanX >= idv.numColumns
-                            || widgetInfo.minSpanY >= idv.numRows) {
-                        continue;
-                    }
-                    return widgetInfo;
-                }
-                return null;
-            }
-        });
-        if (info == null) {
-            throw new IllegalArgumentException("No valid widget provider");
-        }
-        return info;
+        assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
     }
 
     /**
@@ -336,7 +266,7 @@
         item.minSpanY = info.minSpanY;
         item.user = mWidgetManager.getUser(info);
         item.cellX = 0;
-        item.cellY = 0;
+        item.cellY = 1;
         item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
 
         if (bindWidget) {
@@ -392,30 +322,12 @@
         item.minSpanX = 2;
         item.minSpanY = 2;
         item.cellX = 0;
-        item.cellY = 0;
+        item.cellY = 1;
         item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
         return item;
     }
 
     /**
-     * Runs the callback on the UI thread and returns the result.
-     */
-    private <T> T getOnUiThread(final Callable<T> callback) {
-        final AtomicReference<T> result = new AtomicReference<>(null);
-        try {
-            runTestOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        result.set(callback.call());
-                    } catch (Exception e) { }
-                }
-            });
-        } catch (Throwable t) { }
-        return result.get();
-    }
-
-    /**
      * Blocks the current thread until all the jobs in the main worker thread are complete.
      */
     private void waitUntilLoaderIdle() throws InterruptedException {
diff --git a/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java b/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java
index 476eb0a..35f686f 100644
--- a/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java
+++ b/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java
@@ -116,75 +116,4 @@
     // Add more tests for other devices, however, running them once on a single device is enough
     // for verifying that for a platform version, the WindowManager and DisplayMetrics is
     // working as intended.
-
-    /**
-     * Make sure that the height for the QSB is what we expect in normal mode.
-     */
-    public void testQsbNormalHeight() {
-        Resources resources = getContext().getResources();
-        DeviceProfile landscapeProfile = mInvariantProfile.landscapeProfile;
-        DeviceProfile portraitProfile = mInvariantProfile.portraitProfile;
-        landscapeProfile.setSearchBarHeight(LauncherCallbacks.SEARCH_BAR_HEIGHT_NORMAL);
-        portraitProfile.setSearchBarHeight(LauncherCallbacks.SEARCH_BAR_HEIGHT_NORMAL);
-        Rect portraitBounds = portraitProfile.getSearchBarBounds(true); // RTL shouldn't matter.
-        int portraitHeight = (int) Utilities.dpiFromPx(portraitBounds.height(),
-                resources.getDisplayMetrics());
-        Rect landscapeBounds = landscapeProfile.getSearchBarBounds(true); // RTL shouldn't matter.
-        int landscapeHeight = (int) Utilities.dpiFromPx(landscapeBounds.height(),
-                resources.getDisplayMetrics());
-        if (portraitProfile.isTablet) {
-            assertEquals(8 + 48 + 24, portraitHeight);
-        } else {
-            assertEquals(8 + 48 + 12, portraitHeight);
-        }
-        // Make sure the height that we pass in the widget options bundle is the height of the
-        // search bar + 8dps padding top and bottom.
-        Point portraitDimens = portraitProfile.getSearchBarDimensForWidgetOpts(resources);
-        int portraitWidgetOptsHeight = portraitDimens.y;
-        Point landscapeDimens = landscapeProfile.getSearchBarDimensForWidgetOpts(resources);
-        int landscapeWidgetOptsHeight = landscapeDimens.y;
-        assertEquals(8 + 48 + 8, (int) Utilities.dpiFromPx(portraitWidgetOptsHeight,
-                resources.getDisplayMetrics()));
-        if (!landscapeProfile.isVerticalBarLayout()) {
-            assertEquals(portraitHeight, landscapeHeight);
-            assertEquals(portraitWidgetOptsHeight, landscapeWidgetOptsHeight);
-        }
-    }
-
-    /**
-     * Make sure that the height for the QSB is what we expect in tall mode.
-     */
-    public void testQsbTallHeight() {
-        Resources resources = getContext().getResources();
-        DeviceProfile landscapeProfile = mInvariantProfile.landscapeProfile;
-        DeviceProfile portraitProfile = mInvariantProfile.portraitProfile;
-        landscapeProfile.setSearchBarHeight(LauncherCallbacks.SEARCH_BAR_HEIGHT_TALL);
-        portraitProfile.setSearchBarHeight(LauncherCallbacks.SEARCH_BAR_HEIGHT_TALL);
-        Rect portraitBounds = portraitProfile.getSearchBarBounds(true); // RTL shouldn't matter.
-        int portraitHeight = (int) Utilities.dpiFromPx(portraitBounds.height(),
-                resources.getDisplayMetrics());
-        Rect landscapeBounds = landscapeProfile.getSearchBarBounds(true); // RTL shouldn't matter.
-        int landscapeHeight = (int) Utilities.dpiFromPx(landscapeBounds.height(),
-                resources.getDisplayMetrics());
-        if (portraitProfile.isPhone) {
-            // This fails on some devices due to http://b/26884580 (portraitHeight is 101, not 100).
-            // TODO: Remove the comparision against 101 once b/26884580 is fixed
-            // assertEquals(4 + 94 + 2, portraitHeight);
-            assertTrue(portraitHeight == (4 + 94 + 2) || portraitHeight == (4 + 95 + 2));
-        } else {
-            assertEquals(8 + 94 + 24, portraitHeight);
-        }
-        // Make sure the height that we pass in the widget options bundle is the height of the
-        // search bar + 8dps padding top and bottom.
-        Point portraitDimens = portraitProfile.getSearchBarDimensForWidgetOpts(resources);
-        int portraitWidgetOptsHeight = portraitDimens.y;
-        Point landscapeDimens = landscapeProfile.getSearchBarDimensForWidgetOpts(resources);
-        int landscapeWidgetOptsHeight = landscapeDimens.y;
-        assertEquals(8 + 94 + 8, (int) Utilities.dpiFromPx(portraitWidgetOptsHeight,
-                resources.getDisplayMetrics()));
-        if (!landscapeProfile.isVerticalBarLayout()) {
-            assertEquals(portraitHeight, landscapeHeight);
-            assertEquals(portraitWidgetOptsHeight, landscapeWidgetOptsHeight);
-        }
-    }
 }
diff --git a/tests/src/com/android/launcher3/QuickAddWidgetTest.java b/tests/src/com/android/launcher3/QuickAddWidgetTest.java
deleted file mode 100644
index 0078294..0000000
--- a/tests/src/com/android/launcher3/QuickAddWidgetTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.android.launcher3;
-
-import android.content.Intent;
-import android.graphics.Point;
-import android.os.SystemClock;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-
-import java.util.List;
-
-/**
- * Add an arbitrary widget from the widget picker very quickly to test potential race conditions.
- */
-@LargeTest
-public class QuickAddWidgetTest extends InstrumentationTestCase {
-    // Disabled because it's flaky and not particularly useful. But this class could still be useful
-    // as an example if we want other UI tests in the future.
-    private static final boolean DISABLED = true;
-
-    private UiDevice mDevice;
-    private String mTargetPackage;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mDevice = UiDevice.getInstance(getInstrumentation());
-
-        // Set Launcher3 as home.
-        mTargetPackage = getInstrumentation().getTargetContext().getPackageName();
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME)
-                .setPackage(mTargetPackage)
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        getInstrumentation().getContext().startActivity(homeIntent);
-        mDevice.wait(Until.hasObject(By.pkg(mTargetPackage).depth(0)), 3000);
-    }
-
-    public void testAddWidgetQuickly() throws Exception {
-        if (DISABLED) return;
-        mDevice.pressMenu(); // Enter overview mode.
-        mDevice.wait(Until.findObject(By.text("Widgets")), 3000).click();
-        UiObject2 calendarWidget = getWidgetByName("Clock");
-        Point center = calendarWidget.getVisibleCenter();
-        // Touch widget just long enough to pick it up (longPressTimeout), then let go immediately.
-        getInstrumentation().sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
-                SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, center.x, center.y, 0));
-        Thread.sleep(ViewConfiguration.getLongPressTimeout() + 50);
-        getInstrumentation().sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
-                SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, center.x, center.y, 0));
-
-        assertTrue("Drag was never started", isOnHomescreen());
-    }
-
-    private UiObject2 getWidgetByName(String name) {
-        UiObject2 widgetsList = mDevice.wait(Until.findObject(By.res(mTargetPackage,
-                "widgets_list_view")), 3000);
-        do {
-            UiObject2 widget = getVisibleWidgetByName(name);
-            if (widget != null) {
-                return widget;
-            }
-        } while (widgetsList.scroll(Direction.DOWN, 1f));
-        return getVisibleWidgetByName(name);
-    }
-
-    private UiObject2 getVisibleWidgetByName(String name) {
-        List<UiObject2> visibleWidgets = mDevice.wait(Until.findObjects(By.clazz(
-                "android.widget.LinearLayout")), 3000);
-        for (UiObject2 widget : visibleWidgets) {
-            if (widget.hasObject(By.text(name))) {
-                return widget;
-            }
-        }
-        return null;
-    }
-
-    private boolean isOnHomescreen() {
-        return mDevice.wait(Until.hasObject(By.res(mTargetPackage, "hotseat")), 3000);
-    }
-}
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
index ccd8f73..ebf06ba 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
@@ -208,6 +208,57 @@
         }});
     }
 
+    public void testWorkspace_first_row_blocked() throws Exception {
+        // The first screen has one item on the 4th column which needs moving, as the first row
+        // will be kept empty.
+        long[][][] ids = createGrid(new int[][][]{{
+                { -1, -1, -1, -1},
+                {  3,  1,  7,  0},
+                {  8,  7,  7, -1},
+                {  5,  2,  7, -1},
+        }}, 0);
+
+        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages, new HashMap<String, Point>(),
+                new Point(4, 4), new Point(3, 4)).migrateWorkspace();
+
+        // Items in the second column of the first screen should get placed on a new screen.
+        verifyWorkspace(new long[][][] {{
+                {          -1,           -1,           -1},
+                {ids[0][1][0], ids[0][1][1], ids[0][1][2]},
+                {ids[0][2][0], ids[0][2][1], ids[0][2][2]},
+                {ids[0][3][0], ids[0][3][1], ids[0][3][2]},
+        }, {
+                {ids[0][1][3]},
+        }});
+    }
+
+    public void testWorkspace_items_moved_to_empty_first_row() throws Exception {
+        // Items will get moved to the next screen to keep the first screen empty.
+        long[][][] ids = createGrid(new int[][][]{{
+                { -1, -1, -1, -1},
+                {  0,  1,  0,  0},
+                {  8,  7,  7, -1},
+                {  5,  6,  7, -1},
+        }}, 0);
+
+        new GridSizeMigrationTask(getMockContext(), mIdp, mValidPackages, new HashMap<String, Point>(),
+                new Point(4, 4), new Point(3, 3)).migrateWorkspace();
+
+        // Items in the second column of the first screen should get placed on a new screen.
+        verifyWorkspace(new long[][][] {{
+                {          -1,           -1,           -1},
+                {ids[0][2][0], ids[0][2][1], ids[0][2][2]},
+                {ids[0][3][0], ids[0][3][1], ids[0][3][2]},
+        }, {
+                {ids[0][1][1], ids[0][1][0], ids[0][1][2]},
+                {ids[0][1][3]},
+        }});
+    }
+
+    private long[][][] createGrid(int[][][] typeArray) throws Exception {
+        return createGrid(typeArray, 1);
+    }
+
     /**
      * Initializes the DB with dummy elements to represent the provided grid structure.
      * @param typeArray A 3d array of item types. {@see #addItem(int, long, long, int, int)} for
@@ -215,14 +266,18 @@
      *                  two represent the workspace grid.
      * @return the same grid representation where each entry is the corresponding item id.
      */
-    private long[][][] createGrid(int[][][] typeArray) throws Exception {
+    private long[][][] createGrid(int[][][] typeArray, long startScreen) throws Exception {
+        LauncherSettings.Settings.call(getMockContentResolver(),
+                LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
         long[][][] ids = new long[typeArray.length][][];
 
         for (int i = 0; i < typeArray.length; i++) {
             // Add screen to DB
-            long screenId = LauncherSettings.Settings.call(getMockContentResolver(),
-                    LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
-                    .getLong(LauncherSettings.Settings.EXTRA_VALUE);
+            long screenId = startScreen + i;
+
+            // Keep the screen id counter up to date
+            LauncherSettings.Settings.call(getMockContentResolver(),
+                    LauncherSettings.Settings.METHOD_NEW_SCREEN_ID);
 
             ContentValues v = new ContentValues();
             v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
@@ -270,7 +325,8 @@
                     } else {
                         assertEquals(1, c.getCount());
                         c.moveToNext();
-                        assertEquals(id, c.getLong(0));
+                        assertEquals(String.format("Failed to verify item ad %d %d, %d", i, y, x),
+                                id, c.getLong(0));
                         total++;
                     }
                     c.close();
diff --git a/tests/src/com/android/launcher3/LauncherBackupAgentTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
similarity index 88%
rename from tests/src/com/android/launcher3/LauncherBackupAgentTest.java
rename to tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 020a557..29f738b 100644
--- a/tests/src/com/android/launcher3/LauncherBackupAgentTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -1,4 +1,4 @@
-package com.android.launcher3;
+package com.android.launcher3.provider;
 
 import android.content.ContentValues;
 import android.database.Cursor;
@@ -10,14 +10,14 @@
 import com.android.launcher3.LauncherSettings.Favorites;
 
 /**
- * Tests for {@link LauncherBackupAgent}
+ * Tests for {@link RestoreDbTask}
  */
 @MediumTest
-public class LauncherBackupAgentTest extends AndroidTestCase {
+public class RestoreDbTaskTest extends AndroidTestCase {
 
     public void testGetProfileId() throws Exception {
         SQLiteDatabase db = new MyDatabaseHelper(23).getWritableDatabase();
-        assertEquals(23, new LauncherBackupAgent().getDefaultProfileId(db));
+        assertEquals(23, new RestoreDbTask().getDefaultProfileId(db));
     }
 
     public void testMigrateProfileId() throws Exception {
@@ -32,7 +32,7 @@
         // Verify item add
         assertEquals(5, getCount(db, "select * from favorites where profileId = 42"));
 
-        new LauncherBackupAgent().migrateProfileId(db, 33);
+        new RestoreDbTask().migrateProfileId(db, 33);
 
         // verify data migrated
         assertEquals(0, getCount(db, "select * from favorites where profileId = 42"));
diff --git a/tests/src/com/android/launcher3/ui/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/AddWidgetTest.java
new file mode 100644
index 0000000..a0ca60c
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/AddWidgetTest.java
@@ -0,0 +1,64 @@
+package com.android.launcher3.ui;
+
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.Workspace.ItemOperator;
+import com.android.launcher3.util.Condition;
+import com.android.launcher3.util.Wait;
+import com.android.launcher3.widget.WidgetCell;
+
+/**
+ * Test to add widget from widget tray
+ */
+@LargeTest
+public class AddWidgetTest extends LauncherInstrumentationTestCase {
+
+    private LauncherAppWidgetProviderInfo widgetInfo;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        widgetInfo = findWidgetProvider(false /* hasConfigureScreen */);
+    }
+
+    public void testDragIcon_portrait() throws Throwable {
+        lockRotation(true);
+        performTest();
+    }
+
+    public void testDragIcon_landscape() throws Throwable {
+        lockRotation(false);
+        performTest();
+    }
+
+    private void performTest() throws Throwable {
+        clearHomescreen();
+        Launcher launcher = startLauncher();
+
+        // Open widget tray and wait for load complete.
+        final UiObject2 widgetContainer = openWidgetsTray();
+        assertTrue(Wait.atMost(Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT));
+
+        // Drag widget to homescreen
+        UiObject2 widget = scrollAndFind(widgetContainer, By.clazz(WidgetCell.class)
+                .hasDescendant(By.text(widgetInfo.getLabel(mTargetContext.getPackageManager()))));
+        dragToWorkspace(widget);
+
+        assertNotNull(launcher.getWorkspace().getFirstMatch(new ItemOperator() {
+            @Override
+            public boolean evaluate(ItemInfo info, View view) {
+                return info instanceof LauncherAppWidgetInfo &&
+                        ((LauncherAppWidgetInfo) info).providerName.equals(widgetInfo.provider);
+            }
+        }));
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java b/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
new file mode 100644
index 0000000..abe6b95
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
@@ -0,0 +1,52 @@
+package com.android.launcher3.ui;
+
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.launcher3.compat.LauncherActivityInfoCompat;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.Condition;
+import com.android.launcher3.util.Wait;
+
+/**
+ * Test for verifying apps is launched from all-apps
+ */
+@LargeTest
+public class AllAppsAppLaunchTest extends LauncherInstrumentationTestCase {
+
+    private LauncherActivityInfoCompat mSettingsApp;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
+                .getActivityList("com.android.settings", UserHandleCompat.myUserHandle()).get(0);
+    }
+
+    public void testAppLauncher_portrait() throws Exception {
+        lockRotation(true);
+        performTest();
+    }
+
+    public void testAppLauncher_landscape() throws Exception {
+        lockRotation(false);
+        performTest();
+    }
+
+    private void performTest() throws Exception {
+        startLauncher();
+
+        // Open all apps and wait for load complete
+        final UiObject2 appsContainer = openAllApps();
+        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
+
+        // Open settings app and verify app launched
+        scrollAndFind(appsContainer, By.text(mSettingsApp.getLabel().toString())).click();
+        assertTrue(mDevice.wait(Until.hasObject(By.pkg(
+                mSettingsApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
new file mode 100644
index 0000000..56fc90a
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
@@ -0,0 +1,57 @@
+package com.android.launcher3.ui;
+
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.launcher3.compat.LauncherActivityInfoCompat;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.Condition;
+import com.android.launcher3.util.Wait;
+
+/**
+ * Test for dragging an icon from all-apps to homescreen.
+ */
+@LargeTest
+public class AllAppsIconToHomeTest extends LauncherInstrumentationTestCase {
+
+    private LauncherActivityInfoCompat mSettingsApp;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
+                .getActivityList("com.android.settings", UserHandleCompat.myUserHandle()).get(0);
+    }
+
+    public void testDragIcon_portrait() throws Throwable {
+        lockRotation(true);
+        performTest();
+    }
+
+    public void testDragIcon_landscape() throws Throwable {
+        lockRotation(false);
+        performTest();
+    }
+
+    private void performTest() throws Throwable {
+        clearHomescreen();
+        startLauncher();
+
+        // Open all apps and wait for load complete.
+        final UiObject2 appsContainer = openAllApps();
+        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
+
+        // Drag icon to homescreen.
+        UiObject2 icon = scrollAndFind(appsContainer, By.text(mSettingsApp.getLabel().toString()));
+        dragToWorkspace(icon);
+
+        // Verify that the icon works on homescreen.
+        mDevice.findObject(By.text(mSettingsApp.getLabel().toString())).click();
+        assertTrue(mDevice.wait(Until.hasObject(By.pkg(
+                mSettingsApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java b/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
new file mode 100644
index 0000000..a59f0ff
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
@@ -0,0 +1,266 @@
+package com.android.launcher3.ui;
+
+import android.app.SearchManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Point;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.test.InstrumentationTestCase;
+import android.view.MotionEvent;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.LauncherClings;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.util.ManagedProfileHeuristic;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Locale;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Base class for all instrumentation tests providing various utility methods.
+ */
+public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
+
+    public static final long DEFAULT_UI_TIMEOUT = 3000;
+
+    protected UiDevice mDevice;
+    protected Context mTargetContext;
+    protected String mTargetPackage;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        mTargetContext = getInstrumentation().getTargetContext();
+        mTargetPackage = mTargetContext.getPackageName();
+    }
+
+    protected void lockRotation(boolean naturalOrientation) throws RemoteException {
+        Utilities.getPrefs(mTargetContext)
+                .edit()
+                .putBoolean(Utilities.ALLOW_ROTATION_PREFERENCE_KEY, !naturalOrientation)
+                .commit();
+
+        if (naturalOrientation) {
+            mDevice.setOrientationNatural();
+        } else {
+            mDevice.setOrientationRight();
+        }
+    }
+
+    /**
+     * Starts the launcher activity in the target package and returns the Launcher instance.
+     */
+    protected Launcher startLauncher() {
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .setPackage(mTargetPackage)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return (Launcher) getInstrumentation().startActivitySync(homeIntent);
+    }
+
+    /**
+     * Grants the launcher permission to bind widgets.
+     */
+    protected void grantWidgetPermission() throws IOException {
+        // Check bind widget permission
+        if (mTargetContext.getPackageManager().checkPermission(
+                mTargetPackage, android.Manifest.permission.BIND_APPWIDGET)
+                != PackageManager.PERMISSION_GRANTED) {
+            ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
+                    "appwidget grantbind --package " + mTargetPackage);
+            // Read the input stream fully.
+            FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+            while (fis.read() != -1);
+            fis.close();
+        }
+    }
+
+    /**
+     * Opens all apps and returns the recycler view
+     */
+    protected UiObject2 openAllApps() {
+        mDevice.wait(Until.findObject(
+                By.desc(mTargetContext.getString(R.string.all_apps_button_label))), DEFAULT_UI_TIMEOUT).click();
+        return findViewById(R.id.apps_list_view);
+    }
+
+    /**
+     * Opens widget tray and returns the recycler view.
+     */
+    protected UiObject2 openWidgetsTray() {
+        mDevice.pressMenu(); // Enter overview mode.
+        mDevice.wait(Until.findObject(
+                By.text(mTargetContext.getString(R.string.widget_button_text)
+                        .toUpperCase(Locale.getDefault()))), DEFAULT_UI_TIMEOUT).click();
+        return findViewById(R.id.widgets_list_view);
+    }
+
+    /**
+     * Scrolls the {@param container} until it finds an object matching {@param condition}.
+     * @return the matching object.
+     */
+    protected UiObject2 scrollAndFind(UiObject2 container, BySelector condition) {
+        do {
+            UiObject2 widget = container.findObject(condition);
+            if (widget != null) {
+                return widget;
+            }
+        } while (container.scroll(Direction.DOWN, 1f));
+        return container.findObject(condition);
+    }
+
+    /**
+     * Drags an icon to the center of homescreen.
+     */
+    protected void dragToWorkspace(UiObject2 icon) {
+        Point center = icon.getVisibleCenter();
+
+        // Action Down
+        sendPointer(MotionEvent.ACTION_DOWN, center);
+
+        // Wait until "Remove/Delete target is visible
+        assertNotNull(findViewById(R.id.delete_target_text));
+
+        Point moveLocation = findViewById(R.id.drag_layer).getVisibleCenter();
+
+        // Move to center
+        while(!moveLocation.equals(center)) {
+            center.x = getNextMoveValue(moveLocation.x, center.x);
+            center.y = getNextMoveValue(moveLocation.y, center.y);
+            sendPointer(MotionEvent.ACTION_MOVE, center);
+        }
+        sendPointer(MotionEvent.ACTION_UP, center);
+
+        // Wait until remove target is gone.
+        mDevice.wait(Until.gone(getSelectorForId(R.id.delete_target_text)), DEFAULT_UI_TIMEOUT);
+    }
+
+    private int getNextMoveValue(int targetValue, int oldValue) {
+        if (targetValue - oldValue > 10) {
+            return oldValue + 10;
+        } else if (targetValue - oldValue < -10) {
+            return oldValue - 10;
+        } else {
+            return targetValue;
+        }
+    }
+
+    private void sendPointer(int action, Point point) {
+        MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(),
+                SystemClock.uptimeMillis(), action, point.x, point.y, 0);
+        getInstrumentation().sendPointerSync(event);
+        event.recycle();
+    }
+
+    /**
+     * Removes all icons from homescreen and hotseat.
+     */
+    public void clearHomescreen() throws Throwable {
+        LauncherSettings.Settings.call(mTargetContext.getContentResolver(),
+                LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
+        LauncherSettings.Settings.call(mTargetContext.getContentResolver(),
+                LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
+        LauncherClings.markFirstRunClingDismissed(mTargetContext);
+        ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Reset the loader state
+                LauncherAppState.getInstance().getModel().resetLoadedState(true, true);
+            }
+        });
+    }
+
+    /**
+     * Runs the callback on the UI thread and returns the result.
+     */
+    protected <T> T getOnUiThread(final Callable<T> callback) {
+        final AtomicReference<T> result = new AtomicReference<>(null);
+        try {
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        result.set(callback.call());
+                    } catch (Exception e) { }
+                }
+            });
+        } catch (Throwable t) { }
+        return result.get();
+    }
+
+    /**
+     * Finds a widget provider which can fit on the home screen.
+     * @param hasConfigureScreen if true, a provider with a config screen is returned.
+     */
+    protected LauncherAppWidgetProviderInfo findWidgetProvider(final boolean hasConfigureScreen) {
+        LauncherAppWidgetProviderInfo info = getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
+            @Override
+            public LauncherAppWidgetProviderInfo call() throws Exception {
+                InvariantDeviceProfile idv =
+                        LauncherAppState.getInstance().getInvariantDeviceProfile();
+
+                ComponentName searchComponent = ((SearchManager) mTargetContext
+                        .getSystemService(Context.SEARCH_SERVICE)).getGlobalSearchActivity();
+                String searchPackage = searchComponent == null
+                        ? null : searchComponent.getPackageName();
+
+                for (AppWidgetProviderInfo info :
+                        AppWidgetManagerCompat.getInstance(mTargetContext).getAllProviders()) {
+                    if ((info.configure != null) ^ hasConfigureScreen) {
+                        continue;
+                    }
+                    // Exclude the widgets in search package, as Launcher already binds them in
+                    // QSB, so they can cause conflicts.
+                    if (info.provider.getPackageName().equals(searchPackage)) {
+                        continue;
+                    }
+                    LauncherAppWidgetProviderInfo widgetInfo = LauncherAppWidgetProviderInfo
+                            .fromProviderInfo(mTargetContext, info);
+                    if (widgetInfo.minSpanX >= idv.numColumns
+                            || widgetInfo.minSpanY >= idv.numRows) {
+                        continue;
+                    }
+                    return widgetInfo;
+                }
+                return null;
+            }
+        });
+        if (info == null) {
+            throw new IllegalArgumentException("No valid widget provider");
+        }
+        return info;
+    }
+
+    protected UiObject2 findViewById(int id) {
+        return mDevice.wait(Until.findObject(getSelectorForId(id)), DEFAULT_UI_TIMEOUT);
+    }
+
+    protected BySelector getSelectorForId(int id) {
+        String name = mTargetContext.getResources().getResourceEntryName(id);
+        return By.res(mTargetPackage, name);
+    }
+}
diff --git a/tests/src/com/android/launcher3/RotationPreferenceTest.java b/tests/src/com/android/launcher3/ui/RotationPreferenceTest.java
similarity index 74%
rename from tests/src/com/android/launcher3/RotationPreferenceTest.java
rename to tests/src/com/android/launcher3/ui/RotationPreferenceTest.java
index 7259d35..e84ad04 100644
--- a/tests/src/com/android/launcher3/RotationPreferenceTest.java
+++ b/tests/src/com/android/launcher3/ui/RotationPreferenceTest.java
@@ -1,24 +1,20 @@
-package com.android.launcher3;
+package com.android.launcher3.ui;
 
-import android.content.Context;
-import android.content.Intent;
 import android.content.SharedPreferences;
 import android.graphics.Rect;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiSelector;
-import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
 /**
  * Test for auto rotate preference.
  */
 @MediumTest
-public class RotationPreferenceTest extends InstrumentationTestCase {
-
-    private UiDevice mDevice;
-    private Context mTargetContext;
-    private String mTargetPackage;
+public class RotationPreferenceTest extends LauncherInstrumentationTestCase {
 
     private SharedPreferences mPrefs;
     private boolean mOriginalRotationValue;
@@ -48,7 +44,7 @@
 
         setRotationEnabled(false);
         mDevice.setOrientationRight();
-        goToLauncher();
+        startLauncher();
 
         Rect hotseat = getHotseatBounds();
         assertTrue(hotseat.width() > hotseat.height());
@@ -62,21 +58,12 @@
 
         setRotationEnabled(true);
         mDevice.setOrientationRight();
-        goToLauncher();
+        startLauncher();
 
         Rect hotseat = getHotseatBounds();
         assertTrue(hotseat.width() < hotseat.height());
     }
 
-    private void goToLauncher() {
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME)
-                .setPackage(mTargetPackage)
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        getInstrumentation().getContext().startActivity(homeIntent);
-        mDevice.findObject(new UiSelector().packageName(mTargetPackage)).waitForExists(6000);
-    }
-
     private void setRotationEnabled(boolean enabled) {
         mPrefs.edit().putBoolean(Utilities.ALLOW_ROTATION_PREFERENCE_KEY, enabled).commit();
     }
diff --git a/tests/src/com/android/launcher3/util/Condition.java b/tests/src/com/android/launcher3/util/Condition.java
new file mode 100644
index 0000000..e9ee67c
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/Condition.java
@@ -0,0 +1,54 @@
+package com.android.launcher3.util;
+
+import android.support.test.uiautomator.UiObject2;
+
+import com.android.launcher3.MainThreadExecutor;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public abstract class Condition {
+
+    public abstract boolean isTrue() throws Throwable;
+
+    /**
+     * Converts the condition to be run on UI thread.
+     */
+    public static Condition runOnUiThread(final Condition condition) {
+        final MainThreadExecutor executor = new MainThreadExecutor();
+        return new Condition() {
+            @Override
+            public boolean isTrue() throws Throwable {
+                final AtomicBoolean value = new AtomicBoolean(false);
+                final Throwable[] exceptions = new Throwable[1];
+                final CountDownLatch latch = new CountDownLatch(1);
+                executor.execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            value.set(condition.isTrue());
+                        } catch (Throwable e) {
+                            exceptions[0] = e;
+                        }
+
+                    }
+                });
+                latch.await(1, TimeUnit.SECONDS);
+                if (exceptions[0] != null) {
+                    throw exceptions[0];
+                }
+                return value.get();
+            }
+        };
+    }
+
+    public static Condition minChildCount(final UiObject2 obj, final int childCount) {
+        return new Condition() {
+            @Override
+            public boolean isTrue() {
+                return obj.getChildCount() >= childCount;
+            }
+        };
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/TestLauncherProvider.java b/tests/src/com/android/launcher3/util/TestLauncherProvider.java
index bd3e86c..6ca2121 100644
--- a/tests/src/com/android/launcher3/util/TestLauncherProvider.java
+++ b/tests/src/com/android/launcher3/util/TestLauncherProvider.java
@@ -37,7 +37,7 @@
         }
 
         @Override
-        protected long getDefaultUserSerial() {
+        public long getDefaultUserSerial() {
             return 0;
         }
 
diff --git a/tests/src/com/android/launcher3/util/Wait.java b/tests/src/com/android/launcher3/util/Wait.java
new file mode 100644
index 0000000..02a1913
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/Wait.java
@@ -0,0 +1,30 @@
+package com.android.launcher3.util;
+
+import android.os.SystemClock;
+
+/**
+ * A utility class for waiting for a condition to be true.
+ */
+public class Wait {
+
+    private static final long DEFAULT_SLEEP_MS = 200;
+
+    public static boolean atMost(Condition condition, long timeout) {
+        return atMost(condition, timeout, DEFAULT_SLEEP_MS);
+    }
+
+    public static boolean atMost(Condition condition, long timeout, long sleepMillis) {
+        long endTime = SystemClock.uptimeMillis() + timeout;
+        while (SystemClock.uptimeMillis() < endTime) {
+            try {
+                if (condition.isTrue()) {
+                    return true;
+                }
+            } catch (Throwable t) {
+                // Ignore
+            }
+            SystemClock.sleep(sleepMillis);
+        }
+        return false;
+    }
+}