Merge "Adding TransformingTouchDelegate to allow transforming touch events before sending to the delegate." into ub-launcher3-calgary
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index eae02ca..3730555 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -61,6 +61,7 @@
   SHORTCUT = 2;
   WIDGET = 3;
   FOLDER_ICON = 4;
+  DEEPSHORTCUT = 5;
 }
 
 // Used to define what type of container a Target would represent.
@@ -74,6 +75,7 @@
   OVERVIEW = 6;
   PREDICTION = 7;
   SEARCHRESULT = 8;
+  DEEPSHORTCUTS = 9;
 }
 
 // Used to define what type of control a Target would represent.
@@ -106,8 +108,16 @@
     FLING = 4;
     PINCH = 5;
   }
+ enum Direction {
+    NONE = 0;
+    UP = 1;
+    DOWN = 2;
+    LEFT = 3;
+    RIGHT = 4;
+  }
   optional Type type = 1;
   optional Touch touch = 2;
+  optional Direction dir = 3;
 }
 
 //
@@ -126,4 +136,4 @@
   optional int64 action_duration_millis = 4;
   optional int64 elapsed_container_millis = 5;
   optional int64 elapsed_session_millis = 6;
-}
\ No newline at end of file
+}
diff --git a/res/anim/discovery_bounce.xml b/res/anim/discovery_bounce.xml
new file mode 100644
index 0000000..1f7d466
--- /dev/null
+++ b/res/anim/discovery_bounce.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:ordering="sequentially"
+        android:startOffset="200">
+
+    <objectAnimator
+        android:propertyName="progress"
+        android:duration="250"
+        android:interpolator="@interpolator/disco_bounce_section1"
+        android:valueFrom="1f"
+        android:valueTo=".94f"
+        android:valueType="floatType"/>
+    <objectAnimator
+        android:propertyName="progress"
+        android:duration="216"
+        android:interpolator="@interpolator/disco_bounce_section2"
+        android:valueFrom=".94f"
+        android:valueTo="1.012f"
+        android:valueType="floatType"/>
+    <objectAnimator
+        android:propertyName="progress"
+        android:duration="234"
+        android:interpolator="@interpolator/disco_bounce_section3"
+        android:valueFrom="1.012f"
+        android:valueTo="1f"
+        android:valueType="floatType"/>
+</set>
diff --git a/res/drawable/bg_white_pill.xml b/res/drawable/bg_white_pill.xml
index 29c3145..f92f739 100644
--- a/res/drawable/bg_white_pill.xml
+++ b/res/drawable/bg_white_pill.xml
@@ -16,7 +16,6 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
-    <solid android:color="@color/quantum_panel_bg_color" />
-    <size android:height="48dp" />
-    <corners android:radius="24dp" />
+    <solid android:color="#FFFFFF" />
+    <corners android:radius="@dimen/bg_pill_radius" />
 </shape>
\ No newline at end of file
diff --git a/res/values-sw768dp-port/dimens.xml b/res/drawable/deep_shortcuts_drag_handle.xml
similarity index 67%
rename from res/values-sw768dp-port/dimens.xml
rename to res/drawable/deep_shortcuts_drag_handle.xml
index 6fb2bf6..d5fca2e 100644
--- a/res/values-sw768dp-port/dimens.xml
+++ b/res/drawable/deep_shortcuts_drag_handle.xml
@@ -14,7 +14,13 @@
      limitations under the License.
 -->
 
-<resources>
-<!-- Container -->
-    <dimen name="container_max_width">736dp</dimen>
-</resources>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+
+    <path
+        android:pathData="M20 9H4v2h16V9zM4 15h16v-2H4v2z"
+        android:fillColor="#757575"/>
+</vector>
\ No newline at end of file
diff --git a/res/interpolator/disco_bounce_section1.xml b/res/interpolator/disco_bounce_section1.xml
new file mode 100644
index 0000000..2156216
--- /dev/null
+++ b/res/interpolator/disco_bounce_section1.xml
@@ -0,0 +1,22 @@
+<?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
+  -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:controlX1="0.9"
+                  android:controlY1="0"
+                  android:controlX2="0.5"
+                  android:controlY2="1"/>
diff --git a/res/interpolator/disco_bounce_section2.xml b/res/interpolator/disco_bounce_section2.xml
new file mode 100644
index 0000000..86cc789
--- /dev/null
+++ b/res/interpolator/disco_bounce_section2.xml
@@ -0,0 +1,22 @@
+<?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
+  -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:controlX1="0.9"
+                  android:controlY1="0"
+                  android:controlX2="0.6"
+                  android:controlY2="1"/>
diff --git a/res/interpolator/disco_bounce_section3.xml b/res/interpolator/disco_bounce_section3.xml
new file mode 100644
index 0000000..1acef03
--- /dev/null
+++ b/res/interpolator/disco_bounce_section3.xml
@@ -0,0 +1,22 @@
+<?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
+  -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:controlX1="0.1"
+                  android:controlY1="0"
+                  android:controlX2="0.7"
+                  android:controlY2="1"/>
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 632aff0..5c1fec7 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -44,7 +44,8 @@
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:layout_gravity="right" />
+            android:layout_gravity="right"
+            launcher:layout_ignoreInsets="true" />
 
         <include
             android:id="@+id/drop_target_bar"
@@ -56,7 +57,7 @@
 
         <com.android.launcher3.pageindicators.PageIndicatorCaretLandscape
             android:id="@+id/page_indicator"
-            android:layout_width="48dp"
+            android:layout_width="@dimen/dynamic_grid_page_indicator_height"
             android:layout_height="@dimen/dynamic_grid_page_indicator_height"
             android:layout_gravity="bottom|left"/>
 
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 0321631..b394fa8 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -45,7 +45,8 @@
         <include layout="@layout/hotseat"
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" />
+            android:layout_height="match_parent"
+            launcher:layout_ignoreInsets="true" />
 
         <include layout="@layout/overview_panel"
             android:id="@+id/overview_panel"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 86544d3..b59c715 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -44,7 +44,8 @@
         <include layout="@layout/hotseat"
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" />
+            android:layout_height="match_parent"
+            launcher:layout_ignoreInsets="true" />
 
         <include
             android:id="@+id/drop_target_bar"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index ad1fa82..5c2c4b8 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -22,8 +22,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
-    android:paddingBottom="@dimen/container_bounds_inset"
-    android:paddingTop="@dimen/container_bounds_inset"
     launcher:revealBackground="@drawable/quantum_panel_shape">
 
     <View
@@ -62,24 +60,10 @@
             android:layout_width="match_parent"
             android:layout_height="@dimen/all_apps_search_bar_height"
             android:layout_gravity="center|top"
-            android:paddingLeft="@dimen/container_fastscroll_thumb_max_width"
-            android:paddingRight="@dimen/container_fastscroll_thumb_max_width"
+            android:paddingTop="@dimen/all_apps_search_bar_margin_top"
             android:gravity="center|bottom"
             android:orientation="horizontal"
-            android:saveEnabled="false"
-            android:paddingTop="@dimen/all_apps_search_bar_margin_top" >
-
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:gravity="center_vertical"
-                android:id="@+id/search_hint"
-                android:layout_gravity="center_horizontal"
-                android:drawablePadding="@dimen/all_apps_search_bar_icon_margin_right"
-                android:drawableStart="@drawable/ic_allapps_search"
-                android:text="@string/all_apps_search_bar_hint"
-                android:textColor="@drawable/all_apps_search_hint"
-                android:textSize="16sp" />
+            android:saveEnabled="false">
 
             <com.android.launcher3.ExtendedEditText
                 android:id="@+id/search_box_input"
@@ -87,13 +71,14 @@
                 android:layout_height="match_parent"
                 android:background="@android:color/transparent"
                 android:focusableInTouchMode="true"
-                android:gravity="start|center_vertical"
+                android:gravity="center"
                 android:imeOptions="actionSearch|flagNoExtractUi"
                 android:inputType="text|textNoSuggestions|textCapWords"
                 android:maxLines="1"
                 android:scrollHorizontally="true"
                 android:singleLine="true"
                 android:textColor="#4c4c4c"
+                android:hint="@string/all_apps_search_bar_hint"
                 android:textColorHint="@drawable/all_apps_search_hint"
                 android:textSize="16sp" />
         </FrameLayout>
diff --git a/res/layout/all_apps_icon.xml b/res/layout/all_apps_icon.xml
index 3836fed..3d4bef7 100644
--- a/res/layout/all_apps_icon.xml
+++ b/res/layout/all_apps_icon.xml
@@ -21,8 +21,7 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="center"
-    android:paddingTop="@dimen/all_apps_icon_top_bottom_padding"
-    android:paddingBottom="@dimen/all_apps_icon_top_bottom_padding"
     android:focusable="true"
-    launcher:iconDisplay="all_apps" />
+    launcher:iconDisplay="all_apps"
+    launcher:centerVertically="true" />
 
diff --git a/res/layout/all_apps_search_market.xml b/res/layout/all_apps_search_market.xml
index 0199212..3f19b25 100644
--- a/res/layout/all_apps_search_market.xml
+++ b/res/layout/all_apps_search_market.xml
@@ -18,7 +18,7 @@
     android:id="@+id/search_market_text"
     android:layout_width="match_parent"
     android:layout_height="48dp"
-    android:gravity="start|center_vertical"
+    android:gravity="center"
     android:paddingLeft="@dimen/container_fastscroll_thumb_max_width"
     android:paddingRight="@dimen/container_fastscroll_thumb_max_width"
     android:fontFamily="sans-serif-medium"
diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml
index b879235..4fcbbd2 100644
--- a/res/layout/deep_shortcut.xml
+++ b/res/layout/deep_shortcut.xml
@@ -16,5 +16,13 @@
 
 <com.android.launcher3.shortcuts.DeepShortcutView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/Icon.DeepShortcut"
-    android:focusable="true"/>
+    android:layout_width="@dimen/bg_pill_width"
+    android:layout_height="@dimen/bg_pill_height"
+    android:elevation="@dimen/deep_shortcuts_elevation"
+    android:background="@drawable/bg_white_pill">
+
+    <com.android.launcher3.shortcuts.DeepShortcutTextView
+        android:id="@+id/deep_shortcut"
+        style="@style/Icon.DeepShortcut"
+        android:focusable="true"/>
+</com.android.launcher3.shortcuts.DeepShortcutView>
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
index 74f7ca1..c4431be 100644
--- a/res/layout/widgets_view.xml
+++ b/res/layout/widgets_view.xml
@@ -22,8 +22,6 @@
     android:id="@+id/widgets_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingTop="@dimen/container_bounds_inset"
-    android:paddingBottom="@dimen/container_bounds_inset"
     android:descendantFocusability="afterDescendants"
     launcher:revealBackground="@drawable/quantum_panel_shape_dark"
     android:theme="@style/WidgetContainerTheme">
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 4ffb771..0a9aa4f 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Stel op"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dit is \'n stelselprogram en kan nie gedeïnstalleer word nie."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Naamlose vouer"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Het <xliff:g id="APP_NAME">%1$s</xliff:g> gedeaktiveer"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Bladsy %1$d van %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Tuisskerm %1$d van %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nuwe tuisskermbladsy"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 3397aca..fbf16b4 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"ማዋቀሪያ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ይህ የስርዓት መተግበሪያ ነው እና ማራገፍ አይቻልም።"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"ስም-አልባ አቃፊ"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ተሰናክሏል"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"ገጽ %1$d ከ%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"መነሻ ማያ ገጽ %1$d ከ%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"አዲስ የመነሻ ማያ ገጽ"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index e7cd610..0b81d7d 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"الإعداد"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"هذا تطبيق نظام وتتعذر إزالته."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"مجلد بدون اسم"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"تم تعطيل <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"‏الصفحة %1$d من %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"‏الشاشة الرئيسية %1$d من %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"صفحة الشاشة الرئيسية الجديدة"</string>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
index 556ee6e..4c10722 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az-rAZ/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Quraşdırma"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu sistem tətbiqi olduğu üçün sistemdən silinə bilməz."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Adsız Qovluq"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> deaktiv edildi"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Səhifə %1$d of %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Əsas Səhifə ekranı %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Yeni əsas ekran səhifəsi"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 5a91a70..795ad8d 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Настройване"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Това е системно приложение и не може да се деинсталира."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Папка без име"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Деактивирахте <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Страница %1$d от %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Начален екран %1$d от %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Нова страница на началния екран"</string>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index d00af24..c3179bc 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"সেটআপ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"এটি একটি সিস্টেম অ্যাপ্লিকেশান এবং আনইনস্টল করা যাবে না৷"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"নামবিহীন ফোল্ডার"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> অক্ষম করা হয়েছে"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$dটির মধ্যে %1$dটি পৃষ্ঠা"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dটির %1$d নম্বর হোম স্ক্রীন"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"নতুন হোম স্ক্রীনের পৃষ্ঠা"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 0f09c91..31402b4 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuració"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Aquesta aplicació és una aplicació del sistema i no es pot desinstal·lar."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sense nom"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"S\'ha desactivat <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Pàgina %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla d\'inici %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Pàgina de la pantalla d\'inici nova"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 91e4aa0..2c492cf 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Nastavení"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Toto je systémová aplikace a nelze ji odinstalovat."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Složka bez názvu"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> je zakázána"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Strana %1$d z %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Plocha %1$d z %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nová stránka plochy"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 6829c88..133ec75 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfigurer"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dette er en systemapp, som ikke kan afinstalleres."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unavngiven mappe"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> er deaktiveret"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Side %1$d ud af %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startskærm %1$d ud af %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ny startskærm"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 20f5484..6a461f9 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Einrichten"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dies ist eine Systemanwendung, die nicht deinstalliert werden kann."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unbenannter Ordner"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> deaktiviert"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Seite %1$d von %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startbildschirm %1$d von %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Neue Startbildschirmseite"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 90633eb..1399279 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Ρύθμιση"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Αυτή είναι μια εφαρμογή συστήματος και δεν είναι δυνατή η κατάργηση της εγκατάστασής της."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Φάκελος χωρίς όνομα"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> είναι απενεργοποιημένη"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Σελίδα %1$d από %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Αρχική οθόνη %1$d από %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Νέα σελίδα αρχικής οθόνης"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 4507b7d..c70e0de 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Setup"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Disabled <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d of %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Home screen %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"New home screen page"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 4507b7d..c70e0de 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Setup"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Disabled <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d of %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Home screen %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"New home screen page"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 4507b7d..c70e0de 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Setup"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Disabled <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d of %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Home screen %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"New home screen page"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index aac9375..c6d12aa 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuración"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta es una aplicación del sistema y no se puede desinstalar."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sin nombre"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Se inhabilitó <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla principal %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nueva página en la pantalla principal"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 367c9b0..a200e92 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuración"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta aplicación es del sistema y no se puede desinstalar."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sin nombre"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Se ha inhabilitado <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla de inicio %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nueva página de pantalla de inicio"</string>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
index 5f810c9..6e90d86 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et-rEE/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Seadistamine"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"See on süsteemirakendus ja seda ei saa desinstallida."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nimetu kaust"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> on keelatud"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Leht %1$d/%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Avaekraan %1$d/%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Uus avaekraan"</string>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index 8fe826d..29356be 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfigurazioa"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Sistema-aplikazioa da hau eta ezin da desinstalatu."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Izenik gabeko karpeta"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> desgaituta dago"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d/%2$d orria"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d/%2$d hasierako pantaila"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Hasierako pantailaren orri berria"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 5fdf041..2e2acf1 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"تنظیم"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"این برنامه سیستمی است و حذف نصب نمی‌شود."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"پوشه بی‌نام"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> غیرفعال شد"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"‏صفحه %1$d از %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"‏صفحه اصلی %1$d از %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"صفحه اصلی جدید"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 75951e2..c5e0123 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Asetus"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Tämä on järjestelmäsovellus, eikä sitä voi poistaa."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nimetön kansio"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> poistettiin käytöstä"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Sivu %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Aloitusruutu %1$d/%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Uusi aloitusnäytön sivu"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 422308b..21b1afa 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuration"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Impossible de désinstaller cette application, car il s\'agit d\'une application système."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dossier sans nom"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"L\'application <xliff:g id="APP_NAME">%1$s</xliff:g> est désactivée"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d sur %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Écran d\'accueil %1$d sur %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nouvelle page d\'écran d\'accueil"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 310e933..d94954b 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuration"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Impossible de désinstaller cette application, car il s\'agit d\'une application système."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dossier sans nom"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> est désactivé."</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d sur %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Écran d\'accueil %1$d sur %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nouvelle page d\'écran d\'accueil"</string>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index 21b7e01..efd5ec1 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuración"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta aplicación é do sistema e non se pode desinstalar."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Cartafol sen nome"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Desactivouse <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Páxina %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla de inicio %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova páxina da pantalla de inicio"</string>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index 6cc387b..55b7bb0 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"સેટઅપ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"આ એક સિસ્ટમ ઍપ્લિકેશન છે અને અનઇન્સ્ટોલ કરી શકાતી નથી."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"અનામી ફોલ્ડર"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> અક્ષમ કરી"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d માંથી %1$d પૃષ્ઠ"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d માંથી %1$d હોમ સ્ક્રીન"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"નવું હોમ સ્ક્રીન પૃષ્ઠ"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 0a40726..c86e1b2 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"यह एक सिस्टम ऐप्लिकेशन है और इसे अनइंस्टॉल नहीं किया जा सकता."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"अनामित फ़ोल्डर"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> अक्षम है"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"पृष्ठ %2$d में से %1$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"होम स्क्रीन %2$d में से %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"नया होम स्‍क्रीन पृष्‍ठ"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 6e5f123..303c4dd 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Postavljanje"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ovo je aplikacija sustava i ne može se ukloniti."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovana mapa"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> onemogućena"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Stranica %1$d od %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Početni zaslon %1$d od %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog zaslona"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index db5ff86..addf977 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Beállítás"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ez egy rendszeralkalmazás, és nem lehet eltávolítani."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Névtelen mappa"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> letiltva"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d/%1$d. oldal"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d/%1$d. kezdőképernyő"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Új kezdőképernyő oldal"</string>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index 00b1bed..0502c14 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Կարգավորում"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Սա համակարգային ծրագիր է և չի կարող ապատեղադրվել:"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Անանուն պանակ"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն անջատված է"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Էջ %1$d՝ %2$d-ից"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Հիմնական էկրան %1$d` %2$d-ից"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Հիմնական էկրանի նոր էջ"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index f48278f..464c99d 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Siapkan"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini adalah aplikasi sistem dan tidak dapat dicopot pemasangannya."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folder Tanpa Nama"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> dinonaktifkan"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Laman %1$d dari %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Layar utama %1$d dari %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Laman layar utama baru"</string>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
index e97c1b7..756d058 100644
--- a/res/values-is-rIS/strings.xml
+++ b/res/values-is-rIS/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Uppsetning"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Þetta er kerfisforrit sem ekki er hægt að fjarlægja."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Ónefnd mappa"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Óvirkt <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Síða %1$d af %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Heimaskjár %1$d af %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ný síða á heimaskjá"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index d03ece9..37fd313 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configurazione"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Questa è un\'app di sistema e non può essere disinstallata."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Cartella senza nome"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"App <xliff:g id="APP_NAME">%1$s</xliff:g> disattivata"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Pagina %1$d di %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Schermata Home %1$d di %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nuova pagina Schermata Home"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index fdf5cc5..db2470b 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"הגדר"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"זוהי אפליקציית מערכת ולא ניתן להסיר את התקנתה."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"תיקיה ללא שם"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> מושבתת"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"‏דף %1$d מתוך %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"‏מסך דף הבית %1$d מתוך %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"מסך דף הבית חדש"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 8368042..b638f03 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"セットアップ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"このシステムアプリはアンインストールできません。"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"名前のないフォルダ"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」は無効です"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d/%2$dページ"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"ホーム画面: %1$d/%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"新しいホーム画面ページ"</string>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index 64f5fb0..ac1ada2 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"დაყენება"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ეს სისტემური აპია და მისი წაშლა შეუძლებელია."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"უსახელო საქაღალდე"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> გაითიშა"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"გვერდი %1$d %2$d-დან"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"მთავარი ეკრანი %1$d, %2$d-დან"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"მთავარი ეკრანის ახალი გვერდი"</string>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
index 26b1daf..c88a8b6 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk-rKZ/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Орнату"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Бұл жүйе қолданбасы, сондықтан оны алу мүмкін емес."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Атауы жоқ қалта"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> өшірілді"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d бет, барлығы %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d негізгі экран, барлығы %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Жаңа негізгі экран беті"</string>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
index bcb1eee..ce2f501 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km-rKH/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"រៀបចំ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"នេះ​​​ជា​កម្មវិធី​ប្រព័ន្ធ មិន​អាច​លុប​បាន​ទេ។"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"ថត​គ្មាន​ឈ្មោះ"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"បានបិទដំណើរការ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"ទំព័រ %1$d នៃ %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"អេក្រង់​ដើម %1$d នៃ %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"ទំព័រអេក្រង់ដើមថ្មី"</string>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index 9b50fe8..c5d7e09 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"ಸೆಟಪ್"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ಇದೊಂದು ಅಪ್ಲಿಕೇಶನ್ ಆಗಿದೆ ಮತ್ತು ಅಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"ಹೆಸರಿಲ್ಲದ ಫೋಲ್ಡರ್"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d ರಲ್ಲಿ %1$d ಪುಟ"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d ರಲ್ಲಿ %1$d ಮುಖಪುಟದ ಪರದೆ"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"ಹೊಸ ಮುಖಪುಟ ಪರದೆ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 19ec6eb..49d6851 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"설정"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"시스템 앱은 제거할 수 없습니다."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"이름이 없는 폴더"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> 사용 안함"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"페이지 %1$d/%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"홈 화면 %1$d/%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"새로운 메인 스크린 페이지"</string>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
index 25c4672..a9b7ec0 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky-rKG/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Орнотуу"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Бул системдик колдонмо жана аны чечкенге болбойт."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Аты жок фолдер"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> өчүрүлгөн"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d ичинен %1$d барак"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Үй экраны %2$d ичинен %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Жаңы башкы экран барагы"</string>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
index 37dd3e0..3234089 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo-rLA/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"ຕິດຕັ້ງ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ນີ້ແມ່ນແອັບຯຂອງລະບົບ ແລະບໍ່ສາມາດຖອນການຕິດຕັ້ງອອກໄດ້."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"ໂຟນເດີຍັງບໍ່ຖືກຕັ້ງຊື່"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"ປິດການນຳໃຊ້ <xliff:g id="APP_NAME">%1$s</xliff:g> ແລ້ວ"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"ໜ້າ %1$d ຈາກ %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"ໜ້າຈໍຫຼັກ %1$d ໃນ %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"ໜ້າ​ຂອງ​ໜ້າ​ຈໍ​ຫຼັກ​ໃໝ່"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 83ca181..e0cced5 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Sąranka"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Tai sistemos programa ir jos negalima pašalinti."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Aplankas be pavadinimo"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ išjungta"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d psl. iš %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d pagrindinis ekranas iš %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Naujas pagrindinio ekrano puslapis"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 2b19963..4fb6164 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -35,8 +35,7 @@
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Meklēt citas lietotnes"</string>
     <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>
-    <!-- no translation found for all_apps_button_label (8130441508702294465) -->
-    <skip />
+    <string name="all_apps_button_label" msgid="8130441508702294465">"Lietotņu saraksts"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Sākums"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Noņemt"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Atinstalēt"</string>
@@ -52,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Notiek iestatīšana"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Šī ir sistēmas lietotne, un to nevar atinstalēt."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Mape bez nosaukuma"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> ir atspējota"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d. lapa no %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Sākuma ekrāns: %1$d no %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Jauna sākuma ekrāna lapa"</string>
@@ -68,10 +66,8 @@
     <string name="settings_button_text" msgid="8119458837558863227">"Iestatījumi"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Atspējojis administrators"</string>
     <string name="accessibility_action_overview" msgid="6257665857640347026">"Kopsavilkums"</string>
-    <!-- no translation found for allow_rotation_title (7728578836261442095) -->
-    <skip />
-    <!-- no translation found for allow_rotation_desc (8662546029078692509) -->
-    <skip />
+    <string name="allow_rotation_title" msgid="7728578836261442095">"Atļaut sākuma ekrāna pagriešanu"</string>
+    <string name="allow_rotation_desc" msgid="8662546029078692509">"Pagriežot tālruni"</string>
     <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Pašreizējā displeja iestatījumā nav atļauta pagriešana."</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Nezināma"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Noņemt"</string>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
index 62f6dbe..2c2c8e9 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Поставување"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ова е системска апликација и не може да се деинсталира."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Неименувана папка"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> е оневозможена"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Страница %1$d од %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Екран на почетна страница %1$d од %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Нова страница на почетен екран"</string>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index 2db9c23..9cf75f3 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"സജ്ജീകരിക്കുക"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ഇതൊരു സിസ്‌റ്റം അപ്ലിക്കേഷനായതിനാൽ അൺഇൻസ്‌റ്റാളുചെയ്യാനാവില്ല."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"പേരുനൽകാത്ത ഫോൾഡർ"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"പേജ് %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"ഹോം സ്‌ക്രീൻ %1$d / %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"പുതിയ ഹോം സ്ക്രീൻ പേജ്"</string>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
index 95add4c..de4258a 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn-rMN/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Тохируулга"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Энэ апп нь системийн апп ба устгах боломжгүй."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Нэргүй фолдер"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г идэвхгүй болгосон"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d-н %1$d хуудас"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d-н Нүүр дэлгэц %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Шинэ үндсэн нүүр хуудас"</string>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index 98d0d44..3a8ab8a 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"हा सिस्टम अॅप आहे आणि विस्थापित केला जाऊ शकत नाही."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"अनामित फोल्डर"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> अक्षम केला आहे"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d पैकी %1$d पृष्ठ"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d पैकी %1$d मुख्य स्क्रीन"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"नवीन मुख्य स्क्रीन पृष्ठ"</string>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index 7c3af15..073a9db 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Persediaan"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini ialah apl sistem dan tidak boleh dinyahpasang."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folder Tanpa Nama"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> dilumpuhkan"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Halaman %1$d daripada %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Skrin Laman Utama %1$d daripada %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Halaman skrin utama baharu"</string>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index 373a7ed..4bf15e7 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"စဖွင့်သတ်မှတ်ရန်"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ဤအပ်ပလီကေးရှင်းမှာ စစ်စတန်ပိုင်းဆိုင်ရာ အပ်ပလီကေးရှင်းဖြစ်ပါသည်။ ထုတ်ပစ်၍ မရပါ"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"အမည်မရှိအကန့်"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ပိတ်ထားသည်"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"စာမျက်နှာ %1$d မှ %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"ပင်မစာမျက်နှာ %1$d မှ %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"ပင်မမျက်နှာပြင် စာမျက်နှာသစ်"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 6db69f4..57d12f7 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfigurering"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dette er en systemapp som ikke kan avinstalleres."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Mappe uten navn"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Slo av <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Side %1$d av %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startside %1$d av %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ny side på startskjermen"</string>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index f670fb1..aa971e8 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"यो प्रणाली अनुप्रयोग हो र यसलाई स्थापना रद्द गर्न सकिँदैन।"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"बेनाम फोल्डर"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"असक्षम पारिएको <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"पृष्ठ %2$d को %1$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"गृह स्क्रिन %1$d को %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"नयाँ गृह स्क्रिन पृष्ठ"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 077a968..8d0854f 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuratie"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dit is een systeemapp die niet kan worden verwijderd."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Naamloze map"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> is uitgeschakeld"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Pagina %1$d van %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startscherm %1$d van %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nieuwe startschermpagina"</string>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
index d2b827e..14d2ed8 100644
--- a/res/values-pa-rIN/strings.xml
+++ b/res/values-pa-rIN/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"ਸਥਾਪਤ ਕਰੋ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ਇਹ ਇੱਕ ਸਿਸਟਮ ਐਪ ਹੈ ਅਤੇ ਇਸਨੂੰ ਅਣਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"ਬਿਨਾਂ ਨਾਮ ਦਿੱਤਾ ਫੋਲਡਰ"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"ਸਫ਼ਾ %2$d ਦਾ %1$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"ਹੋਮ ਸਕ੍ਰੀਨ %2$d ਦੀ %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"ਨਵਾਂ ਹੋਮ ਸਕ੍ਰੀਨ ਸਫ਼ਾ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 9011a47..b83fecf 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfiguracja"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"To aplikacja systemowa i nie można jej odinstalować."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folder bez nazwy"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest wyłączona"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Strona %1$d z %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ekran główny %1$d z %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nowa strona ekranu głównego"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 33740de..da907aa 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuração"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"É uma aplicação de sistema e não pode ser desinstalada."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Pasta sem nome"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> desativado"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ecrã principal %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova página do ecrã principal"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 0a0dc46..94bba01 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuração"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Este é um app do sistema e não pode ser desinstalado."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Pasta sem nome"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> desativado"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Tela inicial %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova página na tela inicial"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 0d84e0d..c6b470c 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configurați"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Aceasta este o aplicație de sistem și nu poate fi dezinstalată."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dosar fără nume"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"S-a dezactivat <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Pagina %1$d din %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ecranul de pornire %1$d din %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Pagină nouă pe ecranul de pornire"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index b56b184..b814a27 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Настройка"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Это системное приложение, его нельзя удалить."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Папка без названия"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> отключено"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Стр. %1$d из %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Главные экран %1$d из %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Новый экран"</string>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index a9d1166..966d019 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"ස්ථාපනය කරන්න"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"මෙය පද්ධති යෙදුමක් වන අතර අස්ථාපනය කළ නොහැක."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"නම් නොකළ ෆෝල්ඩරය"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> අබල කෙරිණි"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d හි %1$d පිටුව"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"මුල් පිටු තිරය %2$d හි %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"නව මුල් පිටුව"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index dfcc790..9a403a7 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Nastavenie"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Toto je systémová aplikácia a nedá sa odinštalovať."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nepomenovaný priečinok"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> je zakázaná"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Stránka %1$d z %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Plocha %1$d z %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nová stránka plochy"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 0a481ee..0cb9190 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Nastavitev"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"To je sistemska aplikacija in je ni mogoče odstraniti."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovana mapa"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogočena"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Stran %1$d od %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Začetni zaslon %1$d od %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova stran na začetnem zaslonu"</string>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
index 1a72965..0850c55 100644
--- a/res/values-sq-rAL/strings.xml
+++ b/res/values-sq-rAL/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfiguro"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ky është aplikacion sistemi dhe nuk mund të çinstalohet."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dosje e paemërtuar"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> u çaktivizua"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Faqja: %1$d nga gjithsej %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ekrani bazë: %1$d nga gjithsej %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Faqja e ekranit të ri kryesor"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 5a9c89a..bac6ab1 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Подешавање"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ово је системска апликација и не може да се деинсталира."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Неименовани директоријум"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је онемогућена"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d. страница од %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d. почетни екран од %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Нова страница почетног екрана"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 6b68c83..40c5a25 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfiguration"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Det här är en systemapp som inte kan avinstalleras."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Namnlös mapp"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inaktiverats"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Sidan %1$d av %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startskärmen %1$d av %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ny sida på startskärmen"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index a0f4c77..75b2952 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Sanidi"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Hii ni programu ya mfumo na haiwezi kuondolewa."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folda isiyo na jina"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> imezimwa"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Ukurasa%1$d wa %2$d"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for workspace_scroll_format (8458889198184077399) -->
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
deleted file mode 100644
index 1f97d24..0000000
--- a/res/values-sw600dp-land/dimens.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-<!-- Container -->
-    <dimen name="container_max_width">736dp</dimen>
-</resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 85a436c..2838088 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -15,21 +15,15 @@
 -->
 
 <resources>
-<!-- Container -->
-    <dimen name="container_min_margin">16dp</dimen>
-
 <!-- All Apps -->
     <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
     <dimen name="all_apps_grid_section_text_size">26sp</dimen>
-    <dimen name="all_apps_icon_top_bottom_padding">12dp</dimen>
     <dimen name="all_apps_background_canvas_width">850dp</dimen>
     <dimen name="all_apps_background_canvas_height">525dp</dimen>
-    <dimen name="all_apps_icon_width_gap">36dp</dimen>
 
 <!-- Widget tray -->
     <dimen name="widget_section_indent">56dp</dimen>
 
-
 <!-- DragController -->
     <dimen name="drag_flingToDeleteMinVelocity">-1000dp</dimen>
 </resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index c2d20a3..358d9b6 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -18,7 +18,6 @@
 <!-- All Apps -->
     <dimen name="all_apps_button_scale_down">8dp</dimen>
     <dimen name="all_apps_search_bar_height">54dp</dimen>
-    <dimen name="all_apps_icon_top_bottom_padding">14dp</dimen>
     <dimen name="all_apps_empty_search_message_top_offset">64dp</dimen>
     <dimen name="all_apps_empty_search_bg_top_offset">180dp</dimen>
 
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index 203d127..4413cc7 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"அமைவு"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"இது அமைப்பு பயன்பாடு என்பதால் நிறுவல் நீக்கம் செய்ய முடியாது."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"பெயரிடப்படாத கோப்புறை"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> முடக்கப்பட்டது"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"பக்கம் %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"முகப்புத் திரை %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"புதிய முகப்புத் திரை பக்கம்"</string>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index 1e9dd6b..3951fff 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"సెటప్ చేయి"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ఇది సిస్టమ్ అనువర్తనం మరియు దీన్ని అన్‌ఇన్‌స్టాల్ చేయడం సాధ్యపడదు."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"పేరు లేని ఫోల్డర్"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> నిలిపివేయబడింది"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$dలో %1$dవ పేజీ"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dలో %1$dవ హోమ్ స్క్రీన్"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"కొత్త హోమ్ స్క్రీన్ పేజీ"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 4372b17..90e9bca 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"ตั้งค่า"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"นี่เป็นแอประบบและไม่สามารถถอนการติดตั้งได้"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"โฟลเดอร์ที่ไม่มีชื่อ"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"ปิดใช้ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"หน้า %1$d จาก %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"หน้าจอหลัก %1$d จาก %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"หน้าใหม่ในหน้าจอหลัก"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 99cab07..997a4eb 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"I-setup"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Isa itong app ng system at hindi maaaring i-uninstall."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Walang Pangalang Folder"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Naka-disable ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Pahina %1$d ng %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Home screen %1$d ng %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Bagong page ng home screen"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index c52bad8..6f7a19c 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Kurulum"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu bir sistem uygulamasıdır ve yüklemesi kaldırılamaz."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Adsız Klasör"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> devre dışı"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Sayfa %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ana ekran %1$d / %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Yeni ana ekran sayfası"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index ebbf279..5f240fe 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Налаштування"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Це системна програма, її неможливо видалити."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Папка без назви"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> вимкнено"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Сторінка %1$d з %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Головний екран %1$d з %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Нова сторінка головного екрана"</string>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
index 32ed80c..9bb683c 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur-rPK/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"ترتیب دیں"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"یہ ایک سسٹم ایپ ہے اور اسے اَن انسٹال نہیں کیا جا سکتا ہے۔"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"بلا نام فولڈر"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> غیر فعال ہے"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"‏صفحہ ‎%1$d از ‎%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"‏ہوم اسکرین ‎%1$d از ‎%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"نیا ہوم اسکرین صفحہ"</string>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index 019f410..5e76c6f 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Sozlash"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu tizim ilovasi, shuning uchun o‘chirib bo‘lmaydi."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nomsiz jild"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi o‘chirib qo‘yildi"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$ddan %1$d ta sahifa"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Uy ekrani %2$ddan %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Yangi bosh ekran sahifasi"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index ed2a1de..82e463f 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Thiết lập"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Đây là ứng dụng hệ thống và không thể gỡ cài đặt."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Thư mục chưa đặt tên"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Đã vô hiệu hóa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Trang %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Màn hình chính %1$d / %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Trang màn hình chính mới"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index c25047d..d46585a 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -35,8 +35,7 @@
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"搜索更多应用"</string>
     <string name="out_of_space" msgid="4691004494942118364">"此主屏幕上已没有空间。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"收藏栏已满"</string>
-    <!-- no translation found for all_apps_button_label (8130441508702294465) -->
-    <skip />
+    <string name="all_apps_button_label" msgid="8130441508702294465">"应用列表"</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>
@@ -52,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"设置"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"这是系统应用,无法卸载。"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"未命名文件夹"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"已停用<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"第%1$d页,共%2$d页"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"主屏幕:第%1$d屏,共%2$d屏"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"主屏幕新页面"</string>
@@ -68,10 +66,8 @@
     <string name="settings_button_text" msgid="8119458837558863227">"设置"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"已被您的管理员停用"</string>
     <string name="accessibility_action_overview" msgid="6257665857640347026">"概览"</string>
-    <!-- no translation found for allow_rotation_title (7728578836261442095) -->
-    <skip />
-    <!-- no translation found for allow_rotation_desc (8662546029078692509) -->
-    <skip />
+    <string name="allow_rotation_title" msgid="7728578836261442095">"允许旋转主屏幕"</string>
+    <string name="allow_rotation_desc" msgid="8662546029078692509">"手机旋转时"</string>
     <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"当前的显示设置不允许旋转设备"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"未知"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"移除"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index f2d6999..d72865b 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"設定"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"這是系統應用程式,無法將其解除安裝。"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"未命名的資料夾"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」已停用"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"第 %1$d 頁,共 %2$d 頁"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"主畫面 %1$d,共 %2$d 個"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"新主畫面頁面"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 37548e4..ae98163 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"設定"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"這是系統應用程式,不可解除安裝。"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"未命名的資料夾"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"已停用 <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"第 %1$d 頁,共 %2$d 頁"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"主螢幕:第 %1$d 頁,共 %2$d 頁"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"新的主畫面頁面"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 017dcd4..991056a 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -51,8 +51,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"Ukumisa"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Lolu uhlelo lokusebenza lwesistimu futhi alikwazi ukukhishwa."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Ifolda engenagama"</string>
-    <!-- no translation found for disabled_app_label (6673129024321402780) -->
-    <skip />
+    <string name="disabled_app_label" msgid="6673129024321402780">"Kukhutshaziwe <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Ikhasi elingu-%1$d kwangu-%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Isikrini sasekhaya esingu-%1$d se-%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ikhasi elisha lesikrini sasekhaya"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 308c71c..3cfaf02 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -29,6 +29,7 @@
         </attr>
         <attr name="deferShadowGeneration" format="boolean" />
         <attr name="customShadows" format="boolean" />
+        <attr name="centerVertically" format="boolean" />
     </declare-styleable>
 
     <!-- PagedView specific attributes. These attributes are used to customize
diff --git a/res/values/colors.xml b/res/values/colors.xml
index dccc53e..21d9d5c 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -4,16 +4,16 @@
 **
 ** Copyright 2008, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** 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 
+**     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 
+** 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.
 */
 -->
@@ -37,6 +37,8 @@
     <color name="outline_color">#FFFFFFFF</color>
     <color name="all_apps_divider_color">#1E000000</color>
     <color name="all_apps_caret_color">#FFFFFFFF</color>
+    <color name="all_apps_caret_shadow_color">#22000000</color>
+    <color name="all_apps_container_color">#FFF2F2F2</color>
 
     <color name="spring_loaded_panel_color">#40FFFFFF</color>
     <color name="spring_loaded_highlighted_panel_border_color">#FFF</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index a678958..c962dec 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -86,6 +86,11 @@
     <!-- View ID used by cell layout to jail its content -->
     <item type="id" name="cell_layout_jail_id" />
 
+<!-- Deep shortcuts -->
+    <integer name="config_deepShortcutOpenDuration">300</integer>
+    <integer name="config_deepShortcutOpenStagger">20</integer>
+    <integer name="config_deepShortcutHoverDuration">120</integer>
+
 <!-- Accessibility actions -->
     <item type="id" name="action_remove" />
     <item type="id" name="action_uninstall" />
@@ -96,4 +101,5 @@
     <item type="id" name="action_move_screen_backwards" />
     <item type="id" name="action_move_screen_forwards" />
     <item type="id" name="action_resize" />
+    <item type="id" name="action_deep_shortcuts" />
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 38775f1..6897269 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -16,20 +16,26 @@
 
 <resources>
 <!-- Dynamic Grid -->
-    <dimen name="dynamic_grid_edge_margin">6dp</dimen>
-    <dimen name="dynamic_grid_page_indicator_height">24dp</dimen>
+    <dimen name="dynamic_grid_edge_margin">8dp</dimen>
+    <dimen name="dynamic_grid_page_indicator_height">28dp</dimen>
     <dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
     <dimen name="dynamic_grid_page_indicator_extra_touch_height">12dp</dimen>
-    <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
-    <dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
+    <dimen name="dynamic_grid_page_indicator_gutter_width_left_nav_bar">38dp</dimen>
+    <dimen name="dynamic_grid_page_indicator_gutter_width_right_nav_bar">48dp</dimen>
+    <dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
     <dimen name="dynamic_grid_overview_min_icon_zone_height">80dp</dimen>
     <dimen name="dynamic_grid_overview_max_icon_zone_height">120dp</dimen>
     <dimen name="dynamic_grid_overview_bar_item_width">80dp</dimen>
-    <dimen name="dynamic_grid_overview_bar_spacer_width">20dp</dimen>
-
+    <dimen name="dynamic_grid_overview_bar_spacer_width">25dp</dimen>
+    <dimen name="dynamic_grid_hotseat_height">88dp</dimen>
+    <dimen name="dynamic_grid_hotseat_top_padding">8dp</dimen>
+    <dimen name="dynamic_grid_hotseat_gutter_width">24dp</dimen>
     <dimen name="dynamic_grid_workspace_top_padding">12dp</dimen>
+    <dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
     <!-- Minimum space between workspace and hotseat in spring loaded mode -->
     <dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
+    <dimen name="dynamic_grid_container_land_left_padding">118dp</dimen>
+    <dimen name="dynamic_grid_container_land_right_padding">66dp</dimen>
 
 <!-- Drop target bar -->
     <dimen name="dynamic_grid_drop_target_size">48dp</dimen>
@@ -54,28 +60,24 @@
     <dimen name="container_fastscroll_popup_size">72dp</dimen>
     <dimen name="container_fastscroll_popup_text_size">48dp</dimen>
 
-    <item name="container_margin" format="fraction" type="fraction">0%</item>
-    <dimen name="container_min_margin">8dp</dimen>
-    <dimen name="container_max_width">0dp</dimen>
-
 <!-- All Apps -->
     <dimen name="all_apps_button_scale_down">0dp</dimen>
     <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
     <dimen name="all_apps_grid_section_y_offset">8dp</dimen>
     <dimen name="all_apps_grid_section_text_size">24sp</dimen>
     <dimen name="all_apps_search_bar_height">60dp</dimen>
-    <dimen name="all_apps_search_bar_margin_top">5dp</dimen>
+    <dimen name="all_apps_search_bar_margin_top">12dp</dimen>
     <dimen name="all_apps_search_bar_icon_margin_right">4dp</dimen>
     <dimen name="all_apps_search_bar_icon_margin_top">1dp</dimen>
-    <dimen name="all_apps_icon_top_bottom_padding">8dp</dimen>
-    <dimen name="all_apps_icon_width_gap">24dp</dimen>
     <dimen name="all_apps_list_bottom_padding">8dp</dimen>
     <dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
     <dimen name="all_apps_empty_search_bg_top_offset">144dp</dimen>
     <dimen name="all_apps_background_canvas_width">700dp</dimen>
     <dimen name="all_apps_background_canvas_height">475dp</dimen>
     <dimen name="all_apps_caret_stroke_width">2dp</dimen>
-    <dimen name="all_apps_caret_inset">8dp</dimen>
+    <dimen name="all_apps_caret_shadow_spread">1dp</dimen>
+    <dimen name="all_apps_caret_size">13dp</dimen>
+    <dimen name="all_apps_caret_workspace_offset">4dp</dimen>
 
 <!-- Search bar in All Apps -->
     <dimen name="all_apps_header_max_elevation">3dp</dimen>
@@ -85,6 +87,7 @@
     <dimen name="all_apps_divider_margin_vertical">8dp</dimen>
 
     <dimen name="all_apps_bezel_swipe_height">24dp</dimen>
+
 <!-- Widget tray -->
     <dimen name="widget_preview_label_vertical_padding">8dp</dimen>
     <dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
@@ -152,12 +155,16 @@
 
 <!-- Deep shortcuts -->
     <dimen name="deep_shortcuts_elevation">9dp</dimen>
-    <dimen name="deep_shortcuts_width">180dp</dimen>
+    <dimen name="bg_pill_width">180dp</dimen>
+    <dimen name="bg_pill_height">48dp</dimen>
+    <dimen name="bg_pill_radius">24dp</dimen>
     <dimen name="deep_shortcuts_spacing">4dp</dimen>
     <dimen name="deep_shortcuts_drag_view_scale">6dp</dimen>
     <!-- an icon with shortcuts must be dragged this much distance away from the nearest edge
          of the shortcut container before the container is removed. -->
     <dimen name="deep_shortcuts_start_drag_threshold">35dp</dimen>
     <dimen name="deep_shortcut_icon_size">36dp</dimen>
+    <dimen name="deep_shortcuts_arrow_horizontal_offset">19dp</dimen>
+    <dimen name="deep_shortcut_anim_translation_y">5dp</dimen>
 
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7bd9ff7..757e29d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -249,4 +249,7 @@
     <!-- Accessibility confirmation for widget resize. -->
     <string name="widget_resized">Widget resized to width <xliff:g id="number" example="2">%1$s</xliff:g> height <xliff:g id="number" example="1">%2$s</xliff:g></string>
 
+    <!-- Accessibility action to show quick actions menu for an icon. [CHAR_LIMIT=30] -->
+    <string name="action_deep_shortcut" translatable="false">Quick links</string>
+
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 3e827a6..627c433 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -78,13 +78,11 @@
     </style>
 
     <style name="Icon.DeepShortcut">
-        <item name="android:background">@drawable/bg_white_pill</item>
         <item name="android:gravity">start|center_vertical</item>
-        <item name="android:minWidth">@dimen/deep_shortcuts_width</item>
-        <item name="android:maxWidth">@dimen/deep_shortcuts_width</item>
         <item name="android:elevation">@dimen/deep_shortcuts_elevation</item>
         <item name="android:paddingLeft">7dp</item>
-        <item name="android:drawablePadding">12dp</item>
+        <item name="android:paddingRight">12dp</item>
+        <item name="android:drawablePadding">9dp</item>
         <item name="android:textColor">@color/quantum_panel_text_color</item>
         <item name="android:shadowRadius">0</item>
         <item name="customShadows">false</item>
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
index f9c2407..96942ee 100644
--- a/src/com/android/launcher3/BaseContainerView.java
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.InsetDrawable;
@@ -32,11 +31,16 @@
 /**
  * A base container view, which supports resizing.
  */
-public abstract class BaseContainerView extends FrameLayout {
+public abstract class BaseContainerView extends FrameLayout
+        implements DeviceProfile.LauncherLayoutChangeListener {
 
-    protected final int mHorizontalPadding;
+    protected int mContainerPaddingLeft;
+    protected int mContainerPaddingRight;
+    protected int mContainerPaddingTop;
+    protected int mContainerPaddingBottom;
 
-    private final Drawable mRevealDrawable;
+    private InsetDrawable mRevealDrawable;
+    protected final Drawable mBaseDrawable;
 
     private View mRevealView;
     private View mContent;
@@ -52,42 +56,49 @@
     public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
-        Launcher launcher = Launcher.getLauncher(context);
-        int width = launcher.getDeviceProfile().availableWidthPx;
-        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
-                this instanceof AllAppsContainerView &&
-                !launcher.getDeviceProfile().isVerticalBarLayout()) {
-            mHorizontalPadding = 0;
-        } else {
-            mHorizontalPadding = DeviceProfile.getContainerPadding(context, width);
-        }
-
         if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
-            mRevealDrawable = new InsetDrawable(new ColorDrawable(Color.WHITE), mHorizontalPadding,
-                    0, mHorizontalPadding, 0);
+            mBaseDrawable = new ColorDrawable();
         } else {
             TypedArray a = context.obtainStyledAttributes(attrs,
                     R.styleable.BaseContainerView, defStyleAttr, 0);
-            mRevealDrawable = new InsetDrawable(
-                    a.getDrawable(R.styleable.BaseContainerView_revealBackground),
-                    mHorizontalPadding, 0, mHorizontalPadding, 0);
+            mBaseDrawable = a.getDrawable(R.styleable.BaseContainerView_revealBackground);
             a.recycle();
         }
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
+        grid.addLauncherLayoutChangedListener(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
+        grid.removeLauncherLayoutChangedListener(this);
+    }
+
+    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
         mContent = findViewById(R.id.main_content);
         mRevealView = findViewById(R.id.reveal_view);
 
-        mRevealView.setBackground(mRevealDrawable.getConstantState().newDrawable());
-        mContent.setBackground(mRevealDrawable);
+        updatePaddings();
+    }
 
-        // We let the content have a intent background, but still have full width.
-        // This allows the scroll bar to be used responsive outside the background bounds as well.
-        mContent.setPadding(0, 0, 0, 0);
+    @Override
+    public void onLauncherLayoutChanged() {
+        updatePaddings();
+    }
+
+    public void setRevealDrawableColor(int color) {
+        ((ColorDrawable) mBaseDrawable).setColor(color);
     }
 
     public final View getContentView() {
@@ -97,4 +108,36 @@
     public final View getRevealView() {
         return mRevealView;
     }
+
+    private void updatePaddings() {
+        Context context = getContext();
+        Launcher launcher = Launcher.getLauncher(context);
+
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
+                this instanceof AllAppsContainerView &&
+                !launcher.getDeviceProfile().isVerticalBarLayout()) {
+            mContainerPaddingLeft = mContainerPaddingRight = 0;
+            mContainerPaddingTop = mContainerPaddingBottom = 0;
+        } else {
+            DeviceProfile grid = launcher.getDeviceProfile();
+            int[] padding = grid.getContainerPadding(context);
+            mContainerPaddingLeft = padding[0] + grid.edgeMarginPx;
+            mContainerPaddingRight = padding[1] + grid.edgeMarginPx;
+            if (!launcher.getDeviceProfile().isVerticalBarLayout()) {
+                mContainerPaddingTop = mContainerPaddingBottom = grid.edgeMarginPx;
+            } else {
+                mContainerPaddingTop = mContainerPaddingBottom = 0;
+            }
+        }
+
+        mRevealDrawable = new InsetDrawable(mBaseDrawable,
+                mContainerPaddingLeft, mContainerPaddingTop, mContainerPaddingRight,
+                mContainerPaddingBottom);
+        mRevealView.setBackground(mRevealDrawable);
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
+            // Skip updating the content background
+        } else {
+            mContent.setBackground(mRevealDrawable);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 33e4e2a..33b3ad3 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -24,6 +24,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Region;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -55,17 +56,19 @@
 
     private static SparseArray<Theme> sPreloaderThemes = new SparseArray<Theme>(2);
 
-    private static final float SHADOW_LARGE_RADIUS = 4.0f;
-    private static final float SHADOW_SMALL_RADIUS = 1.75f;
-    private static final float SHADOW_Y_OFFSET = 2.0f;
-    private static final int SHADOW_LARGE_COLOUR = 0xDD000000;
-    private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
+    // Dimensions in DP
+    private static final float AMBIENT_SHADOW_RADIUS = 2.5f;
+    private static final float KEY_SHADOW_RADIUS = 1f;
+    private static final float KEY_SHADOW_OFFSET = 0.5f;
+    private static final int AMBIENT_SHADOW_COLOR = 0x33000000;
+    private static final int KEY_SHADOW_COLOR = 0x66000000;
 
     private static final int DISPLAY_WORKSPACE = 0;
     private static final int DISPLAY_ALL_APPS = 1;
 
     private final Launcher mLauncher;
     private Drawable mIcon;
+    private final boolean mCenterVertically;
     private final Drawable mBackground;
     private OnLongClickListener mOnLongClickListener;
     private final CheckLongPressHelper mLongPressHelper;
@@ -119,9 +122,11 @@
         if (display == DISPLAY_WORKSPACE) {
             setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
         } else if (display == DISPLAY_ALL_APPS) {
-            setTextSize(TypedValue.COMPLEX_UNIT_SP, grid.allAppsIconTextSizeSp);
+            setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
+            setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
             defaultIconSize = grid.allAppsIconSizePx;
         }
+        mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
 
         mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
                 defaultIconSize);
@@ -132,6 +137,10 @@
             // Draw the background itself as the parent is drawn twice.
             mBackground = getBackground();
             setBackground(null);
+
+            // Set shadow layer as the larger shadow to that the textView does not clip the shadow.
+            float density = getResources().getDisplayMetrics().density;
+            setShadowLayer(density * AMBIENT_SHADOW_RADIUS, 0, 0, AMBIENT_SHADOW_COLOR);
         } else {
             mBackground = null;
         }
@@ -140,10 +149,6 @@
         mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
 
         mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
-        if (mCustomShadowsEnabled) {
-            setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR);
-        }
-
         setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
     }
 
@@ -404,13 +409,15 @@
         }
 
         // We enhance the shadow by drawing the shadow twice
-        getPaint().setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR);
+        float density = getResources().getDisplayMetrics().density;
+        getPaint().setShadowLayer(density * AMBIENT_SHADOW_RADIUS, 0, 0, AMBIENT_SHADOW_COLOR);
         super.draw(canvas);
         canvas.save(Canvas.CLIP_SAVE_FLAG);
         canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
                 getScrollX() + getWidth(),
                 getScrollY() + getHeight(), Region.Op.INTERSECT);
-        getPaint().setShadowLayer(SHADOW_SMALL_RADIUS, 0.0f, 0.0f, SHADOW_SMALL_COLOUR);
+        getPaint().setShadowLayer(
+                density * KEY_SHADOW_RADIUS, 0.0f, density * KEY_SHADOW_OFFSET, KEY_SHADOW_COLOR);
         super.draw(canvas);
         canvas.restore();
     }
@@ -428,6 +435,19 @@
     }
 
     @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mCenterVertically) {
+            Paint.FontMetrics fm = getPaint().getFontMetrics();
+            int cellHeightPx = mIconSize + getCompoundDrawablePadding() +
+                    (int) Math.ceil(fm.bottom - fm.top);
+            int height = MeasureSpec.getSize(heightMeasureSpec);
+            setPadding(getPaddingLeft(), (height - cellHeightPx) / 2, getPaddingRight(),
+                    getPaddingBottom());
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         if (mBackground != null) mBackground.setCallback(null);
@@ -509,19 +529,23 @@
      * Sets the icon for this view based on the layout direction.
      */
     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-    public void setIcon(Drawable icon) {
+    private void setIcon(Drawable icon) {
         mIcon = icon;
         if (mIconSize != -1) {
             mIcon.setBounds(0, 0, mIconSize, mIconSize);
         }
+        applyCompoundDrawables(mIcon);
+    }
+
+    protected void applyCompoundDrawables(Drawable icon) {
         if (mLayoutHorizontal) {
             if (Utilities.ATLEAST_JB_MR1) {
-                setCompoundDrawablesRelative(mIcon, null, null, null);
+                setCompoundDrawablesRelative(icon, null, null, null);
             } else {
-                setCompoundDrawables(mIcon, null, null, null);
+                setCompoundDrawables(icon, null, null, null);
             }
         } else {
-            setCompoundDrawables(null, mIcon, null, null);
+            setCompoundDrawables(null, icon, null, null);
         }
     }
 
@@ -628,6 +652,13 @@
     }
 
     /**
+     * Returns true if the view can show custom shortcuts.
+     */
+    public boolean hasDeepShortcuts() {
+        return !mLauncher.getShortcutIdsForItem((ItemInfo) getTag()).isEmpty();
+    }
+
+    /**
      * Returns the start delay when animating between certain {@link FastBitmapDrawable} states.
      */
     private static int getStartDelayForStateChange(final FastBitmapDrawable.State fromState,
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 9030dae..77f6612 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -406,7 +406,8 @@
             mTouchFeedbackView.animate().cancel();
         } else {
             if (mTouchFeedbackView.setBitmap(background)) {
-                mTouchFeedbackView.alignWithIconView(icon, mShortcutsAndWidgets);
+                mTouchFeedbackView.alignWithIconView(icon, mShortcutsAndWidgets,
+                        null /* clipAgainstView */);
                 mTouchFeedbackView.animateShadow();
             }
         }
diff --git a/src/com/android/launcher3/ClickShadowView.java b/src/com/android/launcher3/ClickShadowView.java
index e2bc6ba..aad1112 100644
--- a/src/com/android/launcher3/ClickShadowView.java
+++ b/src/com/android/launcher3/ClickShadowView.java
@@ -21,6 +21,7 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.Rect;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
@@ -91,13 +92,27 @@
      * Aligns the shadow with {@param view}
      * @param viewParent immediate parent of {@param view}. It must be a sibling of this view.
      */
-    public void alignWithIconView(BubbleTextView view, ViewGroup viewParent) {
+    public void alignWithIconView(BubbleTextView view, ViewGroup viewParent, View clipAgainstView) {
         float leftShift = view.getLeft() + viewParent.getLeft() - getLeft();
         float topShift = view.getTop() + viewParent.getTop() - getTop();
         int iconWidth = view.getRight() - view.getLeft();
+        int iconHeight = view.getBottom() - view.getTop();
         int iconHSpace = iconWidth - view.getCompoundPaddingRight() - view.getCompoundPaddingLeft();
         float drawableWidth = view.getIcon().getBounds().width();
 
+        if (clipAgainstView != null) {
+            // Set the bounds to clip against
+            int[] coords = new int[] {0, 0};
+            Utilities.getDescendantCoordRelativeToAncestor(clipAgainstView, (View) getParent(),
+                    coords, false);
+            int clipLeft = (int) Math.max(0, coords[0] - leftShift - mShadowPadding);
+            int clipTop = (int) Math.max(0, coords[1] - topShift - mShadowPadding) ;
+            setClipBounds(new Rect(clipLeft, clipTop, clipLeft + iconWidth, clipTop + iconHeight));
+        } else {
+            // Reset the clip bounds
+            setClipBounds(null);
+        }
+
         setTranslationX(leftShift
                 + viewParent.getTranslationX()
                 + view.getCompoundPaddingLeft() * view.getScaleX()
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2b130e5..15f47b4 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -29,13 +29,18 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.FrameLayout;
 
 import com.android.launcher3.config.FeatureFlags;
 
+import java.util.ArrayList;
+
 public class DeviceProfile {
 
+    public interface LauncherLayoutChangeListener {
+        void onLauncherLayoutChanged();
+    }
+
     public final InvariantDeviceProfile inv;
 
     // Device properties
@@ -68,13 +73,18 @@
     private int desiredWorkspaceLeftRightMarginPx;
     public final int edgeMarginPx;
     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;
 
+    // Page indicator
+    private final int pageIndicatorHeightPx;
+    private final int pageIndicatorLandGutterLeftNavBarPx;
+    private final int pageIndicatorLandGutterRightNavBarPx;
+    private final int pageIndicatorLandWorkspaceOffsetPx;
+
     // Workspace icons
     public int iconSizePx;
     public int iconTextSizePx;
@@ -96,17 +106,30 @@
     public int hotseatCellHeightPx;
     public int hotseatIconSizePx;
     private int hotseatBarHeightPx;
+    private int hotseatBarTopPaddingPx;
+    private int hotseatLandGutterPx;
 
     // All apps
     public int allAppsNumCols;
     public int allAppsNumPredictiveCols;
     public int allAppsButtonVisualSize;
-    public final int allAppsIconSizePx;
-    public final float allAppsIconTextSizeSp;
+    public int allAppsIconSizePx;
+    public int allAppsIconDrawablePaddingPx;
+    public float allAppsIconTextSizePx;
+
+    // Containers
+    private final int containerLeftPaddingPx;
+    private final int containerRightPaddingPx;
 
     // Drop Target
     public int dropTargetBarSizePx;
 
+    // Insets
+    private Rect mInsets = new Rect();
+
+    // Listeners
+    private ArrayList<LauncherLayoutChangeListener> mListeners = new ArrayList<>();
+
     public DeviceProfile(Context context, InvariantDeviceProfile inv,
             Point minSize, Point maxSize,
             int width, int height, boolean isLandscape) {
@@ -130,9 +153,15 @@
                 this.getClass().getName());
         defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
         edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
-        desiredWorkspaceLeftRightMarginPx = 2 * edgeMarginPx;
+        desiredWorkspaceLeftRightMarginPx = edgeMarginPx;
         pageIndicatorHeightPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_height);
+        pageIndicatorLandGutterLeftNavBarPx = res.getDimensionPixelSize(
+                R.dimen.dynamic_grid_page_indicator_gutter_width_left_nav_bar);
+        pageIndicatorLandWorkspaceOffsetPx =
+                res.getDimensionPixelSize(R.dimen.all_apps_caret_workspace_offset);
+        pageIndicatorLandGutterRightNavBarPx = res.getDimensionPixelSize(
+                R.dimen.dynamic_grid_page_indicator_gutter_width_right_nav_bar);
         defaultPageSpacingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing);
         topWorkspacePadding =
@@ -152,12 +181,14 @@
         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;
-
-        // AllApps uses the original non-scaled icon size
-        allAppsIconSizePx = Utilities.pxFromDp(inv.iconSize, dm);
+        hotseatBarHeightPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height);
+        hotseatBarTopPaddingPx =
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
+        hotseatLandGutterPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_gutter_width);
+        containerLeftPaddingPx =
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_container_land_left_padding);
+        containerRightPaddingPx =
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_container_land_right_padding);
 
         // Determine sizes.
         widthPx = width;
@@ -175,6 +206,18 @@
         computeAllAppsButtonSize(context);
     }
 
+    public void addLauncherLayoutChangedListener(LauncherLayoutChangeListener listener) {
+        if (!mListeners.contains(listener)) {
+            mListeners.add(listener);
+        }
+    }
+
+    public void removeLauncherLayoutChangedListener(LauncherLayoutChangeListener listener) {
+        if (mListeners.contains(listener)) {
+            mListeners.remove(listener);
+        }
+    }
+
     /**
      * Determine the exact visual footprint of the all apps button, taking into account scaling
      * and internal padding of the drawable.
@@ -208,6 +251,9 @@
         iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale);
         iconDrawablePaddingPx = drawablePadding;
         hotseatIconSizePx = (int) (Utilities.pxFromDp(inv.hotseatIconSize, dm) * scale);
+        allAppsIconSizePx = iconSizePx;
+        allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
+        allAppsIconTextSizePx = iconTextSizePx;
 
         // Calculate the actual text height
         Paint textPaint = new Paint();
@@ -220,7 +266,6 @@
         dragViewScale = (iconSizePx + scaleDps) / iconSizePx;
 
         // Hotseat
-        hotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx;
         hotseatCellWidthPx = iconSizePx;
         hotseatCellHeightPx = iconSizePx;
 
@@ -247,20 +292,15 @@
         folderIconPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
     }
 
+    public void updateInsets(Rect insets) {
+        mInsets.set(insets);
+    }
+
     /**
      * @param recyclerViewWidth the available width of the AllAppsRecyclerView
      */
-    public void updateAppsViewNumCols(Resources res, int recyclerViewWidth) {
-        int appsViewLeftMarginPx =
-                res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
-        int allAppsCellWidthGap =
-                res.getDimensionPixelSize(R.dimen.all_apps_icon_width_gap);
-        int availableAppsWidthPx = (recyclerViewWidth > 0) ? recyclerViewWidth : availableWidthPx;
-        int numAppsCols = (availableAppsWidthPx + allAppsCellWidthGap - appsViewLeftMarginPx) /
-                (allAppsIconSizePx + allAppsCellWidthGap);
-        int numPredictiveAppCols = Math.max(inv.minAllAppsPredictionColumns, numAppsCols);
-        allAppsNumCols = numAppsCols;
-        allAppsNumPredictiveCols = numPredictiveAppCols;
+    public void updateAppsViewNumCols() {
+        allAppsNumCols = allAppsNumPredictiveCols = inv.numColumns;
     }
 
     /** Returns the width and height of the search bar, ignoring any padding. */
@@ -309,9 +349,13 @@
     public Rect getWorkspacePadding(Rect recycle) {
         Rect padding = recycle == null ? new Rect() : recycle;
         if (isVerticalBarLayout()) {
-            // 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);
+            if (mInsets.left > 0) {
+                padding.set(mInsets.left + pageIndicatorLandGutterLeftNavBarPx, 0,
+                        hotseatBarHeightPx + hotseatLandGutterPx - mInsets.left, 2 * edgeMarginPx);
+            } else {
+                padding.set(pageIndicatorLandGutterRightNavBarPx, 0,
+                        hotseatBarHeightPx + hotseatLandGutterPx, 2 * edgeMarginPx);
+            }
         } else {
             int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
             if (isTablet) {
@@ -331,15 +375,35 @@
                         availablePaddingX / 2, paddingBottom + availablePaddingY / 2);
             } else {
                 // Pad the top and bottom of the workspace with search/hotseat bar sizes
-                padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
+                padding.set(desiredWorkspaceLeftRightMarginPx,
                         topWorkspacePadding,
-                        desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
+                        desiredWorkspaceLeftRightMarginPx,
                         paddingBottom);
             }
         }
         return padding;
     }
 
+    /**
+     * @return the bounds for which the open folders should be contained within
+     */
+    public Rect getAbsoluteOpenFolderBounds() {
+        if (isVerticalBarLayout()) {
+            // Folders should only appear right of the drop target bar and left of the hotseat
+            return new Rect(mInsets.left + dropTargetBarSizePx + edgeMarginPx,
+                    mInsets.top,
+                    mInsets.left + availableWidthPx - hotseatBarHeightPx - edgeMarginPx,
+                    mInsets.top + availableHeightPx);
+        } else {
+            // Folders should only appear below the drop target bar and above the hotseat
+            return new Rect(mInsets.left,
+                    mInsets.top + dropTargetBarSizePx + edgeMarginPx,
+                    mInsets.left + availableWidthPx,
+                    mInsets.top + availableHeightPx - hotseatBarHeightPx - pageIndicatorHeightPx -
+                            edgeMarginPx);
+        }
+    }
+
     private int getWorkspacePageSpacing() {
         if (isVerticalBarLayout() || isLargeTablet) {
             // In landscape mode the page spacing is set to the default.
@@ -348,7 +412,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(null).left);
+            return Math.max(defaultPageSpacingPx, getWorkspacePadding(null).left + 1);
         }
     }
 
@@ -389,7 +453,7 @@
         return visibleChildren;
     }
 
-    public void layout(Launcher launcher) {
+    public void layout(Launcher launcher, boolean notifyListeners) {
         FrameLayout.LayoutParams lp;
         boolean hasVerticalBarLayout = isVerticalBarLayout();
         final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources());
@@ -400,22 +464,23 @@
         lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
         lp.width = searchBarBounds.x;
         lp.height = searchBarBounds.y;
-        lp.topMargin = edgeMarginPx;
+        lp.topMargin = mInsets.top + edgeMarginPx;
         searchBar.setLayoutParams(lp);
 
         // Layout the workspace
         PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
-        Rect padding = getWorkspacePadding(null);
-        workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom);
+        Rect workspacePadding = getWorkspacePadding(null);
+        workspace.setPadding(workspacePadding.left, workspacePadding.top, workspacePadding.right,
+                workspacePadding.bottom);
         workspace.setPageSpacing(getWorkspacePageSpacing());
 
         View qsbContainer = launcher.getQsbContainer();
         lp = (FrameLayout.LayoutParams) qsbContainer.getLayoutParams();
-        lp.topMargin = padding.top;
+        lp.topMargin = mInsets.top + workspacePadding.top;
         qsbContainer.setLayoutParams(lp);
 
         // Layout the hotseat
-        View hotseat = launcher.findViewById(R.id.hotseat);
+        Hotseat hotseat = (Hotseat) launcher.findViewById(R.id.hotseat);
         lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams();
         // We want the edges of the hotseat to line up with the edges of the workspace, but the
         // icons in the hotseat are a different size, and so don't line up perfectly. To account for
@@ -428,26 +493,27 @@
             // 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 = hotseatBarHeightPx;
+            lp.width = hotseatBarHeightPx + mInsets.left + mInsets.right;
             lp.height = LayoutParams.MATCH_PARENT;
-            hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
+            hotseat.getLayout().setPadding(mInsets.left, mInsets.top, mInsets.right,
+                    workspacePadding.bottom);
         } else if (isTablet) {
             // Pad the hotseat with the workspace padding calculated above
             lp.gravity = Gravity.BOTTOM;
             lp.width = LayoutParams.MATCH_PARENT;
-            lp.height = hotseatBarHeightPx;
-            hotseat.findViewById(R.id.layout).setPadding(
-                    hotseatAdjustment + padding.left, 0,
-                    hotseatAdjustment + padding.right, 2 * edgeMarginPx);
+            lp.height = hotseatBarHeightPx + mInsets.bottom;
+            hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left,
+                    hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right,
+                    mInsets.bottom);
         } else {
             // For phones, layout the hotseat without any bottom margin
             // to ensure that we have space for the folders
             lp.gravity = Gravity.BOTTOM;
             lp.width = LayoutParams.MATCH_PARENT;
-            lp.height = hotseatBarHeightPx;
-            hotseat.findViewById(R.id.layout).setPadding(
-                    hotseatAdjustment + padding.left, 0,
-                    hotseatAdjustment + padding.right, 0);
+            lp.height = hotseatBarHeightPx + mInsets.bottom;
+            hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left,
+                    hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right,
+                    mInsets.bottom);
         }
         hotseat.setLayoutParams(lp);
 
@@ -455,11 +521,21 @@
         View pageIndicator = launcher.findViewById(R.id.page_indicator);
         if (pageIndicator != null) {
             lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams();
-            if (!hasVerticalBarLayout) {
+            if (isVerticalBarLayout()) {
+                if (mInsets.left > 0) {
+                    lp.leftMargin = mInsets.left + pageIndicatorLandGutterLeftNavBarPx -
+                            lp.width - pageIndicatorLandWorkspaceOffsetPx;
+                } else if (mInsets.right > 0) {
+                    lp.leftMargin = pageIndicatorLandGutterRightNavBarPx - lp.width -
+                            pageIndicatorLandWorkspaceOffsetPx;
+                }
+                lp.bottomMargin = workspacePadding.bottom;
+            } else {
                 // Put the page indicators above the hotseat
                 lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
                 lp.width = LayoutParams.WRAP_CONTENT;
-                lp.bottomMargin = hotseatBarHeightPx;
+                lp.height = pageIndicatorHeightPx;
+                lp.bottomMargin = hotseatBarHeightPx + mInsets.bottom;
             }
             pageIndicator.setLayoutParams(lp);
         }
@@ -468,7 +544,7 @@
         ViewGroup overviewMode = launcher.getOverviewPanel();
         if (overviewMode != null) {
             lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams();
-            lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+            lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
 
             int visibleChildCount = getVisibleChildCount(overviewMode);
             int totalItemWidth = visibleChildCount * overviewModeBarItemWidthPx;
@@ -476,30 +552,15 @@
 
             lp.width = Math.min(availableWidthPx, maxWidth);
             lp.height = getOverviewModeButtonBarHeight();
+            // Center the overview buttons on the workspace page
+            lp.leftMargin = workspacePadding.left + (availableWidthPx -
+                    workspacePadding.left - workspacePadding.right - lp.width) / 2;
             overviewMode.setLayoutParams(lp);
+        }
 
-            if (lp.width > totalItemWidth && visibleChildCount > 1) {
-                // We have enough space. Lets add some margin too.
-                int margin = (lp.width - totalItemWidth) / (visibleChildCount-1);
-                View lastChild = null;
-
-                // Set margin of all visible children except the last visible child
-                for (int i = 0; i < visibleChildCount; i++) {
-                    if (lastChild != null) {
-                        MarginLayoutParams clp = (MarginLayoutParams) lastChild.getLayoutParams();
-                        if (isLayoutRtl) {
-                            clp.leftMargin = margin;
-                        } else {
-                            clp.rightMargin = margin;
-                        }
-                        lastChild.setLayoutParams(clp);
-                        lastChild = null;
-                    }
-                    View thisChild = overviewMode.getChildAt(i);
-                    if (thisChild.getVisibility() != View.GONE) {
-                        lastChild = thisChild;
-                    }
-                }
+        if (notifyListeners) {
+            for (int i = mListeners.size() - 1; i >= 0; i--) {
+                mListeners.get(i).onLauncherLayoutChanged();
             }
         }
     }
@@ -517,17 +578,20 @@
     }
 
 
-    public static final int getContainerPadding(Context context, int availableWidth) {
+    /**
+     * @return the left/right paddings for all containers.
+     */
+    public final int[] getContainerPadding(Context context) {
         Resources res = context.getResources();
 
-        int maxSize = res.getDimensionPixelSize(R.dimen.container_max_width);
-        int minMargin = res.getDimensionPixelSize(R.dimen.container_min_margin);
-
-        if (maxSize > 0) {
-            return Math.max(minMargin, (availableWidth - maxSize) / 2);
-        } else {
-            return Math.max(minMargin,
-                    (int) res.getFraction(R.fraction.container_margin, availableWidth, 1));
+        // No paddings for portrait phone
+        if (isPhone && !isVerticalBarLayout()) {
+            return new int[] {0, 0};
         }
+
+        // In landscape, we just match the vertical display width
+        int containerWidth = heightPx;
+        int padding = (availableWidthPx - containerWidth) / 2;
+        return new int[]{ padding, padding };
     }
 }
diff --git a/src/com/android/launcher3/HolographicOutlineHelper.java b/src/com/android/launcher3/HolographicOutlineHelper.java
index 1cff8ef..427acea 100644
--- a/src/com/android/launcher3/HolographicOutlineHelper.java
+++ b/src/com/android/launcher3/HolographicOutlineHelper.java
@@ -79,7 +79,7 @@
      * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
      * bitmap.
      */
-    void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
+    public void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
             int outlineColor) {
         applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true);
     }
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index b75d2c0..084de70 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -38,7 +39,7 @@
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 
 public class Hotseat extends FrameLayout
-        implements UserEventDispatcher.LaunchSourceProvider, Insettable {
+        implements UserEventDispatcher.LaunchSourceProvider {
 
     private CellLayout mContent;
 
@@ -48,9 +49,6 @@
     private final boolean mHasVerticalHotseat;
 
     @ViewDebug.ExportedProperty(category = "launcher")
-    private Rect mInsets = new Rect();
-
-    @ViewDebug.ExportedProperty(category = "launcher")
     private int mBackgroundColor;
     @ViewDebug.ExportedProperty(category = "launcher")
     private ColorDrawable mBackground;
@@ -67,7 +65,9 @@
         super(context, attrs, defStyle);
         mLauncher = (Launcher) context;
         mHasVerticalHotseat = mLauncher.getDeviceProfile().isVerticalBarLayout();
-        mBackground = new ColorDrawable();
+        mBackgroundColor = ColorUtils.setAlphaComponent(
+                context.getColor(R.color.all_apps_container_color), 0);
+        mBackground = new ColorDrawable(mBackgroundColor);
         setBackground(mBackground);
     }
 
@@ -177,28 +177,6 @@
         targetParent.containerType = LauncherLogProto.HOTSEAT;
     }
 
-    //Overridden so that the background color extends behind the navigation buttons.
-    @Override
-    public void setInsets(Rect insets) {
-        int rightInset = insets.right - mInsets.right;
-        int bottomInset = insets.bottom - mInsets.bottom;
-        mInsets.set(insets);
-        LayoutParams lp = (LayoutParams) getLayoutParams();
-        if (mHasVerticalHotseat) {
-            setPadding(getPaddingLeft(), getPaddingTop(),
-            getPaddingRight() + rightInset, getPaddingBottom());
-            if (lp.width != LayoutParams.MATCH_PARENT && lp.width != LayoutParams.WRAP_CONTENT) {
-                lp.width += rightInset;
-            }
-        } else {
-            setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
-            getPaddingBottom() + bottomInset);
-            if (lp.height != LayoutParams.MATCH_PARENT && lp.height != LayoutParams.WRAP_CONTENT) {
-                lp.height += bottomInset;
-            }
-        }
-    }
-
     public void updateColor(ExtractedColors extractedColors, boolean animate) {
         if (!mHasVerticalHotseat) {
             int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX, Color.TRANSPARENT);
@@ -227,7 +205,7 @@
         }
     }
 
-    public int getBackgroundDrawableAlpha() {
-        return Color.alpha(mBackgroundColor);
+    public int getBackgroundDrawableColor() {
+        return mBackgroundColor;
     }
 }
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 9ce941b..a49162c 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -72,6 +72,7 @@
     private static final String EMPTY_CLASS_NAME = ".";
 
     private static final boolean DEBUG = false;
+    private static final boolean DEBUG_IGNORE_CACHE = false;
 
     private static final int LOW_RES_SCALE_FACTOR = 5;
 
@@ -552,7 +553,7 @@
             mCache.put(cacheKey, entry);
 
             // Check the DB first.
-            if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
+            if (!getEntryFromDB(cacheKey, entry, useLowResIcon) || DEBUG_IGNORE_CACHE) {
                 if (info != null) {
                     entry.icon = Utilities.createBadgedIconBitmap(
                             mIconProvider.getIcon(info, mIconDpi), info.getUser(),
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 4e6911c..38545e2 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -67,6 +67,7 @@
     /**
      * The minimum number of predicted apps in all apps.
      */
+    @Deprecated
     int minAllAppsPredictionColumns;
 
     /**
@@ -103,11 +104,6 @@
 
     InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, int maapc,
             float is, float its, int hs, float his, int dlId) {
-        // Ensure that we have an odd number of hotseat items (since we need to place all apps)
-        if (hs % 2 == 0) {
-            throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
-        }
-
         name = n;
         minWidthDps = w;
         minHeightDps = h;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b7f033e..f8b7c74 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -117,6 +117,7 @@
 import com.android.launcher3.pageindicators.PageIndicator;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.shortcuts.DeepShortcutsContainer;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.MultiHashMap;
 import com.android.launcher3.util.PackageManagerHelper;
@@ -197,6 +198,7 @@
 
     static final String INTRO_SCREEN_DISMISSED = "launcher.intro_screen_dismissed";
     static final String FIRST_RUN_ACTIVITY_DISPLAYED = "launcher.first_run_activity_displayed";
+    static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
 
     /** The different states that Launcher can be in. */
     enum State { NONE, WORKSPACE, WORKSPACE_SPRING_LOADED, APPS, APPS_SPRING_LOADED,
@@ -287,6 +289,7 @@
     private IconCache mIconCache;
     private ExtractedColors mExtractedColors;
     private LauncherAccessibilityDelegate mAccessibilityDelegate;
+    private boolean mIsResumeFromActionScreenOff;
     @Thunk boolean mUserPresent = true;
     private boolean mVisible = false;
     private boolean mHasFocus = false;
@@ -438,7 +441,7 @@
         setContentView(R.layout.launcher);
 
         setupViews();
-        mDeviceProfile.layout(this);
+        mDeviceProfile.layout(this, false /* notifyListeners */);
         mExtractedColors = new ExtractedColors();
         loadExtractedColorsAndColorItems();
 
@@ -521,6 +524,11 @@
         }
     }
 
+    public void onInsetsChanged(Rect insets) {
+        mDeviceProfile.updateInsets(insets);
+        mDeviceProfile.layout(this, true /* notifyListeners */);
+    }
+
     /**
      * Call this after onCreate to set or clear overlay.
      */
@@ -1073,6 +1081,10 @@
             InstallShortcutReceiver.disableAndFlushInstallQueue(this);
         }
 
+        if (shouldShowDiscoveryBounce()) {
+            mAllAppsController.showDiscoveryBounce();
+        }
+        mIsResumeFromActionScreenOff = false;
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onResume();
         }
@@ -1617,6 +1629,7 @@
                         mAppsView.reset();
                     }
                 }
+                mIsResumeFromActionScreenOff = true;
             } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
                 mUserPresent = true;
                 updateAutoAdvanceState();
@@ -2009,9 +2022,9 @@
     }
 
     @Override
-    public void startActivityForResult(Intent intent, int requestCode) {
+    public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
         onStartForResult(requestCode);
-        super.startActivityForResult(intent, requestCode);
+        super.startActivityForResult(intent, requestCode, options);
     }
 
     @Override
@@ -2498,7 +2511,8 @@
             if (v instanceof FolderIcon) {
                 onClickFolderIcon(v);
             }
-        } else if (v instanceof PageIndicator || (v == mAllAppsButton && mAllAppsButton != null)) {
+        } else if ((FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && v instanceof PageIndicator) ||
+                (v == mAllAppsButton && mAllAppsButton != null)) {
             onClickAllAppsButton(v);
         } else if (tag instanceof AppInfo) {
             startAppShortcutOrInfoActivity(v);
@@ -2585,6 +2599,8 @@
     protected void onClickAllAppsButton(View v) {
         if (LOGD) Log.d(TAG, "onClickAllAppsButton");
         if (!isAppsViewVisible()) {
+            getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.TAP,
+                    LauncherLogProto.ALL_APPS_BUTTON);
             showAppsView(true /* animated */, false /* resetListToTop */,
                     true /* updatePredictedApps */, false /* focusSearchBar */);
         }
@@ -2593,6 +2609,8 @@
     protected void onLongClickAllAppsButton(View v) {
         if (LOGD) Log.d(TAG, "onLongClickAllAppsButton");
         if (!isAppsViewVisible()) {
+            getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.LONGPRESS,
+                    LauncherLogProto.ALL_APPS_BUTTON);
             showAppsView(true /* animated */, false /* resetListToTop */,
                     true /* updatePredictedApps */, true /* focusSearchBar */);
         }
@@ -2725,10 +2743,12 @@
 
         int pageScroll = mWorkspace.getScrollForPage(mWorkspace.getPageNearestToCenterOfScreen());
         float offset = mWorkspace.mWallpaperOffset.wallpaperOffsetForScroll(pageScroll);
-        startActivityForResult(new Intent(Intent.ACTION_SET_WALLPAPER)
+
+        Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
                 .setPackage(pickerPackage)
-                .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset),
-                REQUEST_PICK_WALLPAPER);
+                .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset);
+        intent.setSourceBounds(getViewBounds(v));
+        startActivityForResult(intent, REQUEST_PICK_WALLPAPER, getActivityLaunchOptions(v));
     }
 
     /**
@@ -2876,6 +2896,12 @@
         return null;
     }
 
+    private Rect getViewBounds(View v) {
+        int[] pos = new int[2];
+        v.getLocationOnScreen(pos);
+        return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
+    }
+
     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();
@@ -2896,10 +2922,7 @@
         // 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()));
+            intent.setSourceBounds(getViewBounds(v));
         }
         try {
             if (Utilities.ATLEAST_MARSHMALLOW && item != null
@@ -3118,7 +3141,15 @@
      * @return The open shortcuts container, or null if there is none
      */
     public DeepShortcutsContainer getOpenShortcutsContainer() {
-        return (DeepShortcutsContainer) mDragLayer.findViewById(R.id.deep_shortcuts_container);
+        // Iterate in reverse order. Shortcuts container is added later to the dragLayer,
+        // and will be one of the last views.
+        for (int i = mDragLayer.getChildCount() - 1; i >= 0; i--) {
+            View child = mDragLayer.getChildAt(i);
+            if (child instanceof DeepShortcutsContainer) {
+                return (DeepShortcutsContainer) child;
+            }
+        }
+        return null;
     }
 
     @Override
@@ -3127,7 +3158,8 @@
         if (isWorkspaceLocked()) return false;
         if (mState != State.WORKSPACE) return false;
 
-        if (v == mAllAppsButton && mAllAppsButton != null) {
+        if ((FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && v instanceof PageIndicator) ||
+                (v == mAllAppsButton && mAllAppsButton != null)) {
             onLongClickAllAppsButton(v);
             return true;
         }
@@ -3325,6 +3357,7 @@
      */
     public void showAppsView(boolean animated, boolean resetListToTop, boolean updatePredictedApps,
             boolean focusSearchBar) {
+        markAppsViewShown();
         if (resetListToTop) {
             mAppsView.scrollToTop();
         }
@@ -4335,10 +4368,6 @@
                 !mSharedPrefs.getBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, false);
     }
 
-    protected boolean hasRunFirstRunActivity() {
-        return mSharedPrefs.getBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, false);
-    }
-
     public boolean showFirstRunActivity() {
         if (shouldRunFirstRunActivity() &&
                 hasFirstRunActivity()) {
@@ -4358,6 +4387,29 @@
         editor.apply();
     }
 
+    private void markAppsViewShown() {
+        if (mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false)) {
+            return;
+        }
+        mSharedPrefs.edit().putBoolean(APPS_VIEW_SHOWN, true).apply();
+    }
+
+    private boolean shouldShowDiscoveryBounce() {
+        if (mState != mState.WORKSPACE) {
+            return false;
+        }
+        if (mLauncherCallbacks != null && mLauncherCallbacks.shouldShowDiscoveryBounce()) {
+            return true;
+        }
+        if (!mIsResumeFromActionScreenOff) {
+            return false;
+        }
+        if (mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false)) {
+            return false;
+        }
+        return true;
+    }
+
     /**
      * To be overridden by subclasses to indicate that there is an in-activity full-screen intro
      * screen that must be displayed and dismissed.
@@ -4433,13 +4485,6 @@
                 UserHandleCompat.myUserHandle());
     }
 
-    // TODO: This method should be a part of LauncherSearchCallback
-    public void startDrag(View dragView, ItemInfo dragInfo, DragSource source) {
-        dragView.setTag(dragInfo);
-        mWorkspace.onExternalDragStartedWithItem(dragView);
-        mWorkspace.beginExternalDragShared(dragView, source);
-    }
-
     protected void moveWorkspaceToDefaultScreen() {
         mWorkspace.moveToDefaultScreen(false);
     }
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index e971631..2bbe0fb 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -110,4 +110,6 @@
      *                  but for implementation purposes is passed around as an object.
      */
     public void setLauncherSearchCallback(Object callbacks);
+
+    public boolean shouldShowDiscoveryBounce();
 }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index a75edb7..ddd60c8 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -2782,7 +2782,7 @@
                 for (UserHandleCompat user : mUserManager.getUserProfiles()) {
                     List<ShortcutInfoCompat> shortcuts = mDeepShortcutManager
                             .queryForAllShortcuts(user);
-                    updateDeepShortcutMap(null, shortcuts);
+                    updateDeepShortcutMap(null, user, shortcuts);
                 }
                 synchronized (LoaderTask.this) {
                     if (mStopped) {
@@ -2804,13 +2804,17 @@
         }
     }
 
-    // Clear all the shortcuts for the given package, and re-add the new shortcuts.
-    private void updateDeepShortcutMap(String packageName, List<ShortcutInfoCompat> shortcuts) {
-        // Remove all keys associated with the given package.
+    /**
+     * Clear all the shortcuts for the given package, and re-add the new shortcuts.
+     */
+    private void updateDeepShortcutMap(
+            String packageName, UserHandleCompat user, List<ShortcutInfoCompat> shortcuts) {
         if (packageName != null) {
             Iterator<ComponentKey> keysIter = mBgDeepShortcutMap.keySet().iterator();
             while (keysIter.hasNext()) {
-                if (keysIter.next().componentName.getPackageName().equals(packageName)) {
+                ComponentKey next = keysIter.next();
+                if (next.componentName.getPackageName().equals(packageName)
+                        && next.user.equals(user)) {
                     keysIter.remove();
                 }
             }
@@ -3336,7 +3340,7 @@
             bindUpdatedShortcuts(updatedShortcutInfos, mUser);
 
             // Update the deep shortcut map, in case the list of ids has changed for an activity.
-            updateDeepShortcutMap(mPackageName, mShortcuts);
+            updateDeepShortcutMap(mPackageName, mUser, mShortcuts);
             bindDeepShortcuts();
         }
     }
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 7bcf5d0..643d48a 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -44,6 +44,7 @@
     @TargetApi(23)
     @Override
     protected boolean fitSystemWindows(Rect insets) {
+        boolean rawInsetsChanged = !mInsets.equals(insets);
         mDrawSideInsetBar = (insets.right > 0 || insets.left > 0) &&
                 (!Utilities.ATLEAST_MARSHMALLOW ||
                 getContext().getSystemService(ActivityManager.class).isLowRamDevice());
@@ -61,6 +62,12 @@
             }
         }
 
+        if (rawInsetsChanged) {
+            // Update the grid again
+            Launcher launcher = Launcher.getLauncher(getContext());
+            launcher.onInsetsChanged(insets);
+        }
+
         return true; // I'll take it from here
     }
 
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index c3b7fe7..1fe0813 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -35,8 +35,8 @@
 import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.CircleRevealOutlineProvider;
 import com.android.launcher3.util.Thunk;
-import com.android.launcher3.util.UiThreadCircularReveal;
 import com.android.launcher3.widget.WidgetsContainerView;
 
 import java.util.HashMap;
@@ -250,7 +250,7 @@
 
         final View contentView = toView.getContentView();
         playCommonTransitionAnimations(toWorkspaceState, fromView, toView,
-                animated, initialized, animation, revealDuration, layerViews);
+                animated, initialized, animation, layerViews);
         if (!animated || !initialized) {
             if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
                     toWorkspaceState == Workspace.State.NORMAL_HIDDEN) {
@@ -345,8 +345,8 @@
                 float startRadius = pCb.getMaterialRevealViewStartFinalRadius();
                 AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener(
                         revealView, buttonView);
-                Animator reveal = UiThreadCircularReveal.createCircularReveal(revealView, width / 2,
-                        height / 2, startRadius, revealRadius);
+                Animator reveal = new CircleRevealOutlineProvider(width / 2, height / 2,
+                        startRadius, revealRadius).createRevealAnimator(revealView);
                 reveal.setDuration(revealDuration);
                 reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
                 if (listener != null) {
@@ -414,11 +414,22 @@
 
             return animation;
         } else if (animType == PULLUP) {
+            // We are animating the content view alpha, so ensure we have a layer for it
+            layerViews.put(contentView, BUILD_AND_SET_LAYER);
+
             animation.addListener(new AnimatorListenerAdapter() {
                   @Override
                   public void onAnimationEnd(Animator animation) {
                       dispatchOnLauncherTransitionEnd(fromView, animated, false);
                       dispatchOnLauncherTransitionEnd(toView, animated, false);
+
+                      // Disable all necessary layers
+                      for (View v : layerViews.keySet()) {
+                          if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+                              v.setLayerType(View.LAYER_TYPE_NONE, null);
+                          }
+                      }
+
                       cleanupAnimation();
                       pCb.onTransitionComplete();
                   }
@@ -435,9 +446,20 @@
                     // we waited for a layout/draw pass
                     if (mCurrentAnimation != stateAnimation)
                         return;
+
                     dispatchOnLauncherTransitionStart(fromView, animated, false);
                     dispatchOnLauncherTransitionStart(toView, animated, false);
 
+                    // Enable all necessary layers
+                    for (View v : layerViews.keySet()) {
+                        if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+                            v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                        }
+                        if (Utilities.ATLEAST_LOLLIPOP && v.isAttachedToWindow()) {
+                            v.buildLayer();
+                        }
+                    }
+
                     toView.requestFocus();
                     stateAnimation.start();
                 }
@@ -453,7 +475,7 @@
      */
     private void playCommonTransitionAnimations(
             Workspace.State toWorkspaceState, View fromView, View toView,
-            boolean animated, boolean initialized, AnimatorSet animation, int revealDuration,
+            boolean animated, boolean initialized, AnimatorSet animation,
             HashMap<View, Integer> layerViews) {
         // Create the workspace animation.
         // NOTE: this call apparently also sets the state for the workspace if !animated
@@ -580,7 +602,7 @@
         boolean multiplePagesVisible = toWorkspaceState.hasMultipleVisiblePages;
 
         playCommonTransitionAnimations(toWorkspaceState, fromWorkspace, null,
-                animated, animated, animation, revealDuration, layerViews);
+                animated, animated, animation, layerViews);
 
         if (animated) {
             dispatchOnLauncherTransitionPrepare(fromWorkspace, animated, multiplePagesVisible);
@@ -661,6 +683,8 @@
                 res.getInteger(R.integer.config_overlayItemsAlphaStagger);
 
         final View toView = mLauncher.getWorkspace();
+        final View revealView = fromView.getRevealView();
+        final View contentView = fromView.getContentView();
 
         final HashMap<View, Integer> layerViews = new HashMap<>();
 
@@ -673,7 +697,7 @@
         boolean multiplePagesVisible = toWorkspaceState.hasMultipleVisiblePages;
 
         playCommonTransitionAnimations(toWorkspaceState, fromView, toView,
-                animated, initialized, animation, revealDuration, layerViews);
+                animated, initialized, animation, layerViews);
         if (!animated || !initialized) {
             if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
                     fromWorkspaceState == Workspace.State.NORMAL_HIDDEN) {
@@ -695,9 +719,6 @@
             return null;
         }
         if (animType == CIRCULAR_REVEAL) {
-            final View revealView = fromView.getRevealView();
-            final View contentView = fromView.getContentView();
-
             // hideAppsCustomizeHelper is called in some cases when it is already hidden
             // don't perform all these no-op animations. In particularly, this was causing
             // the all-apps button to pop in and out.
@@ -789,8 +810,8 @@
                     float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
                     AnimatorListenerAdapter listener =
                             pCb.getMaterialRevealViewAnimatorListener(revealView, buttonView);
-                    Animator reveal = UiThreadCircularReveal.createCircularReveal(revealView, width / 2,
-                            height / 2, revealRadius, finalRadius);
+                    Animator reveal = new CircleRevealOutlineProvider(width / 2, height / 2,
+                            revealRadius, finalRadius).createRevealAnimator(revealView);
                     reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
                     reveal.setDuration(revealDuration);
                     reveal.setStartDelay(itemsAlphaStagger);
@@ -864,6 +885,9 @@
 
             return animation;
         } else if (animType == PULLUP) {
+            // We are animating the content view alpha, so ensure we have a layer for it
+            layerViews.put(contentView, BUILD_AND_SET_LAYER);
+
             animation.addListener(new AnimatorListenerAdapter() {
                 boolean canceled = false;
                 @Override
@@ -876,10 +900,19 @@
                     if (canceled) return;
                     dispatchOnLauncherTransitionEnd(fromView, animated, false);
                     dispatchOnLauncherTransitionEnd(toView, animated, false);
+
                     // Run any queued runnables
                     if (onCompleteRunnable != null) {
                         onCompleteRunnable.run();
                     }
+
+                    // Disable all necessary layers
+                    for (View v : layerViews.keySet()) {
+                        if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+                            v.setLayerType(View.LAYER_TYPE_NONE, null);
+                        }
+                    }
+
                     cleanupAnimation();
                     pCb.onTransitionComplete();
                 }
@@ -898,9 +931,20 @@
                     // we waited for a layout/draw pass
                     if (mCurrentAnimation != stateAnimation)
                         return;
+
                     dispatchOnLauncherTransitionStart(fromView, animated, false);
                     dispatchOnLauncherTransitionStart(toView, animated, false);
 
+                    // Enable all necessary layers
+                    for (View v : layerViews.keySet()) {
+                        if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+                            v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                        }
+                        if (Utilities.ATLEAST_LOLLIPOP && v.isAttachedToWindow()) {
+                            v.buildLayer();
+                        }
+                    }
+
                     // Focus the new view
                     toView.requestFocus();
                     stateAnimation.start();
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index c016aa9..d98734b 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -129,7 +129,7 @@
             if (child instanceof LauncherAppWidgetHostView) {
                 // Widgets have their own padding, so skip
             } else {
-                // Otherwise, center the icon
+                // Otherwise, center the icon/folder
                 int cHeight = getCellContentHeight();
                 int cellPaddingY = (int) Math.max(0, ((lp.height - cHeight) / 2f));
                 int cellPaddingX = (int) (grid.edgeMarginPx / 2f);
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index b8f0ec9..a9f73c2 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -307,7 +307,7 @@
                 .getShortcutIconDrawable(shortcutInfo,
                         launcherAppState.getInvariantDeviceProfile().fillResIconDpi);
         Bitmap icon = unbadgedIcon == null ? null
-                : Utilities.createBadgedIconBitmap(unbadgedIcon, user, context);
+                : Utilities.createBadgedIconBitmapWithShadow(unbadgedIcon, user, context);
         setIcon(icon != null ? icon : launcherAppState.getIconCache().getDefaultIcon(user));
     }
 
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index cedbe74..ef78195 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -40,6 +40,7 @@
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
@@ -64,6 +65,7 @@
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.graphics.ShadowGenerator;
 import com.android.launcher3.util.IconNormalizer;
 
 import java.io.ByteArrayOutputStream;
@@ -111,8 +113,8 @@
                 && "NMR1".compareTo(VERSION.CODENAME) <= 0;
     }
 
-    // TODO: use Build.VERSION_CODES when available
-    public static final boolean ATLEAST_MARSHMALLOW = Build.VERSION.SDK_INT >= 23;
+    public static final boolean ATLEAST_MARSHMALLOW =
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
 
     public static final boolean ATLEAST_LOLLIPOP_MR1 =
             Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1;
@@ -244,7 +246,7 @@
     public static Bitmap createBadgedIconBitmap(
             Drawable icon, UserHandleCompat user, Context context) {
         float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
-                1 : IconNormalizer.getInstance().getScale(icon);
+                1 : IconNormalizer.getInstance().getScale(icon, null);
         Bitmap bitmap = createIconBitmap(icon, context, scale);
         if (Utilities.ATLEAST_LOLLIPOP && user != null
                 && !UserHandleCompat.myUserHandle().equals(user)) {
@@ -262,6 +264,34 @@
     }
 
     /**
+     * Same as {@link #createBadgedIconBitmap} but adds a shadow before badging the icon
+     */
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public static Bitmap createBadgedIconBitmapWithShadow(
+            Drawable icon, UserHandleCompat user, Context context) {
+        RectF iconBounds = new RectF();
+        float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
+                1 : IconNormalizer.getInstance().getScale(icon, iconBounds);
+        scale = Math.min(scale, ShadowGenerator.getScaleForBounds(iconBounds));
+
+        Bitmap bitmap = createIconBitmap(icon, context, scale);
+        bitmap = ShadowGenerator.getInstance().recreateIcon(bitmap);
+        if (Utilities.ATLEAST_LOLLIPOP && user != null
+                && !UserHandleCompat.myUserHandle().equals(user)) {
+            BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap);
+            Drawable badged = context.getPackageManager().getUserBadgedIcon(
+                    drawable, user.getUser());
+            if (badged instanceof BitmapDrawable) {
+                return ((BitmapDrawable) badged).getBitmap();
+            } else {
+                return createIconBitmap(badged, context);
+            }
+        } else {
+            return bitmap;
+        }
+    }
+
+    /**
      * Returns a bitmap suitable for the all apps view.
      */
     public static Bitmap createIconBitmap(Drawable icon, Context context) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 344c389..946c306 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -35,11 +35,9 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
-import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Handler;
@@ -53,11 +51,9 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
-import android.widget.Space;
 import android.widget.TextView;
 
 import com.android.launcher3.Launcher.CustomContentCallbacks;
@@ -73,6 +69,7 @@
 import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.dragndrop.DragScroller;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.SpringLoadedDragController;
@@ -250,7 +247,7 @@
 
     private HolographicOutlineHelper mOutlineHelper;
     @Thunk Bitmap mDragOutline = null;
-    public static final int DRAG_BITMAP_PADDING = 2;
+    public static final int DRAG_BITMAP_PADDING = DragPreviewProvider.DRAG_BITMAP_PADDING;
     private boolean mWorkspaceFadeInAdjacentScreens;
 
     final WallpaperOffsetInterpolator mWallpaperOffset;
@@ -315,6 +312,7 @@
     // Total over scrollX in the overlay direction.
     private float mOverlayTranslation;
     private int mFirstPageScrollX;
+    private boolean mIgnoreQsbScroll;
 
     // Handles workspace state transitions
     private WorkspaceStateTransitionAnimation mStateTransitionAnimation;
@@ -366,16 +364,7 @@
 
     @Override
     public void setInsets(Rect insets) {
-        int extraLeftPadding = insets.left - mInsets.left;
         mInsets.set(insets);
-        if (extraLeftPadding != 0) {
-            /**
-             * Initial layout assumes that the insets is on the right,
-             * {@link DeviceProfile#getWorkspacePadding()}. Compensate for the difference.
-             */
-            setPadding(getPaddingLeft() + extraLeftPadding, getPaddingTop(),
-                    getPaddingRight() - extraLeftPadding, getPaddingBottom());
-        }
 
         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);
         if (customScreen != null) {
@@ -542,8 +531,9 @@
      */
     public Folder getOpenFolder() {
         DragLayer dragLayer = mLauncher.getDragLayer();
-        int count = dragLayer.getChildCount();
-        for (int i = 0; i < count; i++) {
+        // Iterate in reverse order. Folder is added later to the dragLayer,
+        // and will be one of the last views.
+        for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
             View child = dragLayer.getChildAt(i);
             if (child instanceof Folder) {
                 Folder folder = (Folder) child;
@@ -1395,8 +1385,10 @@
     }
 
     private void onWorkspaceOverallScrollChanged() {
-        mLauncher.getQsbContainer().setTranslationX(
-                mOverlayTranslation + mFirstPageScrollX - getScrollX());
+        if (!mIgnoreQsbScroll) {
+            mLauncher.getQsbContainer().setTranslationX(
+                    mOverlayTranslation + mFirstPageScrollX - getScrollX());
+        }
     }
 
     @Override
@@ -1517,21 +1509,26 @@
     /**
      * Moves the Hotseat UI in the provided direction.
      * @param direction the direction to move the workspace
-     * @param translation the amound of shift.
+     * @param translation the amount of shift.
      * @param alpha the alpha for the hotseat page
      */
     public void setHotseatTranslationAndAlpha(Direction direction, float translation, float alpha) {
         Property<View, Float> property = direction.viewProperty;
-        property.set(mPageIndicator, translation);
+        // Skip the page indicator movement in the vertical bar layout
+        if (direction != Direction.Y || !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+            property.set(mPageIndicator, translation);
+        }
         property.set(mLauncher.getHotseat(), translation);
         setHotseatAlphaAtIndex(alpha, direction.ordinal());
     }
 
     private void setHotseatAlphaAtIndex(float alpha, int index) {
         mHotseatAlpha[index] = alpha;
-        float finalAlpha = mHotseatAlpha[0] * mHotseatAlpha[1] * mHotseatAlpha[2];
+        final float hotseatAlpha = mHotseatAlpha[0] * mHotseatAlpha[1] * mHotseatAlpha[2];
+        final float pageIndicatorAlpha = mHotseatAlpha[0] * mHotseatAlpha[2];
 
-        mLauncher.getHotseat().setAlpha(finalAlpha);
+        mLauncher.getHotseat().setAlpha(hotseatAlpha);
+        mPageIndicator.setAlpha(pageIndicatorAlpha);
     }
 
     public ValueAnimator createHotseatAlphaAnimator(float finalValue) {
@@ -1803,6 +1800,33 @@
         super.onLayout(changed, left, top, right, bottom);
         mFirstPageScrollX = getScrollForPage(0);
         onWorkspaceOverallScrollChanged();
+
+        final LayoutTransition transition = getLayoutTransition();
+        // If the transition is running defer updating max scroll, as some empty pages could
+        // still be present, and a max scroll change could cause sudden jumps in scroll.
+        if (transition != null && transition.isRunning()) {
+            transition.addTransitionListener(new LayoutTransition.TransitionListener() {
+
+                @Override
+                public void startTransition(LayoutTransition transition, ViewGroup container,
+                                            View view, int transitionType) {
+                    mIgnoreQsbScroll = true;
+                }
+
+                @Override
+                public void endTransition(LayoutTransition transition, ViewGroup container,
+                                          View view, int transitionType) {
+                    // Wait until all transitions are complete.
+                    if (!transition.isRunning()) {
+                        mIgnoreQsbScroll = false;
+                        transition.removeTransitionListener(this);
+                        mFirstPageScrollX = getScrollForPage(0);
+                        onWorkspaceOverallScrollChanged();
+                    }
+                }
+            });
+        }
+
     }
 
     @Override
@@ -1955,56 +1979,6 @@
                 position[0], position[1], 0, null);
     }
 
-    /*
-    *
-    * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we
-    * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
-    *
-    * These methods mark the appropriate pages as accepting drops (which alters their visual
-    * appearance).
-    *
-    */
-    private static Rect getDrawableBounds(Drawable d) {
-        Rect bounds = new Rect();
-        d.copyBounds(bounds);
-        if (bounds.width() == 0 || bounds.height() == 0) {
-            bounds.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
-        } else {
-            bounds.offsetTo(0, 0);
-        }
-        if (d instanceof PreloadIconDrawable) {
-            int inset = -((PreloadIconDrawable) d).getOutset();
-            bounds.inset(inset, inset);
-        }
-        return bounds;
-    }
-
-    public void onExternalDragStartedWithItem(View v) {
-        // Compose a drag bitmap with the view scaled to the icon size
-        DeviceProfile grid = mLauncher.getDeviceProfile();
-        int iconSize = grid.iconSizePx;
-        int bmpWidth = v.getMeasuredWidth();
-        int bmpHeight = v.getMeasuredHeight();
-
-        // If this is a text view, use its drawable instead
-        if (v instanceof TextView) {
-            Drawable d = getTextViewIcon((TextView) v);
-            Rect bounds = getDrawableBounds(d);
-            bmpWidth = bounds.width();
-            bmpHeight = bounds.height();
-        }
-
-        // Compose the bitmap to create the icon from
-        Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight,
-                Bitmap.Config.ARGB_8888);
-        mCanvas.setBitmap(b);
-        drawDragView(v, mCanvas, 0);
-        mCanvas.setBitmap(null);
-
-        // The outline is used to visualize where the item will land if dropped
-        mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, iconSize, iconSize, true);
-    }
-
     public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {
         // Find a page that has enough space to place this widget (after rearranging/resizing).
         // Start at the current page and search right (on LTR) until finding a page with enough
@@ -2278,89 +2252,6 @@
     }
 
     /**
-     * Draw the View v into the given Canvas.
-     *
-     * @param v the view to draw
-     * @param destCanvas the canvas to draw on
-     * @param padding the horizontal and vertical padding to use when drawing
-     */
-    private static void drawDragView(View v, Canvas destCanvas, int padding) {
-        destCanvas.save();
-        if (v instanceof TextView) {
-            Drawable d = getTextViewIcon((TextView) v);
-            Rect bounds = getDrawableBounds(d);
-            destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);
-            d.draw(destCanvas);
-        } else {
-            final Rect clipRect = sTempRect;
-            v.getDrawingRect(clipRect);
-
-            boolean textVisible = false;
-            if (v instanceof FolderIcon) {
-                // For FolderIcons the text can bleed into the icon area, and so we need to
-                // hide the text completely (which can't be achieved by clipping).
-                if (((FolderIcon) v).getTextVisible()) {
-                    ((FolderIcon) v).setTextVisible(false);
-                    textVisible = true;
-                }
-            }
-            destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);
-            destCanvas.clipRect(clipRect, Op.REPLACE);
-            v.draw(destCanvas);
-
-            // Restore text visibility of FolderIcon if necessary
-            if (textVisible) {
-                ((FolderIcon) v).setTextVisible(true);
-            }
-        }
-        destCanvas.restore();
-    }
-
-    /**
-     * Returns a new bitmap to show when the given View is being dragged around.
-     * Responsibility for the bitmap is transferred to the caller.
-     * @param expectedPadding padding to add to the drag view. If a different padding was used
-     * its value will be changed
-     */
-    public Bitmap createDragBitmap(View v, AtomicInteger expectedPadding) {
-        Bitmap b;
-
-        int padding = expectedPadding.get();
-        if (v instanceof TextView) {
-            Drawable d = getTextViewIcon((TextView) v);
-            Rect bounds = getDrawableBounds(d);
-            b = Bitmap.createBitmap(bounds.width() + padding,
-                    bounds.height() + padding, Bitmap.Config.ARGB_8888);
-            expectedPadding.set(padding - bounds.left - bounds.top);
-        } else {
-            b = Bitmap.createBitmap(
-                    v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
-        }
-
-        mCanvas.setBitmap(b);
-        drawDragView(v, mCanvas, padding);
-        mCanvas.setBitmap(null);
-
-        return b;
-    }
-
-    /**
-     * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
-     * Responsibility for the bitmap is transferred to the caller.
-     */
-    private Bitmap createDragOutline(View v, int padding) {
-        final int outlineColor = getResources().getColor(R.color.outline_color);
-        final Bitmap b = Bitmap.createBitmap(
-                v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
-
-        mCanvas.setBitmap(b);
-        drawDragView(v, mCanvas, padding);
-        mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor);
-        mCanvas.setBitmap(null);
-        return b;
-    }
-
-    /**
      * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
      * Responsibility for the bitmap is transferred to the caller.
      */
@@ -2410,29 +2301,28 @@
     }
 
     public void beginDragShared(View child, DragSource source, boolean accessible) {
-        beginDragShared(child, new Point(), source, accessible);
+        beginDragShared(child, new Point(), source, accessible, new DragPreviewProvider(child));
     }
 
     public void beginDragShared(View child, Point relativeTouchPos, DragSource source,
-            boolean accessible) {
+                                boolean accessible, DragPreviewProvider previewProvider) {
         child.clearFocus();
         child.setPressed(false);
 
         // The outline is used to visualize where the item will land if dropped
-        mDragOutline = createDragOutline(child, DRAG_BITMAP_PADDING);
+        mDragOutline = previewProvider.createDragOutline(mCanvas);
 
         mLauncher.onDragStarted(child);
         // The drag bitmap follows the touch point around on the screen
-        AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);
-        final Bitmap b = createDragBitmap(child, padding);
+        final Bitmap b = previewProvider.createDragBitmap(mCanvas);
+        int halfPadding = previewProvider.previewPadding / 2;
 
         final int bmpWidth = b.getWidth();
         final int bmpHeight = b.getHeight();
 
         float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);
         int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);
-        int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2
-                        - padding.get() / 2);
+        int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2 - halfPadding);
 
         DeviceProfile grid = mLauncher.getDeviceProfile();
         Point dragVisualizeOffset = null;
@@ -2458,12 +2348,11 @@
             dragLayerY += top;
             // Note: The drag region is used to calculate drag layer offsets, but the
             // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
-            dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2);
+            dragVisualizeOffset = new Point(- halfPadding, halfPadding);
             dragRect = new Rect(left, top, right, bottom);
         } else if (child instanceof FolderIcon) {
             int previewSize = grid.folderIconSizePx;
-            dragVisualizeOffset = new Point(-padding.get() / 2,
-                    padding.get() / 2 - child.getPaddingTop());
+            dragVisualizeOffset = new Point(- halfPadding, halfPadding - child.getPaddingTop());
             dragRect = new Rect(0, child.getPaddingTop(), child.getWidth(), previewSize);
         }
 
@@ -2497,58 +2386,6 @@
         }
     }
 
-    public void beginExternalDragShared(View child, DragSource source) {
-        DeviceProfile grid = mLauncher.getDeviceProfile();
-        int iconSize = grid.iconSizePx;
-
-        // Notify launcher of drag start
-        mLauncher.onDragStarted(child);
-
-        // Compose a new drag bitmap that is of the icon size
-        AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);
-        final Bitmap tmpB = createDragBitmap(child, padding);
-        Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
-        Paint p = new Paint();
-        p.setFilterBitmap(true);
-        mCanvas.setBitmap(b);
-        mCanvas.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()),
-                new Rect(0, 0, iconSize, iconSize), p);
-        mCanvas.setBitmap(null);
-
-        // Find the child's location on the screen
-        int bmpWidth = tmpB.getWidth();
-        float iconScale = (float) bmpWidth / iconSize;
-        float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY) * iconScale;
-        int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);
-        int dragLayerY = Math.round(mTempXY[1]);
-
-        // Note: The drag region is used to calculate drag layer offsets, but the
-        // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
-        Point dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2);
-        Rect dragRect = new Rect(0, 0, iconSize, iconSize);
-
-        Object dragObject = child.getTag();
-        if (!(dragObject instanceof ItemInfo)) {
-            String msg = "Drag started with a view that has no tag set. This "
-                    + "will cause a crash (issue 11627249) down the line. "
-                    + "View: " + child + "  tag: " + child.getTag();
-            throw new IllegalStateException(msg);
-        }
-
-        // Start the drag
-        DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source,
-                (ItemInfo) dragObject, DragController.DRAG_ACTION_MOVE, dragVisualizeOffset,
-                dragRect, scale, false);
-        dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
-
-        // Recycle temporary bitmaps
-        tmpB.recycle();
-
-        if (!FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND) {
-            mLauncher.enterSpringLoadedDragMode();
-        }
-    }
-
     public boolean transitionStateShouldAllowDrop() {
         return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&
                 (mState == State.NORMAL || mState == State.SPRING_LOADED));
@@ -2747,6 +2584,7 @@
                 fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,
                         postAnimationRunnable);
             } else {
+                fi.prepareCreate(v);
                 fi.addItem(destInfo);
                 fi.addItem(sourceInfo);
             }
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index c2631b0..598ba74 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -394,24 +394,14 @@
             overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel,
                     accessibilityEnabled));
 
-            // For animation optimations, we may need to provide the Launcher transition
-            // with a set of views on which to force build layers in certain scenarios.
-            overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            qsbContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            if (layerViews != null) {
-                // If layerViews is not null, we add these views, and indicate that
-                // the caller can manage layer state.
-                layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
-                layerViews.put(qsbContainer, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
-
-                layerViews.put(mLauncher.getHotseat(),
-                        LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
-                layerViews.put(mWorkspace.getPageIndicator(),
-                        LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
-            } else {
-                // Otherwise let the animator handle layer management.
-                overviewPanelAlpha.withLayer();
-            }
+            // For animation optimization, we may need to provide the Launcher transition
+            // with a set of views on which to force build and manage layers in certain scenarios.
+            layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+            layerViews.put(qsbContainer, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+            layerViews.put(mLauncher.getHotseat(),
+                    LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+            layerViews.put(mWorkspace.getPageIndicator(),
+                    LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
 
             if (states.workspaceToOverview) {
                 hotseatAlpha.setInterpolator(new DecelerateInterpolator(2));
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 6bf8abf..0562cf5 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -18,6 +18,7 @@
 
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeleteDropTarget;
 import com.android.launcher3.DragSource;
@@ -36,6 +37,8 @@
 import com.android.launcher3.UninstallDropTarget;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragController.DragListener;
+import com.android.launcher3.shortcuts.DeepShortcutTextView;
+import com.android.launcher3.shortcuts.DeepShortcutsContainer;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
@@ -45,13 +48,14 @@
 
     private static final String TAG = "LauncherAccessibilityDelegate";
 
-    private static final int REMOVE = R.id.action_remove;
-    private static final int INFO = R.id.action_info;
-    private static final int UNINSTALL = R.id.action_uninstall;
-    private static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace;
-    private static final int MOVE = R.id.action_move;
-    private static final int MOVE_TO_WORKSPACE = R.id.action_move_to_workspace;
-    private static final int RESIZE = R.id.action_resize;
+    protected static final int REMOVE = R.id.action_remove;
+    protected static final int INFO = R.id.action_info;
+    protected static final int UNINSTALL = R.id.action_uninstall;
+    protected static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace;
+    protected static final int MOVE = R.id.action_move;
+    protected static final int MOVE_TO_WORKSPACE = R.id.action_move_to_workspace;
+    protected static final int RESIZE = R.id.action_resize;
+    protected static final int DEEP_SHORTCUTS = R.id.action_deep_shortcuts;
 
     public enum DragType {
         ICON,
@@ -65,7 +69,7 @@
         public View item;
     }
 
-    private final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
+    protected final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
     @Thunk final Launcher mLauncher;
 
     private DragInfo mDragInfo = null;
@@ -88,14 +92,24 @@
                 launcher.getText(R.string.action_move_to_workspace)));
         mActions.put(RESIZE, new AccessibilityAction(RESIZE,
                         launcher.getText(R.string.action_resize)));
+        mActions.put(DEEP_SHORTCUTS, new AccessibilityAction(DEEP_SHORTCUTS,
+                launcher.getText(R.string.action_deep_shortcut)));
     }
 
     @Override
     public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(host, info);
+        addActions(host, info);
+    }
+
+    protected void addActions(View host, AccessibilityNodeInfo info) {
         if (!(host.getTag() instanceof ItemInfo)) return;
         ItemInfo item = (ItemInfo) host.getTag();
 
+        if (host instanceof BubbleTextView && ((BubbleTextView) host).hasDeepShortcuts()) {
+            info.addAction(mActions.get(DEEP_SHORTCUTS));
+        }
+
         if (DeleteDropTarget.supportsAccessibleDrop(item)) {
             info.addAction(mActions.get(REMOVE));
         }
@@ -215,6 +229,9 @@
                     }
                 })
                 .show();
+            return true;
+        } else if (action == DEEP_SHORTCUTS) {
+            return DeepShortcutsContainer.showForIcon((BubbleTextView) host) != null;
         }
         return false;
     }
@@ -397,7 +414,7 @@
     /**
      * Find empty space on the workspace and returns the screenId.
      */
-    private long findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) {
+    protected long findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) {
         Workspace workspace = mLauncher.getWorkspace();
         ArrayList<Long> workspaceScreens = workspace.getScreenOrder();
         long screenId;
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
new file mode 100644
index 0000000..ff70279
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -0,0 +1,73 @@
+/*
+ * 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.accessibility;
+
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutInfo;
+
+import java.util.ArrayList;
+
+/**
+ * Extension of {@link LauncherAccessibilityDelegate} with actions specific to shortcuts in
+ * deep shortcuts menu.
+ */
+public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDelegate {
+
+    public ShortcutMenuAccessibilityDelegate(Launcher launcher) {
+        super(launcher);
+    }
+
+    @Override
+    protected void addActions(View host, AccessibilityNodeInfo info) {
+        info.addAction(mActions.get(ADD_TO_WORKSPACE));
+    }
+
+    @Override
+    public boolean performAction(View host, ItemInfo item, int action) {
+        if (action == ADD_TO_WORKSPACE) {
+            final ShortcutInfo info = (ShortcutInfo) item;
+            final int[] coordinates = new int[2];
+            final long screenId = findSpaceOnWorkspace(item, coordinates);
+            Runnable onComplete = new Runnable() {
+                @Override
+                public void run() {
+                    LauncherModel.addItemToDatabase(mLauncher, info,
+                            LauncherSettings.Favorites.CONTAINER_DESKTOP,
+                            screenId, coordinates[0], coordinates[1]);
+                    ArrayList<ItemInfo> itemList = new ArrayList<>();
+                    itemList.add(info);
+                    mLauncher.bindItems(itemList, 0, itemList.size(), true);
+                    mLauncher.closeShortcutsContainer();
+                    announceConfirmation(R.string.item_added_to_workspace);
+                }
+            };
+
+            if (!mLauncher.showWorkspace(true, onComplete)) {
+                onComplete.run();
+            }
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index f0469e3..428f784 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.allapps;
 
-import android.animation.ObjectAnimator;
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Resources;
@@ -23,6 +22,8 @@
 import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView;
 import android.text.Selection;
+import android.text.Spannable;
+import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
 import android.text.method.TextKeyListener;
 import android.util.AttributeSet;
@@ -31,7 +32,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
 
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.BaseContainerView;
@@ -49,6 +49,7 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.Folder;
+import com.android.launcher3.graphics.TintedDrawableSpan;
 import com.android.launcher3.keyboard.FocusedItemDecorator;
 import com.android.launcher3.util.ComponentKey;
 
@@ -209,6 +210,7 @@
      */
     public void addApps(List<AppInfo> apps) {
         mApps.addApps(apps);
+        mSearchBarController.refreshSearchResult();
     }
 
     /**
@@ -216,6 +218,7 @@
      */
     public void updateApps(List<AppInfo> apps) {
         mApps.updateApps(apps);
+        mSearchBarController.refreshSearchResult();
     }
 
     /**
@@ -223,6 +226,7 @@
      */
     public void removeApps(List<AppInfo> apps) {
         mApps.removeApps(apps);
+        mSearchBarController.refreshSearchResult();
     }
 
     public void setSearchBarVisible(boolean visible) {
@@ -309,39 +313,19 @@
 
         mSearchContainer = findViewById(R.id.search_container);
         mSearchInput = (ExtendedEditText) findViewById(R.id.search_box_input);
+
+        // Update the hint to contain the icon.
+        // Prefix the original hint with two spaces. The first space gets replaced by the icon
+        // using span. The second space is used for a singe space character between the hint
+        // and the icon.
+        SpannableString spanned = new SpannableString("  " + mSearchInput.getHint());
+        spanned.setSpan(new TintedDrawableSpan(getContext(), R.drawable.ic_allapps_search),
+                0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+        mSearchInput.setHint(spanned);
+
         mSearchContainerOffsetTop = getResources().getDimensionPixelSize(
                 R.dimen.all_apps_search_bar_margin_top);
 
-        final View searchHint = findViewById(R.id.search_hint);
-        final ObjectAnimator searchInputAnimator = ObjectAnimator.ofFloat(mSearchInput,
-                View.TRANSLATION_X, 0);
-        searchInputAnimator.setDuration(getContext().getResources().getInteger(
-                R.integer.config_searchHintAnimationDuration));
-        searchInputAnimator.setInterpolator(AnimationUtils.loadInterpolator(getContext(),
-                android.R.interpolator.accelerate_decelerate));
-
-        mSearchInput.setOnFocusChangeListener(new OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View view, boolean focused) {
-                if (focused) {
-                    searchHint.setVisibility(View.INVISIBLE);
-                    if (searchInputAnimator.isRunning()) {
-                        searchInputAnimator.end();
-                    }
-
-                    if (Utilities.isRtl(getContext().getResources())) {
-                        searchInputAnimator.setFloatValues(-searchHint.getLeft(), 0);
-                    } else {
-                        searchInputAnimator.setFloatValues(searchHint.getLeft(), 0);
-                    }
-                    searchInputAnimator.start();
-                } else {
-                    searchHint.setVisibility(View.VISIBLE);
-                    mSearchInput.setTranslationX(0);
-                }
-            }
-        });
-
         mElevationController = Utilities.ATLEAST_LOLLIPOP
                 ? new HeaderElevationController.ControllerVL(mSearchContainer)
                 : new HeaderElevationController.ControllerV16(mSearchContainer);
@@ -366,9 +350,7 @@
 
         // TODO(hyunyoungs): clean up setting the content and the reveal view.
         if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
-            getContentView().setBackground(null);
             getRevealView().setVisibility(View.VISIBLE);
-            getRevealView().setAlpha(AllAppsTransitionController.ALL_APPS_FINAL_ALPHA);
         }
     }
 
@@ -380,12 +362,10 @@
         int widthPx = MeasureSpec.getSize(widthMeasureSpec);
         int heightPx = MeasureSpec.getSize(heightMeasureSpec);
         updatePaddingsAndMargins(widthPx, heightPx);
-        mContentBounds.set(mHorizontalPadding, 0, widthPx - mHorizontalPadding, heightPx);
+        mContentBounds.set(mContainerPaddingLeft, 0, widthPx - mContainerPaddingRight, heightPx);
 
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        int availableWidth = (!mContentBounds.isEmpty() ? mContentBounds.width() : widthPx)
-                - 2 * mAppsRecyclerView.getMaxScrollbarWidth();
-        grid.updateAppsViewNumCols(getResources(), availableWidth);
+        grid.updateAppsViewNumCols();
         if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
             if (mNumAppsPerRow != grid.inv.numColumns ||
                     mNumPredictedAppsPerRow != grid.inv.numColumns) {
@@ -401,9 +381,9 @@
                             getResources().getDimensionPixelSize(
                                     R.dimen.container_fastscroll_thumb_max_width);
                     mSearchContainer.setPadding(
-                            rvPadding - mHorizontalPadding + thumbMaxWidth,
+                            rvPadding - mContainerPaddingLeft + thumbMaxWidth,
                             mSearchContainer.getPaddingTop(),
-                            rvPadding - mHorizontalPadding + thumbMaxWidth,
+                            rvPadding - mContainerPaddingRight + thumbMaxWidth,
                             mSearchContainer.getPaddingBottom());
                 }
             }
@@ -416,7 +396,7 @@
         // 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.
-        grid.updateAppsViewNumCols(getResources(), availableWidth);
+        grid.updateAppsViewNumCols();
         if (mNumAppsPerRow != grid.allAppsNumCols ||
                 mNumPredictedAppsPerRow != grid.allAppsNumPredictiveCols) {
             mNumAppsPerRow = grid.allAppsNumCols;
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 0f0c333..d8f9fb1 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -20,6 +20,7 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
@@ -37,6 +38,8 @@
 
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -63,7 +66,7 @@
     public static final int VIEW_TYPE_PREDICTION_ICON = 1 << 2;
     // The message shown when there are no filtered results
     public static final int VIEW_TYPE_EMPTY_SEARCH = 1 << 3;
-    // A divider that separates the apps list and the search market button
+    // The message to continue to a market search when there are no filtered results
     public static final int VIEW_TYPE_SEARCH_MARKET = 1 << 4;
 
     // We use various dividers for various purposes.  They share enough attributes to reuse layouts,
@@ -331,7 +334,9 @@
     private final boolean mIsRtl;
 
     // Section drawing
+    @Deprecated
     private final int mSectionNamesMargin;
+    @Deprecated
     private final int mSectionHeaderOffset;
     private final Paint mSectionTextPaint;
 
@@ -452,6 +457,14 @@
                 icon.setLongPressTimeout(ViewConfiguration.get(parent.getContext())
                         .getLongPressTimeout());
                 icon.setOnFocusChangeListener(mIconFocusListener);
+
+                // Ensure the all apps icon height matches the workspace icons
+                DeviceProfile profile = mLauncher.getDeviceProfile();
+                Point cellSize = profile.getCellSize();
+                GridLayoutManager.LayoutParams lp =
+                        (GridLayoutManager.LayoutParams) icon.getLayoutParams();
+                lp.height = cellSize.y;
+                icon.setLayoutParams(lp);
                 return new ViewHolder(icon);
             }
             case VIEW_TYPE_EMPTY_SEARCH:
@@ -515,8 +528,6 @@
                 TextView searchView = (TextView) holder.mContent;
                 if (mMarketSearchIntent != null) {
                     searchView.setVisibility(View.VISIBLE);
-                    searchView.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
-                            Gravity.START | Gravity.CENTER_VERTICAL);
                 } else {
                     searchView.setVisibility(View.GONE);
                 }
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 93da297..641656c 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -120,10 +120,9 @@
         // Icons
         BubbleTextView icon = (BubbleTextView) adapter.onCreateViewHolder(this,
                 AllAppsGridAdapter.VIEW_TYPE_ICON).mContent;
-        icon.applyDummyInfo();
-        icon.measure(widthMeasureSpec, heightMeasureSpec);
-        mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, icon.getMeasuredHeight());
-        mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, icon.getMeasuredHeight());
+        int iconHeight = icon.getLayoutParams().height;
+        mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, iconHeight);
+        mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, iconHeight);
 
         // Search divider
         View searchDivider = adapter.onCreateViewHolder(this,
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
index 09a7d59..1d5b209 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.util.AttributeSet;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
@@ -26,6 +27,7 @@
 import com.android.launcher3.ClickShadowView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
 
 /**
  * A container for RecyclerView to allow for the click shadow view to be shown behind an icon that
@@ -63,7 +65,8 @@
             mTouchFeedbackView.setBitmap(null);
             mTouchFeedbackView.animate().cancel();
         } else if (mTouchFeedbackView.setBitmap(background)) {
-            mTouchFeedbackView.alignWithIconView(icon, (ViewGroup) icon.getParent());
+            View rv = findViewById(R.id.apps_list_view);
+            mTouchFeedbackView.alignWithIconView(icon, (ViewGroup) icon.getParent(), rv);
             mTouchFeedbackView.animateShadow();
         }
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
index ac35932..e75210b 100644
--- a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
@@ -45,6 +45,7 @@
     protected AlphabeticalAppsList mApps;
     protected Callbacks mCb;
     protected ExtendedEditText mInput;
+    private String mQuery;
 
     protected DefaultAppSearchAlgorithm mSearchAlgorithm;
     protected InputMethodManager mInputMethodManager;
@@ -90,16 +91,25 @@
 
     @Override
     public void afterTextChanged(final Editable s) {
-        String query = s.toString();
-        if (query.isEmpty()) {
+        mQuery = s.toString();
+        if (mQuery.isEmpty()) {
             mSearchAlgorithm.cancel(true);
             mCb.clearSearchResult();
         } else {
             mSearchAlgorithm.cancel(false);
-            mSearchAlgorithm.doSearch(query, mCb);
+            mSearchAlgorithm.doSearch(mQuery, mCb);
         }
     }
 
+    protected void refreshSearchResult() {
+        if (mQuery == null) {
+            return;
+        }
+        // If play store continues auto updating an app, we want to show partial result.
+        mSearchAlgorithm.cancel(false);
+        mSearchAlgorithm.doSearch(mQuery, mCb);
+    }
+
     @Override
     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
         // Skip if it's not the right action
@@ -130,6 +140,7 @@
      * Resets the search bar state.
      */
     public void reset() {
+        mQuery = null;
         unfocusSearchField();
         mCb.clearSearchResult();
         mInput.setText("");
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index f6e028b..78280f7 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -1,8 +1,10 @@
 package com.android.launcher3.allapps;
 
 import android.animation.Animator;
+import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -12,15 +14,16 @@
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
-import com.android.launcher3.pageindicators.CaretDrawable;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.PagedView;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
-import com.android.launcher3.Workspace.Direction;
+import com.android.launcher3.pageindicators.CaretDrawable;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.TouchController;
 
 /**
@@ -43,14 +46,14 @@
     private final Interpolator mDecelInterpolator = new DecelerateInterpolator(1f);
 
     private static final float ANIMATION_DURATION = 1200;
-    public static final float ALL_APPS_FINAL_ALPHA = .9f;
 
     private static final float PARALLAX_COEFFICIENT = .125f;
 
     private AllAppsContainerView mAppsView;
+    private int mAllAppsBackgroundColor;
     private Workspace mWorkspace;
     private Hotseat mHotseat;
-    private float mHotseatBackgroundAlpha;
+    private int mHotseatBackgroundColor;
 
     private ObjectAnimator mCaretAnimator;
     private final long mCaretAnimationDuration;
@@ -60,16 +63,17 @@
 
     private final Launcher mLauncher;
     private final VerticalPullDetector mDetector;
+    private final ArgbEvaluator mEvaluator;
 
-    // Animation in this class is controlled by a single variable {@link mShiftCurrent}.
-    // Visually, it represents top y coordinate of the all apps container. Using the
-    // {@link mShiftRange} as the denominator, this fraction value ranges in [0, 1].
-    //
-    // When {@link mShiftCurrent} is 0, all apps container is pulled up.
-    // When {@link mShiftCurrent} is {@link mShirtRange}, all apps container is pulled down.
+    // Animation in this class is controlled by a single variable {@link mProgress}.
+    // Visually, it represents top y coordinate of the all apps container if multiplied with
+    // {@link mShiftRange}.
+
+    // When {@link mProgress} is 0, all apps container is pulled up.
+    // When {@link mProgress} is 1, all apps container is pulled down.
     private float mShiftStart;      // [0, mShiftRange]
-    private float mShiftCurrent;    // [0, mShiftRange]
     private float mShiftRange;      // changes depending on the orientation
+    private float mProgress;        // [0, 1], mShiftRange * mProgress = shiftCurrent
 
     private static final float DEFAULT_SHIFT_RANGE = 10;
 
@@ -83,18 +87,26 @@
 
     private boolean mLightStatusBar;
 
-    public AllAppsTransitionController(Launcher launcher) {
-        mLauncher = launcher;
-        mDetector = new VerticalPullDetector(launcher);
+    // Used in discovery bounce animation to provide the transition without workspace changing.
+    private boolean mIsTranslateWithoutWorkspace = false;
+    private AnimatorSet mDiscoBounceAnimation;
+
+    public AllAppsTransitionController(Launcher l) {
+        mLauncher = l;
+        mDetector = new VerticalPullDetector(l);
         mDetector.setListener(this);
-        mShiftCurrent = mShiftRange = DEFAULT_SHIFT_RANGE;
-        mBezelSwipeUpHeight = launcher.getResources().getDimensionPixelSize(
+        mShiftRange = DEFAULT_SHIFT_RANGE;
+        mProgress = 1f;
+        mBezelSwipeUpHeight = l.getResources().getDimensionPixelSize(
                 R.dimen.all_apps_bezel_swipe_height);
 
-        mCaretAnimationDuration = launcher.getResources().getInteger(
+        mCaretAnimationDuration = l.getResources().getInteger(
                 R.integer.config_caretAnimationDuration);
-        mCaretInterpolator = AnimationUtils.loadInterpolator(launcher,
+        mCaretInterpolator = AnimationUtils.loadInterpolator(l,
                 R.interpolator.caret_animation_interpolator);
+
+        mEvaluator = new ArgbEvaluator();
+        mAllAppsBackgroundColor = l.getColor(R.color.all_apps_container_color);
     }
 
     @Override
@@ -170,11 +182,11 @@
     }
 
     private boolean isInDisallowRecatchTopZone() {
-        return mShiftCurrent / mShiftRange < RECATCH_REJECTION_FRACTION;
+        return mProgress < RECATCH_REJECTION_FRACTION;
     }
 
     private boolean isInDisallowRecatchBottomZone() {
-        return mShiftCurrent / mShiftRange > 1 - RECATCH_REJECTION_FRACTION;
+        return mProgress > 1 - RECATCH_REJECTION_FRACTION;
     }
 
     @Override
@@ -190,8 +202,8 @@
         if (mAppsView == null) {
             return false;   // early termination.
         }
-        float progress = Math.min(Math.max(0, mShiftStart + displacement), mShiftRange);
-        setProgress(progress);
+        float shift = Math.min(Math.max(0, mShiftStart + displacement), mShiftRange);
+        setProgress(shift / mShiftRange);
         return true;
     }
 
@@ -206,6 +218,10 @@
                 calculateDuration(velocity, mAppsView.getTranslationY());
 
                 if (!mLauncher.isAllAppsVisible()) {
+                    mLauncher.getUserEventDispatcher().logActionOnContainer(
+                            LauncherLogProto.Action.FLING,
+                            LauncherLogProto.Action.UP,
+                            LauncherLogProto.HOTSEAT);
                     mLauncher.showAppsView(true, true, false, false);
                 } else {
                     animateToAllApps(mCurrentAnimation, mAnimationDuration, true);
@@ -230,6 +246,10 @@
             } else {
                 calculateDuration(velocity, Math.abs(mAppsView.getTranslationY()));
                 if (!mLauncher.isAllAppsVisible()) {
+                    mLauncher.getUserEventDispatcher().logActionOnContainer(
+                            LauncherLogProto.Action.SWIPE,
+                            LauncherLogProto.Action.UP,
+                            LauncherLogProto.HOTSEAT);
                     mLauncher.showAppsView(true, true, false, false);
                 } else {
                     animateToAllApps(mCurrentAnimation, mAnimationDuration, true);
@@ -248,25 +268,21 @@
             mStatusBarHeight = mLauncher.getDragLayer().getInsets().top;
             mHotseat.setVisibility(View.VISIBLE);
             mHotseat.bringToFront();
-
             if (!mLauncher.isAllAppsVisible()) {
                 mLauncher.tryAndUpdatePredictedApps();
-
-                mHotseatBackgroundAlpha = mHotseat.getBackgroundDrawableAlpha() / 255f;
+                mHotseatBackgroundColor = mHotseat.getBackgroundDrawableColor();
                 mHotseat.setBackgroundTransparent(true /* transparent */);
                 mAppsView.setVisibility(View.VISIBLE);
                 mAppsView.getContentView().setVisibility(View.VISIBLE);
                 mAppsView.getContentView().setBackground(null);
                 mAppsView.getRevealView().setVisibility(View.VISIBLE);
-                mAppsView.getRevealView().setAlpha(mHotseatBackgroundAlpha);
+                mAppsView.setRevealDrawableColor(mHotseatBackgroundColor);
             }
-        } else {
-            setProgress(mShiftCurrent);
         }
     }
 
-    private void updateLightStatusBar(float progress) {
-        boolean enable = progress <= mStatusBarHeight / 2;
+    private void updateLightStatusBar(float shift) {
+        boolean enable = shift <= mStatusBarHeight / 2;
         // Do not modify status bar on landscape as all apps is not full bleed.
         if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
             return;
@@ -289,37 +305,43 @@
     }
 
     /**
-     * @param progress y value of the border between hotseat and all apps
+     * @param progress value between 0 and 1
      */
     public void setProgress(float progress) {
-        updateLightStatusBar(progress);
-        mShiftCurrent = progress;
-        float alpha = calcAlphaAllApps(progress);
-        float workspaceHotseatAlpha = 1 - alpha;
+        mProgress = progress;
+        float shiftCurrent = progress * mShiftRange;
 
-        mAppsView.getRevealView().setAlpha(Math.min(ALL_APPS_FINAL_ALPHA, Math.max(mHotseatBackgroundAlpha,
-                mDecelInterpolator.getInterpolation(alpha))));
+        float workspaceHotseatAlpha = Utilities.boundToRange(progress, 0f, 1f);
+        float alpha = 1 - workspaceHotseatAlpha;
+
+        float interpolation = mAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
+
+        int color = (Integer) mEvaluator.evaluate(alpha,
+                mHotseatBackgroundColor, mAllAppsBackgroundColor);
+        mAppsView.setRevealDrawableColor(color);
         mAppsView.getContentView().setAlpha(alpha);
-        mAppsView.setTranslationY(progress);
-        mWorkspace.setWorkspaceYTranslationAndAlpha(
-                PARALLAX_COEFFICIENT * (-mShiftRange + progress),
-                mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
+        mAppsView.setTranslationY(shiftCurrent);
+
         if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-            mWorkspace.setHotseatTranslationAndAlpha(Direction.Y, -mShiftRange + progress,
-                    mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
+            mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y, -mShiftRange + shiftCurrent,
+                    interpolation);
         } else {
-            mWorkspace.setHotseatTranslationAndAlpha(Direction.Y,
-                    PARALLAX_COEFFICIENT * (-mShiftRange + progress),
-                    mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
+            mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y,
+                    PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent),
+                    interpolation);
         }
+
+        if (mIsTranslateWithoutWorkspace) {
+            return;
+        }
+        mWorkspace.setWorkspaceYTranslationAndAlpha(
+                PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent),
+                interpolation);
+        updateLightStatusBar(shiftCurrent);
     }
 
     public float getProgress() {
-        return mShiftCurrent;
-    }
-
-    private float calcAlphaAllApps(float progress) {
-        return ((mShiftRange - progress) / mShiftRange);
+        return mProgress;
     }
 
     private void calculateDuration(float velocity, float disp) {
@@ -342,10 +364,8 @@
             mShiftStart = mAppsView.getTranslationY();
         }
         final float fromAllAppsTop = mAppsView.getTranslationY();
-        final float toAllAppsTop = 0;
-
         ObjectAnimator driftAndAlpha = ObjectAnimator.ofFloat(this, "progress",
-                fromAllAppsTop, toAllAppsTop);
+                fromAllAppsTop / mShiftRange, 0f);
         driftAndAlpha.setDuration(mAnimationDuration);
         driftAndAlpha.setInterpolator(new PagedView.ScrollInterpolator());
         animationOut.play(driftAndAlpha);
@@ -375,6 +395,36 @@
         }
     }
 
+    public void showDiscoveryBounce() {
+        // cancel existing animation in case user locked and unlocked at a super human speed.
+        cancelDiscoveryAnimation();
+
+        // assumption is that this variable is always null
+        mDiscoBounceAnimation = (AnimatorSet) AnimatorInflater.loadAnimator(mLauncher,
+                R.anim.discovery_bounce);
+        mDiscoBounceAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animator) {
+                mIsTranslateWithoutWorkspace = true;
+                preparePull(true);
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animator) {
+                finishPullDown(false);
+                mDiscoBounceAnimation = null;
+                mIsTranslateWithoutWorkspace = false;
+            }
+        });
+        mDiscoBounceAnimation.setTarget(this);
+        mAppsView.post(new Runnable() {
+            @Override
+            public void run() {
+                mDiscoBounceAnimation.start();
+            }
+        });
+    }
+
     public void animateToWorkspace(AnimatorSet animationOut, long duration, boolean start) {
         if (animationOut == null) {
             return;
@@ -385,10 +435,9 @@
             mShiftStart = mAppsView.getTranslationY();
         }
         final float fromAllAppsTop = mAppsView.getTranslationY();
-        final float toAllAppsTop = mShiftRange;
 
         ObjectAnimator driftAndAlpha = ObjectAnimator.ofFloat(this, "progress",
-                fromAllAppsTop, toAllAppsTop);
+                fromAllAppsTop / mShiftRange, 1f);
         driftAndAlpha.setDuration(mAnimationDuration);
         driftAndAlpha.setInterpolator(new PagedView.ScrollInterpolator());
         animationOut.play(driftAndAlpha);
@@ -399,7 +448,6 @@
             @Override
             public void onAnimationCancel(Animator animation) {
                 canceled = true;
-                setProgress(mShiftCurrent);
             }
 
             @Override
@@ -430,7 +478,7 @@
         mHotseat.setBackgroundTransparent(false /* transparent */);
         mHotseat.setVisibility(View.VISIBLE);
         mAppsView.reset();
-        setProgress(mShiftRange);
+        setProgress(1f);
         if (animated) {
             animateCaret();
         } else {
@@ -441,10 +489,18 @@
 
     private void cancelAnimation() {
         if (mCurrentAnimation != null) {
-            mCurrentAnimation.setDuration(0);
             mCurrentAnimation.cancel();
             mCurrentAnimation = null;
         }
+        cancelDiscoveryAnimation();
+    }
+
+    public void cancelDiscoveryAnimation() {
+        if (mDiscoBounceAnimation == null) {
+            return;
+        }
+        mDiscoBounceAnimation.cancel();
+        mDiscoBounceAnimation = null;
     }
 
     private void cleanUpAnimation() {
@@ -478,13 +534,14 @@
 
     @Override
     public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                               int oldLeft, int oldTop, int oldRight, int oldBottom) {
-        float prevShiftRatio = mShiftCurrent / mShiftRange;
+            int oldLeft, int oldTop, int oldRight, int oldBottom) {
         if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
             mShiftRange = top;
         } else {
             mShiftRange = bottom;
         }
-        setProgress(mShiftRange * prevShiftRatio);
+        setProgress(mProgress);
     }
+
+
 }
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index b70c165..7127ec4 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -440,7 +440,7 @@
                     mPredictedApps.add(info);
                 } else {
                     if (ProviderConfig.IS_DOGFOOD_BUILD) {
-                        Log.e(TAG, "Predicted app not found: " + ck.flattenToString(mLauncher));
+                        Log.e(TAG, "Predicted app not found: " + ck);
                     }
                 }
                 // Stop at the number of predicted apps
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index dc93bca..3447d51 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -252,8 +252,7 @@
         final float scaleDps = FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND ?
                 res.getDimensionPixelSize(R.dimen.dragViewScale) : 0f;
         final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX,
-                registrationY, 0, 0, b.getWidth(), b.getHeight(),
-                initialDragViewScale, scaleDps);
+                registrationY, initialDragViewScale, scaleDps);
 
         mDragObject.dragComplete = false;
         if (mIsAccessibleDrag) {
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 5f8faab..28b6f3e 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -280,6 +280,10 @@
         int action = ev.getAction();
 
         if (action == MotionEvent.ACTION_DOWN) {
+            // Cancel discovery bounce animation when a user start interacting on anywhere on
+            // dray layer even if mAllAppsController is NOT the active controller.
+            // TODO: handle other input other than touch
+            mAllAppsController.cancelDiscoveryAnimation();
             if (handleTouchDown(ev, true)) {
                 return true;
             }
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index a5644ad..e95f07b 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -84,13 +84,13 @@
      * @param registrationY The y coordinate of the registration point.
      */
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY, int left,
-            int top, int width, int height, final float initialScale, final float finalScaleDps) {
+    public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY,
+                    final float initialScale, final float finalScaleDps) {
         super(launcher);
         mDragLayer = launcher.getDragLayer();
         mDragController = launcher.getDragController();
 
-        final float scale = (width + finalScaleDps) / width;
+        final float scale = (bitmap.getWidth() + finalScaleDps) / bitmap.getWidth();
 
         // Set the initial scale to avoid any jumps
         setScaleX(initialScale);
@@ -125,8 +125,8 @@
             }
         });
 
-        mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height);
-        setDragRegion(new Rect(0, 0, width, height));
+        mBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight());
+        setDragRegion(new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()));
 
         // The point in our scaled bitmap that the touch events are located
         mRegistrationX = registrationX;
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 556be0c..fdbb214 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -80,8 +80,8 @@
 import com.android.launcher3.pageindicators.PageIndicatorDots;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.util.CircleRevealOutlineProvider;
 import com.android.launcher3.util.Thunk;
-import com.android.launcher3.util.UiThreadCircularReveal;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -554,8 +554,8 @@
             int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
             float radius = (float) Math.hypot(rx, ry);
 
-            Animator reveal = UiThreadCircularReveal.createCircularReveal(this, (int) getPivotX(),
-                    (int) getPivotY(), 0, radius);
+            Animator reveal = new CircleRevealOutlineProvider((int) getPivotX(),
+                    (int) getPivotY(), 0, radius).createRevealAnimator(this);
             reveal.setDuration(mMaterialExpandDuration);
             reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
 
@@ -1030,27 +1030,25 @@
     }
 
     private void centerAboutIcon() {
-        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
 
+        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
         DragLayer parent = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
         int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
         int height = getFolderHeight();
 
         float scale = parent.getDescendantRectRelativeToSelf(mFolderIcon, sTempRect);
-
-        DeviceProfile grid = mLauncher.getDeviceProfile();
-
-        int centerX = (int) (sTempRect.left + sTempRect.width() * scale / 2);
-        int centerY = (int) (sTempRect.top + sTempRect.height() * scale / 2);
+        int centerX = sTempRect.centerX();
+        int centerY = sTempRect.centerY();
         int centeredLeft = centerX - width / 2;
         int centeredTop = centerY - height / 2;
 
         // We need to bound the folder to the currently visible workspace area
         mLauncher.getWorkspace().getPageAreaRelativeToDragLayer(sTempRect);
         int left = Math.min(Math.max(sTempRect.left, centeredLeft),
-                sTempRect.left + sTempRect.width() - width);
+                sTempRect.right- width);
         int top = Math.min(Math.max(sTempRect.top, centeredTop),
-                sTempRect.top + sTempRect.height() - height);
+                sTempRect.bottom - height);
 
         int distFromEdgeOfScreen = mLauncher.getWorkspace().getPaddingLeft() + getPaddingLeft();
 
@@ -1064,7 +1062,14 @@
             left = sTempRect.left + (sTempRect.width() - width) / 2;
         }
         if (height >= sTempRect.height()) {
+            // Folder height is greater than page height, center on page
             top = sTempRect.top + (sTempRect.height() - height) / 2;
+        } else {
+            // Folder height is less than page height, so bound it to the absolute open folder
+            // bounds if necessary
+            Rect folderBounds = grid.getAbsoluteOpenFolderBounds();
+            left = Math.max(folderBounds.left, Math.min(left, folderBounds.right - width));
+            top = Math.max(folderBounds.top, Math.min(top, folderBounds.bottom - height));
         }
 
         int folderPivotX = width / 2 + (centeredLeft - left);
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index d08cf54..eebbfe8 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -262,14 +262,19 @@
         }
     };
 
+    public Drawable prepareCreate(final View destView) {
+        Drawable animateDrawable = getTopDrawable((TextView) destView);
+        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
+                destView.getMeasuredWidth());
+        return animateDrawable;
+    }
+
     public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
             final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect,
             float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
 
         // These correspond two the drawable and view that the icon was dropped _onto_
-        Drawable animateDrawable = getTopDrawable((TextView) destView);
-        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
-                destView.getMeasuredWidth());
+        Drawable animateDrawable = prepareCreate(destView);
 
         mReferenceDrawable = animateDrawable;
 
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 82c79a9..3df1d24 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -197,7 +197,7 @@
      */
     public int allocateRankForNewItem(ShortcutInfo info) {
         int rank = getItemCount();
-        ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
+        ArrayList<View> views = new ArrayList<>(mFolder.getItemsInReadingOrder());
         views.add(rank, null);
         arrangeChildren(views, views.size(), false);
         setCurrentPage(rank / mMaxItemsPerPage);
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
new file mode 100644
index 0000000..a00bc92
--- /dev/null
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -0,0 +1,155 @@
+/*
+ * 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.graphics;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.Region.Op;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.launcher3.HolographicOutlineHelper;
+import com.android.launcher3.PreloadIconDrawable;
+import com.android.launcher3.R;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.folder.FolderIcon;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A utility class to generate preview bitmap for dragging.
+ */
+public class DragPreviewProvider {
+
+    public static final int DRAG_BITMAP_PADDING = 2;
+
+    private final Rect mTempRect = new Rect();
+
+    protected final View mView;
+
+    // The padding added to the drag view during the preview generation.
+    public final int previewPadding;
+
+    public DragPreviewProvider(View view) {
+        mView = view;
+
+        if (mView instanceof TextView) {
+            Drawable d = Workspace.getTextViewIcon((TextView) mView);
+            Rect bounds = getDrawableBounds(d);
+            previewPadding = DRAG_BITMAP_PADDING - bounds.left - bounds.top;
+        } else {
+            previewPadding = DRAG_BITMAP_PADDING;
+        }
+    }
+
+    /**
+     * Draw the View v into the given Canvas.
+     *
+     * @param destCanvas the canvas to draw on
+     */
+    private void drawDragView(Canvas destCanvas) {
+        destCanvas.save();
+        if (mView instanceof TextView) {
+            Drawable d = Workspace.getTextViewIcon((TextView) mView);
+            Rect bounds = getDrawableBounds(d);
+            destCanvas.translate(DRAG_BITMAP_PADDING / 2 - bounds.left,
+                    DRAG_BITMAP_PADDING / 2 - bounds.top);
+            d.draw(destCanvas);
+        } else {
+            final Rect clipRect = mTempRect;
+            mView.getDrawingRect(clipRect);
+
+            boolean textVisible = false;
+            if (mView instanceof FolderIcon) {
+                // For FolderIcons the text can bleed into the icon area, and so we need to
+                // hide the text completely (which can't be achieved by clipping).
+                if (((FolderIcon) mView).getTextVisible()) {
+                    ((FolderIcon) mView).setTextVisible(false);
+                    textVisible = true;
+                }
+            }
+            destCanvas.translate(-mView.getScrollX() + DRAG_BITMAP_PADDING / 2,
+                    -mView.getScrollY() + DRAG_BITMAP_PADDING / 2);
+            destCanvas.clipRect(clipRect, Op.REPLACE);
+            mView.draw(destCanvas);
+
+            // Restore text visibility of FolderIcon if necessary
+            if (textVisible) {
+                ((FolderIcon) mView).setTextVisible(true);
+            }
+        }
+        destCanvas.restore();
+    }
+
+    /**
+     * Returns a new bitmap to show when the given View is being dragged around.
+     * Responsibility for the bitmap is transferred to the caller.
+     */
+    public Bitmap createDragBitmap(Canvas canvas) {
+        Bitmap b;
+
+        if (mView instanceof TextView) {
+            Drawable d = Workspace.getTextViewIcon((TextView) mView);
+            Rect bounds = getDrawableBounds(d);
+            b = Bitmap.createBitmap(bounds.width() + DRAG_BITMAP_PADDING,
+                    bounds.height() + DRAG_BITMAP_PADDING, Bitmap.Config.ARGB_8888);
+        } else {
+            b = Bitmap.createBitmap(mView.getWidth() + DRAG_BITMAP_PADDING,
+                    mView.getHeight() + DRAG_BITMAP_PADDING, Bitmap.Config.ARGB_8888);
+        }
+
+        canvas.setBitmap(b);
+        drawDragView(canvas);
+        canvas.setBitmap(null);
+
+        return b;
+    }
+
+    /**
+     * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
+     * Responsibility for the bitmap is transferred to the caller.
+     */
+    public Bitmap createDragOutline(Canvas canvas) {
+        final int outlineColor = mView.getResources().getColor(R.color.outline_color);
+        final Bitmap b = Bitmap.createBitmap(mView.getWidth() + DRAG_BITMAP_PADDING,
+                mView.getHeight() + DRAG_BITMAP_PADDING, Bitmap.Config.ARGB_8888);
+
+        canvas.setBitmap(b);
+        drawDragView(canvas);
+        HolographicOutlineHelper.obtain(mView.getContext())
+                .applyExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
+        canvas.setBitmap(null);
+        return b;
+    }
+
+    protected static Rect getDrawableBounds(Drawable d) {
+        Rect bounds = new Rect();
+        d.copyBounds(bounds);
+        if (bounds.width() == 0 || bounds.height() == 0) {
+            bounds.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
+        } else {
+            bounds.offsetTo(0, 0);
+        }
+        if (d instanceof PreloadIconDrawable) {
+            int inset = -((PreloadIconDrawable) d).getOutset();
+            bounds.inset(inset, inset);
+        }
+        return bounds;
+    }
+}
diff --git a/src/com/android/launcher3/graphics/ScaledPreviewProvider.java b/src/com/android/launcher3/graphics/ScaledPreviewProvider.java
new file mode 100644
index 0000000..a7d121b
--- /dev/null
+++ b/src/com/android/launcher3/graphics/ScaledPreviewProvider.java
@@ -0,0 +1,89 @@
+/*
+ * 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.graphics;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.launcher3.HolographicOutlineHelper;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.graphics.DragPreviewProvider;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Extension of {@link DragPreviewProvider} which generates bitmaps scaled to the default icon size
+ */
+public class ScaledPreviewProvider extends DragPreviewProvider {
+
+    public ScaledPreviewProvider(View v) {
+        super(v);
+    }
+
+    @Override
+    public Bitmap createDragOutline(Canvas canvas) {
+        if (mView instanceof TextView) {
+            Bitmap b = drawScaledPreview(canvas);
+
+            final int outlineColor = mView.getResources().getColor(R.color.outline_color);
+            HolographicOutlineHelper.obtain(mView.getContext())
+                    .applyExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
+            canvas.setBitmap(null);
+            return b;
+        }
+        return super.createDragOutline(canvas);
+    }
+
+    @Override
+    public Bitmap createDragBitmap(Canvas canvas) {
+        if (mView instanceof TextView) {
+            Bitmap b = drawScaledPreview(canvas);
+            canvas.setBitmap(null);
+            return b;
+
+        } else {
+            return super.createDragBitmap(canvas);
+        }
+    }
+
+    private Bitmap drawScaledPreview(Canvas canvas) {
+        Drawable d = Workspace.getTextViewIcon((TextView) mView);
+        Rect bounds = getDrawableBounds(d);
+
+        int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx;
+
+        final Bitmap b = Bitmap.createBitmap(
+                size + DRAG_BITMAP_PADDING,
+                size + DRAG_BITMAP_PADDING,
+                Bitmap.Config.ARGB_8888);
+
+        canvas.setBitmap(b);
+        canvas.save(Canvas.MATRIX_SAVE_FLAG);
+        canvas.translate(DRAG_BITMAP_PADDING / 2, DRAG_BITMAP_PADDING / 2);
+        canvas.scale(((float) size) / bounds.width(), ((float) size) / bounds.height(), 0, 0);
+        canvas.translate(bounds.left, bounds.top);
+        d.draw(canvas);
+        canvas.restore();
+        return b;
+    }
+}
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
new file mode 100644
index 0000000..2b24ec9
--- /dev/null
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -0,0 +1,114 @@
+/*
+ * 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.graphics;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BlurMaskFilter;
+import android.graphics.BlurMaskFilter.Blur;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.util.Preconditions;
+
+/**
+ * Utility class to add shadows to bitmaps.
+ */
+public class ShadowGenerator {
+
+    // Percent of actual icon size
+    private static final float HALF_DISTANCE = 0.5f;
+    private static final float BLUR_FACTOR = 0.5f/48;
+
+    // Percent of actual icon size
+    private static final float KEY_SHADOW_DISTANCE = 1f/48;
+    private static final int KEY_SHADOW_ALPHA = 61;
+
+    private static final int AMBIENT_SHADOW_ALPHA = 30;
+
+    private static final Object LOCK = new Object();
+    // Singleton object guarded by {@link #LOCK}
+    private static ShadowGenerator sShadowGenerator;
+
+    private final int mIconSize;
+
+    private final Canvas mCanvas;
+    private final Paint mBlurPaint;
+    private final Paint mDrawPaint;
+
+    private ShadowGenerator() {
+        mIconSize = LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
+        mCanvas = new Canvas();
+        mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+        mBlurPaint.setMaskFilter(new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL));
+        mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+    }
+
+    public synchronized Bitmap recreateIcon(Bitmap icon) {
+        int[] offset = new int[2];
+        Bitmap shadow = icon.extractAlpha(mBlurPaint, offset);
+        Bitmap result = Bitmap.createBitmap(mIconSize, mIconSize, Config.ARGB_8888);
+        mCanvas.setBitmap(result);
+
+        // Draw ambient shadow
+        mDrawPaint.setAlpha(AMBIENT_SHADOW_ALPHA);
+        mCanvas.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);
+
+        // Draw key shadow
+        mDrawPaint.setAlpha(KEY_SHADOW_ALPHA);
+        mCanvas.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize, mDrawPaint);
+
+        // Draw the icon
+        mDrawPaint.setAlpha(255);
+        mCanvas.drawBitmap(icon, 0, 0, mDrawPaint);
+
+        mCanvas.setBitmap(null);
+        return result;
+    }
+
+    public static ShadowGenerator getInstance() {
+        Preconditions.assertNonUiThread();
+        synchronized (LOCK) {
+            if (sShadowGenerator == null) {
+                sShadowGenerator = new ShadowGenerator();
+            }
+        }
+        return sShadowGenerator;
+    }
+
+    /**
+     * Returns the minimum amount by which an icon with {@param bounds} should be scaled
+     * so that the shadows do not get clipped.
+     */
+    public static float getScaleForBounds(RectF bounds) {
+        float scale = 1;
+
+        // For top, left & right, we need same space.
+        float minSide = Math.min(Math.min(bounds.left, bounds.right), bounds.top);
+        if (minSide < BLUR_FACTOR) {
+            scale = (HALF_DISTANCE - BLUR_FACTOR) / (HALF_DISTANCE - minSide);
+        }
+
+        float bottomSpace = BLUR_FACTOR + KEY_SHADOW_DISTANCE;
+        if (bounds.bottom < bottomSpace) {
+            scale = Math.min(scale, (HALF_DISTANCE - bottomSpace) / (HALF_DISTANCE - bounds.bottom));
+        }
+        return scale;
+    }
+}
diff --git a/src/com/android/launcher3/graphics/TintedDrawableSpan.java b/src/com/android/launcher3/graphics/TintedDrawableSpan.java
new file mode 100644
index 0000000..f72ce03
--- /dev/null
+++ b/src/com/android/launcher3/graphics/TintedDrawableSpan.java
@@ -0,0 +1,62 @@
+/*
+ * 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.graphics;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.drawable.Drawable;
+import android.text.style.DynamicDrawableSpan;
+
+/**
+ * {@link DynamicDrawableSpan} which draws a drawable tinted with the current paint color.
+ */
+public class TintedDrawableSpan extends DynamicDrawableSpan {
+
+    private final Drawable mDrawable;
+    private int mOldTint;
+
+    public TintedDrawableSpan(Context context, int resourceId) {
+        super(ALIGN_BOTTOM);
+        mDrawable = context.getDrawable(resourceId);
+        mOldTint = 0;
+    }
+
+    @Override
+    public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
+        fm = fm == null ? paint.getFontMetricsInt() : fm;
+        int iconSize = fm.bottom - fm.top;
+        mDrawable.setBounds(0, 0, iconSize, iconSize);
+        return super.getSize(paint, text, start, end, fm);
+    }
+
+    @Override
+    public void draw(Canvas canvas, CharSequence text,
+            int start, int end, float x, int top, int y, int bottom, Paint paint) {
+        int color = paint.getColor();
+        if (mOldTint != color) {
+            mOldTint = color;
+            mDrawable.setTint(mOldTint);
+        }
+        super.draw(canvas, text, start, end, x, top, y, bottom, paint);
+    }
+
+    @Override
+    public Drawable getDrawable() {
+        return mDrawable;
+    }
+}
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 584e38e..9e92721 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -1,15 +1,9 @@
 package com.android.launcher3.logging;
 
-import android.os.Bundle;
-import android.util.Log;
-
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 
-
 /**
  * Debugging helper methods.
  * toString() cannot be overriden inside auto generated {@link LauncherLogProto}.
@@ -24,12 +18,17 @@
             case Action.LONGPRESS: return "LONGPRESS";
             case Action.DRAGDROP: return "DRAGDROP";
             case Action.PINCH: return "PINCH";
+            case Action.SWIPE: return "SWIPE";
+            case Action.FLING: return "FLING";
             default: return "UNKNOWN";
         }
     }
 
     public static String getTargetStr(Target t) {
-        String typeStr;
+        String typeStr = "";
+        if (t == null){
+            return typeStr;
+        }
         switch (t.type) {
             case Target.ITEM:
                 return getItemStr(t);
@@ -44,6 +43,9 @@
 
     private static String getItemStr(Target t) {
         String typeStr = "";
+        if (t == null){
+            return typeStr;
+        }
         switch(t.itemType){
             case LauncherLogProto.APP_ICON: typeStr = "ICON"; break;
             case LauncherLogProto.SHORTCUT: typeStr = "SHORTCUT"; break;
@@ -58,6 +60,9 @@
     }
 
     private static String getControlStr(Target t) {
+        if (t == null){
+            return "";
+        }
         switch(t.controlType) {
             case LauncherLogProto.ALL_APPS_BUTTON: return "ALL_APPS_BUTTON";
             case LauncherLogProto.WIDGETS_BUTTON: return "WIDGETS_BUTTON";
@@ -72,8 +77,10 @@
     }
 
     private static String getContainerStr(LauncherLogProto.Target t) {
-        String str;
-        Log.d(TAG, "t.containerType" + t.containerType);
+        String str = "";
+        if (t == null) {
+            return str;
+        }
         switch (t.containerType) {
             case LauncherLogProto.WORKSPACE:
                 str = "WORKSPACE";
@@ -122,4 +129,18 @@
         event.action.type = actionType;
         return event;
     }
+
+    public static LauncherLogProto.LauncherEvent initLauncherEvent(
+            int actionType,
+            int childTargetType){
+        LauncherLogProto.LauncherEvent event = new LauncherLogProto.LauncherEvent();
+
+        event.srcTarget = new LauncherLogProto.Target[1];
+        event.srcTarget[0] = new LauncherLogProto.Target();
+        event.srcTarget[0].type = childTargetType;
+
+        event.action = new LauncherLogProto.Action();
+        event.action.type = actionType;
+        return event;
+    }
 }
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 0deee57..f67f487 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -37,8 +37,8 @@
 public class UserEventDispatcher {
 
     private static final boolean DEBUG_LOGGING = false;
-
     private final static int MAXIMUM_VIEW_HIERARCHY_LEVEL = 5;
+
     /**
      * Implemented by containers to provide a launch source for a given child.
      */
@@ -46,10 +46,11 @@
 
         /**
          * Copies data from the source to the destination proto.
-         * @param v                 source of the data
-         * @param info          source of the data
-         * @param target            dest of the data
-         * @param targetParent      dest of the data
+         *
+         * @param v            source of the data
+         * @param info         source of the data
+         * @param target       dest of the data
+         * @param targetParent dest of the data
          */
         void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent);
     }
@@ -126,12 +127,23 @@
         dispatchUserEvent(createLauncherEvent(v, intent), intent);
     }
 
-    public void logTap(View v) {
-        // TODO
+    public void logActionOnControl(int action, int controlType) {
+        LauncherEvent event = LoggerUtils.initLauncherEvent(Action.TOUCH, Target.CONTROL);
+        event.action.touch = action;
+        event.srcTarget[0].controlType = controlType;
+        event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
+        event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
+        dispatchUserEvent(event, null);
     }
 
-    public void logLongPress() {
-        // TODO
+    public void logActionOnContainer(int action, int dir, int containerType) {
+        LauncherEvent event = LoggerUtils.initLauncherEvent(Action.TOUCH, Target.CONTAINER);
+        event.action.touch = action;
+        event.action.dir = dir;
+        event.srcTarget[0].containerType = containerType;
+        event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
+        event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
+        dispatchUserEvent(event, null);
     }
 
     public void logDragNDrop() {
@@ -152,7 +164,6 @@
     public final void resetElapsedSessionMillis() {
         mElapsedSessionMillis = System.currentTimeMillis();
         mElapsedContainerMillis = System.currentTimeMillis();
-
     }
 
     public final void resetActionDurationMillis() {
@@ -164,8 +175,8 @@
             Log.d("UserEvent", String.format(Locale.US,
                     "action:%s\nchild:%s\nparent:%s\nelapsed container %d ms session %d ms",
                     LoggerUtils.getActionStr(ev.action),
-                    LoggerUtils.getTargetStr(ev.srcTarget[0]),
-                    LoggerUtils.getTargetStr(ev.srcTarget[1]),
+                    LoggerUtils.getTargetStr(ev.srcTarget != null ? ev.srcTarget[0] : null),
+                    LoggerUtils.getTargetStr(ev.srcTarget.length > 1 ? ev.srcTarget[1] : null),
                     ev.elapsedContainerMillis,
                     ev.elapsedSessionMillis));
         }
diff --git a/src/com/android/launcher3/pageindicators/CaretDrawable.java b/src/com/android/launcher3/pageindicators/CaretDrawable.java
index 3a7fc42..fcf3d23 100644
--- a/src/com/android/launcher3/pageindicators/CaretDrawable.java
+++ b/src/com/android/launcher3/pageindicators/CaretDrawable.java
@@ -34,29 +34,43 @@
 
     private float mCaretProgress;
 
-    private Paint mPaint = new Paint();
+    private Paint mShadowPaint = new Paint();
+    private Paint mCaretPaint = new Paint();
     private Path mPath = new Path();
-    private int mInset;
 
     public CaretDrawable(Context context) {
         final Resources res = context.getResources();
 
-        mPaint.setColor(res.getColor(R.color.all_apps_caret_color));
-        mPaint.setAntiAlias(true);
-        mPaint.setStrokeWidth(res.getDimensionPixelSize(R.dimen.all_apps_caret_stroke_width));
-        mPaint.setStyle(Paint.Style.STROKE);
-        mPaint.setStrokeCap(Paint.Cap.SQUARE);
-        mPaint.setStrokeJoin(Paint.Join.MITER);
+        final int strokeWidth = res.getDimensionPixelSize(R.dimen.all_apps_caret_stroke_width);
+        final int shadowSpread = res.getDimensionPixelSize(R.dimen.all_apps_caret_shadow_spread);
 
-        mInset = res.getDimensionPixelSize(R.dimen.all_apps_caret_inset);
+        mCaretPaint.setColor(res.getColor(R.color.all_apps_caret_color));
+        mCaretPaint.setAntiAlias(true);
+        mCaretPaint.setStrokeWidth(strokeWidth);
+        mCaretPaint.setStyle(Paint.Style.STROKE);
+        mCaretPaint.setStrokeCap(Paint.Cap.SQUARE);
+        mCaretPaint.setStrokeJoin(Paint.Join.MITER);
+
+        mShadowPaint.setColor(res.getColor(R.color.all_apps_caret_shadow_color));
+        mShadowPaint.setAntiAlias(true);
+        mShadowPaint.setStrokeWidth(strokeWidth + (shadowSpread * 2));
+        mShadowPaint.setStyle(Paint.Style.STROKE);
+        mShadowPaint.setStrokeCap(Paint.Cap.ROUND);
+        mShadowPaint.setStrokeJoin(Paint.Join.ROUND);
     }
 
     @Override
     public void draw(Canvas canvas) {
-        final float width = getBounds().width();
-        final float height = getBounds().height();
-        final float left = getBounds().left;
-        final float top = getBounds().top;
+        // Assumes caret paint is more important than shadow paint
+        if (Float.compare(mCaretPaint.getAlpha(), 0f) == 0) {
+            return;
+        }
+
+        // Assumes shadow stroke width is larger
+        final float width = getBounds().width() - mShadowPaint.getStrokeWidth();
+        final float height = getBounds().height() - mShadowPaint.getStrokeWidth();
+        final float left = getBounds().left + (mShadowPaint.getStrokeWidth() / 2);
+        final float top = getBounds().top + (mShadowPaint.getStrokeWidth() / 2);
 
         final float verticalInset = (height / 4);
         final float caretHeight = (height - (verticalInset * 2));
@@ -66,7 +80,8 @@
         mPath.lineTo(left + (width / 2), top + caretHeight * mCaretProgress);
         mPath.lineTo(left + width, top + caretHeight * (1 - mCaretProgress));
 
-        canvas.drawPath(mPath, mPaint);
+        canvas.drawPath(mPath, mShadowPaint);
+        canvas.drawPath(mPath, mCaretPaint);
     }
 
     @Override
@@ -78,21 +93,18 @@
 
     @Override
     public int getOpacity() {
-        return PixelFormat.OPAQUE;
+        return PixelFormat.TRANSLUCENT;
     }
 
     @Override
     public void setAlpha(int alpha) {
-        // no-op
+        mCaretPaint.setAlpha(alpha);
+        mShadowPaint.setAlpha(alpha);
+        invalidateSelf();
     }
 
     @Override
     public void setColorFilter(ColorFilter cf) {
         // no-op
     }
-
-    @Override
-    public void setBounds(int left, int top, int right, int bottom) {
-        super.setBounds(left + mInset, top + mInset, right - mInset, bottom - mInset);
-    }
 }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
index 8075201..fea47a9 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
@@ -16,13 +16,19 @@
 package com.android.launcher3.pageindicators;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 
 import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
 
 /**
- * Simply draws the caret drawable in the center. Used for the landscape layout.
+ * Simply draws the caret drawable bottom-right aligned in the view. This ensures that we can have
+ * a view with as large an area as we want (for touching) while maintaining a caret of size
+ * all_apps_caret_size.  Used only for the landscape layout.
  */
 public class PageIndicatorCaretLandscape extends PageIndicator {
     // all apps pull up handle drawable.
@@ -38,23 +44,25 @@
     public PageIndicatorCaretLandscape(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        setCaretDrawable(new CaretDrawable(context));
+        int caretSize = context.getResources().getDimensionPixelSize(R.dimen.all_apps_caret_size);
+        CaretDrawable caretDrawable = new CaretDrawable(context);
+        caretDrawable.setBounds(0, 0, caretSize, caretSize);
+        setCaretDrawable(caretDrawable);
+
         Launcher l = (Launcher) context;
         setOnTouchListener(l.getHapticFeedbackTouchListener());
         setOnClickListener(l);
+        setOnLongClickListener(l);
         setOnFocusChangeListener(l.mFocusHandler);
     }
 
     @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        int size = bottom - top;
-        int l = (right - left) / 2 - size / 2;
-        getCaretDrawable().setBounds(l, 0, l + size, size);
-    }
-
-    @Override
     protected void onDraw(Canvas canvas) {
+        Rect drawableBounds = getCaretDrawable().getBounds();
+        int count = canvas.save();
+        canvas.translate(getWidth() - drawableBounds.width(),
+                getHeight() - drawableBounds.height());
         getCaretDrawable().draw(canvas);
+        canvas.restoreToCount(count);
     }
 }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
index 684eb29..0d771ad 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
@@ -62,6 +62,8 @@
     private final int mLineHeight;
     private final TransformingTouchDelegate mTouchDelegate;
     private final int mTouchExtensionHeight;
+    private final int mCaretSizePx;
+    private final int mCaretWorkspaceOffsetPx;
 
     private static final Property<PageIndicatorLineCaret, Integer> PAINT_ALPHA
             = new Property<PageIndicatorLineCaret, Integer>(Integer.class, "paint_alpha") {
@@ -122,14 +124,19 @@
 
     public PageIndicatorLineCaret(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+
+        Resources res = context.getResources();
         mLinePaint = new Paint();
         mLinePaint.setAlpha(0);
+        mCaretSizePx = res.getDimensionPixelSize(R.dimen.all_apps_caret_size);
+        mCaretWorkspaceOffsetPx = res.getDimensionPixelSize(
+                R.dimen.all_apps_caret_workspace_offset);
 
         mLauncher = (Launcher) context;
         setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
         setOnClickListener(mLauncher);
+        setOnLongClickListener(mLauncher);
         setOnFocusChangeListener(mLauncher.mFocusHandler);
-        Resources res = context.getResources();
         setCaretDrawable(new CaretDrawable(context));
         mLineHeight = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_line_height);
         mTouchExtensionHeight = res.getDimensionPixelSize(
@@ -146,9 +153,10 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        int size = bottom - top;
-        int l = (right - left) / 2 - size / 2;
-        getCaretDrawable().setBounds(l, 0, l + size, size);
+        // Top/center align the caret in the page indicator space
+        int l = (right - left) / 2 - mCaretSizePx / 2;
+        getCaretDrawable().setBounds(l, mCaretWorkspaceOffsetPx, l + mCaretSizePx,
+                mCaretWorkspaceOffsetPx + mCaretSizePx);
 
         // The touch area is expanded below this view by #mTouchExtensionHeight
         // which extends to the top of the hotseat.
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
index 66e98cd..450c36d 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -81,11 +81,13 @@
     }
 
     /**
-     * Gets all the shortcuts associated with the given package and user.
+     * Gets all the manifest and dynamic shortcuts associated with the given package and user,
+     * to be displayed in the shortcuts container on long press.
      */
-    public List<ShortcutInfoCompat> queryForAllAppShortcuts(ComponentName activity,
+    public List<ShortcutInfoCompat> queryForShortcutsContainer(ComponentName activity,
             List<String> ids, UserHandleCompat user) {
-        return query(FLAG_GET_ALL, activity.getPackageName(), activity, ids, user);
+        return query(FLAG_MATCH_MANIFEST | FLAG_MATCH_DYNAMIC,
+                activity.getPackageName(), activity, ids, user);
     }
 
     /**
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
new file mode 100644
index 0000000..c48d160
--- /dev/null
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
@@ -0,0 +1,50 @@
+/*
+ * 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.shortcuts;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.R;
+
+/**
+ * A {@link BubbleTextView} that has the shortcut icon on the left and drag handle on the right.
+ */
+public class DeepShortcutTextView extends BubbleTextView {
+
+    public DeepShortcutTextView(Context context) {
+        this(context, null, 0);
+    }
+
+    public DeepShortcutTextView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public DeepShortcutTextView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    /** Use the BubbleTextView icon for the start and the drag handle for the end. */
+    protected void applyCompoundDrawables(Drawable icon) {
+        Drawable dragHandle = getResources().getDrawable(R.drawable.deep_shortcuts_drag_handle);
+        dragHandle.setBounds(0, 0, dragHandle.getIntrinsicWidth(), dragHandle.getIntrinsicHeight());
+        setCompoundDrawablesRelative(icon, null, dragHandle, null);
+    }
+}
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 7997d1e..f9dd336 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -16,19 +16,32 @@
 
 package com.android.launcher3.shortcuts;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
 import android.support.annotation.IntDef;
 import android.util.AttributeSet;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
 
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.LauncherViewPropertyAnimator;
 import com.android.launcher3.R;
+import com.android.launcher3.util.PillRevealOutlineProvider;
 
 /**
- * A {@link BubbleTextView} that represents a deep shortcut within an app.
+ * A {@link android.widget.FrameLayout} that contains a {@link DeepShortcutView}.
+ * This lets us animate the DeepShortcutView (icon and text) separately from the background.
  */
-public class DeepShortcutView extends BubbleTextView {
+public class DeepShortcutView extends FrameLayout {
 
-    private static final float HOVER_SCALE = 1.1f;
+    private static final float HOVER_SCALE = 1.05f;
+
     // The direction this view should translate when animating the hover state.
     // This allows hovered shortcuts to "push" other shortcuts away.
     @IntDef({DIRECTION_UP, DIRECTION_NONE, DIRECTION_DOWN})
@@ -37,12 +50,18 @@
     public static final int DIRECTION_UP = -1;
     public static final int DIRECTION_NONE = 0;
     public static final int DIRECTION_DOWN = 1;
+
     @TranslationDirection
     private int mTranslationDirection = DIRECTION_NONE;
 
     private int mSpacing;
+    private int mRadius;
+    private Rect mPillRect;
     private int mTop;
     private boolean mIsHoveringOver = false;
+    private LauncherViewPropertyAnimator mHoverAnimator;
+
+    private BubbleTextView mBubbleText;
 
     public DeepShortcutView(Context context) {
         this(context, null, 0);
@@ -56,10 +75,76 @@
         super(context, attrs, defStyle);
 
         mSpacing = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_spacing);
+        mRadius = getResources().getDimensionPixelSize(R.dimen.bg_pill_radius);
+        mPillRect = new Rect();
+        mHoverAnimator = new LauncherViewPropertyAnimator(this);
     }
 
-    public int getSpacing() {
-        return mSpacing;
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mBubbleText = (BubbleTextView) findViewById(R.id.deep_shortcut);
+    }
+
+    public BubbleTextView getBubbleText() {
+        return mBubbleText;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        mPillRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
+    }
+
+    @Override
+    public void setPivotX(float pivotX) {
+        super.setPivotX(pivotX);
+        mBubbleText.setPivotX(pivotX);
+    }
+
+    @Override
+    public void setPivotY(float pivotY) {
+        super.setPivotY(pivotY);
+        mBubbleText.setPivotY(pivotY);
+    }
+
+    /**
+     * Creates an animator to play when the shortcut container is being opened.
+     *
+     * @param animationIndex The index at which this animation will be started
+     *                       relative to other DeepShortcutView open animations.
+     */
+    public Animator createOpenAnimation(int animationIndex, boolean isContainerAboveIcon) {
+        final Resources res = getResources();
+        setVisibility(INVISIBLE);
+
+        AnimatorSet openAnimation = LauncherAnimUtils.createAnimatorSet();
+
+        Animator reveal = new PillRevealOutlineProvider((int) getPivotX(), (int) getPivotY(),
+                mPillRect, mRadius).createRevealAnimator(this);
+        reveal.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                setVisibility(VISIBLE);
+            }
+        });
+
+        float transY = res.getDimensionPixelSize(R.dimen.deep_shortcut_anim_translation_y);
+        Animator translationY = ObjectAnimator.ofFloat(this, TRANSLATION_Y,
+                isContainerAboveIcon ? transY : -transY, 0);
+
+        // Only scale mBubbleText (the icon and text, not the background).
+        mBubbleText.setScaleX(0);
+        mBubbleText.setScaleY(0);
+        LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(mBubbleText)
+                .scaleX(1).scaleY(1);
+
+        openAnimation.playTogether(reveal, translationY, scale);
+        openAnimation.setStartDelay(animationIndex * res.getInteger(
+                R.integer.config_deepShortcutOpenStagger));
+        openAnimation.setDuration(res.getInteger(R.integer.config_deepShortcutOpenDuration));
+        openAnimation.setInterpolator(new DecelerateInterpolator());
+        return openAnimation;
     }
 
     /**
@@ -95,16 +180,16 @@
     /**
      * If this shortcut is being hovered over, we scale it up. If another shortcut is being hovered
      * over, we translate this one away from it to account for its increased size.
-     *
-     * TODO: apply motion spec here
      */
     private void animateHoverState() {
+        if (mHoverAnimator.isRunning()) {
+            return;
+        }
         float scale = mIsHoveringOver ? HOVER_SCALE : 1f;
-        setScaleX(scale);
-        setScaleY(scale);
-
-        float translation = (HOVER_SCALE - 1f) * getHeight();
-        setTranslationY(translation * mTranslationDirection);
+        float translateY = (HOVER_SCALE - 1f) * getHeight() * mTranslationDirection;
+        mHoverAnimator.scaleX(scale).scaleY(scale).translationY(translateY)
+                .setDuration(getResources().getInteger(R.integer.config_deepShortcutHoverDuration))
+                .start();
     }
 
     public boolean isHoveringOver() {
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
index d9e34a6..92afeb9 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
@@ -1,6 +1,24 @@
+/*
+ * 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.shortcuts;
 
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.Context;
@@ -12,6 +30,8 @@
 import android.os.Looper;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.view.HapticFeedbackConstants;
+import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -22,22 +42,25 @@
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LogDecelerateInterpolator;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.graphics.ScaledPreviewProvider;
 import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.util.UiThreadCircularReveal;
 
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 /**
@@ -49,13 +72,15 @@
         UserEventDispatcher.LaunchSourceProvider {
     private static final String TAG = "ShortcutsContainer";
 
-    private Launcher mLauncher;
-    private DeepShortcutManager mDeepShortcutsManager;
+    private final Launcher mLauncher;
+    private final DeepShortcutManager mDeepShortcutsManager;
     private final int mDragDeadzone;
     private final int mStartDragThreshold;
+    private final ShortcutMenuAccessibilityDelegate mAccessibilityDelegate;
+
     private BubbleTextView mDeferredDragIcon;
     private int mActivePointerId;
-    private Point mTouchDown = null;
+    private int[] mTouchDown = null;
     private DragView mDragView;
     private float mLastX, mLastY;
     private float mDistanceDragged = 0;
@@ -64,6 +89,29 @@
     private Point mIconLastTouchPos = new Point();
     private boolean mIsLeftAligned;
     private boolean mIsAboveIcon;
+    private boolean mIsAnimatingOpen;
+
+    private boolean mSrcIconDragStarted;
+
+    /**
+     * Sorts shortcuts in rank order, with manifest shortcuts coming before dynamic shortcuts.
+     */
+    private static final Comparator<ShortcutInfoCompat> sShortcutsComparator
+            = new Comparator<ShortcutInfoCompat>() {
+        @Override
+        public int compare(ShortcutInfoCompat a, ShortcutInfoCompat b) {
+            if (a.isDeclaredInManifest() && !b.isDeclaredInManifest()) {
+                return -1;
+            }
+            if (!a.isDeclaredInManifest() && b.isDeclaredInManifest()) {
+                return 1;
+            }
+            return Integer.compare(a.getRank(), b.getRank());
+        }
+    };
+
+    private static final Comparator<ShortcutInfoCompat> sShortcutsComparatorReversed
+            = Collections.reverseOrder(sShortcutsComparator);
 
     public DeepShortcutsContainer(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -73,6 +121,7 @@
         mDragDeadzone = ViewConfiguration.get(context).getScaledTouchSlop();
         mStartDragThreshold = getResources().getDimensionPixelSize(
                 R.dimen.deep_shortcuts_start_drag_threshold);
+        mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(mLauncher);
     }
 
     public DeepShortcutsContainer(Context context, AttributeSet attrs) {
@@ -85,12 +134,15 @@
 
     public void populateAndShow(final BubbleTextView originalIcon, final List<String> ids) {
         // Add dummy views first, and populate with real shortcut info when ready.
+        final int spacing = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_spacing);
+        final LayoutInflater inflater = mLauncher.getLayoutInflater();
         for (int i = 0; i < ids.size(); i++) {
-            final DeepShortcutView shortcut = (DeepShortcutView)
-                    mLauncher.getLayoutInflater().inflate(R.layout.deep_shortcut, this, false);
+            final DeepShortcutView shortcut =
+                    (DeepShortcutView) inflater.inflate(R.layout.deep_shortcut, this, false);
             if (i < ids.size() - 1) {
-                ((LayoutParams) shortcut.getLayoutParams()).bottomMargin = shortcut.getSpacing();
+                ((LayoutParams) shortcut.getLayoutParams()).bottomMargin = spacing;
             }
+            shortcut.getBubbleText().setAccessibilityDelegate(mAccessibilityDelegate);
             addView(shortcut);
         }
 
@@ -109,16 +161,19 @@
             @Override
             public void run() {
                 final List<ShortcutInfoCompat> shortcuts = mDeepShortcutsManager
-                        .queryForAllAppShortcuts(activity, ids, user);
+                        .queryForShortcutsContainer(activity, ids, user);
+                // We want the lowest rank to be closest to the user's finger.
+                final Comparator<ShortcutInfoCompat> shortcutsComparator = mIsAboveIcon ?
+                        sShortcutsComparatorReversed : sShortcutsComparator;
+                Collections.sort(shortcuts, shortcutsComparator);
                 for (int i = 0; i < shortcuts.size(); i++) {
                     final ShortcutInfoCompat shortcut = shortcuts.get(i);
                     final ShortcutInfo launcherShortcutInfo = ShortcutInfo
                             .fromDeepShortcutInfo(shortcut, mLauncher);
-                    CharSequence label = shortcut.getLongLabel();
-                    if (TextUtils.isEmpty(label)) {
-                        label = shortcut.getShortLabel();
-                    }
-                    uiHandler.post(new UpdateShortcutChild(i, launcherShortcutInfo, label));
+                    CharSequence shortLabel = shortcut.getShortLabel();
+                    CharSequence longLabel = shortcut.getLongLabel();
+                    uiHandler.post(new UpdateShortcutChild(i, launcherShortcutInfo,
+                            shortLabel, longLabel));
                 }
             }
         });
@@ -128,46 +183,70 @@
     private class UpdateShortcutChild implements Runnable {
         private int mShortcutChildIndex;
         private ShortcutInfo mShortcutChildInfo;
-        private CharSequence mLabel;
+        private CharSequence mShortLabel;
+        private CharSequence mLongLabel;
 
         public UpdateShortcutChild(int shortcutChildIndex, ShortcutInfo shortcutChildInfo,
-                CharSequence label) {
+                CharSequence shortLabel, CharSequence longLabel) {
             mShortcutChildIndex = shortcutChildIndex;
             mShortcutChildInfo = shortcutChildInfo;
-            mLabel = label;
+            mShortLabel = shortLabel;
+            mLongLabel = longLabel;
         }
 
         @Override
         public void run() {
-            DeepShortcutView shortcutView = (DeepShortcutView) getChildAt(mShortcutChildIndex);
+            BubbleTextView shortcutView = getShortcutAt(mShortcutChildIndex).getBubbleText();
             shortcutView.applyFromShortcutInfo(mShortcutChildInfo,
                     LauncherAppState.getInstance().getIconCache());
-            shortcutView.setText(mLabel);
+            // Use the long label as long as it exists and fits.
+            int availableWidth = shortcutView.getWidth() - shortcutView.getTotalPaddingLeft()
+                    - shortcutView.getTotalPaddingRight();
+            boolean usingLongLabel = !TextUtils.isEmpty(mLongLabel)
+                    && shortcutView.getPaint().measureText(mLongLabel.toString()) <= availableWidth;
+            shortcutView.setText(usingLongLabel ? mLongLabel : mShortLabel);
             shortcutView.setOnClickListener(mLauncher);
             shortcutView.setOnLongClickListener(DeepShortcutsContainer.this);
             shortcutView.setOnTouchListener(DeepShortcutsContainer.this);
         }
     }
 
-    // TODO: update this animation
+    private DeepShortcutView getShortcutAt(int index) {
+        return (DeepShortcutView) getChildAt(index);
+    }
+
     private void animateOpen(BubbleTextView originalIcon) {
         orientAboutIcon(originalIcon);
 
         setVisibility(View.VISIBLE);
-        int rx = (int) Math.max(Math.max(getMeasuredWidth() - getPivotX(), 0), getPivotX());
-        int ry = (int) Math.max(Math.max(getMeasuredHeight() - getPivotY(), 0), getPivotY());
-        float radius = (float) Math.hypot(rx, ry);
-        Animator reveal = UiThreadCircularReveal.createCircularReveal(this, (int) getPivotX(),
-                (int) getPivotY(), 0, radius);
-        reveal.setDuration(getResources().getInteger(R.integer.config_materialFolderExpandDuration));
-        reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
-        reveal.start();
+
+        final AnimatorSet shortcutAnims = LauncherAnimUtils.createAnimatorSet();
+        final int numShortcuts = getChildCount();
+        final int arrowOffset = getResources().getDimensionPixelSize(
+                R.dimen.deep_shortcuts_arrow_horizontal_offset);
+        final int pivotX = mIsLeftAligned ? arrowOffset : getMeasuredWidth() - arrowOffset;
+        final int pivotY = getShortcutAt(0).getMeasuredHeight() / 2;
+        for (int i = 0; i < numShortcuts; i++) {
+            DeepShortcutView deepShortcutView = getShortcutAt(i);
+            deepShortcutView.setPivotX(pivotX);
+            deepShortcutView.setPivotY(pivotY);
+            int animationIndex = mIsAboveIcon ? numShortcuts - i - 1 : i;
+            shortcutAnims.play(deepShortcutView.createOpenAnimation(animationIndex, mIsAboveIcon));
+        }
+        shortcutAnims.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mIsAnimatingOpen = false;
+            }
+        });
+        mIsAnimatingOpen = true;
+        shortcutAnims.start();
     }
 
     /**
      * Orients this container above or below the given icon, aligning with the left or right.
      *
-     * These are the preferred orientations, in order:
+     * These are the preferred orientations, in order (RTL prefers right-aligned over left):
      * - Above and left-aligned
      * - Above and right-aligned
      * - Below and left-aligned
@@ -176,7 +255,7 @@
      * So we always align left if there is enough horizontal space
      * and align above if there is enough vertical space.
      *
-     * TODO: draw pointer based on orientation.
+     * TODO: draw arrow based on orientation.
      */
     private void orientAboutIcon(BubbleTextView icon) {
         int width = getMeasuredWidth();
@@ -184,24 +263,30 @@
 
         DragLayer dragLayer = mLauncher.getDragLayer();
         dragLayer.getDescendantRectRelativeToSelf(icon, mTempRect);
-        // Align left and above by default.
-        int x = mTempRect.left + icon.getPaddingLeft();
-        int y = mTempRect.top - height;
         Rect insets = dragLayer.getInsets();
 
-        mIsLeftAligned = x + width < dragLayer.getRight() - insets.right;
-        if (!mIsLeftAligned) {
-            x = mTempRect.right - width - icon.getPaddingRight();
+        // Align left (right in RTL) if there is room.
+        boolean isRtl = Utilities.isRtl(getResources());
+        int leftAlignedX = mTempRect.left + icon.getPaddingLeft();
+        int rightAlignedX = mTempRect.right - width - icon.getPaddingRight();
+        int x = leftAlignedX;
+        boolean canBeLeftAligned = leftAlignedX + width < dragLayer.getRight() - insets.right;
+        boolean canBeRightAligned = rightAlignedX > dragLayer.getLeft() + insets.left;
+        if (!canBeLeftAligned || (isRtl && canBeRightAligned)) {
+            x = rightAlignedX;
+        }
+        mIsLeftAligned = x == leftAlignedX;
+        if (isRtl) {
+            x -= dragLayer.getWidth() - width;
         }
 
+        // Open above icon if there is room.
+        int y = mTempRect.top - height;
         mIsAboveIcon = mTempRect.top - height > dragLayer.getTop() + insets.top;
         if (!mIsAboveIcon) {
             y = mTempRect.bottom;
         }
 
-        setPivotX(width / 2);
-        setPivotY(height / 2);
-
         // Insets are added later, so subtract them now.
         y -= insets.top;
 
@@ -232,13 +317,12 @@
         final int registrationY = motionDownY - dragLayerY;
 
         float scaleDps = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_drag_view_scale);
-        mDragView = new DragView(mLauncher, b, registrationX, registrationY,
-                0, 0, b.getWidth(), b.getHeight(), 1f, scaleDps);
+        mDragView = new DragView(mLauncher, b, registrationX, registrationY, 1f, scaleDps);
         mLastX = mLastY = mDistanceDragged = 0;
         mDragView.show(motionDownX, motionDownY);
     }
 
-    public boolean onForwardedEvent(MotionEvent ev, int activePointerId, Point touchDown) {
+    public boolean onForwardedEvent(MotionEvent ev, int activePointerId, int[] touchDown) {
         mActivePointerId = activePointerId;
         mTouchDown = touchDown;
         return dispatchTouchEvent(ev);
@@ -274,7 +358,8 @@
 
             boolean containerContainsTouch = x >= 0 && y >= 0 && x < getWidth() && y < getHeight();
             if (shouldStartDeferredDrag((int) x, (int) y, containerContainsTouch)) {
-                cleanupDeferredDrag();
+                mSrcIconDragStarted = true;
+                cleanupDeferredDrag(true);
                 mDeferredDragIcon.getParent().requestDisallowInterceptTouchEvent(false);
                 mDeferredDragIcon.getOnLongClickListener().onLongClick(mDeferredDragIcon);
                 mLauncher.getDragController().onTouchEvent(ev);
@@ -282,8 +367,8 @@
             } else {
                 // Determine whether touch is over a shortcut.
                 boolean hoveringOverShortcut = false;
-                for (int i = 0; i < childCount; i++) {
-                    DeepShortcutView shortcut = (DeepShortcutView) getChildAt(i);
+                for (int i = 0; i < childCount && !mIsAnimatingOpen; i++) {
+                    DeepShortcutView shortcut = getShortcutAt(i);
                     if (shortcut.updateHoverState(containerContainsTouch, hoveringOverShortcut, y)) {
                         hoveringOverShortcut = true;
                     }
@@ -304,15 +389,18 @@
                 }
             }
         } else if (action == MotionEvent.ACTION_UP) {
-            cleanupDeferredDrag();
+            cleanupDeferredDrag(true);
             // Launch a shortcut if user was hovering over it.
             for (int i = 0; i < childCount; i++) {
-                DeepShortcutView shortcut = (DeepShortcutView) getChildAt(i);
+                DeepShortcutView shortcut = getShortcutAt(i);
                 if (shortcut.isHoveringOver()) {
-                    shortcut.performClick();
+                    shortcut.getBubbleText().performClick();
                     break;
                 }
             }
+        } else if (action == MotionEvent.ACTION_CANCEL) {
+            // Do not change the source icon visibility if we are already dragging the source icon.
+            cleanupDeferredDrag(!mSrcIconDragStarted);
         }
         return true;
     }
@@ -332,16 +420,18 @@
      */
     private boolean shouldStartDeferredDrag(int x, int y, boolean containerContainsTouch) {
         int closestEdgeY = mIsAboveIcon ? getMeasuredHeight() : 0;
-        double distToEdge = Math.abs(mTouchDown.y - closestEdgeY);
-        double newDistToEdge = Math.hypot(x - mTouchDown.x, y - closestEdgeY);
-        return  !containerContainsTouch && (newDistToEdge - distToEdge > mStartDragThreshold);
+        double distToEdge = Math.abs(mTouchDown[1] - closestEdgeY);
+        double newDistToEdge = Math.hypot(x - mTouchDown[0], y - closestEdgeY);
+        return !containerContainsTouch && (newDistToEdge - distToEdge > mStartDragThreshold);
     }
 
-    public void cleanupDeferredDrag() {
+    public void cleanupDeferredDrag(boolean updateSrcVisibility) {
         if (mDragView != null) {
             mDragView.remove();
         }
-        mDeferredDragIcon.setVisibility(VISIBLE);
+        if (updateSrcVisibility) {
+            mDeferredDragIcon.setVisibility(VISIBLE);
+        }
     }
 
     @Override
@@ -363,7 +453,8 @@
         if (!mLauncher.isDraggingEnabled()) return false;
 
         // Long clicked on a shortcut.
-        mLauncher.getWorkspace().beginDragShared(v, mIconLastTouchPos, this, false);
+        mLauncher.getWorkspace().beginDragShared(v, mIconLastTouchPos, this, false,
+                new ScaledPreviewProvider(v));
         // TODO: support dragging from within folder without having to close it
         mLauncher.closeFolder();
         return false;
@@ -386,8 +477,7 @@
 
     @Override
     public float getIntrinsicIconScaleFactor() {
-        return (float) getResources().getDimensionPixelSize(R.dimen.deep_shortcut_icon_size)
-                / mLauncher.getDeviceProfile().iconSizePx;
+        return 1f;
     }
 
     @Override
@@ -420,10 +510,30 @@
 
     @Override
     public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
-        target.itemType = LauncherLogProto.SHORTCUT; // TODO: change to DYNAMIC_SHORTCUT
-        target.gridX = info.cellX;
-        target.gridY = info.cellY;
-        target.pageIndex = 0;
-        targetParent.containerType = LauncherLogProto.FOLDER; // TODO: change to DYNAMIC_SHORTCUTS
+        target.itemType = LauncherLogProto.DEEPSHORTCUT;
+        // TODO: add target.rank
+        targetParent.containerType = LauncherLogProto.DEEPSHORTCUTS;
+    }
+
+    /**
+     * Shows the shortcuts container for {@param icon}
+     * @return the container if shown or null.
+     */
+    public static DeepShortcutsContainer showForIcon(BubbleTextView icon) {
+        Launcher launcher = Launcher.getLauncher(icon.getContext());
+        List<String> ids = launcher.getShortcutIdsForItem((ItemInfo) icon.getTag());
+        if (!ids.isEmpty()) {
+            // There are shortcuts associated with the app, so defer its drag.
+            final DeepShortcutsContainer container =
+                    (DeepShortcutsContainer) launcher.getLayoutInflater().inflate(
+                            R.layout.deep_shortcuts_container, launcher.getDragLayer(), false);
+            container.setVisibility(View.INVISIBLE);
+            launcher.getDragLayer().addView(container);
+            container.populateAndShow(icon, ids);
+            icon.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
+                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+            return container;
+        }
+        return null;
     }
 }
diff --git a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
index 8dbeaa7..00553df 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
@@ -97,6 +97,14 @@
         return mShortcutInfo.isPinned();
     }
 
+    public boolean isDeclaredInManifest() {
+        return mShortcutInfo.isDeclaredInManifest();
+    }
+
+    public int getRank() {
+        return mShortcutInfo.getRank();
+    }
+
     @Override
     public String toString() {
         return mShortcutInfo.toString();
diff --git a/src/com/android/launcher3/shortcuts/ShortcutKey.java b/src/com/android/launcher3/shortcuts/ShortcutKey.java
index c9d66eb..c15f91d 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutKey.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutKey.java
@@ -2,7 +2,6 @@
 
 import android.content.ComponentName;
 
-import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.util.ComponentKey;
 
@@ -22,9 +21,4 @@
         return new ShortcutKey(shortcutInfo.getPackage(), shortcutInfo.getUserHandle(),
                 shortcutInfo.getId());
     }
-
-    @Override
-    public String toString() {
-        return flattenToString(LauncherAppState.getInstance().getContext());
-    }
 }
diff --git a/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java b/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java
index 63c8363..f94595b 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutsContainerListener.java
@@ -1,10 +1,6 @@
 package com.android.launcher3.shortcuts;
 
-import android.content.Context;
-import android.graphics.Point;
 import android.os.SystemClock;
-import android.view.HapticFeedbackConstants;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -12,14 +8,10 @@
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CheckLongPressHelper;
-import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragLayer;
 
-import java.util.List;
-
 /**
  * A {@link android.view.View.OnTouchListener} that creates a {@link DeepShortcutsContainer} and
  * forwards touch events to it. This listener should be put on any icon that supports shortcuts.
@@ -53,9 +45,13 @@
 
     private Launcher mLauncher;
     private DragLayer mDragLayer;
-    private MotionEvent mTouchDownEvent;
-    /** The coordinates of the touch down, relative do the shortcuts container. */
-    private final Point mTouchDown;
+    /** The coordinates of the touch down, relative to the shortcuts container. */
+    private final int[] mTouchDown;
+    private boolean mHasMappedTouchDownToContainerCoord;
+
+    /** If true, the gesture is not handled. The value is reset when next gesture starts. */
+    private boolean mIgnoreCurrentGesture;
+    private DeepShortcutsContainer mShortcutsContainer;
 
     public ShortcutsContainerListener(BubbleTextView icon) {
         mSrcIcon = icon;
@@ -68,21 +64,24 @@
 
         mLauncher = Launcher.getLauncher(mSrcIcon.getContext());
         mDragLayer = mLauncher.getDragLayer();
-        mTouchDown = new Point();
+        mTouchDown = new int[2];
     }
 
     @Override
     public boolean onTouch(View v, MotionEvent event) {
-        if (mLauncher.getShortcutIdsForItem((ItemInfo) v.getTag()).isEmpty()) {
-            // There are no shortcuts associated with this item, so return to normal touch handling.
-            return false;
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            // There are no shortcuts associated with this item,
+            // so return to normal touch handling.
+            mIgnoreCurrentGesture = !mSrcIcon.hasDeepShortcuts();
+
+            mTouchDown[0] = (int) event.getX();
+            mTouchDown[1] = (int) event.getY();
+            mDragLayer.getDescendantCoordRelativeToSelf(mSrcIcon, mTouchDown);
+            mHasMappedTouchDownToContainerCoord = false;
         }
 
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            if (mTouchDownEvent != null) {
-                mTouchDownEvent.recycle();
-            }
-            mTouchDownEvent = MotionEvent.obtainNoHistory(event);
+        if (mIgnoreCurrentGesture) {
+            return false;
         }
 
         final boolean wasForwarding = mForwarding;
@@ -128,25 +127,8 @@
      * @return true to start forwarding, false otherwise
      */
     protected boolean onForwardingStarted() {
-        List<String> ids = mLauncher.getShortcutIdsForItem((ItemInfo) mSrcIcon.getTag());
-        if (!ids.isEmpty()) {
-            // There are shortcuts associated with the app, so defer its drag.
-            LayoutInflater layoutInflater = (LayoutInflater) mLauncher.getSystemService
-                    (Context.LAYOUT_INFLATER_SERVICE);
-            final DeepShortcutsContainer deepShortcutsContainer = (DeepShortcutsContainer)
-                    layoutInflater.inflate(R.layout.deep_shortcuts_container, mDragLayer, false);
-            deepShortcutsContainer.setVisibility(View.INVISIBLE);
-            mDragLayer.addView(deepShortcutsContainer);
-            deepShortcutsContainer.populateAndShow(mSrcIcon, ids);
-            mSrcIcon.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
-                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
-
-            // Convert touch down event to the container's coordinates.
-            Utilities.translateEventCoordinates(mSrcIcon, deepShortcutsContainer, mTouchDownEvent);
-            mTouchDown.set((int) mTouchDownEvent.getX(), (int) mTouchDownEvent.getY());
-            return true;
-        }
-        return false;
+        mShortcutsContainer = DeepShortcutsContainer.showForIcon(mSrcIcon);
+        return mShortcutsContainer != null;
     }
 
     /**
@@ -155,6 +137,7 @@
      * @return true to stop forwarding, false otherwise
      */
     protected boolean onForwardingStopped() {
+        mShortcutsContainer = null;
         return true;
     }
 
@@ -221,8 +204,8 @@
     private void onLongPress() {
         clearCallbacks();
 
-        final View src = mSrcIcon;
-        if (!src.isEnabled() || mLauncher.getShortcutIdsForItem((ItemInfo) src.getTag()).isEmpty()) {
+        final BubbleTextView src = mSrcIcon;
+        if (!src.isEnabled() || !src.hasDeepShortcuts()) {
             // Ignore long-press if the view is disabled or doesn't have shortcuts.
             return;
         }
@@ -252,18 +235,25 @@
      */
     private boolean onTouchForwarded(MotionEvent srcEvent) {
         final View src = mSrcIcon;
-
-        final DeepShortcutsContainer dst = mLauncher.getOpenShortcutsContainer();
+        final DeepShortcutsContainer dst = mShortcutsContainer;
         if (dst == null) {
             return false;
         }
+        if (!dst.isLaidOut()) {
+            return true;
+        }
 
         // Convert event to destination-local coordinates.
         final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent);
         Utilities.translateEventCoordinates(src, dst, dstEvent);
 
+        // Convert touch down event to destination-local coordinates.
+        if (!mHasMappedTouchDownToContainerCoord) {
+            mDragLayer.mapCoordInSelfToDescendent(dst, mTouchDown);
+            mHasMappedTouchDownToContainerCoord = true;
+        }
+
         // Forward converted event to destination view, then recycle it.
-        // TODO: don't create objects in onForwardedEvent.
         final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId, mTouchDown);
         dstEvent.recycle();
 
diff --git a/src/com/android/launcher3/testing/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java
index c62ce0e..ae552d2 100644
--- a/src/com/android/launcher3/testing/LauncherExtension.java
+++ b/src/com/android/launcher3/testing/LauncherExtension.java
@@ -255,5 +255,10 @@
         @Override
         public void onDetachedFromWindow() {
         }
+
+        @Override
+        public boolean shouldShowDiscoveryBounce() {
+            return false;
+        }
     }
 }
diff --git a/src/com/android/launcher3/util/CircleRevealOutlineProvider.java b/src/com/android/launcher3/util/CircleRevealOutlineProvider.java
new file mode 100644
index 0000000..c192120
--- /dev/null
+++ b/src/com/android/launcher3/util/CircleRevealOutlineProvider.java
@@ -0,0 +1,57 @@
+/*
+ * 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.util;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class CircleRevealOutlineProvider extends RevealOutlineAnimation {
+
+    private int mCenterX;
+    private int mCenterY;
+    private float mRadius0;
+    private float mRadius1;
+
+    /**
+     * @param x reveal center x
+     * @param y reveal center y
+     * @param r0 initial radius
+     * @param r1 final radius
+     */
+    public CircleRevealOutlineProvider(int x, int y, float r0, float r1) {
+        mCenterX = x;
+        mCenterY = y;
+        mRadius0 = r0;
+        mRadius1 = r1;
+    }
+
+    @Override
+    public boolean shouldRemoveElevationDuringAnimation() {
+        return true;
+    }
+
+    @Override
+    public void setProgress(float progress) {
+        mOutlineRadius = (1 - progress) * mRadius0 + progress * mRadius1;
+
+        mOutline.left = (int) (mCenterX - mOutlineRadius);
+        mOutline.top = (int) (mCenterY - mOutlineRadius);
+        mOutline.right = (int) (mCenterX + mOutlineRadius);
+        mOutline.bottom = (int) (mCenterY + mOutlineRadius);
+    }
+}
diff --git a/src/com/android/launcher3/util/ComponentKey.java b/src/com/android/launcher3/util/ComponentKey.java
index b7aafae..144b411 100644
--- a/src/com/android/launcher3/util/ComponentKey.java
+++ b/src/com/android/launcher3/util/ComponentKey.java
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 
@@ -60,17 +61,6 @@
         mHashCode = Arrays.hashCode(new Object[] {componentName, user});
     }
 
-    /**
-     * Encodes a component key as a string of the form [flattenedComponentString#userId].
-     */
-    public String flattenToString(Context context) {
-        String flattened = componentName.flattenToString();
-        if (user != null) {
-            flattened += "#" + UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
-        }
-        return flattened;
-    }
-
     @Override
     public int hashCode() {
         return mHashCode;
@@ -81,4 +71,12 @@
         ComponentKey other = (ComponentKey) o;
         return other.componentName.equals(componentName) && other.user.equals(user);
     }
+
+    /**
+     * Encodes a component key as a string of the form [flattenedComponentString#userId].
+     */
+    @Override
+    public String toString() {
+        return componentName.flattenToString() + "#" + user;
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/util/IconNormalizer.java b/src/com/android/launcher3/util/IconNormalizer.java
index 4087d7b..040a1b5 100644
--- a/src/com/android/launcher3/util/IconNormalizer.java
+++ b/src/com/android/launcher3/util/IconNormalizer.java
@@ -19,6 +19,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 
 import com.android.launcher3.LauncherAppState;
@@ -74,8 +75,10 @@
      *
      * This closeness is used to determine the ratio of hull area to the full icon size.
      * Refer {@link #MAX_CIRCLE_AREA_FACTOR} and {@link #MAX_SQUARE_AREA_FACTOR}
+     *
+     * @param outBounds optional rect to receive the fraction distance from each edge.
      */
-    public synchronized float getScale(Drawable d) {
+    public synchronized float getScale(Drawable d, RectF outBounds) {
         int width = d.getIntrinsicWidth();
         int height = d.getIntrinsicHeight();
         if (width <= 0 || height <= 0) {
@@ -168,6 +171,14 @@
             scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1  - hullByRect);
         }
 
+        if (outBounds != null) {
+            outBounds.left = ((float) leftX) / width;
+            outBounds.right = 1 - ((float) rightX) / width;
+
+            outBounds.top = ((float) topY) / height;
+            outBounds.bottom = 1 - ((float) bottomY) / height;
+        }
+
         float areaScale = area / (width * height);
         // Use sqrt of the final ratio as the images is scaled across both width and height.
         float scale = areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
diff --git a/src/com/android/launcher3/util/PillRevealOutlineProvider.java b/src/com/android/launcher3/util/PillRevealOutlineProvider.java
new file mode 100644
index 0000000..09ff9bd
--- /dev/null
+++ b/src/com/android/launcher3/util/PillRevealOutlineProvider.java
@@ -0,0 +1,66 @@
+/*
+ * 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.util;
+
+import android.annotation.TargetApi;
+import android.graphics.Rect;
+import android.os.Build;
+import android.view.ViewOutlineProvider;
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+/**
+ * A {@link ViewOutlineProvider} that animates a reveal in a "pill" shape.
+ * A pill is simply a round rect, but we assume the width is greater than
+ * the height and that the radius is equal to half the height.
+ */
+public class PillRevealOutlineProvider extends RevealOutlineAnimation {
+
+    private int mCenterX;
+    private int mCenterY;
+    private Rect mPillRect;
+
+    /**
+     * @param x reveal center x
+     * @param y reveal center y
+     * @param pillRect round rect that represents the final pill shape
+     * @param pillRectRadius radius of the round rect
+     */
+    public PillRevealOutlineProvider(int x, int y, Rect pillRect, float pillRectRadius) {
+        mCenterX = x;
+        mCenterY = y;
+        mPillRect = pillRect;
+        mOutlineRadius = pillRectRadius;
+    }
+
+    @Override
+    public boolean shouldRemoveElevationDuringAnimation() {
+        return false;
+    }
+
+    @Override
+    public void setProgress(float progress) {
+        // Assumes width is greater than height.
+        int centerToEdge = Math.max(mCenterX, mPillRect.width() - mCenterX);
+        int currentSize = (int) (progress * centerToEdge);
+
+        // Bound the outline to the final pill shape defined by mPillRect.
+        mOutline.left = Math.max(mPillRect.left, mCenterX - currentSize);
+        mOutline.top = Math.max(mPillRect.top, mCenterY - currentSize);
+        mOutline.right = Math.min(mPillRect.right, mCenterX + currentSize);
+        mOutline.bottom = Math.min(mPillRect.bottom, mCenterY + currentSize);
+    }
+}
diff --git a/src/com/android/launcher3/util/RevealOutlineAnimation.java b/src/com/android/launcher3/util/RevealOutlineAnimation.java
new file mode 100644
index 0000000..4447c3b
--- /dev/null
+++ b/src/com/android/launcher3/util/RevealOutlineAnimation.java
@@ -0,0 +1,72 @@
+package com.android.launcher3.util;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+import com.android.launcher3.Utilities;
+
+/**
+ * A {@link ViewOutlineProvider} that has helper functions to create reveal animations.
+ * This class should be extended so that subclasses can define the reveal shape as the
+ * animation progresses from 0 to 1.
+ */
+public abstract class RevealOutlineAnimation extends ViewOutlineProvider {
+    protected Rect mOutline;
+    protected float mOutlineRadius;
+
+    public RevealOutlineAnimation() {
+        mOutline = new Rect();
+    }
+
+    /** Returns whether elevation should be removed for the duration of the reveal animation. */
+    abstract boolean shouldRemoveElevationDuringAnimation();
+    /** Sets the progress, from 0 to 1, of the reveal animation. */
+    abstract void setProgress(float progress);
+
+    public ValueAnimator createRevealAnimator(final View revealView) {
+        ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+        final float elevation = revealView.getElevation();
+
+        va.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationStart(Animator animation) {
+                revealView.setOutlineProvider(RevealOutlineAnimation.this);
+                revealView.setClipToOutline(true);
+                if (shouldRemoveElevationDuringAnimation()) {
+                    revealView.setTranslationZ(-elevation);
+                }
+            }
+
+            public void onAnimationEnd(Animator animation) {
+                revealView.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
+                revealView.setClipToOutline(false);
+                if (shouldRemoveElevationDuringAnimation()) {
+                    revealView.setTranslationZ(0);
+                }
+            }
+
+        });
+
+        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                float progress = arg0.getAnimatedFraction();
+                setProgress(progress);
+                revealView.invalidateOutline();
+                if (!Utilities.ATLEAST_LOLLIPOP_MR1) {
+                    revealView.invalidate();
+                }
+            }
+        });
+        return va;
+    }
+
+    @Override
+    public void getOutline(View v, Outline outline) {
+        outline.setRoundRect(mOutline, mOutlineRadius);
+    }
+}
diff --git a/src/com/android/launcher3/util/RevealOutlineProvider.java b/src/com/android/launcher3/util/RevealOutlineProvider.java
deleted file mode 100644
index 0db3984..0000000
--- a/src/com/android/launcher3/util/RevealOutlineProvider.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.android.launcher3.util;
-
-import android.annotation.TargetApi;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.os.Build;
-import android.view.View;
-import android.view.ViewOutlineProvider;
-
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class RevealOutlineProvider extends ViewOutlineProvider {
-
-    private int mCenterX;
-    private int mCenterY;
-    private float mRadius0;
-    private float mRadius1;
-    private int mCurrentRadius;
-
-    private final Rect mOval;
-
-    /**
-     * @param x reveal center x
-     * @param y reveal center y
-     * @param r0 initial radius
-     * @param r1 final radius
-     */
-    public RevealOutlineProvider(int x, int y, float r0, float r1) {
-        mCenterX = x;
-        mCenterY = y;
-        mRadius0 = r0;
-        mRadius1 = r1;
-
-        mOval = new Rect();
-    }
-
-    public void setProgress(float progress) {
-        mCurrentRadius = (int) ((1 - progress) * mRadius0 + progress * mRadius1);
-
-        mOval.left = mCenterX - mCurrentRadius;
-        mOval.top = mCenterY - mCurrentRadius;
-        mOval.right = mCenterX + mCurrentRadius;
-        mOval.bottom = mCenterY + mCurrentRadius;
-    }
-
-    @Override
-    public void getOutline(View v, Outline outline) {
-        outline.setRoundRect(mOval, mCurrentRadius);
-    }
-}
diff --git a/src/com/android/launcher3/util/UiThreadCircularReveal.java b/src/com/android/launcher3/util/UiThreadCircularReveal.java
deleted file mode 100644
index f2b5e5e..0000000
--- a/src/com/android/launcher3/util/UiThreadCircularReveal.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.android.launcher3.util;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.TargetApi;
-import android.os.Build;
-import android.view.View;
-import android.view.ViewOutlineProvider;
-
-import com.android.launcher3.Utilities;
-
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class UiThreadCircularReveal {
-
-    public static ValueAnimator createCircularReveal(View v, int x, int y, float r0, float r1) {
-        return createCircularReveal(v, x, y, r0, r1, ViewOutlineProvider.BACKGROUND);
-    }
-
-    public static ValueAnimator createCircularReveal(View v, int x, int y, float r0, float r1,
-            final ViewOutlineProvider originalProvider) {
-        ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
-
-        final View revealView = v;
-        final RevealOutlineProvider outlineProvider = new RevealOutlineProvider(x, y, r0, r1);
-        final float elevation = v.getElevation();
-
-        va.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationStart(Animator animation) {
-                revealView.setOutlineProvider(outlineProvider);
-                revealView.setClipToOutline(true);
-                revealView.setTranslationZ(-elevation);
-            }
-
-            public void onAnimationEnd(Animator animation) {
-                revealView.setOutlineProvider(originalProvider);
-                revealView.setClipToOutline(false);
-                revealView.setTranslationZ(0);
-            }
-
-        });
-
-        va.addUpdateListener(new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                float progress = arg0.getAnimatedFraction();
-                outlineProvider.setProgress(progress);
-                revealView.invalidateOutline();
-                if (!Utilities.ATLEAST_LOLLIPOP_MR1) {
-                    revealView.invalidate();
-                }
-            }
-        });
-        return va;
-    }
-}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 8a58d34..34bee1b 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -20,7 +20,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView.State;
 import android.util.AttributeSet;
@@ -32,7 +31,6 @@
 import com.android.launcher3.BaseContainerView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeleteDropTarget;
-import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.folder.Folder;
@@ -62,6 +60,9 @@
     private DragController mDragController;
     private IconCache mIconCache;
 
+    private final Rect mTmpBgPaddingRect = new Rect();
+    private final Rect mTmpRect = new Rect();
+
     /* Recycler view related member variables */
     private WidgetsRecyclerView mRecyclerView;
     private WidgetsListAdapter mAdapter;
@@ -97,18 +98,24 @@
         mRecyclerView = (WidgetsRecyclerView) getContentView().findViewById(R.id.widgets_list_view);
         mRecyclerView.setAdapter(mAdapter);
         mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+    }
 
-        Rect bgPadding = new Rect();
-        getRevealView().getBackground().getPadding(bgPadding);
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        getRevealView().getBackground().getPadding(mTmpBgPaddingRect);
         if (Utilities.isRtl(getResources())) {
-            getContentView().setPadding(0, bgPadding.top,
-                    bgPadding.right, bgPadding.bottom);
-            mRecyclerView.updateBackgroundPadding(new Rect(bgPadding.left, 0, 0, 0));
+            getContentView().setPadding(0, mTmpBgPaddingRect.top, mTmpBgPaddingRect.right,
+                    mTmpBgPaddingRect.bottom);
+            mTmpRect.set(mTmpBgPaddingRect.left, 0, 0, 0);
+            mRecyclerView.updateBackgroundPadding(mTmpRect);
         } else {
-            getContentView().setPadding(bgPadding.left, bgPadding.top,
-                    0, bgPadding.bottom);
-            mRecyclerView.updateBackgroundPadding(new Rect(0, 0, bgPadding.right, 0));
+            getContentView().setPadding(mTmpBgPaddingRect.left, mTmpBgPaddingRect.top, 0,
+                    mTmpBgPaddingRect.bottom);
+            mTmpRect.set(0, 0, mTmpBgPaddingRect.right, 0);
+            mRecyclerView.updateBackgroundPadding(mTmpRect);
         }
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
     //