merged ub-launcher3-dorval-polish2, and resolved conflicts
am: 9623a6f891

Change-Id: I0eb34275308647e8021c452d59a8c93c57b14ea4
diff --git a/Android.mk b/Android.mk
index c8a53d2..d41e184 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,7 +17,7 @@
 LOCAL_PATH := $(call my-dir)
 
 #
-# Build app code.
+# Build rule for Launcher3 app.
 #
 include $(CLEAR_VARS)
 
@@ -33,7 +33,8 @@
     $(call all-java-files-under, src) \
     $(call all-java-files-under, src_config) \
     $(call all-java-files-under, src_flags) \
-    $(call all-proto-files-under, protos)
+    $(call all-proto-files-under, protos) \
+    $(call all-proto-files-under, proto_overrides)
 
 LOCAL_RESOURCE_DIR := \
     $(LOCAL_PATH)/res \
@@ -42,7 +43,7 @@
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
 LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
 
 LOCAL_AAPT_FLAGS := \
@@ -62,14 +63,65 @@
 include $(BUILD_PACKAGE)
 
 #
+# Build rule for Launcher3 Go app for Android Go devices.
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-v4 \
+    android-support-v7-recyclerview \
+    android-support-v7-palette \
+    android-support-dynamic-animation
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src) \
+    $(call all-java-files-under, src_config) \
+    $(call all-java-files-under, go/src_flags) \
+    $(call all-proto-files-under, protos) \
+    $(call all-proto-files-under, proto_overrides)
+
+LOCAL_RESOURCE_DIR := \
+    $(LOCAL_PATH)/go/res \
+    $(LOCAL_PATH)/res \
+    prebuilts/sdk/current/support/v7/recyclerview/res \
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
+
+LOCAL_AAPT_FLAGS := \
+    --auto-add-overlay \
+    --extra-packages android.support.v7.recyclerview \
+
+LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 21
+LOCAL_PACKAGE_NAME := Launcher3Go
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
+
+LOCAL_FULL_LIBS_MANIFEST_FILES := \
+    $(LOCAL_PATH)/AndroidManifest.xml \
+    $(LOCAL_PATH)/AndroidManifest-common.xml
+
+LOCAL_MANIFEST_FILE := go/AndroidManifest.xml
+
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
+
+include $(BUILD_PACKAGE)
+
+#
 # Launcher proto buffer jar used for development
 #
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := $(call all-proto-files-under, protos)
+LOCAL_SRC_FILES := $(call all-proto-files-under, protos) $(call all-proto-files-under, proto_overrides)
 
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
 LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
 
 LOCAL_MODULE_TAGS := optional
diff --git a/build.gradle b/build.gradle
index c23a299..886ccac 100644
--- a/build.gradle
+++ b/build.gradle
@@ -35,28 +35,49 @@
             applicationId 'com.android.launcher3'
             testApplicationId 'com.android.launcher3.tests'
         }
+
+        l3go {
+            applicationId 'com.android.launcher3'
+            testApplicationId 'com.android.launcher3.tests'
+        }
     }
     sourceSets {
         main {
             res.srcDirs = ['res']
-            java.srcDirs = ['src', 'src_flags']
+            java.srcDirs = ['src']
             manifest.srcFile 'AndroidManifest-common.xml'
-            proto.srcDirs 'protos/'
+            proto {
+                srcDir 'protos/'
+                srcDir 'proto_overrides/'
+            }
         }
 
         androidTest {
-            java.srcDirs = ['tests/src']
             res.srcDirs = ['tests/res']
+            java.srcDirs = ['tests/src']
             manifest.srcFile "tests/AndroidManifest-common.xml"
         }
 
         aosp {
+            java.srcDirs = ['src_flags']
             manifest.srcFile "AndroidManifest.xml"
         }
 
         aospAndroidTest {
             manifest.srcFile "tests/AndroidManifest.xml"
         }
+
+        l3go {
+            res.srcDirs = ['go/res']
+            java.srcDirs = ['go/src_flags']
+            // Note: we are using the Launcher3 manifest here because the gradle manifest-merger uses
+            // different attributes than the build system.
+            manifest.srcFile "AndroidManifest.xml"
+        }
+
+        l3goAndroidTest {
+            manifest.srcFile "tests/AndroidManifest.xml"
+        }
     }
 }
 
@@ -71,10 +92,10 @@
     compile "com.android.support:support-dynamic-animation:${SUPPORT_LIBS_VERSION}"
     compile "com.android.support:recyclerview-v7:${SUPPORT_LIBS_VERSION}"
     compile "com.android.support:palette-v7:${SUPPORT_LIBS_VERSION}"
-    compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-2'
+    compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7'
 
     testCompile 'junit:junit:4.12'
-    androidTestCompile "org.mockito:mockito-core:1.+"
+    androidTestCompile "org.mockito:mockito-core:1.9.5"
     androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
     androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
     androidTestCompile 'com.android.support.test:runner:0.5'
@@ -92,6 +113,7 @@
                 task.builtins {
                     remove java
                     javanano {
+                        option "java_package=launcher_log_extension.proto|com.android.launcher3.userevent.nano"
                         option "java_package=launcher_log.proto|com.android.launcher3.userevent.nano"
                         option "java_package=launcher_dump.proto|com.android.launcher3.model.nano"
                         option "enum_style=java"
diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml
new file mode 100644
index 0000000..ed8e0ad
--- /dev/null
+++ b/go/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2017, 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.
+*/
+-->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.launcher3" >
+
+    <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
+
+    <application
+        android:backupAgent="com.android.launcher3.LauncherBackupAgent"
+        android:fullBackupOnly="true"
+        android:fullBackupContent="@xml/backupscheme"
+        android:hardwareAccelerated="true"
+        android:icon="@drawable/ic_launcher_home"
+        android:label="@string/derived_app_name"
+        android:theme="@style/LauncherTheme"
+        android:largeHeap="@bool/config_largeHeap"
+        android:restoreAnyVersion="true"
+        android:supportsRtl="true" >
+
+        <!-- Activity for handling PinItemRequest. Only supports shortcuts -->
+        <activity android:name="com.android.launcher3.dragndrop.AddItemActivity"
+            android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+            android:excludeFromRecents="true"
+            android:autoRemoveFromRecents="true"
+            android:label="@string/action_add_to_workspace"
+            tools:merge="override" >
+            <intent-filter>
+                <action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/go/res/layout/widget_cell_content.xml b/go/res/layout/widget_cell_content.xml
new file mode 100644
index 0000000..49506d9
--- /dev/null
+++ b/go/res/layout/widget_cell_content.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/widget_preview_label_vertical_padding"
+        android:paddingBottom="@dimen/widget_preview_label_vertical_padding"
+        android:paddingLeft="@dimen/widget_preview_label_horizontal_padding"
+        android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
+        android:orientation="horizontal">
+
+        <!-- The name of the widget. -->
+        <TextView
+            android:id="@+id/widget_name"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:ellipsize="end"
+            android:fadingEdge="horizontal"
+            android:fontFamily="sans-serif-condensed"
+            android:gravity="center"
+            android:singleLine="true"
+            android:maxLines="1"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="14sp" />
+
+        <!-- The original dimensions of the widget (can't be the same text as above due to different
+             style. -->
+        <TextView
+            android:id="@+id/widget_dims"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="5dp"
+            android:layout_marginLeft="5dp"
+            android:visibility="gone"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="14sp"
+            android:fontFamily="sans-serif-condensed"
+            android:alpha="0.8" />
+    </LinearLayout>
+
+    <!-- The image of the widget. This view does not support padding. Any placement adjustment
+         should be done using margins. -->
+    <com.android.launcher3.widget.WidgetImageView
+        android:id="@+id/widget_preview"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+</merge>
\ No newline at end of file
diff --git a/go/res/values-af/strings.xml b/go/res/values-af/strings.xml
new file mode 100644
index 0000000..10ac473
--- /dev/null
+++ b/go/res/values-af/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Raak en hou om \'n kortpad op te tel."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dubbeltik en hou om \'n kortpad op te tel of gebruik gepasmaakte handelinge."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Kortpaaie"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-kortpaaie"</string>
+</resources>
diff --git a/go/res/values-am/strings.xml b/go/res/values-am/strings.xml
new file mode 100644
index 0000000..b3b253f
--- /dev/null
+++ b/go/res/values-am/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"አንድ አቋራጭ ለመውሰድ ነክተው ይያዙ"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"አንድ አቋራጭ ለመውሰድ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ አድርገው ይያዙ።"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"አቋራጮች"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> አቋራጮች"</string>
+</resources>
diff --git a/go/res/values-ar/strings.xml b/go/res/values-ar/strings.xml
new file mode 100644
index 0000000..2b3b807
--- /dev/null
+++ b/go/res/values-ar/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"المس مع الاستمرار لاختيار اختصار."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"يمكنك النقر نقرًا مزدوجًا مع الاستمرار لاختيار اختصار أو استخدام الإجراءات المخصصة."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"الاختصارات"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"اختصارات <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-az-rAZ/strings.xml b/go/res/values-az-rAZ/strings.xml
new file mode 100644
index 0000000..c4b8cb7
--- /dev/null
+++ b/go/res/values-az-rAZ/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Qısayolu seçmək üçün toxunub saxlayın."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Qısayollar"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> qısayolları"</string>
+</resources>
diff --git a/go/res/values-b+sr+Latn/strings.xml b/go/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..0da5699
--- /dev/null
+++ b/go/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dodirnite i zadržite da biste izabrali prečicu."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvaput dodirnite i zadržite da biste izabrali prečicu ili koristite prilagođene radnje."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Prečice"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Prečice za <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-bs-rBA/strings.xml b/go/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..7042468
--- /dev/null
+++ b/go/res/values-bs-rBA/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dodirnite i držite da uzmete prečicu."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvaput dodirnite i držite da uzmete prečicu ili koristite prilagođene akcije."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Prečice"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Prečice aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-da/strings.xml b/go/res/values-da/strings.xml
new file mode 100644
index 0000000..821d36a
--- /dev/null
+++ b/go/res/values-da/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Hold en genvej nede for at samle den op."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tryk to gange, og hold en genvej nede for at samle den op og bruge tilpassede handlinger."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Genveje"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-genveje"</string>
+</resources>
diff --git a/go/res/values-en-rAU/strings.xml b/go/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..2ee2c26
--- /dev/null
+++ b/go/res/values-en-rAU/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Touch &amp; hold to pick up a shortcut."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap &amp; hold to pick up a shortcut or use custom actions."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string>
+</resources>
diff --git a/go/res/values-en-rGB/strings.xml b/go/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..2ee2c26
--- /dev/null
+++ b/go/res/values-en-rGB/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Touch &amp; hold to pick up a shortcut."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap &amp; hold to pick up a shortcut or use custom actions."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string>
+</resources>
diff --git a/go/res/values-en-rIN/strings.xml b/go/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..2ee2c26
--- /dev/null
+++ b/go/res/values-en-rIN/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Touch &amp; hold to pick up a shortcut."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap &amp; hold to pick up a shortcut or use custom actions."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string>
+</resources>
diff --git a/go/res/values-fa/strings.xml b/go/res/values-fa/strings.xml
new file mode 100644
index 0000000..8bc5256
--- /dev/null
+++ b/go/res/values-fa/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"برای انتخاب یک میان‌بر، لمس کنید و نگه‌دارید."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"برای انتخاب یک میان‌بر، دو ضربه سریع بزنید و نگه‌دارید یا از اقدام‌های سفارشی استفاده کنید."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"میان‌برها"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"میان‌برهای <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-hr/strings.xml b/go/res/values-hr/strings.xml
new file mode 100644
index 0000000..fccdeb5
--- /dev/null
+++ b/go/res/values-hr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dodirnite i zadržite kako biste podigli prečac."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvaput dodirnite i zadržite pritisak kako biste podigli prečac ili pokušajte prilagođenim radnjama."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Prečaci"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Prečaci za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-in/strings.xml b/go/res/values-in/strings.xml
new file mode 100644
index 0000000..c8b9da3
--- /dev/null
+++ b/go/res/values-in/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tap lama untuk memilih pintasan."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tap dua kali &amp; tahan untuk memilih pintasan atau menggunakan tindakan khusus."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Pintasan"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Pintasan <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-it/strings.xml b/go/res/values-it/strings.xml
new file mode 100644
index 0000000..bc5d998
--- /dev/null
+++ b/go/res/values-it/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tocca e tieni premuto per scegliere la scorciatoia"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tocca due volte e tieni premuto per scegliere una scorciatoia o per usare azioni personalizzate."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Scorciatoie"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Scorciatoie di <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-ja/strings.xml b/go/res/values-ja/strings.xml
new file mode 100644
index 0000000..8f02d7f
--- /dev/null
+++ b/go/res/values-ja/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"ショートカットを追加するには押し続けます。"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ダブルタップ後に押し続けてショートカットを選択するか、カスタム操作を使用してください。"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"ショートカット"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"「<xliff:g id="NAME">%1$s</xliff:g>」のショートカット"</string>
+</resources>
diff --git a/go/res/values-ka-rGE/strings.xml b/go/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..1b46534
--- /dev/null
+++ b/go/res/values-ka-rGE/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"მალსახმობები"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-ის მალსახმობები"</string>
+</resources>
diff --git a/go/res/values-ky-rKG/strings.xml b/go/res/values-ky-rKG/strings.xml
new file mode 100644
index 0000000..4c7e973
--- /dev/null
+++ b/go/res/values-ky-rKG/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Кыска жолду тандоо үчүн басып туруңуз."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Кыска жолдор"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> кыска жол"</string>
+</resources>
diff --git a/go/res/values-lo-rLA/strings.xml b/go/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..7864884
--- /dev/null
+++ b/go/res/values-lo-rLA/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"ປຸ່ມລັດ"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"ປຸ່ມລັດ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-lt/strings.xml b/go/res/values-lt/strings.xml
new file mode 100644
index 0000000..8f49032
--- /dev/null
+++ b/go/res/values-lt/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dukart pal. ir palaik., kad pasir. spart. klav."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dukart palieskite ir palaikykite, kad pasirinkt. spartųjį klavišą ar naudotumėte tinkintus veiksmus."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Spartieji klavišai"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"„<xliff:g id="NAME">%1$s</xliff:g>“ spartieji klavišai"</string>
+</resources>
diff --git a/go/res/values-nl/strings.xml b/go/res/values-nl/strings.xml
new file mode 100644
index 0000000..5bcd016
--- /dev/null
+++ b/go/res/values-nl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tik en houd vast om snelkoppeling toe te voegen."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dubbeltik en houd vast om een snelkoppeling toe te voegen of aangepaste acties te gebruiken."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Snelkoppelingen"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-snelkoppelingen"</string>
+</resources>
diff --git a/go/res/values-pl/strings.xml b/go/res/values-pl/strings.xml
new file mode 100644
index 0000000..45a1dc2
--- /dev/null
+++ b/go/res/values-pl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Kliknij i przytrzymaj, by wybrać skrót."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Kliknij dwukrotnie i przytrzymaj, by wybrać skrót lub użyć działań niestandardowych."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Skróty"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> – skróty"</string>
+</resources>
diff --git a/go/res/values-pt-rPT/strings.xml b/go/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..7a75a05
--- /dev/null
+++ b/go/res/values-pt-rPT/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Toque sem soltar para escolher um atalho."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toque duas vezes sem soltar para escolher um atalho ou utilize ações personalizadas."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Atalhos"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Atalhos da aplicação <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-pt/strings.xml b/go/res/values-pt/strings.xml
new file mode 100644
index 0000000..53bbfc4
--- /dev/null
+++ b/go/res/values-pt/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Toque e segure para selecionar um atalho."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toque duas vezes na tela e segure para selecionar um atalho ou usar ações personalizadas."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Atalhos"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Atalhos do app <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-si-rLK/strings.xml b/go/res/values-si-rLK/strings.xml
new file mode 100644
index 0000000..4b25c90
--- /dev/null
+++ b/go/res/values-si-rLK/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"කෙටි මං"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"කෙටි මං <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-sk/strings.xml b/go/res/values-sk/strings.xml
new file mode 100644
index 0000000..fc02933
--- /dev/null
+++ b/go/res/values-sk/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Skratku pridáte pridržaním."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Skratku pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Skratky"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Skratky aplikácie <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-sl/strings.xml b/go/res/values-sl/strings.xml
new file mode 100644
index 0000000..6ecedfb
--- /dev/null
+++ b/go/res/values-sl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Pridržite bližnjico, da jo izberete."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvakrat se dotaknite bližnjice in jo pridržite, da jo izberete, ali pa uporabite dejanja po meri."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Bližnjice"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Bližnjice za <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-sr/strings.xml b/go/res/values-sr/strings.xml
new file mode 100644
index 0000000..0b9aea2
--- /dev/null
+++ b/go/res/values-sr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Додирните и задржите да бисте изабрали пречицу."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Двапут додирните и задржите да бисте изабрали пречицу или користите прилагођене радње."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Пречице"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Пречице за <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-sv/strings.xml b/go/res/values-sv/strings.xml
new file mode 100644
index 0000000..c3f434c
--- /dev/null
+++ b/go/res/values-sv/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tryck länge om du vill ta upp en genväg."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tryck snabbt två gånger och håll kvar om du vill ta upp en genväg eller använda anpassade åtgärder."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Genvägar"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Genvägar för <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-sw/strings.xml b/go/res/values-sw/strings.xml
new file mode 100644
index 0000000..0379ed0
--- /dev/null
+++ b/go/res/values-sw/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Gusa na ushikilie ili uchague njia ya mkato."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Gonga mara mbili na ushikilie ile uchague njia ya mkato au utumie vitendo maalum."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Njia za mkato"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Njia za mkato za <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-tr/strings.xml b/go/res/values-tr/strings.xml
new file mode 100644
index 0000000..f0f3cce
--- /dev/null
+++ b/go/res/values-tr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Kısayol seçmek için dokunun ve basılı tutun."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Bir kısayolu seçmek veya özel işlemleri kullanmak için iki kez dokunun ve basılı tutun."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Kısayollar"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> kısayolları"</string>
+</resources>
diff --git a/go/res/values-uk/strings.xml b/go/res/values-uk/strings.xml
new file mode 100644
index 0000000..8d1f583
--- /dev/null
+++ b/go/res/values-uk/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Натисніть і утримуйте, щоб вибрати ярлик."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Двічі натисніть і утримуйте, щоб вибрати ярлик, або виконайте іншу дію."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Ярлики"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Ярлики додатка <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-uz-rUZ/strings.xml b/go/res/values-uz-rUZ/strings.xml
new file mode 100644
index 0000000..318bc15
--- /dev/null
+++ b/go/res/values-uz-rUZ/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Yorliqni tanlab olish uchun bosib turing."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Yorliqlar"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi yorliqlari"</string>
+</resources>
diff --git a/go/res/values-zu/strings.xml b/go/res/values-zu/strings.xml
new file mode 100644
index 0000000..e5051df
--- /dev/null
+++ b/go/res/values-zu/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Thinta futhi ubambe ukuze ukhethe isinqamuleli."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Thepha kabulu futhi ubambe ukuze ukhethe isinqamuleli noma usebenzise izenzo zangokwezifiso."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Izinqamuleli"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> izinqamuleli"</string>
+</resources>
diff --git a/go/res/values/strings.xml b/go/res/values/strings.xml
new file mode 100644
index 0000000..8ef2e62
--- /dev/null
+++ b/go/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2017 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Message to tell the user to press and hold on a shortcut to add it [CHAR_LIMIT=50] -->
+    <string name="long_press_widget_to_add">Touch &amp; hold to pick up a shortcut.</string>
+    <!-- Accessibility spoken hint message in widget picker, which allows user to add a shortcut. Custom action is the label for additional accessibility actions available in this mode [CHAR_LIMIT=100] -->
+    <string name="long_accessible_way_to_add">Double-tap &amp; hold to pick up a shortcut or use custom actions.</string>
+    <!-- Text for shortcut add button -->
+    <string name="widget_button_text">Shortcuts</string>
+
+    <!-- Strings for widgets & more in the popup container/bottom sheet -->
+    <!-- Title for a bottom sheet that shows shortcuts for a particular app -->
+    <string name="widgets_bottom_sheet_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> shortcuts</string>
+
+</resources>
diff --git a/go/src_flags/com/android/launcher3/config/FeatureFlags.java b/go/src_flags/com/android/launcher3/config/FeatureFlags.java
new file mode 100644
index 0000000..5bb2ac9
--- /dev/null
+++ b/go/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 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.config;
+
+/**
+ * Defines a set of flags used to control various launcher behaviors
+ */
+public final class FeatureFlags extends BaseFlags {
+
+    private FeatureFlags() {}
+
+    // Features to control Launcher3Go behavior
+    public static final boolean GO_DISABLE_WIDGETS = true;
+}
diff --git a/proto_overrides/launcher_log_extension.proto b/proto_overrides/launcher_log_extension.proto
new file mode 100644
index 0000000..2995aa2
--- /dev/null
+++ b/proto_overrides/launcher_log_extension.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+syntax = "proto2";
+
+option java_package = "com.android.launcher3.userevent";
+option java_outer_classname = "LauncherLogExtensions";
+
+package userevent;
+
+//
+// Use this to add any app specific extensions to the proto.
+//
+message LauncherEventExtension {
+}
+
+message TargetExtension {
+}
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 93e09ae..0bbec18 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -15,6 +15,8 @@
  */
 syntax = "proto2";
 
+import "launcher_log_extension.proto";
+
 option java_package = "com.android.launcher3.userevent";
 option java_outer_classname = "LauncherLogProto";
 
@@ -52,6 +54,7 @@
   optional int32 span_x = 13 [default = 1];// Used for ItemType.WIDGET
   optional int32 span_y = 14 [default = 1];// Used for ItemType.WIDGET
   optional int32 predictedRank = 15;
+  optional TargetExtension extension = 16;
 }
 
 // Used to define what type of item a Target would represent.
@@ -144,7 +147,6 @@
 //         Action (Touch) + Target + Target
 //
 message LauncherEvent {
-
   required Action action = 1;
 
   // List of targets that touch actions can be operated on.
@@ -157,4 +159,6 @@
 
   optional bool is_in_multi_window_mode = 7;
   optional bool is_in_landscape_mode = 8;
+
+  optional LauncherEventExtension extension = 9;
 }
diff --git a/res/drawable/all_apps_alpha_mask.png b/res/drawable/all_apps_alpha_mask.png
deleted file mode 100644
index ed53ff9..0000000
--- a/res/drawable/all_apps_alpha_mask.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/gutter_horizontal.xml b/res/drawable/gutter_horizontal.xml
new file mode 100644
index 0000000..95b03df
--- /dev/null
+++ b/res/drawable/gutter_horizontal.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This "gutter" has a shadow at the top and a subtler shadow on the bottom. -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient android:type="linear"
+              android:angle="-90"
+              android:startColor="#ffE0E0E0"
+              android:centerColor="#ffffffff"
+              android:endColor="#ffF5F5F5" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/ic_warning.xml b/res/drawable/ic_warning.xml
new file mode 100644
index 0000000..332563d
--- /dev/null
+++ b/res/drawable/ic_warning.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/textColorPrimary" >
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M22.85,19.39L12.93,2.25c-0.41-0.71-1.44-0.71-1.85,0L1.15,19.39C0.73,20.11,1.25,21,2.07,21h19.85
+        C22.75,21,23.27,20.11,22.85,19.39z M11,10c0-0.55,0.45-1,1-1s1,0.45,1,1v3c0,0.55-0.45,1-1,1s-1-0.45-1-1V10z M12,18.2
+        c-0.61,0-1.1-0.49-1.1-1.1S11.39,16,12,16s1.1,0.49,1.1,1.1C13.1,17.71,12.61,18.2,12,18.2z"/>
+</vector>
diff --git a/res/interpolator/large_folder_preview_item_interpolator.xml b/res/interpolator/large_folder_preview_item_close_interpolator.xml
similarity index 90%
copy from res/interpolator/large_folder_preview_item_interpolator.xml
copy to res/interpolator/large_folder_preview_item_close_interpolator.xml
index dcf0157..d28af63 100644
--- a/res/interpolator/large_folder_preview_item_interpolator.xml
+++ b/res/interpolator/large_folder_preview_item_close_interpolator.xml
@@ -18,7 +18,7 @@
 -->
 
 <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:controlX1="0"
-    android:controlY1="1"
-    android:controlX2="0"
+    android:controlX1="0.3"
+    android:controlY1="0"
+    android:controlX2="1"
     android:controlY2="1"/>
diff --git a/res/interpolator/large_folder_preview_item_interpolator.xml b/res/interpolator/large_folder_preview_item_open_interpolator.xml
similarity index 96%
rename from res/interpolator/large_folder_preview_item_interpolator.xml
rename to res/interpolator/large_folder_preview_item_open_interpolator.xml
index dcf0157..b5661ab 100644
--- a/res/interpolator/large_folder_preview_item_interpolator.xml
+++ b/res/interpolator/large_folder_preview_item_open_interpolator.xml
@@ -20,5 +20,5 @@
 <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
     android:controlX1="0"
     android:controlY1="1"
-    android:controlX2="0"
+    android:controlX2="0.5"
     android:controlY2="1"/>
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 2bbd76d..dab0743 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -42,7 +42,12 @@
             android:layout_gravity="center"
             launcher:pageIndicator="@id/page_indicator" />
 
-        <include layout="@layout/gradient_scrim" />
+        <com.android.launcher3.graphics.GradientView
+            android:id="@+id/gradient_bg"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="gone"
+            launcher:layout_ignoreInsets="true"/>
 
         <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
@@ -60,13 +65,6 @@
             android:id="@+id/overview_panel"
             android:visibility="gone" />
 
-        <com.android.launcher3.pageindicators.PageIndicatorCaretLandscape
-            android:id="@+id/page_indicator"
-            android:theme="@style/HomeScreenElementTheme"
-            android:layout_width="@dimen/dynamic_grid_page_indicator_size"
-            android:layout_height="@dimen/dynamic_grid_page_indicator_size"
-            android:layout_gravity="bottom|left"/>
-
         <include layout="@layout/widgets_view"
             android:id="@+id/widgets_view"
             android:layout_width="match_parent"
@@ -79,6 +77,13 @@
             android:layout_height="match_parent"
             android:visibility="invisible" />
 
+        <com.android.launcher3.pageindicators.PageIndicatorCaretLandscape
+            android:id="@+id/page_indicator"
+            android:theme="@style/HomeScreenElementTheme"
+            android:layout_width="@dimen/dynamic_grid_min_page_indicator_size"
+            android:layout_height="@dimen/dynamic_grid_min_page_indicator_size"
+            android:layout_gravity="bottom|left"/>
+
     </com.android.launcher3.dragndrop.DragLayer>
 
 </com.android.launcher3.LauncherRootView>
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 93c9078..bace51a 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -44,7 +44,12 @@
             launcher:pageIndicator="@+id/page_indicator">
         </com.android.launcher3.Workspace>
 
-        <include layout="@layout/gradient_scrim" />
+        <com.android.launcher3.graphics.GradientView
+            android:id="@+id/gradient_bg"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="gone"
+            launcher:layout_ignoreInsets="true"/>
 
         <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index ca4d846..18d235c 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -43,7 +43,12 @@
             launcher:pageIndicator="@id/page_indicator">
         </com.android.launcher3.Workspace>
 
-        <include layout="@layout/gradient_scrim" />
+        <com.android.launcher3.graphics.GradientView
+            android:id="@+id/gradient_bg"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="gone"
+            launcher:layout_ignoreInsets="true"/>
 
         <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 93662fc..6340619 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -49,7 +49,7 @@
         <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.allapps.AllAppsRecyclerView
             android:id="@+id/apps_list_view"
-            android:layout_below="@+id/search_container"
+            android:layout_below="@id/search_container_all_apps"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_gravity="center_horizontal|top"
@@ -62,7 +62,7 @@
          platform bug, which prevents using custom attributes in <include> tag -->
         <include
             layout="?android:attr/keyboardLayout"
-            android:id="@+id/search_container" />
+            android:id="@id/search_container_all_apps" />
 
         <include layout="@layout/all_apps_fast_scroller" />
 
diff --git a/res/layout/gradient_scrim.xml b/res/layout/gradient_scrim.xml
deleted file mode 100644
index c40c5fc..0000000
--- a/res/layout/gradient_scrim.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
-    <com.android.launcher3.graphics.GradientView
-        android:id="@+id/gradient_bg"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:visibility="gone"
-        app:layout_ignoreInsets="true"/>
-
-    <com.android.launcher3.graphics.ScrimView
-        android:id="@+id/scrim_bg"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:visibility="gone"
-        app:layout_ignoreInsets="true"/>
-</merge>
\ No newline at end of file
diff --git a/res/layout/horizontal_divider.xml b/res/layout/horizontal_divider.xml
deleted file mode 100644
index 167f8f5..0000000
--- a/res/layout/horizontal_divider.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<View xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/popup_item_divider_height"
-    android:background="?attr/popupColorTertiary" />
\ No newline at end of file
diff --git a/res/layout/notification.xml b/res/layout/notification.xml
index 085dfa9..4a02aa1 100644
--- a/res/layout/notification.xml
+++ b/res/layout/notification.xml
@@ -28,6 +28,13 @@
         android:orientation="vertical"
         android:clipChildren="false">
 
+        <View
+            android:id="@+id/gutter_top"
+            android:layout_width="match_parent"
+            android:layout_height="4dp"
+            android:theme="@style/PopupGutter"
+            android:visibility="gone" />
+
         <FrameLayout
             android:id="@+id/header"
             android:layout_width="match_parent"
@@ -35,22 +42,23 @@
             android:paddingStart="@dimen/notification_padding_start"
             android:paddingEnd="@dimen/notification_padding_end"
             android:background="?attr/popupColorPrimary"
-            android:elevation="@dimen/notification_elevation">
+            android:elevation="@dimen/notification_elevation"
+            android:layout_below="@id/gutter_top" >
             <TextView
                 android:id="@+id/notification_text"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:layout_gravity="start"
-                android:gravity="center_vertical"
+                android:gravity="bottom"
                 android:text="@string/notifications_header"
                 android:textSize="@dimen/notification_header_text_size"
-                android:textColor="?android:attr/textColorSecondary" />
+                android:textColor="?android:attr/textColorPrimary" />
             <TextView
                 android:id="@+id/notification_count"
                 android:layout_width="@dimen/notification_icon_size"
                 android:layout_height="match_parent"
                 android:layout_gravity="end"
-                android:gravity="center"
+                android:gravity="bottom|center_horizontal"
                 android:textSize="@dimen/notification_header_count_text_size"
                 android:fontFamily="sans-serif-medium"
                 android:textColor="?android:attr/textColorPrimary" />
@@ -76,6 +84,14 @@
             android:layout_height="@dimen/notification_footer_height"
             android:layout_below="@id/divider" />
 
+        <View
+            android:id="@+id/gutter_bottom"
+            android:layout_width="match_parent"
+            android:layout_height="4dp"
+            android:theme="@style/PopupGutter"
+            android:visibility="gone"
+            android:layout_below="@id/footer" />
+
     </RelativeLayout>
 
 </com.android.launcher3.notification.NotificationItemView>
diff --git a/res/layout/notification_main.xml b/res/layout/notification_main.xml
index 7a8cf6d..f681e8b 100644
--- a/res/layout/notification_main.xml
+++ b/res/layout/notification_main.xml
@@ -38,7 +38,7 @@
             android:layout_height="wrap_content"
             android:textAlignment="viewStart"
             android:fontFamily="sans-serif"
-            android:textSize="@dimen/notification_main_text_size"
+            android:textSize="@dimen/notification_main_title_size"
             android:textColor="?android:attr/textColorPrimary"
             android:lines="1"
             android:ellipsize="end" />
diff --git a/res/layout/notification_pref_warning.xml b/res/layout/notification_pref_warning.xml
new file mode 100644
index 0000000..795699e
--- /dev/null
+++ b/res/layout/notification_pref_warning.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="48dp"
+    android:layout_height="match_parent"
+    android:background="?android:attr/selectableItemBackgroundBorderless"
+    android:contentDescription="@string/title_missing_notification_access"
+    android:scaleType="center"
+    android:src="@drawable/ic_warning"
+    android:tint="?android:attr/textColorSecondary" />
diff --git a/res/layout/page_indicator.xml b/res/layout/page_indicator.xml
index 14ff2bd..92f52d6 100644
--- a/res/layout/page_indicator.xml
+++ b/res/layout/page_indicator.xml
@@ -18,11 +18,11 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:theme="@style/HomeScreenElementTheme"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/dynamic_grid_page_indicator_size">
+    android:layout_height="@dimen/dynamic_grid_min_page_indicator_size">
         <ImageView
             android:id="@+id/all_apps_handle"
             android:layout_width="48dp"
-            android:layout_height="match_parent"
+            android:layout_height="@dimen/dynamic_grid_min_page_indicator_size"
             android:layout_gravity="top|center"
             android:scaleType="centerInside"/>
 </com.android.launcher3.pageindicators.PageIndicatorLineCaret>
diff --git a/res/layout/popup_container.xml b/res/layout/popup_container.xml
index e9cfe24..67db4a5 100644
--- a/res/layout/popup_container.xml
+++ b/res/layout/popup_container.xml
@@ -19,8 +19,8 @@
     android:id="@+id/deep_shortcuts_container"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp"
+    android:paddingTop="4dp"
+    android:paddingBottom="4dp"
     android:clipToPadding="false"
     android:clipChildren="false"
     android:elevation="@dimen/deep_shortcuts_elevation"
diff --git a/res/layout/all_apps_search_container.xml b/res/layout/search_container_all_apps.xml
similarity index 98%
rename from res/layout/all_apps_search_container.xml
rename to res/layout/search_container_all_apps.xml
index 2528034..c430521 100644
--- a/res/layout/all_apps_search_container.xml
+++ b/res/layout/search_container_all_apps.xml
@@ -15,7 +15,7 @@
 -->
 <com.android.launcher3.allapps.search.AppsSearchContainerLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/search_container"
+    android:id="@id/search_container_all_apps"
     android:layout_width="match_parent"
     android:layout_height="@dimen/all_apps_search_bar_height"
     android:layout_gravity="center|top"
diff --git a/res/layout/qsb_container.xml b/res/layout/search_container_workspace.xml
similarity index 95%
rename from res/layout/qsb_container.xml
rename to res/layout/search_container_workspace.xml
index 6fa843d..1c617b1 100644
--- a/res/layout/qsb_container.xml
+++ b/res/layout/search_container_workspace.xml
@@ -19,7 +19,7 @@
         android:orientation="vertical"
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:id="@+id/qsb_container"
+        android:id="@id/search_container_workspace"
         android:padding="0dp" >
 
     <fragment
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index 4d80aac..afa19b8 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -29,7 +29,7 @@
         android:layout_height="match_parent"
         android:paddingLeft="8dp"
         android:paddingRight="8dp"
-        android:paddingTop="6dp"
+        android:paddingTop="16dp"
         launcher:pageIndicator="@+id/folder_page_indicator" />
 
     <LinearLayout
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index e91f966..2e6ce94 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -29,7 +29,7 @@
         android:layout_height="match_parent"
         android:paddingLeft="8dp"
         android:paddingRight="8dp"
-        android:paddingTop="6dp"
+        android:paddingTop="16dp"
         launcher:pageIndicator="@+id/folder_page_indicator" />
 
     <LinearLayout
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index fe00d7a..d71b4c7 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breed by %2$d hoog"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Raak en hou om self te plaas"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Voeg outomaties by"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Deursoek programme"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Laai tans programme …"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Geen programme gevind wat met \"<xliff:g id="QUERY">%1$s</xliff:g>\" ooreenstem nie"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Deursoek programme"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Laai tans programme …"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Kon geen programme kry wat by \"<xliff:g id="QUERY">%1$s</xliff:g>\" pas nie"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Soek meer programme"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Kennisgewings"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Niks meer spasie op die tuisskerm nie."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Kennisgewingkolle"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aan"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Af"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Kennisgewingtoegang word benodig"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Skakel programkennisgewings vir <xliff:g id="NAME">%1$s</xliff:g> aan om kennisgewingkolle te sien"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Verander instellings"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Voeg ikoon by tuisskerm"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Vir nuwe programme"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Verander ikoon se vorm"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Gebruik stelselverstek"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Vierkant"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Sirkelvierkant"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Sirkel"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Traandruppel"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Pas ikoonvormveranderings toe"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Onbekend"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Verwyder"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Soek"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index aebb428..293b452 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ስፋት በ%2$d ከፍታ"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"ራስዎ ለማስቀመጥ ነክተው ይያዙት"</string>
     <string name="place_automatically" msgid="8064208734425456485">"በራስ-ሰር አክል"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"መተግበሪያዎችን ይፈልጉ"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"መተግበሪያዎችን በመጫን ላይ..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"ከ«<xliff:g id="QUERY">%1$s</xliff:g>» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"መተግበሪያዎችን ፈልግ"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"መተግበሪያዎችን በመጫን ላይ…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"ከ«<xliff:g id="QUERY">%1$s</xliff:g>» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"ተጨማሪ መተግበሪያዎች ይፈልጉ"</string>
     <string name="notifications_header" msgid="1404149926117359025">"ማሳወቂያዎች"</string>
     <string name="out_of_space" msgid="4691004494942118364">"በዚህ መነሻ ማያ ገጽ ላይ ምንም ቦታ የለም።"</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"የማሳወቂያ ነጥቦች"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"በርቷል"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ጠፍቷል"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"የማሳወቂያ መዳረሻ ያስፈልጋል"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"የማሳወቂያ ነጥቦችን ለማሳየት የመተግብሪያ ማሳወቂያዎችን ለ<xliff:g id="NAME">%1$s</xliff:g> ያብሩ"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"ቅንብሮችን ቀይር"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"አዶ ወደ የመነሻ ማያ ገጽ አክል"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ለአዲስ መተግበሪያዎች"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"የአዶ ቅርፅ ለውጥ"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"የሥርዓቱን ነባሪ ተጠቀም"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"ካሬ"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"ክብ"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"የእንባ ጠብታ"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"የአዶ ቅርች ለውጦች"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"የማይታወቅ"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"አስወግድ"</string>
     <string name="abandoned_search" msgid="891119232568284442">"ፈልግ"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index a45e40e..6447bf0 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‏العرض %1$d الطول %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"المس مع الاستمرار للإضافة يدويًا"</string>
     <string name="place_automatically" msgid="8064208734425456485">"إضافة تلقائيًا"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"البحث في التطبيقات"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"جارٍ تحميل التطبيقات…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"لم يتم العثور على أية تطبيقات تتطابق مع \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"بحث في التطبيقات"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"جارٍ تحميل التطبيقات…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"لم يتم العثور على أي تطبيقات تتطابق مع \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"البحث عن مزيد من التطبيقات"</string>
     <string name="notifications_header" msgid="1404149926117359025">"الإشعارات"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ليس هناك مساحة أخرى في هذه الشاشة الرئيسية."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"نقاط الإشعارات"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"قيد التشغيل"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"قيد الإيقاف"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"يلزم تمكين الوصول إلى الإشعارات"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"لعرض نقاط الإشعارات، يجب تشغيل إشعارات التطبيق في <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"تغيير الإعدادات"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"إضافة رمز إلى الشاشة الرئيسية"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"للتطبيقات الجديدة"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"تغيير شكل الرمز"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"استخدام الإعداد الافتراضي للنظام"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"مربّع"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"رمز دائري مربّع"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"دائرة"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"رمز على شكل دمعة"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"جارٍ تطبيق تغييرات شكل الرمز"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"غير معروفة"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"إزالة"</string>
     <string name="abandoned_search" msgid="891119232568284442">"بحث"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index cb296f4..777512a 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"širina od %1$d i visina od %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Dodirnite i zadržite da biste postavili ručno"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Automatski dodaj"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pretražite aplikacije"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Aplikacije se učitavaju..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nije pronađena nijedna aplikacija za „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretražite aplikacije"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikacije se učitavaju…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nije pronađena nijedna aplikacija za „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Pretraži još aplikacija"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Obaveštenja"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Nema više prostora na ovom početnom ekranu."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Tačke za obaveštenja"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Uključeno"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Isključeno"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreban je pristup za obaveštenja"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Da biste prikazali tačke za obaveštenja, uključite obaveštenja za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Promenite podešavanja"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonu na početni ekran"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Promenite oblik ikona"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Koristi podrazumevano sistemsko podešavanje"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Zaobljeni kvadrat"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Krug"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Suza"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Primenjuju se promene oblika ikona"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Nepoznato"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Ukloni"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Pretraži"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index f5dba2d..615fd57 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -41,7 +41,7 @@
     <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>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"Звесткі пра праграму"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"Звесткі пра праграмы"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"усталёўваць ярлыкі"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Дазваляе праграмам дадаваць ярлыкі без умяшання карыстальніка."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"счытваць налады і ярлыкі на Галоўнай старонцы"</string>
@@ -65,12 +65,26 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Папка: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Віджэты"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Шпалеры"</string>
-    <string name="settings_button_text" msgid="8119458837558863227">"Налады"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Налады галоўнага экрана"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Адключаная адміністратарам"</string>
     <string name="accessibility_action_overview" msgid="6257665857640347026">"Агляд"</string>
     <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="icon_badging_title" msgid="874121399231955394">"Значкі апавяшчэнняў"</string>
+    <string name="icon_badging_desc_on" msgid="2627952638544674079">"Уключана"</string>
+    <string name="icon_badging_desc_off" msgid="5503319969924580241">"Выключана"</string>
+    <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Дадаць значок на Галоўны экран"</string>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Для новых праграм"</string>
+    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
+    <skip />
+    <string name="icon_shape_system_default" msgid="1709762974822753030">"Выкарыстоўваць стандартныя формы"</string>
+    <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
+    <string name="icon_shape_squircle" msgid="5658049910802669495">"Прамавугольнік са скругленымі вугламі"</string>
+    <string name="icon_shape_circle" msgid="6550072265930144217">"Круг"</string>
+    <string name="icon_shape_teardrop" msgid="4525869388200835463">"Сляза"</string>
+    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
+    <skip />
     <string name="package_state_unknown" msgid="7592128424511031410">"Невядома"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Выдаліць"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Шукаць"</string>
@@ -104,4 +118,7 @@
     <string name="widget_resized" msgid="9130327887929620">"Памеры віджэта зменены на: шырыня <xliff:g id="NUMBER_0">%1$s</xliff:g>, вышыня <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Ярлыкі"</string>
     <string name="shortcuts_menu_description" msgid="406159963824238648">"Ярлыкі (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) для <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Ярлыкі (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) і апавяшчэнні (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) для <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="action_dismiss_notification" msgid="5909461085055959187">"Адхіліць"</string>
+    <string name="notification_dismissed" msgid="6002233469409822874">"Апавяшчэнне адхілена"</string>
 </resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index d5df3f2..3e05e0b 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ширина %1$d и височина %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Докоснете и задръжте, за да поставите ръчно"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Автоматично добавяне"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Търсене в приложенията"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Приложенията се зареждат…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Няма намерени приложения, съответстващи на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Търсене в приложенията"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Приложенията се зареждат…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Няма намерени приложения, съответстващи на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Търсене на още приложения"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Известия"</string>
     <string name="out_of_space" msgid="4691004494942118364">"На този начален екран няма повече място."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Точки за известия"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Включено"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Изключено"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Необходим е достъп до известията"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"За да се показват точки за известия, включете известията за приложението <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Промяна на настройките"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Добавяне на икона към началния екран"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нови приложения"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Промяна на формата на иконите"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Използване на стандартната системна настройка"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Комбинация от кръг и квадрат"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Кръг"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Сълза"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Промените във формата на иконите се прилагат"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Няма информация"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Премахване"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Търсене"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 88b02bb..b1a1f85 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d d\'amplada per %2$d d\'alçada"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Toca i mantén premut l\'element per col·locar-lo manualment"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Afegeix automàticament"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Cerca a les aplicacions"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"S\'estan carregant les aplicacions..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No s\'ha trobat cap aplicació que coincideixi amb <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca aplicacions"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"S\'estan carregant les aplicacions…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"No s\'ha trobat cap aplicació que coincideixi amb \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Cerca més aplicacions"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificacions"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Ja no queda espai en aquesta pantalla d\'inici."</string>
@@ -77,19 +77,20 @@
     <string name="allow_rotation_desc" msgid="8662546029078692509">"En girar el telèfon"</string>
     <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"La configuració actual de la pantalla no permet la rotació"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Punts de notificació"</string>
-    <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activada"</string>
-    <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivada"</string>
+    <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activat"</string>
+    <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivat"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Cal que tingui accés a les notificacions"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Per veure els punts de notificació, activa les notificacions de l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Canvia la configuració"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Afegeix la icona a la pantalla d\'inici"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Per a les aplicacions noves"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Canvia la forma de les icones"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Utilitza l\'opció predeterminada del sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Quadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Quadrat arrodonit"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Cercle"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Llàgrima"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"S\'estan aplicant els canvis de forma de les icones"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconegut"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Suprimeix"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Cerca"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 1a80e39..abc44c7 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"šířka %1$d, výška %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Chcete-li položku umístit ručně, klepněte na ni a podržte ji"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Přidat automaticky"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Hledat aplikace"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Načítání aplikací…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Dotazu „<xliff:g id="QUERY">%1$s</xliff:g>“ neodpovídají žádné aplikace"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hledat v aplikacích"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Načítání aplikací…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Dotazu „<xliff:g id="QUERY">%1$s</xliff:g>“ neodpovídají žádné aplikace"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Vyhledat další aplikace"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Oznámení"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na této ploše již není místo."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Puntíky s oznámeními"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Zapnuto"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Vypnuto"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Je třeba udělit přístup k oznámením"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Chcete-li zobrazovat puntíky s oznámeními, zapněte oznámení z aplikace <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Změnit nastavení"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Přidat ikonu na plochu"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pro nové aplikace"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Změnit tvar ikony"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Použít výchozí nastavení systému"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Čtverec"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kruh/čtverec"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Kruh"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Slza"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Tvar ikony se mění"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Neznámé"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Odstranit"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Hledat"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 17316b3..653105e 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d i bredden og %2$d i højden"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tryk, og hold fingeren nede for at placere manuelt"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Tilføj automatisk"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Søg i Apps"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Indlæser apps…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Der blev ikke fundet nogen apps, som matcher \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søg efter apps"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Indlæser apps…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Der blev ikke fundet nogen apps, som matcher \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Søg efter flere apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Underretninger"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Der er ikke mere plads på denne startskærm."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Underretningscirkler"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Til"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Fra"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Kræver adgang til underretninger"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Hvis du vil se underretningscirkler, skal du aktivere appunderretninger for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Skift indstillinger"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Føj ikon til startskærmen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For nye apps"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Skift ikonform"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Brug systemstandarden"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kvadrat med runde hjørner"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Cirkel"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Dråbeform"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Anvender ændringer af ikonform"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Ukendt"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Fjern"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Søg"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 72f7399..1c4cd7a 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breit und %2$d hoch"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Zum manuellen Hinzufügen gedrückt halten"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Automatisch hinzufügen"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"In Apps suchen"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Apps werden geladen..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Keine Apps für \"<xliff:g id="QUERY">%1$s</xliff:g>\" gefunden"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps finden"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Apps werden geladen…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Keine Apps für \"<xliff:g id="QUERY">%1$s</xliff:g>\" gefunden"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Weitere Apps suchen"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Benachrichtigungen"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Auf diesem Startbildschirm ist kein Platz mehr vorhanden."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"App-Benachrichtigungspunkte"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktiviert"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Deaktiviert"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Benachrichtigungszugriff erforderlich"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Um dir Benachrichtigungspunkte anzeigen zu lassen, aktiviere die Benachrichtigungen für die App \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Einstellungen ändern"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Symbol zu Startbildschirm hinzufügen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Für neue Apps"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Form des Symbols ändern"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Systemstandardeinstellung verwenden"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Quadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Superkreis"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Kreis"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Träne"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Änderungen an der Form des Symbols werden übernommen"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Unbekannt"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Entfernen"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Suchen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 406101c..25c8866 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Πλάτος %1$d επί ύψος %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Αγγίξτε παρατεταμένα για μη αυτόματη τοποθέτηση"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Αυτόματη προσθήκη"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Αναζήτηση εφαρμογών"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Φόρτωση εφαρμογών…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Δεν βρέθηκαν εφαρμογές για το ερώτημα \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Αναζήτηση εφαρμογών"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Φόρτωση εφαρμογών…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Δεν βρέθηκαν εφαρμογές αντιστοίχισης για \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Αναζήτηση περισσότερων εφαρμογών"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Ειδοποιήσεις"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Δεν υπάρχει χώρος σε αυτήν την αρχική οθόνη."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Κουκκίδες ειδοποίησης"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Ενεργή"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Ανενεργή"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Απαιτείται πρόσβαση στις ειδοποιήσεις"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Για να εμφανιστούν οι Κουκκίδες ειδοποίησης, ενεργοποιήστε τις κουκκίδες εφαρμογής για την εφαρμογή <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Αλλαγή ρυθμίσεων"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Προσθήκη εικονιδίου στην Αρχική οθόνη"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Για νέες εφαρμογές"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Αλλαγή σχήματος εικονιδίου"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Χρήση προεπιλογής συστήματος"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Τετράγωνο"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Στρογγυλεμένο τετράγωνο"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Κύκλος"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Δάκρυ"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Εφαρμογή αλλαγών σχήματος εικονιδίων"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Άγνωστο"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Κατάργηση"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Αναζήτηση"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 4e0ba03..f3f10cc 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Touch &amp; hold to place manually"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Add automatically"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Search for more apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Circle"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Teardrop"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Applying icon shape changes"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Search"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 4e0ba03..f3f10cc 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Touch &amp; hold to place manually"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Add automatically"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Search for more apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Circle"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Teardrop"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Applying icon shape changes"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Search"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 4e0ba03..f3f10cc 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Touch &amp; hold to place manually"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Add automatically"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Search for more apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Circle"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Teardrop"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Applying icon shape changes"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Search"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index bef4757..f60e186 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de ancho por %2$d de alto"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Mantén presionado para ubicarlo manualmente"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Agregar automáticamente"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Buscar aplicaciones"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicaciones…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No hay aplicaciones que coincidan con <xliff:g id="QUERY">%1$s</xliff:g>."</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar apps"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando apps…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"No hay apps que coincidan con \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Buscar más apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificaciones"</string>
     <string name="out_of_space" msgid="4691004494942118364">"No hay más espacio en esta pantalla principal."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Puntos de notificación"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activada"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivada"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Se necesita acceso a las notificaciones"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar los puntos de notificación, activa las notificaciones de la app para <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Cambiar la configuración"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Agregar ícono a la pantalla principal"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para nuevas apps"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambiar forma de los íconos"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Usar el sistema predeterminado"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Cuadrado"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Cuadrado con esquinas redondeadas"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Círculo"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Gota"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Aplicando cambio en la forma de los íconos"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index e49ac3f..3ab41ca 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de ancho por %2$d de alto"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Mantenlo pulsado para añadirlo manualmente"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Añadir automáticamente"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Busca aplicaciones"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicaciones…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No se han encontrado aplicaciones que contengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar aplicaciones"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando aplicaciones…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"No se han encontrado aplicaciones que contengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Buscar más aplicaciones"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificaciones"</string>
     <string name="out_of_space" msgid="4691004494942118364">"No queda espacio en la pantalla de inicio."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Puntos de notificación"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activada"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivada"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Se necesita acceso a las notificaciones"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar burbujas de notificación, activa las notificaciones de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Cambiar ajustes"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Añadir icono a la pantalla de inicio"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para nuevas aplicaciones"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambiar forma de los iconos"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Usar opción predeterminada del sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Cuadrado"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Cuadrado con esquinas redondeadas"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Círculo"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Lágrima"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Aplicando cambios en la forma de los iconos"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Quitar"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index feb63ca..6eca89e 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -65,12 +65,26 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Kaust: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Vidinad"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Taustapildid"</string>
-    <string name="settings_button_text" msgid="8119458837558863227">"Seaded"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Avalehe seaded"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Keelas administraator"</string>
     <string name="accessibility_action_overview" msgid="6257665857640347026">"Ülevaade"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Luba avaekraani pööramine"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Kui telefoni pööratakse"</string>
     <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Praegune kuvaseade ei luba pööramist"</string>
+    <string name="icon_badging_title" msgid="874121399231955394">"Märguandetäpid"</string>
+    <string name="icon_badging_desc_on" msgid="2627952638544674079">"Sees"</string>
+    <string name="icon_badging_desc_off" msgid="5503319969924580241">"Väljas"</string>
+    <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Lisa ikoon avaekraanile"</string>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Uute rakenduste puhul"</string>
+    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
+    <skip />
+    <string name="icon_shape_system_default" msgid="1709762974822753030">"Kasuta süsteemi vaikeseadet"</string>
+    <string name="icon_shape_square" msgid="633575066111622774">"Ruut"</string>
+    <string name="icon_shape_squircle" msgid="5658049910802669495">"Ümarate nurkadega ruut"</string>
+    <string name="icon_shape_circle" msgid="6550072265930144217">"Ring"</string>
+    <string name="icon_shape_teardrop" msgid="4525869388200835463">"Tilk"</string>
+    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
+    <skip />
     <string name="package_state_unknown" msgid="7592128424511031410">"Teadmata"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eemalda"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Otsing"</string>
@@ -104,4 +118,7 @@
     <string name="widget_resized" msgid="9130327887929620">"Vidina suurust muudeti. Laius: <xliff:g id="NUMBER_0">%1$s</xliff:g>. Kõrgus: <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Otseteed"</string>
     <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> otseteed rakenduse <xliff:g id="APP_NAME">%2$s</xliff:g> jaoks"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> otseteed ja <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> märguannet rakendusele <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="action_dismiss_notification" msgid="5909461085055959187">"Loobu"</string>
+    <string name="notification_dismissed" msgid="6002233469409822874">"Märguandest loobuti"</string>
 </resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 4edc4e7..8fe874b 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‏%1$d عرض در %2$d طول"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"برای قرار دادن به‌صورت دستی لمس کنید و بکشید"</string>
     <string name="place_automatically" msgid="8064208734425456485">"افزودن خودکار"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"جستجوی برنامه‌ها"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"در حال بارگیری برنامه‌ها..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"هیچ برنامه‌ای مطابق با «<xliff:g id="QUERY">%1$s</xliff:g>» پیدا نشد"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"جستجوی برنامه‌ها"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"درحال بارگیری برنامه‌‌ها…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"هیچ برنامه‌ای در مطابقت با «<xliff:g id="QUERY">%1$s</xliff:g>» پیدا نشد"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"جستجوی برنامه‌های بیشتر"</string>
     <string name="notifications_header" msgid="1404149926117359025">"اعلان‌ها"</string>
     <string name="out_of_space" msgid="4691004494942118364">"فضای بیشتری در این صفحه اصلی موجود نیست."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"نقطه‌های اعلان"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"روشن"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"خاموش"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"دسترسی به اعلان نیاز است"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"برای نمایش «نقطه‌های اعلان»، اعلان‌های برنامه را برای <xliff:g id="NAME">%1$s</xliff:g> روشن کنید"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"تغییر تنظیمات"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"افزودن نماد به صفحه اصلی"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"برای برنامه‌های جدید"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"تغییر شکل نماد"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"استفاده از پیش‌فرض سیستم"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"مربع"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"مربع با گوشه‌های گرد"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"دایره"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"قطره اشک"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"درحال اعمال کردن تغییرات شکل نماد"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"نامشخص"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"حذف"</string>
     <string name="abandoned_search" msgid="891119232568284442">"جستجو"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index f24cbae..016dbbc 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Leveys: %1$d, korkeus: %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Sijoita manuaalisesti koskettamalla pitkään."</string>
     <string name="place_automatically" msgid="8064208734425456485">"Lisää automaattisesti"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sovellushaku"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Ladataan sovelluksia…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"”<xliff:g id="QUERY">%1$s</xliff:g>” ei palauttanut sovelluksia."</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hae sovelluksia"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Ladataan sovelluksia…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"<xliff:g id="QUERY">%1$s</xliff:g> ei palauttanut sovelluksia."</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Hae lisää sovelluksia"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Ilmoitukset"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Tässä aloitusruudussa ei ole enää tilaa."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Pistemerkit"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Käytössä"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Pois käytöstä"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Ilmoituksien käyttöoikeus tarvitaan"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"<xliff:g id="NAME">%1$s</xliff:g> tarvitsee ilmoitusten käyttöoikeuden, jotta pistemerkkejä voidaan näyttää."</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Muuta asetuksia"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Lisää kuvake aloitusruutuun"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Uusille sovelluksille"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Muuta kuvakkeen muotoa"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Käytä järjestelmän oletusarvoa"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Neliö"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Ympyräneliö"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Ympyrä"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Pisara"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Sovelletaan kuvakkeiden muotojen muutoksia"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Tuntematon"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Poista"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Haku"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 5a3bd54..e57433d 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largeur sur %2$d de hauteur"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Maintenez le doigt sur l\'élément pour le placer manuellement"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Ajouter automatiquement"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Rechercher des applications"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Chargement des applications en cours..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Aucune application trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applications"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Chargement des applications en cours…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Aucune application trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Rechercher plus d\'applications"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Pas d\'espace libre sur l\'écran d\'accueil."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Points de notification"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activé"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Désactivé"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"L\'accès aux notifications est requis"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Pour afficher les points de notification, activez les notifications d\'application pour <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Modifier les paramètres"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ajouter l\'icône à l\'écran d\'accueil"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pour les nouvelles applications"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Modifier la forme de l\'icône"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Utiliser les valeurs système par défaut"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Carré"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Carré aux coins ronds"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Cercle"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Goutte"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Application des changements à la forme de l\'icône en cours…"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Inconnu"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Supprimer"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Rechercher"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 2897af0..dde4392 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largeur et %2$d de hauteur"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Appuyez de manière prolongée pour placer l\'élément manuellement"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Ajouter automatiquement"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Rechercher dans les applications"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Chargement des applications en cours…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Aucune application ne correspond à la requête \"<xliff:g id="QUERY">%1$s</xliff:g>\"."</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applications"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Chargement des applications…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Aucune application ne correspond à la requête \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Rechercher plus d\'applications"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Pas d\'espace libre sur cet écran d\'accueil."</string>
@@ -70,7 +70,7 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Dossier \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fonds d\'écran"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Paramètres du domicile"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Paramètres de l\'écran d\'accueil"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Désactivé par votre administrateur"</string>
     <string name="accessibility_action_overview" msgid="6257665857640347026">"Vue d\'ensemble"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Autoriser la rotation de l\'écran d\'accueil"</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Pastilles de notification"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activé"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Désactivé"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Accès aux notifications requis"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Pour afficher les pastilles de notification, activez les notifications de l\'application <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Modifier les paramètres"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ajouter l\'icône à l\'écran d\'accueil"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pour les nouvelles applications"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Modifier la forme des icônes"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Utiliser la valeur système par défaut"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Carré"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Cercle"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Goutte"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Application des modifications de forme des icônes…"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Inconnu"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Supprimer"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Rechercher"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 371f6b7..02c470b 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d चौड़ाई गुणा %2$d ऊंचाई"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"मैन्युअल रूप से जोड़ने के लिए स्पर्श करके रखें"</string>
     <string name="place_automatically" msgid="8064208734425456485">"अपने आप जोड़ें"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ऐप्‍स खोजें"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"ऐप्स लोड हो रहे हैं..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" से मिलान करने वाला कोई ऐप नहीं मिला"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ऐप्लिकेशन खोजें"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"ऐप्लिकेशन लोड हो रहे हैं…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" से मिलता-जुलता कोई ऐप्लिकेशन नहीं मिला"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"अधिक ऐप्लिकेशन खोजें"</string>
     <string name="notifications_header" msgid="1404149926117359025">"नोटिफ़िकेशन"</string>
     <string name="out_of_space" msgid="4691004494942118364">"इस होम स्‍क्रीन पर स्थान शेष नहीं है."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"नोटिफ़िकेशन बिंदु"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"चालू"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"बंद"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"नोटिफ़िकेशन एक्‍सेस ज़रूरी है"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"नोटिफ़िकेशन बिंदु दिखाने के लिए, <xliff:g id="NAME">%1$s</xliff:g> के ऐप्लिकेशन नोटिफ़िकेशन चालू करें"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"सेटिंग बदलें"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"होम स्क्रीन में आइकन जोड़ें"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नए ऐप्लिकेशन के लिए"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"आइकन का आकार बदलें"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"सिस्टम डिफ़ॉल्ट का उपयोग करें"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"वर्ग"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"गोल कोनों वाला वर्ग"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"मंडली"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"आंसू की बूंद"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"आइकन के आकार में बदलाव लागू किए जा रहे हैं"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"अज्ञात"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"निकालें"</string>
     <string name="abandoned_search" msgid="891119232568284442">"खोजें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 0912677..aaae258 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d širine i %2$d visine"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Dodirnite i zadržite stavku da biste je postavili ručno"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Dodaj automatski"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pretraži aplikacije"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Učitavanje aplikacija…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nema aplikacija podudarnih s upitom \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretraži aplikacije"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Učitavanje aplikacija…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nema aplikacija podudarnih s upitom \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Traži više aplikacija"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Obavijesti"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na ovom početnom zaslonu više nema mjesta."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Točke obavijesti"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Uključeno"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Isključeno"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreban je pristup obavijestima"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Za prikaz točaka obavijesti uključite obavijesti aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Promjena postavki"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonu na početni zaslon"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Promijeni oblik ikona"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Upotrijebi zadane postavke sustava"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Zaobljeni kvadrat"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Krug"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Suza"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Primjena promjena oblika ikona"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Nepoznato"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Ukloni"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Traži"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 3ffd508..2da64b0 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d széles és %2$d magas"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tartsa lenyomva a manuális hozzáadáshoz"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Automatikus hozzáadás"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Alkalmazások keresése"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Alkalmazások betöltése…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Egy alkalmazás sem található a(z) „<xliff:g id="QUERY">%1$s</xliff:g>” lekérdezésre."</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Alkalmazások keresése"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Alkalmazások betöltése…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nem található alkalmazás a(z) „<xliff:g id="QUERY">%1$s</xliff:g>” lekérdezésre"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"További alkalmazások keresése"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Értesítések"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Nincs több hely ezen a kezdőképernyőn."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Értesítési pöttyök"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Bekapcsolva"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Kikapcsolva"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Értesítésekhez való hozzáférésre van szükség"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Az értesítési pöttyök megjelenítéséhez kapcsolja be a(z) <xliff:g id="NAME">%1$s</xliff:g> alkalmazás értesítéseit"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Beállítások módosítása"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ikon hozzáadása a kezdőképernyőhöz"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Új alkalmazásoknál"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Ikon formájának módosítása"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Alapértelmezett érték használata"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Négyzet"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Kör"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Könnycsepp"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Ikonforma módosításainak alkalmazása…"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Ismeretlen"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eltávolítás"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Keresés"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 5634963..379a960 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"lebar %1$d x tinggi %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Sentuh &amp; tahan untuk menempatkan secara manual"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Tambahkan otomatis"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Telusuri Apps"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Memuat Aplikasi..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Tidak ditemukan Aplikasi yang cocok dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Telusuri aplikasi"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Memuat aplikasi…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Tidak ditemukan aplikasi yang cocok dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Telusuri aplikasi lainnya"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifikasi"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Tidak ada ruang lagi pada layar Utama ini."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Titik notifikasi"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktif"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Nonaktif"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Perlu akses notifikasi"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Guna menampilkan Titik Notifikasi, aktifkan notifikasi aplikasi untuk <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Ubah setelan"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Tambahkan ikon ke layar Utama"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Untuk aplikasi baru"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Ubah bentuk ikon"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Gunakan default sistem"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Persegi"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Persegi bundar"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Lingkaran"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Butiran Air"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Menerapkan perubahan bentuk ikon"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Tidak dikenal"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Buang"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Telusuri"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 8af098d..a52aee4 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d di larghezza per %2$d di altezza"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tieni premuto per posizionare l\'elemento manualmente"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Aggiungi automaticamente"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Cerca app"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Caricamento di app…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nessuna app trovata corrispondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca nelle app"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Caricamento delle app…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nessuna app trovata corrispondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Cerca altre app"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifiche"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Spazio nella schermata Home esaurito."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Indicatori notifica"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Attiva"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Non attiva"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Accesso alle notifiche necessario"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Per mostrare gli indicatori di notifica, attiva le notifiche per l\'app <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Modifica impostazioni"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Aggiungi icone alla schermata Home"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Per le nuove app"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambia la forma delle icone"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Usa impostazione predefinita di sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Quadrato"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Supercerchio"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Cerchio"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Goccia"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Applicazione delle modifiche alla forma delle icone"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Sconosciuto"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Rimuovi"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Cerca"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 2425254..650a90d 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‏רוחב %1$d על גובה %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"גע והחזק כדי להוסיף ידנית"</string>
     <string name="place_automatically" msgid="8064208734425456485">"הוסף באופן אוטומטי"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"חפש אפליקציות"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"טוען אפליקציות…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"לא נמצאו אפליקציות התואמות ל-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"חיפוש אפליקציות"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"טוען אפליקציות…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"לא נמצאו אפליקציות התואמות ל-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"חפש אפליקציות נוספות"</string>
     <string name="notifications_header" msgid="1404149926117359025">"הודעות"</string>
     <string name="out_of_space" msgid="4691004494942118364">"אין עוד מקום במסך דף הבית הזה."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"סימני הודעות"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"מופעלת"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"כבויה"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"נדרשת גישה להודעות"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"כדי להציג את סימני ההודעות, יש להפעיל הודעות מהאפליקציה <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"שנה את ההגדרות"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"הוספת סמל במסך דף הבית"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"לאפליקציות חדשות"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"שינוי הצורה של הסמלים"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"השתמש בברירת המחדל של המערכת"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"ריבוע"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"ריבוע בעל פינות מעוגלות"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"מעגל"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"טיפה"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"משנה את הצורה של הסמלים"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"לא ידוע"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"הסר"</string>
     <string name="abandoned_search" msgid="891119232568284442">"חפש"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index cb5fa15..4071a6c 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"幅 %1$d、高さ %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"押し続けると、手動で追加できます"</string>
     <string name="place_automatically" msgid="8064208734425456485">"自動的に追加"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"アプリを検索"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"アプリを読み込んでいます…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"「<xliff:g id="QUERY">%1$s</xliff:g>」に一致するアプリは見つかりませんでした"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"アプリを検索"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"アプリを読み込んでいます…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"「<xliff:g id="QUERY">%1$s</xliff:g>」に一致するアプリは見つかりませんでした"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"他のアプリを検索"</string>
     <string name="notifications_header" msgid="1404149926117359025">"通知"</string>
     <string name="out_of_space" msgid="4691004494942118364">"このホーム画面に空きスペースがありません。"</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"通知ドット"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ON"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"OFF"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"通知へのアクセス権限が必要"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"通知ドットを表示するには、「<xliff:g id="NAME">%1$s</xliff:g>」のアプリ通知を ON にしてください"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"設定を変更"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ホーム画面にアイコンを追加"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"新しいアプリをダウンロードしたときに"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"アイコンの形の変更"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"システムのデフォルトを使用"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"スクエア"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"スクワークル"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"サークル"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"ティアドロップ"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"アイコンの形の変更を適用しています"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"不明"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"削除"</string>
     <string name="abandoned_search" msgid="891119232568284442">"検索"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 26535f0..e3511d4 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"너비 %1$d, 높이 %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"길게 터치하여 직접 장소 추가"</string>
     <string name="place_automatically" msgid="8064208734425456485">"자동으로 추가"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"앱 검색"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"앱 로드 중..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\'<xliff:g id="QUERY">%1$s</xliff:g>\'와(과) 일치하는 앱이 없습니다."</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"앱 검색"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"앱 로드 중…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"\'<xliff:g id="QUERY">%1$s</xliff:g>\'과(와) 일치하는 앱이 없습니다."</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"더 많은 앱 검색"</string>
     <string name="notifications_header" msgid="1404149926117359025">"알림"</string>
     <string name="out_of_space" msgid="4691004494942118364">"홈 화면에 더 이상 공간이 없습니다."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"알림 표시 점"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"사용"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"사용 안함"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"알림 액세스 권한 필요"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"알림 표시점을 표시하려면 <xliff:g id="NAME">%1$s</xliff:g>의 앱 알림을 사용 설정하세요."</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"설정 변경"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"홈 화면에 아이콘 추가"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"새로 설치한 앱에 적용"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"아이콘 모양 변경"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"시스템 기본값 사용"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"정사각형"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"모서리가 둥근 정사각형"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"원"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"눈물방울"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"아이콘 모양 변경사항을 적용하는 중입니다."</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"알 수 없음"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"삭제"</string>
     <string name="abandoned_search" msgid="891119232568284442">"검색"</string>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 08073ce..1b58e17 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -26,9 +26,12 @@
 
     <!-- Dynamic grid -->
     <dimen name="dynamic_grid_overview_bar_item_width">120dp</dimen>
-    <dimen name="dynamic_grid_page_indicator_size">24dp</dimen>
-    <dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
-    <dimen name="dynamic_grid_cell_padding_x">8dp</dimen>
+    <dimen name="dynamic_grid_min_page_indicator_size">48dp</dimen>
+    <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
+
+    <dimen name="dynamic_grid_cell_layout_padding">0dp</dimen>
+
+    <dimen name="folder_preview_padding">2dp</dimen>
 
     <!-- Hotseat -->
     <dimen name="dynamic_grid_hotseat_land_left_nav_bar_right_padding">18dp</dimen>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 945cbf6..d415e4d 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d plotis ir %2$d aukštis"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Palieskite ir palaikykite, kad padėtumėte patys"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Pridėti automatiškai"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Ieškoti programų"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Įkeliamos programos..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nerasta jokių užklausą „<xliff:g id="QUERY">%1$s</xliff:g>“ atitinkančių programų"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Paieškos programos"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Įkeliamos programos…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nerasta jokių užklausą „<xliff:g id="QUERY">%1$s</xliff:g>“ atitinkančių programų"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Ieškoti daugiau programų"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Pranešimai"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Šiame pagrindiniame ekrane vietos nebėra."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Pranešimų taškai"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Įjungta"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Išjungta"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Reikalinga prieiga prie pranešimų"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Kad būtų rodomi pranešimų taškai, įjunkite programos „<xliff:g id="NAME">%1$s</xliff:g>“ pranešimus."</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Keisti nustatymus"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pridėti piktogr. prie pagrindinio ekrano"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Skirta naujoms programoms"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Pakeisti piktogramos formą"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Naudoti numatytuosius sistemos nustatymus"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadratas"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kvadratais suapvalintais kampais"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Apskritimas"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Ašara"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Taikomi piktogramos formos pakeitimai"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Nežinoma"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Pašalinti"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Ieškoti"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index e3c3482..2d8bfd8 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d plats un %2$d augsts"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Pieskarieties un turiet, lai manuāli pievienotu"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Pievienot automātiski"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Meklēt lietotnes"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Notiek lietotņu ielāde…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Vaicājumam “<xliff:g id="QUERY">%1$s</xliff:g>” neatbilda neviena lietotne."</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Meklēt lietotnes"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Notiek lietotņu ielāde…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Vaicājumam “<xliff:g id="QUERY">%1$s</xliff:g>” neatbilda neviena lietotne"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Meklēt citas lietotnes"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Paziņojumi"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Šajā sākuma ekrānā vairs nav vietas."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Paziņojumu punkti"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Ieslēgts"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Izslēgts"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Nepieciešama piekļuve paziņojumiem"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Lai tiktu rādīti paziņojumu punkti, ieslēdziet paziņojumus lietotnei <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Mainīt iestatījumus"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pievienot ikonu sākuma ekrānā"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Jaunām lietotnēm"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Mainīt ikonu formu"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Izmantot sistēmas noklusējumu"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrāts"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kvadrāts ar noapaļotiem stūriem"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Aplis"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Lāse"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Tiek piemērotas ikonu formas izmaiņas"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Nezināma"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Noņemt"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Meklēt"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 215315a..f7237a0 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -65,12 +65,26 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widget"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Kertas dinding"</string>
-    <string name="settings_button_text" msgid="8119458837558863227">"Tetapan"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Tetapan laman utama"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dilumpuhkan oleh pentadbir anda"</string>
     <string name="accessibility_action_overview" msgid="6257665857640347026">"Ikhtisar"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Benarkan putaran Skrin Utama"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Apabila telefon diputar"</string>
     <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Tetapan Paparan semasa tidak membenarkan putaran"</string>
+    <string name="icon_badging_title" msgid="874121399231955394">"Titik pemberitahuan"</string>
+    <string name="icon_badging_desc_on" msgid="2627952638544674079">"Hidup"</string>
+    <string name="icon_badging_desc_off" msgid="5503319969924580241">"Mati"</string>
+    <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Tambahkan ikon pada Skrin Utama"</string>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Untuk apl baharu"</string>
+    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
+    <skip />
+    <string name="icon_shape_system_default" msgid="1709762974822753030">"Gunakan lalai sistem"</string>
+    <string name="icon_shape_square" msgid="633575066111622774">"Segi empat sama"</string>
+    <string name="icon_shape_squircle" msgid="5658049910802669495">"Segi empat berbucu bulat"</string>
+    <string name="icon_shape_circle" msgid="6550072265930144217">"Bulatan"</string>
+    <string name="icon_shape_teardrop" msgid="4525869388200835463">"Titisan air mata"</string>
+    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
+    <skip />
     <string name="package_state_unknown" msgid="7592128424511031410">"Tidak diketahui"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Alih keluar"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Carian"</string>
@@ -104,4 +118,7 @@
     <string name="widget_resized" msgid="9130327887929620">"Saiz widget diubah menjadi <xliff:g id="NUMBER_0">%1$s</xliff:g> lebar <xliff:g id="NUMBER_1">%2$s</xliff:g> tinggi"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Pintasan"</string>
     <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pintasan untuk <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pintasan dan <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> pemberitahuan untuk <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="action_dismiss_notification" msgid="5909461085055959187">"Ketepikan"</string>
+    <string name="notification_dismissed" msgid="6002233469409822874">"Pemberitahuan diketepikan"</string>
 </resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 2b776d6..bd348b0 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d bredde x %2$d høyde"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Trykk og hold for å plassere manuelt"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Legg til automatisk"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Søk i apper"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Laster inn apper …"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Fant ingen apper som samsvarer med «<xliff:g id="QUERY">%1$s</xliff:g>»"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søk etter apper"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Laster inn appene …"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Fant ingen apper som samsvarer med «<xliff:g id="QUERY">%1$s</xliff:g>»"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Søk etter flere apper"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Varsler"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Denne startsiden er full."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Varselsprikker"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"På"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Av"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Tilgang til varsler er nødvendig"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Slå på appvarsler for <xliff:g id="NAME">%1$s</xliff:g> for å vise varselsprikker"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Endre innstillingene"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Legg til ikon på startsiden"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For nye apper"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Endre ikonets form"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Bruk systemstandard"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Superellipse"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Sirkel"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Dråpe"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Aktiverer endringer av ikonets form"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Ukjent"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Fjern"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Søk"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 0180bb4..7e8def4 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breed en %2$d hoog"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tik op een item en houd dit vast om het handmatig te plaatsen"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Automatisch toevoegen"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Apps zoeken"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Apps laden…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Er zijn geen apps gevonden die overeenkomen met \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps zoeken"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Apps laden…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Er zijn geen apps gevonden die overeenkomen met \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Zoeken naar meer apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Meldingen"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Er is geen ruimte meer op dit startscherm."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Meldingsstipjes"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aan"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Uit"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Toegang tot meldingen vereist"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Als je meldingsstipjes wilt weergeven, schakel je app-meldingen in voor <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Instellingen wijzigen"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pictogram toevoegen aan startscherm"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Voor nieuwe apps"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Vorm van pictogram wijzigen"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Systeemstandaard gebruiken"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Vierkant"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Cirkel"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Traan"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Wijzigingen in vorm van pictogram toepassen"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Onbekend"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Verwijderen"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Zoeken"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index f8a7f66..c07f7de 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Szerokość %1$d, wysokość %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Kliknij i przytrzymaj, by umieścić ręcznie"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Dodaj automatycznie"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Szukaj w aplikacjach"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Wczytuję aplikacje…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nie znaleziono aplikacji pasujących do zapytania „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Wyszukaj aplikacje"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Ładuję aplikacje…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nie znaleziono aplikacji pasujących do zapytania „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Wyszukaj więcej aplikacji"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Powiadomienia"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Brak miejsca na tym ekranie głównym."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Plakietki z powiadomieniami"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Włączono"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Wyłączono"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Wymagany jest dostęp do powiadomień"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Aby pokazać plakietki z powiadomieniami, włącz powiadomienia aplikacji <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Zmień ustawienia"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonę do ekranu głównego"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"W przypadku nowych aplikacji"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Zmień kształt ikon"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Użyj ustawienia domyślnego"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kwadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Zaokrąglony kwadrat"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Okrąg"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Łza"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Zmieniam kształt ikon"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Brak informacji"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Usuń"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Szukaj"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 5c37eb8..100f07b 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largura por %2$d de altura"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Toque sem soltar para colocar manualmente"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Adicionar automaticamente"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pesquisar aplicações"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"A carregar aplicações..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Não foram encontradas aplic. que correspondam a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pesquisar aplicações"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"A carregar aplicações…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenhuma aplicação correspondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Pesquisar mais aplicações"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificações"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Sem espaço suficiente neste Ecrã principal."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Pontos de notificação"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Ativada"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desativada"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Acesso a notificações necessário"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar os Pontos de notificação, ative as notificações de aplicações para o <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Alterar definições"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adicionar ícone ao ecrã principal"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para novas aplicações"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Alterar forma do ícone"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Utilizar a predefinição do sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Quadrado"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Quadrado e círculo"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Círculo"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Lágrima"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"A aplicar alterações à forma do ícone..."</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconhecido"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Remover"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Pesquisar"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index fd24066..d75159f 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largura por %2$d de altura"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Toque e mantenha pressionado para posicionar manualmente"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Adicionar automaticamente"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pesquisar apps"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Carregando apps…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nenhum app encontrado que corresponda a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps de pesquisa"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Carregando apps…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenhum app encontrado que corresponda a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Pesquisar mais apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificações"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Não há mais espaço na tela inicial."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Pontos de notificação"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Ativado"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desativado"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Acesso a notificações necessário"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar pontos de notificação, ative as notificações de app para <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Alterar configurações"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adicionar ícone à tela inicial"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para novos apps"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Alterar forma de ícones"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Usar padrão do sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Quadrado"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Quadrado arredondado"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Círculo"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Lágrima"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Aplicando alterações na forma dos ícones"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconhecido"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Remover"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Pesquisar"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index e7b8144..512d96d 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d lățime și %2$d înălțime"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Atingeți lung pentru a plasa manual"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Adăugați automat"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Căutați aplicații"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Se încarcă aplicațiile..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nu s-a găsit nicio aplicație pentru „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Căutați aplicații"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Se încarcă aplicații…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nu s-a găsit nicio aplicație pentru „<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Căutați mai multe aplicații"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificări"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Nu mai este loc pe acest Ecran de pornire."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Puncte de notificare"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activat"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Dezactivat"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Este necesar accesul la notificări"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Pentru a afișa punctele de notificare, activați notificările din aplicație pentru <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Modificați setările"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adaugă pictograme în ecranul de pornire"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pentru aplicații noi"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Schimbați forma pictogramei"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Folosiți setarea prestabilită a sistemului"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Pătrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Pătrat cu colțuri rotunjite"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Cerc"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Lacrimă"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Se aplică modificările aduse formei pictogramei"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Necunoscut"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminați"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Căutați"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 07ff761..aed8f18 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ширина %1$d, высота %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Нажмите и удерживайте, чтобы добавить вручную"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Добавить автоматически"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Поиск приложений"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Загрузка…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"По запросу \"<xliff:g id="QUERY">%1$s</xliff:g>\" ничего не найдено"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Поиск приложений"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Загрузка приложений…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"По запросу \"<xliff:g id="QUERY">%1$s</xliff:g>\" ничего не найдено"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Искать другие приложения"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Уведомления"</string>
     <string name="out_of_space" msgid="4691004494942118364">"На этом экране все занято"</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Значки уведомлений"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ВКЛ"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ВЫКЛ"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Нет доступа к уведомлениям"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Чтобы показывать значки уведомлений, включите уведомления в приложении \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Изменить настройки"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Добавлять значки"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Добавлять значки установленных приложений на главный экран."</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Изменить форму значков"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Использовать системные настройки по умолчанию"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Квадрат с закругленными краями"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Круг"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Капля"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Применение изменений..."</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Неизвестно"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Удалить"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Найти"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index b7999f4..490f823 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"šírka %1$d, výška %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Položku umiestnite ručne klepnutím a podržaním"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Pridať automaticky"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Hľadať aplikácie"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Načítavajú sa aplikácie..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nenašli sa žiadne aplikácie zodpovedajúce dopytu <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hľadať aplikácie"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Načítavajú sa aplikácie…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenašli sa žiadne aplikácie zodpovedajúce dopytu <xliff:g id="QUERY">%1$s</xliff:g>"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Hľadať ďalšie aplikácie"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Upozornenia"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na tejto ploche už nie je miesto"</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Bodky upozornení"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Zapnuté"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Vypnuté"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Vyžaduje sa prístup k upozorneniam"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Ak chcete, aby sa zobrazovali bodky upozornení, zapnite upozornenia aplikácie <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Zmeniť nastavenia"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pridať ikonu na plochu"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pri inštalácii novej aplikácie"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Zmeniť tvar ikony"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Použiť predvolené nastavenie systému"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Štvorec"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Okrúhly štvorec"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Kruh"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Slza"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Tvar ikony sa mení"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Neznáme"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Odstrániť"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Vyhľadať"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 927b389..0b7d36e 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Širina %1$d, višina %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Dotaknite se elementa in ga pridržite, da ga ročno dodate"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Samodejno dodaj"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Iskanje po aplikacijah"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Nalaganje aplikacij …"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ni aplikacij, ki bi ustrezale poizvedbi »<xliff:g id="QUERY">%1$s</xliff:g>«"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Iskanje programov"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Nalaganje aplikacij …"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Ni aplikacij, ki bi ustrezale poizvedbi »<xliff:g id="QUERY">%1$s</xliff:g>«"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Iskanje več aplikacij"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Obvestila"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na tem začetnem zaslonu ni več prostora."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Obvestilne pike"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Vklopljeno"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Izklopljeno"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreben je dostop do obvestil"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Za prikaz obvestilnih pik vklopite obvestila aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Spremeni nastavitve"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikono na začetni zaslon"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Spremeni obliko ikon"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Uporabi privzeto nastavitev sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Zaobljen kvadrat"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Krog"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Solza"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Uveljavljanje spremenjene oblike ikon"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Neznano"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Odstrani"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Iskanje"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 2cfaee6..f41e02d 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"ширина од %1$d и висина од %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Додирните и задржите да бисте поставили ручно"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Аутоматски додај"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Претражите апликације"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Апликације се учитавају..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Није пронађена ниједна апликација за „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Претражите апликације"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Апликације се учитавају…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Није пронађена ниједна апликација за „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Претражи још апликација"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Обавештења"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Нема више простора на овом почетном екрану."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Тачке за обавештења"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Укључено"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Искључено"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Потребан је приступ за обавештења"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Да бисте приказали тачке за обавештења, укључите обавештења за апликацију <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Промените подешавања"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Додај икону на почетни екран"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нове апликације"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Промените облик икона"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Користи подразумевано системско подешавање"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Заобљени квадрат"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Круг"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Суза"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Примењују се промене облика икона"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Непознато"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Уклони"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Претражи"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index aa6e99a..6c598ff 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d bred gånger %2$d hög"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Placera manuellt genom att trycka länge"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Lägg till automatiskt"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sök efter appar"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Läser in appar …"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Det gick inte att hitta några appar som matchar <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Sök efter appar"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Läser in appar …"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Inga appar som matchar <xliff:g id="QUERY">%1$s</xliff:g> hittades"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Sök efter fler appar"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Aviseringar"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Det finns inte plats för mer på den här startskärmen."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Aviseringsprickar"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"På"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Av"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Åtkomst till aviseringar krävs"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Aktivera appaviseringar för <xliff:g id="NAME">%1$s</xliff:g> om du vill att aviseringsprickar ska visas"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Ändra inställningar"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Lägg till ikonen på startskärmen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"För nya appar"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Ändra form på ikoner"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Använd systemstandard"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kvirkel"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Cirkel"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Droppe"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Ikonernas form ändras"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Okänt"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Ta bort"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Sök"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 3b6d373..3de28e0 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Upana wa %1$d na kimo cha %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Gusa na ushikilie ili uweke mwenyewe"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Ongeza kiotomatiki"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Tafuta Programu"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Inapakia Programu..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Haikupata programu zinazolingana na \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tafuta programu"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Inapakia programu..."</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Haikupata programu zozote zinazolingana na \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Tafuta programu zaidi"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Arifa"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Hakuna nafasi katika skrini hii ya Mwanzo."</string>
@@ -81,17 +81,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Vitone vya arifa"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Imewashwa"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Imezimwa"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Inahitaji idhini ya kufikia arifa"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Ili kuonyesha Vitone vya Arifa, washa kipengele cha arifa za programu katika <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Badilisha mipangilio"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ongeza aikoni kwenye Skrini ya kwanza"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Kwa ajili ya programu mpya"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Badilisha umbo la aikoni"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Tumia umbo chaguo-msingi la mfumo"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Mraba"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Mstatili wenye pembe duara"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Mduara"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Umbo la chozi"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Inabadilisha umbo la aikoni"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Yasiyojulikana"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Ondoa"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Tafuta"</string>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index e836d7d..b211207 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -17,7 +17,6 @@
 <resources>
     <!-- All Apps -->
     <dimen name="all_apps_button_scale_down">8dp</dimen>
-    <dimen name="all_apps_search_bar_height">54dp</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-sw720dp/styles.xml b/res/values-sw720dp/styles.xml
index bb0dbc2..72894dc 100644
--- a/res/values-sw720dp/styles.xml
+++ b/res/values-sw720dp/styles.xml
@@ -26,7 +26,7 @@
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowActionModeOverlay">true</item>
         <item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
-        <item name="android:keyboardLayout">@layout/all_apps_search_container</item>
+        <item name="android:keyboardLayout">@layout/search_container_all_apps</item>
     </style>
 
     <!-- Workspace -->
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index e03931e..b370099 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"กว้าง %1$d x สูง %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"แตะค้างไว้เพื่อวางด้วยตัวเอง"</string>
     <string name="place_automatically" msgid="8064208734425456485">"เพิ่มโดยอัตโนมัติ"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ค้นหาแอป"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"กำลังโหลดแอป…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"ไม่พบแอปที่ตรงกับ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ค้นหาแอป"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"กำลังโหลดแอป…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"ไม่พบแอปที่ตรงกับ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"ค้นหาแอปเพิ่มเติม"</string>
     <string name="notifications_header" msgid="1404149926117359025">"การแจ้งเตือน"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ไม่มีที่ว่างในหน้าจอหลักนี้"</string>
@@ -76,20 +76,21 @@
     <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="icon_badging_title" msgid="874121399231955394">"จุดการแจ้งเตือน"</string>
+    <string name="icon_badging_title" msgid="874121399231955394">"จุดแจ้งเตือน"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"เปิด"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ปิด"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"ต้องได้รับสิทธิ์เข้าถึงการแจ้งเตือน"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"เปิดการแจ้งเตือนแอปของ <xliff:g id="NAME">%1$s</xliff:g> เพื่อแสดงจุดแจ้งเตือน"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"เปลี่ยนการตั้งค่า"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"เพิ่มไอคอนในหน้าจอหลัก"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"สำหรับแอปใหม่"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"เปลี่ยนรูปร่างไอคอน"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"ใช้ค่าเริ่มต้นของระบบ"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"สี่เหลี่ยมจัตุรัส"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"สี่เหลี่ยมขอบมน"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"วงกลม"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"หยดน้ำตา"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"กำลังนำการเปลี่ยนรูปร่างไอคอนไปใช้"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"ไม่รู้จัก"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"ลบ"</string>
     <string name="abandoned_search" msgid="891119232568284442">"ค้นหา"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 12bc013..54135c9 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ang lapad at %2$d ang taas"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Pindutin nang matagal upang manual na ilagay"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Awtomatikong idagdag"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Mga App sa Paghahanap"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Nilo-load ang Mga App…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Walang nakitang Mga App na tumutugma sa \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Maghanap ng mga app"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Naglo-load ng mga app…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Walang nahanap na app na tumutugma sa \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Maghanap ng higit pang mga app"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Mga Notification"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Wala nang lugar sa Home screen na ito."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Mga notification dot"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Naka-on"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Naka-off"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Kinakailangan ng access sa notification"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Upang ipakita ang Mga Notification Dot, i-on ang mga notification ng app para sa <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Baguhin ang mga setting"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Idagdag ang icon sa Home screen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para sa mga bagong app"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Baguhin ang hugis ng icon"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Gamitin ang default ng system"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Parisukat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Bilog"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Teardrop"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Inilalapat ang mga pagbabago sa hugis ng icon"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Hindi kilala"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Alisin"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Maghanap"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index b245bff..cb8b50a 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"genişlik: %1$d, yükseklik: %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Manuel olarak yerleştirmek için dokunun ve basılı tutun"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Otomatik olarak ekle"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Uygulamalarda Ara"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Uygulamalar Yükleniyor…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ile eşleşen uygulama bulunamadı"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Uygulamalarda ara"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Uygulamalar yükleniyor…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ile eşleşen uygulama bulunamadı"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Başka uygulamalar ara"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Bildirimler"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Bu Ana ekranda yer kalmadı."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Bildirim noktaları"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Açık"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Kapalı"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Bildirim erişimi gerekli"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Bildirim Noktaları\'nı göstermek için <xliff:g id="NAME">%1$s</xliff:g> uygulamasının bildirimlerini açın"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Ayarları değiştir"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ana ekrana simge ekle"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Yeni uygulamalar için"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Simge şeklini değiştir"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Sistem varsayılanını kullan"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kare"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kare-daire"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Daire"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Gözyaşı damlası"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Simge şekli değişiklikleri uygulanıyor"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Bilinmiyor"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Kaldır"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Ara"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 8d33910..a9e0109 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ширина – %1$d, висота – %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Натисніть і утримуйте, щоб додати вручну"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Додати автоматично"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Пошук додатків"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Завантаження додатків…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Немає додатків для запиту \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Пошук додатків"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Завантаження додатків…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Немає додатків для запиту \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Шукати ще додатки"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Сповіщення"</string>
     <string name="out_of_space" msgid="4691004494942118364">"На цьому головному екрані більше немає місця."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Значки сповіщень"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Увімкнено"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Вимкнено"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Потрібен доступ до сповіщень"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Щоб показувати значки сповіщень, увімкніть сповіщення в додатку <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Змінити налаштування"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Додати значок на головний екран"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Для нових додатків"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Змінити форму значка"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Використовувати налаштування системи за умовчанням"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Квадрат із заокругленими кутами"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Круг"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Сльоза"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Змінюється форма значка"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Невідомо"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Видалити"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Шукати"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index f6cb8f2..83e1cea 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Rộng %1$d x cao %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Chạm và giữ để đặt theo cách thủ công"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Tự động thêm"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Tìm kiếm ứng dụng"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Đang tải ứng dụng..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Không tìm thấy ứng dụng nào phù hợp với \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tìm kiếm ứng dụng"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Đang tải ứng dụng…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Không tìm thấy ứng dụng nào phù hợp với \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Tìm kiếm thêm ứng dụng"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Thông báo"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Không còn chỗ trên Màn hình chính này."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Dấu chấm thông báo"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Đang bật"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Đã tắt"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Cần quyền truy cập thông báo"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Để hiển thị Dấu chấm thông báo, hãy bật thông báo ứng dụng cho <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Thay đổi cài đặt"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Thêm biểu tượng vào màn hình chính"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Cho ứng dụng mới"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Thay đổi hình dạng biểu tượng"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Sử dụng mặc định của hệ thống"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Hình vuông"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Hình vuông cạnh bo tròn"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Hình tròn"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"Hình giọt nước"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Đang áp dụng các thay đổi hình dạng biểu tượng"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Không xác định"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Xóa"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Tìm kiếm"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 5dcef74..bef12fb 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"宽 %1$d,高 %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"触摸并按住即可手动放置"</string>
     <string name="place_automatically" msgid="8064208734425456485">"自动添加"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"搜索应用"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"正在加载应用…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"未找到与“<xliff:g id="QUERY">%1$s</xliff:g>”相符的应用"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"搜索应用"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"正在加载应用…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"未找到与“<xliff:g id="QUERY">%1$s</xliff:g>”相符的应用"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"搜索更多应用"</string>
     <string name="notifications_header" msgid="1404149926117359025">"通知"</string>
     <string name="out_of_space" msgid="4691004494942118364">"此主屏幕上已没有空间。"</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"通知圆点"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"开启"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"关闭"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"需要获取通知使用权"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"要显示通知圆点,请开启<xliff:g id="NAME">%1$s</xliff:g>的应用通知功能"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"更改设置"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"将图标添加到主屏幕"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"适用于新应用"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"更改图标形状"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"使用系统默认设置"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"方形"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"方圆形"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"圆形"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"泪珠形"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"正在应用图标形状更改"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"未知"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"移除"</string>
     <string name="abandoned_search" msgid="891119232568284442">"搜索"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 2bbc160..7ac5553 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d 闊,%2$d 高"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"按住即可手動新增"</string>
     <string name="place_automatically" msgid="8064208734425456485">"自動新增"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"搜尋應用程式"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"正在載入應用程式…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"無法找到與「<xliff:g id="QUERY">%1$s</xliff:g>」相符的應用程式"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"搜尋應用程式"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"正在載入應用程式…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"找不到與「<xliff:g id="QUERY">%1$s</xliff:g>」相符的應用程式"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"搜尋更多應用程式"</string>
     <string name="notifications_header" msgid="1404149926117359025">"通知"</string>
     <string name="out_of_space" msgid="4691004494942118364">"主畫面已無空間。"</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"通知圓點"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"開啟"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"關閉"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"需要獲取通知存取權"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"如要顯示「通知圓點」,請開啟「<xliff:g id="NAME">%1$s</xliff:g>」的應用程式通知功能"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"變更設定"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"將圖示加到主畫面"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"適用於新安裝的應用程式"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"變更圖示形狀"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"使用系統預設設定"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"正方形"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"方圓形"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"圓形"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"淚珠形"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"正在套用圖示形狀變更"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"不明"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"移除"</string>
     <string name="abandoned_search" msgid="891119232568284442">"搜尋"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index f1605f6..e0c4c99 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"寬度為 %1$d,高度為 %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"按住即可手動放置"</string>
     <string name="place_automatically" msgid="8064208734425456485">"自動新增"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"搜尋應用程式"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"正在載入應用程式…"</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"找不到符合「<xliff:g id="QUERY">%1$s</xliff:g>」的應用程式"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"搜尋應用程式"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"正在載入應用程式…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"找不到與「<xliff:g id="QUERY">%1$s</xliff:g>」相符的應用程式"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"搜尋更多應用程式"</string>
     <string name="notifications_header" msgid="1404149926117359025">"通知"</string>
     <string name="out_of_space" msgid="4691004494942118364">"這個主螢幕已無空間。"</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"通知圓點"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"已啟用"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"已停用"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"需要取得通知存取權"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"如要顯示通知圓點,請開啟「<xliff:g id="NAME">%1$s</xliff:g>」的應用程式通知功能"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"變更設定"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"將圖示加到主螢幕"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"適用於新安裝的應用程式"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"變更圖示形狀"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"使用系統預設值"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"正方形"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"方圓形"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"圓形"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"淚珠形"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"正在套用圖示形狀變更"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"不明"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"移除"</string>
     <string name="abandoned_search" msgid="891119232568284442">"搜尋"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 12d14bd..ef6fdeb 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -35,9 +35,9 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ububanzi ngokungu-%2$d ukuya phezulu"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Thinta futhi ubambe ukuze ubeke ngokwenza"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Engeza ngokuzenzakalelayo"</string>
-    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sesha Izinhlelo Zokusebenza"</string>
-    <string name="all_apps_loading_message" msgid="7557140873644765180">"Ilayisha izinhlelo zokusebenza..."</string>
-    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Azikho izinhlelo zokusebenza ezitholakele ezifana ne-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Sesha izinhlelo zokusebenza"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Ilayisha izinhlelo zokusebenza..."</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Azikho izinhlelo zokusebenza ezitholiwe ezifana ne-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Sesha izinhlelo zokusebenza eziningi"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Izaziso"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Asisekho isikhala kulesi sikrini Sasekhaya."</string>
@@ -79,17 +79,18 @@
     <string name="icon_badging_title" msgid="874121399231955394">"Amachashazi esaziso"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Kuvuliwe"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Kuvaliwe"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Ukufinyelela izaziso kuyadingeka"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Ukuze ubonisa amcashazi esaziso, vula izaziso zohlelo lokusebenza ze-<xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Shintsha izilungiselelo"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Engeza isithonjana eskrinini sasekhaya"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Kwezinhlelo zokusebenza ezintsha"</string>
-    <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
-    <skip />
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"Shintsha isimo sesithonjana"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Sebenzisa okuzenzakalelayo kwesistimu"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Isikwele"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"I-Squircle"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Indingiliza"</string>
     <string name="icon_shape_teardrop" msgid="4525869388200835463">"I-Teardrop"</string>
-    <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
-    <skip />
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"Ifaka izinguquko zesimo sesithonjana"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Akwaziwa"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Susa"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Sesha"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index db1a75d..e9c62a7 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -124,7 +124,7 @@
     <item type="id" name="preview_image_id" />
 
 <!-- Popup items -->
-    <integer name="config_popupOpenCloseDuration">220</integer>
+    <integer name="config_popupOpenCloseDuration">150</integer>
     <integer name="config_popupArrowOpenDuration">80</integer>
     <integer name="config_removeNotificationViewDuration">300</integer>
 
@@ -140,4 +140,10 @@
     <item type="id" name="action_resize" />
     <item type="id" name="action_deep_shortcuts" />
     <item type="id" name="action_dismiss_notification" />
+
+<!-- QSB IDs. DO not change -->
+    <item type="id" name="search_container_workspace" />
+    <item type="id" name="search_container_hotseat" />
+    <item type="id" name="search_container_all_apps" />
+
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a4dff71..28af705 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -16,8 +16,8 @@
 
 <resources>
 <!-- Dynamic Grid -->
-    <dimen name="dynamic_grid_edge_margin">16dp</dimen>
-    <dimen name="dynamic_grid_page_indicator_size">32dp</dimen>
+    <dimen name="dynamic_grid_edge_margin">8dp</dimen>
+    <dimen name="dynamic_grid_min_page_indicator_size">32dp</dimen>
     <dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
     <dimen name="dynamic_grid_page_indicator_gutter_width">50dp</dimen>
     <dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
@@ -30,7 +30,7 @@
     <!-- Minimum space between workspace and hotseat in spring loaded mode -->
     <dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
 
-    <!-- dynamic_grid_edge_margin / 2 -->
+    <dimen name="dynamic_grid_cell_layout_padding">5.5dp</dimen>
     <dimen name="dynamic_grid_cell_padding_x">8dp</dimen>
 
     <!-- Hotseat -->
@@ -213,6 +213,7 @@
     <dimen name="notification_footer_height">32dp</dimen>
     <dimen name="notification_header_text_size">13sp</dimen>
     <dimen name="notification_header_count_text_size">12sp</dimen>
+    <dimen name="notification_main_title_size">16sp</dimen>
     <dimen name="notification_main_text_size">14sp</dimen>
     <dimen name="notification_icon_size">24dp</dimen>
     <dimen name="notification_footer_icon_size">18dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index da6da04..1197b1c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -59,11 +59,11 @@
 
     <!-- All Apps -->
     <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
-    <string name="all_apps_search_bar_hint">Search Apps</string>
+    <string name="all_apps_search_bar_hint">Search apps</string>
     <!-- Loading apps text. [CHAR_LIMIT=50] -->
-    <string name="all_apps_loading_message">Loading Apps&#8230;</string>
+    <string name="all_apps_loading_message">Loading apps&#8230;</string>
     <!-- No-search-results text. [CHAR_LIMIT=50] -->
-    <string name="all_apps_no_search_results">No Apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
+    <string name="all_apps_no_search_results">No apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
     <!-- Label for the button which allows the user to get app search results. [CHAR_LIMIT=50] -->
     <string name="all_apps_search_market_message">Search for more apps</string>
 
@@ -178,6 +178,12 @@
     <string name="icon_badging_desc_on">On</string>
     <!-- Text to indicate that the system icon badging setting is off [CHAR LIMIT=100] -->
     <string name="icon_badging_desc_off">Off</string>
+    <!-- Title for the dialog shown when the app does not has notification access, explaining the requirement for notification access [CHAR LIMIT=50] -->
+    <string name="title_missing_notification_access">Notification access needed</string>
+    <!-- Message explaining to the user that the notification access is required by the app for showing 'Notification dots' [CHAR LIMIT=NONE] -->
+    <string name="msg_missing_notification_access">To show Notification Dots, turn on app notifications for <xliff:g id="name" example="My App">%1$s</xliff:g></string>
+    <!-- Button text in the confirmation dialog which would take the user to the system settings [CHAR LIMIT=50] -->
+    <string name="title_change_settings">Change settings</string>
 
     <!-- Label for the setting that allows the automatic placement of launcher shortcuts for applications and games installed on the device [CHAR LIMIT=40] -->
     <string name="auto_add_shortcuts_label">Add icon to Home screen</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d11b002..5bdf512 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -25,7 +25,7 @@
         <item name="android:windowShowWallpaper">true</item>
         <item name="android:windowNoTitle">true</item>
         <item name="android:colorEdgeEffect">#FF757575</item>
-        <item name="android:keyboardLayout">@layout/all_apps_search_container</item>
+        <item name="android:keyboardLayout">@layout/search_container_all_apps</item>
     </style>
 
     <style name="BaseLauncherThemeWithCustomAttrs" parent="@style/BaseLauncherTheme">
@@ -140,6 +140,13 @@
     <style name="PopupItem">
         <item name="android:colorControlHighlight">?attr/popupColorTertiary</item>
     </style>
+    <style name="PopupGutter">
+        <item name="android:backgroundTintMode">multiply</item>
+        <item name="android:backgroundTint">?attr/popupColorSecondary</item>
+        <item name="android:background">@drawable/gutter_horizontal</item>
+        <item name="android:elevation">@dimen/notification_elevation</item>
+        <item name="android:outlineProvider">none</item>
+    </style>
 
     <!-- Drop targets -->
     <style name="DropTargetButtonBase">
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
index c76f118..28a35b8 100644
--- a/res/xml/launcher_preferences.xml
+++ b/res/xml/launcher_preferences.xml
@@ -16,17 +16,18 @@
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <Preference
+    <com.android.launcher3.views.ButtonPreference
         android:key="pref_icon_badging"
         android:title="@string/icon_badging_title"
-        android:persistent="false">
+        android:persistent="false"
+        android:widgetLayout="@layout/notification_pref_warning" >
         <intent android:action="android.settings.NOTIFICATION_SETTINGS">
             <!-- This extra highlights the "Allow icon badges" field in Notification settings -->
             <extra
                 android:name=":settings:fragment_args_key"
                 android:value="notification_badging" />
         </intent>
-    </Preference>
+    </com.android.launcher3.views.ButtonPreference>
 
     <SwitchPreference
         android:key="pref_add_icon_to_home"
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index 70be7da..b249c95 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -9,10 +9,13 @@
 import android.content.Intent;
 import android.database.Cursor;
 import android.os.Handler;
+import android.support.annotation.WorkerThread;
 import android.util.Log;
 
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.LoaderTask;
+import com.android.launcher3.provider.RestoreDbTask;
 import com.android.launcher3.util.ContentWriter;
 
 public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
@@ -22,6 +25,12 @@
     @Override
     public void onReceive(final Context context, Intent intent) {
         if (AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED.equals(intent.getAction())) {
+            int hostId = intent.getIntExtra(AppWidgetManager.EXTRA_HOST_ID, 0);
+            Log.d(TAG, "Widget ID map received for host:" + hostId);
+            if (hostId != LauncherAppWidgetHost.APPWIDGET_HOST_ID) {
+                return;
+            }
+
             final int[] oldIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS);
             final int[] newIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
             if (oldIds.length == newIds.length) {
@@ -30,7 +39,8 @@
                         .postAtFrontOfQueue(new Runnable() {
                             @Override
                             public void run() {
-                                restoreAppWidgetIds(context, asyncResult, oldIds, newIds);
+                                restoreAppWidgetIds(context, oldIds, newIds);
+                                asyncResult.finish();
                             }
                         });
             } else {
@@ -42,11 +52,26 @@
     /**
      * Updates the app widgets whose id has changed during the restore process.
      */
-    static void restoreAppWidgetIds(Context context, PendingResult asyncResult,
-            int[] oldWidgetIds, int[] newWidgetIds) {
+    @WorkerThread
+    static void restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
+        AppWidgetHost appWidgetHost = new LauncherAppWidgetHost(context);
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            Log.e(TAG, "Skipping widget ID remap as widgets not supported");
+            appWidgetHost.deleteHost();
+            return;
+        }
+        if (!RestoreDbTask.isPending(context)) {
+            // Someone has already gone through our DB once, probably LoaderTask. Skip any further
+            // modifications of the DB.
+            Log.e(TAG, "Skipping widget ID remap as DB already in use");
+            for (int widgetId : newWidgetIds) {
+                Log.d(TAG, "Deleting widgetId: " + widgetId);
+                appWidgetHost.deleteAppWidgetId(widgetId);
+            }
+            return;
+        }
         final ContentResolver cr = context.getContentResolver();
         final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
-        AppWidgetHost appWidgetHost = new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID);
 
         for (int i = 0; i < oldWidgetIds.length; i++) {
             Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
@@ -86,6 +111,5 @@
         if (app != null) {
             app.getModel().forceReload();
         }
-        asyncResult.finish();
     }
 }
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 2b59ede..e496495 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.Intent;
 import android.view.View.AccessibilityDelegate;
 
 import com.android.launcher3.logging.UserEventDispatcher;
@@ -63,4 +64,9 @@
         }
         return mSystemUiController;
     }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+    }
 }
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 6f2c897..aeb82b3 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -44,6 +44,7 @@
 import com.android.launcher3.IconCache.ItemInfoUpdateReceiver;
 import com.android.launcher3.badge.BadgeInfo;
 import com.android.launcher3.badge.BadgeRenderer;
+import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.folder.FolderIconPreviewVerifier;
 import com.android.launcher3.graphics.DrawableFactory;
 import com.android.launcher3.graphics.HolographicOutlineHelper;
@@ -438,6 +439,13 @@
         super.setTextColor(colors);
     }
 
+    public boolean shouldTextBeVisible() {
+        // Text should be visible everywhere but the hotseat.
+        Object tag = getParent() instanceof FolderIcon ? ((View) getParent()).getTag() : getTag();
+        ItemInfo info = tag instanceof ItemInfo ? (ItemInfo) tag : null;
+        return info == null || info.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+    }
+
     public void setTextVisibility(boolean visible) {
         if (visible) {
             super.setTextColor(mTextColor);
@@ -459,7 +467,8 @@
      * @param fadeIn Whether the text should fade in or fade out.
      */
     public ObjectAnimator createTextAlphaAnimator(boolean fadeIn) {
-        return ObjectAnimator.ofInt(this, TEXT_ALPHA_PROPERTY, fadeIn ? Color.alpha(mTextColor) : 0);
+        int toAlpha = shouldTextBeVisible() && fadeIn ? Color.alpha(mTextColor) : 0;
+        return ObjectAnimator.ofInt(this, TEXT_ALPHA_PROPERTY, toAlpha);
     }
 
     @Override
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index d99a30a..aac8005 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -606,7 +606,7 @@
         // Hotseat icons - remove text
         if (child instanceof BubbleTextView) {
             BubbleTextView bubbleChild = (BubbleTextView) child;
-            bubbleChild.setTextVisibility(mContainerType != HOTSEAT);
+            bubbleChild.setTextVisibility(bubbleChild.shouldTextBeVisible());
         }
 
         child.setScaleX(mChildScale);
@@ -860,10 +860,10 @@
         // Expand the background drawing bounds by the padding baked into the background drawable
         mBackground.getPadding(mTempRect);
         mBackground.setBounds(
-                left - mTempRect.left,
-                top - mTempRect.top,
-                right + mTempRect.right,
-                bottom + mTempRect.bottom);
+                left - mTempRect.left - getPaddingLeft(),
+                top - mTempRect.top - getPaddingTop(),
+                right + mTempRect.right + getPaddingRight(),
+                bottom + mTempRect.bottom + getPaddingBottom());
     }
 
     /**
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index dcfb268..031bfe1 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -63,6 +63,8 @@
      */
     private static final float MAX_HORIZONTAL_PADDING_PERCENT = 0.14f;
 
+    private static final float TALL_DEVICE_ASPECT_RATIO_THRESHOLD = 1.82f;
+
     // Overview mode
     private final int overviewModeMinIconZoneHeightPx;
     private final int overviewModeMaxIconZoneHeightPx;
@@ -71,7 +73,8 @@
     private final float overviewModeIconZoneRatio;
 
     // Workspace
-    private int desiredWorkspaceLeftRightMarginPx;
+    private final int desiredWorkspaceLeftRightMarginPx;
+    public final int cellLayoutPaddingLeftRightPx;
     public final int edgeMarginPx;
     public final Rect defaultWidgetPadding;
     private final int defaultPageSpacingPx;
@@ -80,7 +83,7 @@
     public final int workspaceSpringLoadedBottomSpace;
 
     // Page indicator
-    private final int pageIndicatorSizePx;
+    private int pageIndicatorSizePx;
     private final int pageIndicatorLandGutterPx;
     private final int pageIndicatorLandWorkspaceOffsetPx;
 
@@ -171,8 +174,11 @@
                 this.getClass().getName());
         defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
         edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
-        desiredWorkspaceLeftRightMarginPx = edgeMarginPx;
-        pageIndicatorSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_size);
+        desiredWorkspaceLeftRightMarginPx = isVerticalBarLayout() ? 0 : edgeMarginPx;
+        cellLayoutPaddingLeftRightPx =
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding);
+        pageIndicatorSizePx = res.getDimensionPixelSize(
+                R.dimen.dynamic_grid_min_page_indicator_size);
         pageIndicatorLandGutterPx = res.getDimensionPixelSize(
                 R.dimen.dynamic_grid_page_indicator_gutter_width);
         pageIndicatorLandWorkspaceOffsetPx =
@@ -228,8 +234,24 @@
             availableHeightPx = maxSize.y;
         }
 
-        // Calculate the remaining vars
+        // Calculate all of the remaining variables.
         updateAvailableDimensions(dm, res);
+
+        // Now that we have all of the variables calculated, we can tune certain sizes.
+        float aspectRatio = ((float) Math.max(availableWidthPx, availableHeightPx))
+                / Math.min(availableWidthPx, availableHeightPx);
+        boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
+        if (!isVerticalBarLayout() && isPhone && isTallDevice) {
+            // We increase the page indicator size when there is extra space.
+            // ie. For a display with a large aspect ratio, we can keep the icons on the workspace
+            // in portrait mode closer together by increasing the page indicator size.
+            // Note: This calculation was created after noticing a pattern in the design spec.
+            pageIndicatorSizePx = getCellSize().y - iconSizePx - iconDrawablePaddingPx;
+
+            // Recalculate the available dimensions using the new page indicator size.
+            updateAvailableDimensions(dm, res);
+        }
+
         computeAllAppsButtonSize(context);
 
         // This is done last, after iconSizePx is calculated above.
@@ -244,9 +266,7 @@
                 isLandscape);
 
         // Hide labels on the workspace.
-        profile.iconTextSizePx = 0;
-        profile.cellHeightPx = profile.iconSizePx + profile.iconDrawablePaddingPx
-                + Utilities.calculateTextHeight(profile.iconTextSizePx);
+        profile.adjustToHideWorkspaceLabels();
 
         // We use these scales to measure and layout the widgets using their full invariant profile
         // sizes and then draw them scaled and centered to fit in their multi-window mode cellspans.
@@ -270,6 +290,24 @@
     }
 
     /**
+     * Adjusts the profile so that the labels on the Workspace are hidden.
+     * It is important to call this method after the All Apps variables have been set.
+     */
+    private void adjustToHideWorkspaceLabels() {
+        iconTextSizePx = 0;
+        iconDrawablePaddingPx = 0;
+        cellHeightPx = iconSizePx;
+
+        // In normal cases, All Apps cell height should equal the Workspace cell height.
+        // Since we are removing labels from the Workspace, we need to manually compute the
+        // All Apps cell height.
+        allAppsCellHeightPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx
+                + Utilities.calculateTextHeight(allAppsIconTextSizePx)
+                // Top and bottom padding is equal to the drawable padding
+                + allAppsIconDrawablePaddingPx * 2;
+    }
+
+    /**
      * Determine the exact visual footprint of the all apps button, taking into account scaling
      * and internal padding of the drawable.
      */
@@ -307,8 +345,7 @@
 
         if (isVerticalBarLayout()) {
             // Always hide the Workspace text with vertical bar layout.
-            iconTextSizePx = 0;
-            allAppsCellHeightPx += Utilities.calculateTextHeight(allAppsIconTextSizePx);
+            adjustToHideWorkspaceLabels();
         }
 
         cellWidthPx = iconSizePx + iconDrawablePaddingPx;
@@ -344,7 +381,7 @@
         updateFolderCellSize(1f, dm, res);
 
         // Don't let the folder get too close to the edges of the screen.
-        int folderMargin = 4 * edgeMarginPx;
+        int folderMargin = edgeMarginPx;
 
         // Check if the icons fit within the available height.
         float usedHeight = folderCellHeightPx * inv.numFolderRows + folderBottomPanelSize;
@@ -412,7 +449,8 @@
         // Since we are only concerned with the overall padding, layout direction does
         // not matter.
         Point padding = getTotalWorkspacePadding();
-        result.x = calculateCellWidth(availableWidthPx - padding.x, inv.numColumns);
+        int cellPadding = cellLayoutPaddingLeftRightPx * 2;
+        result.x = calculateCellWidth(availableWidthPx - padding.x - cellPadding, inv.numColumns);
         result.y = calculateCellHeight(availableHeightPx - padding.y, inv.numRows);
         return result;
     }
@@ -484,8 +522,8 @@
             return new Rect(mInsets.left,
                     mInsets.top + dropTargetBarSizePx + edgeMarginPx,
                     mInsets.left + availableWidthPx,
-                    mInsets.top + availableHeightPx - hotseatBarHeightPx - pageIndicatorSizePx -
-                            edgeMarginPx);
+                    mInsets.top + availableHeightPx - hotseatBarHeightPx
+                            - pageIndicatorSizePx - edgeMarginPx);
         }
     }
 
@@ -548,7 +586,7 @@
         lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
         lp.width = searchBarBounds.x;
         lp.height = searchBarBounds.y;
-        lp.topMargin = mInsets.top + edgeMarginPx / 2;
+        lp.topMargin = mInsets.top + edgeMarginPx;
         searchBar.setLayoutParams(lp);
 
         // Layout the workspace
@@ -579,15 +617,18 @@
                     ? hotseatBarLeftNavBarRightPaddingPx
                     : hotseatBarRightNavBarRightPaddingPx;
 
-            hotseat.getLayout().setPadding(mInsets.left, mInsets.top, mInsets.right + paddingRight,
+            hotseat.getLayout().setPadding(mInsets.left + cellLayoutPaddingLeftRightPx,
+                    mInsets.top, mInsets.right + paddingRight + cellLayoutPaddingLeftRightPx,
                     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 + mInsets.bottom;
-            hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left,
-                    hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right,
+            hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left
+                            + cellLayoutPaddingLeftRightPx,
+                    hotseatBarTopPaddingPx,
+                    hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx,
                     hotseatBarBottomPaddingPx + mInsets.bottom);
         } else {
             // For phones, layout the hotseat without any bottom margin
@@ -595,8 +636,10 @@
             lp.gravity = Gravity.BOTTOM;
             lp.width = LayoutParams.MATCH_PARENT;
             lp.height = hotseatBarHeightPx + mInsets.bottom;
-            hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left,
-                    hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right,
+            hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left
+                            + cellLayoutPaddingLeftRightPx,
+                    hotseatBarTopPaddingPx,
+                    hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx,
                     hotseatBarBottomPaddingPx + mInsets.bottom);
         }
         hotseat.setLayoutParams(lp);
@@ -636,7 +679,7 @@
 
         // Layout the AllAppsRecyclerView
         View view = launcher.findViewById(R.id.apps_list_view);
-        int paddingLeftRight = hasVerticalBarLayout ? 0 : edgeMarginPx;
+        int paddingLeftRight = desiredWorkspaceLeftRightMarginPx + cellLayoutPaddingLeftRightPx;
         view.setPadding(paddingLeftRight, view.getPaddingTop(), paddingLeftRight,
                 view.getPaddingBottom());
 
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index a51ddd4..3cbc989 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -23,7 +23,6 @@
 import android.view.View;
 import android.view.ViewPropertyAnimator;
 import android.view.ViewTreeObserver;
-
 import com.android.launcher3.util.Thunk;
 
 /*
@@ -33,10 +32,11 @@
  */
 public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
     implements ValueAnimator.AnimatorUpdateListener {
+    private static final String TAG = "FirstFrameAnimatorHlpr";
     private static final boolean DEBUG = false;
     private static final int MAX_DELAY = 1000;
     private static final int IDEAL_FRAME_DURATION = 16;
-    private View mTarget;
+    private final View mTarget;
     private long mStartFrame;
     private long mStartTime = -1;
     private boolean mHandlingOnAnimationUpdate;
@@ -77,7 +77,7 @@
                     sGlobalFrameCounter++;
                     if (DEBUG) {
                         long newTime = System.currentTimeMillis();
-                        Log.d("FirstFrameAnimatorHelper", "TICK " + (newTime - mTime));
+                        Log.d(TAG, "TICK " + (newTime - mTime));
                         mTime = newTime;
                     }
                 }
@@ -139,7 +139,7 @@
 
     public void print(ValueAnimator animation) {
         float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
-        Log.d("FirstFrameAnimatorHelper", sGlobalFrameCounter +
+        Log.d(TAG, sGlobalFrameCounter +
               "(" + (sGlobalFrameCounter - mStartFrame) + ") " + mTarget + " dirty? " +
               mTarget.isDirty() + " " + flatFraction + " " + this + " " + animation);
     }
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 383e6ef..3bcd7af 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -41,7 +41,6 @@
 import android.support.annotation.NonNull;
 import android.text.TextUtils;
 import android.util.Log;
-
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
@@ -52,7 +51,6 @@
 import com.android.launcher3.util.Provider;
 import com.android.launcher3.util.SQLiteCacheHelper;
 import com.android.launcher3.util.Thunk;
-
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -70,7 +68,7 @@
     private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
 
     // Empty class name is used for storing package default entry.
-    private static final String EMPTY_CLASS_NAME = ".";
+    public static final String EMPTY_CLASS_NAME = ".";
 
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_IGNORE_CACHE = false;
@@ -91,7 +89,7 @@
 
     private final Context mContext;
     private final PackageManager mPackageManager;
-    private IconProvider mIconProvider;
+    private final IconProvider mIconProvider;
     @Thunk final UserManagerCompat mUserManager;
     private final LauncherAppsCompat mLauncherApps;
     private final HashMap<ComponentKey, CacheEntry> mCache =
@@ -122,7 +120,8 @@
     }
 
     private Drawable getFullResDefaultActivityIcon() {
-        return getFullResIcon(Resources.getSystem(), android.R.mipmap.sym_def_app_icon);
+        return getFullResIcon(Resources.getSystem(), Utilities.isAtLeastO() ?
+                android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon);
     }
 
     private Drawable getFullResIcon(Resources resources, int iconId) {
@@ -193,7 +192,7 @@
      * Remove any records for the supplied package name from memory.
      */
     private void removeFromMemCacheLocked(String packageName, UserHandle user) {
-        HashSet<ComponentKey> forDeletion = new HashSet<ComponentKey>();
+        HashSet<ComponentKey> forDeletion = new HashSet<>();
         for (ComponentKey key: mCache.keySet()) {
             if (key.componentName.getPackageName().equals(packageName)
                     && key.user.equals(user)) {
@@ -219,7 +218,6 @@
             }
         } catch (NameNotFoundException e) {
             Log.d(TAG, "Package not found", e);
-            return;
         }
     }
 
@@ -264,7 +262,7 @@
             Set<String> ignorePackages) {
         long userSerial = mUserManager.getSerialNumberForUser(user);
         PackageManager pm = mContext.getPackageManager();
-        HashMap<String, PackageInfo> pkgInfoMap = new HashMap<String, PackageInfo>();
+        HashMap<String, PackageInfo> pkgInfoMap = new HashMap<>();
         for (PackageInfo info : pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) {
             pkgInfoMap.put(info.packageName, info);
         }
@@ -274,7 +272,7 @@
             componentMap.put(app.getComponentName(), app);
         }
 
-        HashSet<Integer> itemsToRemove = new HashSet<Integer>();
+        HashSet<Integer> itemsToRemove = new HashSet<>();
         Stack<LauncherActivityInfo> appsToUpdate = new Stack<>();
 
         Cursor c = null;
@@ -704,7 +702,7 @@
         private final HashMap<String, PackageInfo> mPkgInfoMap;
         private final Stack<LauncherActivityInfo> mAppsToAdd;
         private final Stack<LauncherActivityInfo> mAppsToUpdate;
-        private final HashSet<String> mUpdatedPackages = new HashSet<String>();
+        private final HashSet<String> mUpdatedPackages = new HashSet<>();
 
         @Thunk SerializedIconUpdateTask(long userSerial, HashMap<String, PackageInfo> pkgInfoMap,
                 Stack<LauncherActivityInfo> appsToAdd,
@@ -753,7 +751,7 @@
     }
 
     private static final class IconDB extends SQLiteCacheHelper {
-        private final static int DB_VERSION = 16;
+        private final static int DB_VERSION = 17;
 
         private final static int RELEASE_VERSION = DB_VERSION +
                 (FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ? 0 : 1);
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 11c5309..c5be096 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -137,7 +137,18 @@
     }
 
     public ComponentName getTargetComponent() {
-        return getIntent() == null ? null : getIntent().getComponent();
+        Intent intent = getIntent();
+        if (intent == null) {
+            return null;
+        }
+        ComponentName cn = intent.getComponent();
+        if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT && cn == null) {
+            // Legacy shortcuts may not have a componentName but just a packageName. In that case
+            // create a dummy componentName instead of adding additional check everywhere.
+            String pkg = intent.getPackage();
+            return pkg == null ? null : new ComponentName(pkg, IconCache.EMPTY_CLASS_NAME);
+        }
+        return cn;
     }
 
     public void writeToValues(ContentWriter writer) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 26c5c9d..4b31486 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -209,10 +209,8 @@
 
     private boolean mIsSafeModeEnabled;
 
-    public static final int APPWIDGET_HOST_ID = 1024;
     public static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 500;
     private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
-    private static final int ACTIVITY_START_DELAY = 1000;
 
     // How long to wait before the new-shortcut animation automatically pans the workspace
     private static final int NEW_APPS_PAGE_MOVE_DELAY = 500;
@@ -274,6 +272,7 @@
     private boolean mHasFocus = false;
 
     private ObjectAnimator mScrimAnimator;
+    private boolean mShouldFadeInScrim;
 
     private PopupDataProvider mPopupDataProvider;
 
@@ -396,7 +395,10 @@
 
         mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
 
-        mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
+        mAppWidgetHost = new LauncherAppWidgetHost(this);
+        if (Utilities.ATLEAST_MARSHMALLOW) {
+            mAppWidgetHost.addProviderChangeListener(this);
+        }
         mAppWidgetHost.startListening();
 
         // If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,
@@ -467,8 +469,12 @@
             mLauncherCallbacks.onCreate(savedInstanceState);
         }
 
-        // Listen for broadcasts screen off
-        registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
+        // Listen for broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(Intent.ACTION_USER_PRESENT); // When the device wakes up + keyguard is gone
+        registerReceiver(mReceiver, filter);
+        mShouldFadeInScrim = true;
 
         getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
                 Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
@@ -488,7 +494,7 @@
     }
 
     @Override
-    public View findViewById(int id) {
+    public <T extends View> T findViewById(int id) {
         return mLauncherView.findViewById(id);
     }
 
@@ -783,7 +789,7 @@
     }
 
     @Override
-    protected void onActivityResult(
+    public void onActivityResult(
             final int requestCode, final int resultCode, final Intent data) {
         handleActivityResult(requestCode, resultCode, data);
         if (mLauncherCallbacks != null) {
@@ -906,7 +912,7 @@
             NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
         }
 
-        if (mIsResumeFromActionScreenOff && mDragLayer.getBackground() != null) {
+        if (mShouldFadeInScrim && mDragLayer.getBackground() != null) {
             if (mScrimAnimator != null) {
                 mScrimAnimator.cancel();
             }
@@ -923,6 +929,7 @@
             mScrimAnimator.setStartDelay(getWindow().getTransitionBackgroundFadeDuration());
             mScrimAnimator.start();
         }
+        mShouldFadeInScrim = false;
     }
 
     @Override
@@ -1458,23 +1465,25 @@
             mWorkspace.addInScreen(view, info);
         } else {
             // Adding a shortcut to a Folder.
-            final long folderIconId = container;
-            FolderIcon folderIcon = (FolderIcon) mWorkspace.getFirstMatch(new ItemOperator() {
-                @Override
-                public boolean evaluate(ItemInfo info, View view) {
-                    return info != null && info.id == folderIconId;
-                }
-            });
-
+            FolderIcon folderIcon = findFolderIcon(container);
             if (folderIcon != null) {
                 FolderInfo folderInfo = (FolderInfo) folderIcon.getTag();
                 folderInfo.add(info, args.rank, false);
             } else {
-                Log.e(TAG, "Could not find folder with id " + folderIconId + " to add shortcut.");
+                Log.e(TAG, "Could not find folder with id " + container + " to add shortcut.");
             }
         }
     }
 
+    public FolderIcon findFolderIcon(final long folderIconId) {
+        return (FolderIcon) mWorkspace.getFirstMatch(new ItemOperator() {
+            @Override
+            public boolean evaluate(ItemInfo info, View view) {
+                return info != null && info.id == folderIconId;
+            }
+        });
+    }
+
     /**
      * Add a widget to the workspace.
      *
@@ -1534,6 +1543,11 @@
                     }
                 }
                 mIsResumeFromActionScreenOff = true;
+                mShouldFadeInScrim = true;
+            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
+                // ACTION_USER_PRESENT is sent after onStart/onResume. This covers the case where
+                // the user unlocked and the Launcher is not in the foreground.
+                mShouldFadeInScrim = false;
             }
         }
     };
@@ -2257,7 +2271,7 @@
                 onClickFolderIcon(v);
             }
         } else if ((FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && v instanceof PageIndicator) ||
-                (v == mAllAppsButton && mAllAppsButton != null)) {
+            (v == mAllAppsButton && mAllAppsButton != null)) {
             onClickAllAppsButton(v);
         } else if (tag instanceof AppInfo) {
             startAppShortcutOrInfoActivity(v);
@@ -2308,8 +2322,9 @@
     }
 
     /**
-     * Event handler for the "grid" button that appears on the home screen, which
-     * enters all apps mode.
+     * Event handler for the "grid" button or "caret" that appears on the home screen, which
+     * enters all apps mode. In verticalBarLayout the caret can be seen when all apps is open, and
+     * so in that case reverses the action.
      *
      * @param v The view that was clicked.
      */
@@ -2319,6 +2334,8 @@
             getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
                     ControlType.ALL_APPS_BUTTON);
             showAppsView(true /* animated */, true /* updatePredictedApps */);
+        } else {
+            showWorkspace(true);
         }
     }
 
@@ -3046,7 +3063,6 @@
             List<ComponentKey> apps = mLauncherCallbacks.getPredictedApps();
             if (apps != null) {
                 mAppsView.setPredictedApps(apps);
-                getUserEventDispatcher().setPredictedApps(apps);
             }
         }
     }
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 6e8c59b..5573c5c 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -16,12 +16,20 @@
 
 package com.android.launcher3;
 
+import android.app.Activity;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
+import android.content.ActivityNotFoundException;
 import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
 import android.util.SparseArray;
 import android.view.LayoutInflater;
+import android.widget.Toast;
+
+import com.android.launcher3.config.FeatureFlags;
 
 import java.util.ArrayList;
 
@@ -33,14 +41,16 @@
  */
 public class LauncherAppWidgetHost extends AppWidgetHost {
 
-    private final ArrayList<Runnable> mProviderChangeListeners = new ArrayList<Runnable>();
+    public static final int APPWIDGET_HOST_ID = 1024;
+
+    private final ArrayList<ProviderChangedListener> mProviderChangeListeners = new ArrayList<>();
     private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
 
-    private Launcher mLauncher;
+    private final Context mContext;
 
-    public LauncherAppWidgetHost(Launcher launcher, int hostId) {
-        super(launcher, hostId);
-        mLauncher = launcher;
+    public LauncherAppWidgetHost(Context context) {
+        super(context, APPWIDGET_HOST_ID);
+        mContext = context;
     }
 
     @Override
@@ -53,6 +63,10 @@
 
     @Override
     public void startListening() {
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            return;
+        }
+
         try {
             super.startListening();
         } catch (Exception e) {
@@ -66,24 +80,38 @@
         }
     }
 
-    public void addProviderChangeListener(Runnable callback) {
+    @Override
+    public void stopListening() {
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            return;
+        }
+
+        super.stopListening();
+    }
+
+    @Override
+    public int allocateAppWidgetId() {
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            return AppWidgetManager.INVALID_APPWIDGET_ID;
+        }
+
+        return super.allocateAppWidgetId();
+    }
+
+    public void addProviderChangeListener(ProviderChangedListener callback) {
         mProviderChangeListeners.add(callback);
     }
 
-    public void removeProviderChangeListener(Runnable callback) {
+    public void removeProviderChangeListener(ProviderChangedListener callback) {
         mProviderChangeListeners.remove(callback);
     }
 
     protected void onProvidersChanged() {
         if (!mProviderChangeListeners.isEmpty()) {
-            for (Runnable callback : new ArrayList<>(mProviderChangeListeners)) {
-                callback.run();
+            for (ProviderChangedListener callback : new ArrayList<>(mProviderChangeListeners)) {
+                callback.notifyWidgetProvidersChanged();
             }
         }
-
-        if (Utilities.ATLEAST_MARSHMALLOW) {
-            mLauncher.notifyWidgetProvidersChanged();
-        }
     }
 
     public AppWidgetHostView createView(Context context, int appWidgetId,
@@ -109,7 +137,7 @@
                 // will update.
                 LauncherAppWidgetHostView view = mViews.get(appWidgetId);
                 if (view == null) {
-                    view = onCreateView(mLauncher, appWidgetId, appWidget);
+                    view = onCreateView(mContext, appWidgetId, appWidget);
                 }
                 view.setAppWidget(appWidgetId, appWidget);
                 view.switchToErrorView();
@@ -124,11 +152,11 @@
     @Override
     protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
         LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo.fromProviderInfo(
-                mLauncher, appWidget);
+                mContext, appWidget);
         super.onProviderChanged(appWidgetId, info);
         // The super method updates the dimensions of the providerInfo. Update the
         // launcher spans accordingly.
-        info.initSpans(mLauncher);
+        info.initSpans(mContext);
     }
 
     @Override
@@ -142,4 +170,53 @@
         super.clearViews();
         mViews.clear();
     }
+
+    public void startBindFlow(BaseActivity activity,
+            int appWidgetId, AppWidgetProviderInfo info, int requestCode) {
+
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            sendActionCancelled(activity, requestCode);
+            return;
+        }
+
+        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND)
+                .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
+                .putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.provider)
+                .putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE, info.getProfile());
+        // TODO: we need to make sure that this accounts for the options bundle.
+        // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
+        activity.startActivityForResult(intent, requestCode);
+    }
+
+
+    public void startConfigActivity(BaseActivity activity, int widgetId, int requestCode) {
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            sendActionCancelled(activity, requestCode);
+            return;
+        }
+
+        try {
+            startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, null);
+        } catch (ActivityNotFoundException | SecurityException e) {
+            Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+            sendActionCancelled(activity, requestCode);
+        }
+    }
+
+    private void sendActionCancelled(final BaseActivity activity, final int requestCode) {
+        new Handler().post(new Runnable() {
+            @Override
+            public void run() {
+                activity.onActivityResult(requestCode, Activity.RESULT_CANCELED, null);
+            }
+        });
+    }
+
+    /**
+     * Listener for getting notifications on provider changes.
+     */
+    public interface ProviderChangedListener {
+
+        void notifyWidgetProvidersChanged();
+    }
 }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 82bee0e..f1638fd 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -133,7 +133,7 @@
         }
     };
 
-    public interface Callbacks {
+    public interface Callbacks extends LauncherAppWidgetHost.ProviderChangedListener {
         public boolean setLoadOnResume();
         public int getCurrentWorkspaceScreen();
         public void clearPendingBinds();
@@ -159,7 +159,6 @@
                 HashSet<String> packageNames, HashSet<ComponentName> components,
                 UserHandle user);
         public void bindAppInfosRemoved(ArrayList<AppInfo> appInfos);
-        public void notifyWidgetProvidersChanged();
         public void bindAllWidgets(MultiHashMap<PackageItemInfo, WidgetItem> widgets);
         public void onPageBoundSynchronously(int page);
         public void executeOnNextDraw(ViewOnDrawExecutor executor);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 4813571..dc83f36 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -1031,7 +1031,7 @@
         }
 
         public AppWidgetHost newLauncherWidgetHost() {
-            return new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID);
+            return new LauncherAppWidgetHost(mContext);
         }
 
         @Override
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index e7349f0..44b9704 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -387,7 +387,6 @@
     private void startAnimationToWorkspaceFromAllApps(final Workspace.State fromWorkspaceState,
             final Workspace.State toWorkspaceState, final boolean animated, int type,
             final Runnable onCompleteRunnable) {
-        final AllAppsContainerView appsView = mLauncher.getAppsView();
         // No alpha anim from all apps
         PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks(1f) {
             @Override
@@ -417,12 +416,11 @@
             @Override
             void onTransitionComplete() {
                 mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
-                appsView.reset();
             }
         };
         // Only animate the search bar if animating to spring loaded mode from all apps
         startAnimationToWorkspaceFromOverlay(fromWorkspaceState, toWorkspaceState,
-                mLauncher.getStartViewForAllAppsRevealAnimation(), appsView,
+                mLauncher.getStartViewForAllAppsRevealAnimation(), mLauncher.getAppsView(),
                 animated, type, onCompleteRunnable, cb);
     }
 
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 255677a..87f3dda 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -24,7 +24,6 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -49,7 +48,7 @@
 
 import com.android.launcher3.anim.PropertyListBuilder;
 import com.android.launcher3.pageindicators.PageIndicator;
-import com.android.launcher3.util.LauncherEdgeEffect;
+import com.android.launcher3.touch.OverScroll;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.Thunk;
 
@@ -70,6 +69,9 @@
     public static final int PAGE_SNAP_ANIMATION_DURATION = 750;
     protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
 
+    // OverScroll constants
+    private final static int OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION = 270;
+
     private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
     // The page is moved more than halfway, automatically move to the next page on touch up.
     private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f;
@@ -145,6 +147,13 @@
 
     protected boolean mWasInOverscroll = false;
 
+    // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise
+    // it is equal to the scaled overscroll position. We use a separate value so as to prevent
+    // the screens from continuing to translate beyond the normal bounds.
+    protected int mOverScrollX;
+
+    protected int mUnboundedScrollX;
+
     // Page Indicator
     @Thunk int mPageIndicatorViewId;
     protected PageIndicator mPageIndicator;
@@ -178,16 +187,11 @@
     // Convenience/caching
     private static final Matrix sTmpInvMatrix = new Matrix();
     private static final float[] sTmpPoint = new float[2];
-    private static final int[] sTmpIntPoint = new int[2];
     private static final Rect sTmpRect = new Rect();
 
     protected final Rect mInsets = new Rect();
     protected final boolean mIsRtl;
 
-    // Edge effect
-    private final LauncherEdgeEffect mEdgeGlowLeft = new LauncherEdgeEffect();
-    private final LauncherEdgeEffect mEdgeGlowRight = new LauncherEdgeEffect();
-
     public PagedView(Context context) {
         this(context, null);
     }
@@ -227,10 +231,6 @@
         mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * density);
         setOnHierarchyChangeListener(this);
         setWillNotDraw(false);
-
-        int edgeEffectColor = Themes.getAttrColor(getContext(), android.R.attr.colorEdgeEffect);
-        mEdgeGlowLeft.setColor(edgeEffectColor);
-        mEdgeGlowRight.setColor(edgeEffectColor);
     }
 
     protected void setDefaultInterpolator(Interpolator interpolator) {
@@ -404,9 +404,10 @@
         if (getChildCount() == 0) {
             return;
         }
+        int prevPage = mCurrentPage;
         mCurrentPage = validateNewPage(currentPage);
         updateCurrentPageScroll();
-        notifyPageSwitchListener();
+        notifyPageSwitchListener(prevPage);
         invalidate();
     }
 
@@ -414,7 +415,7 @@
      * Should be called whenever the page changes. In the case of a scroll, we wait until the page
      * has settled.
      */
-    protected void notifyPageSwitchListener() {
+    protected void notifyPageSwitchListener(int prevPage) {
         updatePageIndicator();
     }
 
@@ -476,7 +477,7 @@
     }
 
     protected int getUnboundedScrollX() {
-        return getScrollX();
+        return mUnboundedScrollX;
     }
 
     @Override
@@ -499,6 +500,8 @@
             x = Math.max(x, mFreeScrollMinScrollX);
         }
 
+        mUnboundedScrollX = x;
+
         boolean isXBeforeFirstPage = mIsRtl ? (x > mMaxScrollX) : (x < 0);
         boolean isXAfterLastPage = mIsRtl ? (x < 0) : (x > mMaxScrollX);
         if (isXBeforeFirstPage) {
@@ -526,6 +529,7 @@
                 overScroll(0);
                 mWasInOverscroll = false;
             }
+            mOverScrollX = x;
             super.scrollTo(x, y);
         }
 
@@ -565,7 +569,8 @@
         if (mScroller.computeScrollOffset()) {
             // Don't bother scrolling if the page does not need to be moved
             if (getUnboundedScrollX() != mScroller.getCurrX()
-                    || getScrollY() != mScroller.getCurrY()) {
+                    || getScrollY() != mScroller.getCurrY()
+                    || mOverScrollX != mScroller.getCurrX()) {
                 float scaleX = mFreeScroll ? getScaleX() : 1f;
                 int scrollX = (int) (mScroller.getCurrX() * (1 / scaleX));
                 scrollTo(scrollX, mScroller.getCurrY());
@@ -577,9 +582,10 @@
         } else if (mNextPage != INVALID_PAGE && shouldInvalidate) {
             sendScrollAccessibilityEvent();
 
+            int prevPage = mCurrentPage;
             mCurrentPage = validateNewPage(mNextPage);
             mNextPage = INVALID_PAGE;
-            notifyPageSwitchListener();
+            notifyPageSwitchListener(prevPage);
 
             // We don't want to trigger a page end moving unless the page has settled
             // and the user has stopped scrolling
@@ -916,6 +922,7 @@
     @Override
     public void onChildViewRemoved(View parent, View child) {
         updateFreescrollBounds();
+        mCurrentPage = validateNewPage(mCurrentPage);
         invalidate();
     }
 
@@ -973,47 +980,6 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
-        if (getPageCount() > 0) {
-            if (!mEdgeGlowLeft.isFinished()) {
-                final int restoreCount = canvas.save();
-                Rect display = mViewport;
-                canvas.translate(display.left, display.top);
-                canvas.rotate(270);
-
-                getEdgeVerticalPosition(sTmpIntPoint);
-                canvas.translate(display.top - sTmpIntPoint[1], 0);
-                mEdgeGlowLeft.setSize(sTmpIntPoint[1] - sTmpIntPoint[0], display.width());
-                if (mEdgeGlowLeft.draw(canvas)) {
-                    postInvalidateOnAnimation();
-                }
-                canvas.restoreToCount(restoreCount);
-            }
-            if (!mEdgeGlowRight.isFinished()) {
-                final int restoreCount = canvas.save();
-                Rect display = mViewport;
-                canvas.translate(display.left + mPageScrolls[mIsRtl ? 0 : (getPageCount() - 1)], display.top);
-                canvas.rotate(90);
-
-                getEdgeVerticalPosition(sTmpIntPoint);
-
-                canvas.translate(sTmpIntPoint[0] - display.top, -display.width());
-                mEdgeGlowRight.setSize(sTmpIntPoint[1] - sTmpIntPoint[0], display.width());
-                if (mEdgeGlowRight.draw(canvas)) {
-                    postInvalidateOnAnimation();
-                }
-                canvas.restoreToCount(restoreCount);
-            }
-        }
-    }
-
-    /**
-     * Returns the top and bottom position for the edge effect.
-     */
-    protected abstract void getEdgeVerticalPosition(int[] pos);
-
-    @Override
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
         int page = indexToPage(indexOfChild(child));
         if (page != mCurrentPage || !mScroller.isFinished()) {
@@ -1355,14 +1321,15 @@
     }
 
     protected void dampedOverScroll(float amount) {
-        int screenSize = getViewportWidth();
-        float f = (amount / screenSize);
-        if (f < 0) {
-            mEdgeGlowLeft.onPull(-f);
-        } else if (f > 0) {
-            mEdgeGlowRight.onPull(f);
+        if (Float.compare(amount, 0f) == 0) return;
+
+        int overScrollAmount = OverScroll.dampedScroll(amount, getViewportWidth());
+        if (amount < 0) {
+            mOverScrollX = overScrollAmount;
+            super.scrollTo(mOverScrollX, getScrollY());
         } else {
-            return;
+            mOverScrollX = mMaxScrollX + overScrollAmount;
+            super.scrollTo(mOverScrollX, getScrollY());
         }
         invalidate();
     }
@@ -1715,8 +1682,6 @@
         mCancelTap = false;
         mTouchState = TOUCH_STATE_REST;
         mActivePointerId = INVALID_POINTER;
-        mEdgeGlowLeft.onRelease();
-        mEdgeGlowRight.onRelease();
     }
 
     /**
@@ -1830,7 +1795,18 @@
     }
 
     protected void snapToDestination() {
-        snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
+        snapToPage(getPageNearestToCenterOfScreen(), getPageSnapDuration());
+    }
+
+    protected boolean isInOverScroll() {
+        return (mOverScrollX > mMaxScrollX || mOverScrollX < 0);
+    }
+
+    protected int getPageSnapDuration() {
+        if (isInOverScroll()) {
+            return OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION;
+        }
+        return PAGE_SNAP_ANIMATION_DURATION;
     }
 
     public static class ScrollInterpolator implements Interpolator {
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index b7b75f8..d5d5eab 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -17,7 +17,15 @@
 package com.android.launcher3;
 
 import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.ComponentName;
 import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
 import android.database.ContentObserver;
 import android.os.Bundle;
 import android.os.Handler;
@@ -26,8 +34,11 @@
 import android.preference.PreferenceFragment;
 import android.provider.Settings;
 import android.provider.Settings.System;
+import android.view.View;
 
 import com.android.launcher3.graphics.IconShapeOverride;
+import com.android.launcher3.notification.NotificationListener;
+import com.android.launcher3.views.ButtonPreference;
 
 /**
  * Settings activity for Launcher. Currently implements the following setting: Allow rotation
@@ -37,15 +48,19 @@
     private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
     // TODO: use Settings.Secure.NOTIFICATION_BADGING
     private static final String NOTIFICATION_BADGING = "notification_badging";
+    /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
+    private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        // Display the fragment as the main content.
-        getFragmentManager().beginTransaction()
-                .replace(android.R.id.content, new LauncherSettingsFragment())
-                .commit();
+        if (savedInstanceState == null) {
+            // Display the fragment as the main content.
+            getFragmentManager().beginTransaction()
+                    .replace(android.R.id.content, new LauncherSettingsFragment())
+                    .commit();
+        }
     }
 
     /**
@@ -83,17 +98,22 @@
                 rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity()));
             }
 
-            Preference iconBadgingPref = findPreference(ICON_BADGING_PREFERENCE_KEY);
+            ButtonPreference iconBadgingPref =
+                    (ButtonPreference) findPreference(ICON_BADGING_PREFERENCE_KEY);
             if (!Utilities.isAtLeastO()) {
                 getPreferenceScreen().removePreference(
                         findPreference(SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY));
                 getPreferenceScreen().removePreference(iconBadgingPref);
             } else {
                 // Listen to system notification badge settings while this UI is active.
-                mIconBadgingObserver = new IconBadgingObserver(iconBadgingPref, resolver);
+                mIconBadgingObserver = new IconBadgingObserver(
+                        iconBadgingPref, resolver, getFragmentManager());
                 resolver.registerContentObserver(
                         Settings.Secure.getUriFor(NOTIFICATION_BADGING),
                         false, mIconBadgingObserver);
+                resolver.registerContentObserver(
+                        Settings.Secure.getUriFor(NOTIFICATION_ENABLED_LISTENERS),
+                        false, mIconBadgingObserver);
                 mIconBadgingObserver.onChange(true);
             }
 
@@ -151,24 +171,74 @@
      * Content observer which listens for system badging setting changes,
      * and updates the launcher badging setting subtext accordingly.
      */
-    private static class IconBadgingObserver extends ContentObserver {
+    private static class IconBadgingObserver extends ContentObserver
+            implements View.OnClickListener {
 
-        private final Preference mBadgingPref;
+        private final ButtonPreference mBadgingPref;
         private final ContentResolver mResolver;
+        private final FragmentManager mFragmentManager;
 
-        public IconBadgingObserver(Preference badgingPref, ContentResolver resolver) {
+        public IconBadgingObserver(ButtonPreference badgingPref, ContentResolver resolver,
+                FragmentManager fragmentManager) {
             super(new Handler());
             mBadgingPref = badgingPref;
             mResolver = resolver;
+            mFragmentManager = fragmentManager;
         }
 
         @Override
         public void onChange(boolean selfChange) {
             boolean enabled = Settings.Secure.getInt(mResolver, NOTIFICATION_BADGING, 1) == 1;
-            mBadgingPref.setSummary(enabled
-                    ? R.string.icon_badging_desc_on
-                    : R.string.icon_badging_desc_off);
+            int summary = enabled ? R.string.icon_badging_desc_on : R.string.icon_badging_desc_off;
+
+            boolean serviceEnabled = true;
+            if (enabled) {
+                // Check if the listener is enabled or not.
+                String enabledListeners =
+                        Settings.Secure.getString(mResolver, NOTIFICATION_ENABLED_LISTENERS);
+                ComponentName myListener =
+                        new ComponentName(mBadgingPref.getContext(), NotificationListener.class);
+                serviceEnabled = enabledListeners != null &&
+                        (enabledListeners.contains(myListener.flattenToString()) ||
+                                enabledListeners.contains(myListener.flattenToShortString()));
+                if (!serviceEnabled) {
+                    summary = R.string.title_missing_notification_access;
+                }
+            }
+            mBadgingPref.setButtonOnClickListener(serviceEnabled ? null : this);
+            mBadgingPref.setSummary(summary);
+
+        }
+
+        @Override
+        public void onClick(View view) {
+            new NotificationAccessConfirmation().show(mFragmentManager, "notification_access");
         }
     }
 
+    public static class NotificationAccessConfirmation
+            extends DialogFragment implements DialogInterface.OnClickListener {
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            final Context context = getActivity();
+            String msg = context.getString(R.string.msg_missing_notification_access,
+                    context.getString(R.string.derived_app_name));
+            return new AlertDialog.Builder(context)
+                    .setTitle(R.string.title_missing_notification_access)
+                    .setMessage(msg)
+                    .setNegativeButton(android.R.string.cancel, null)
+                    .setPositiveButton(R.string.title_change_settings, this)
+                    .create();
+        }
+
+        @Override
+        public void onClick(DialogInterface dialogInterface, int i) {
+            ComponentName cn = new ComponentName(getActivity(), NotificationListener.class);
+            Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)
+                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                    .putExtra(":settings:fragment_args_key", cn.flattenToString());
+            getActivity().startActivity(intent);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 9100fe2..3aa2db0 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -28,7 +28,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
@@ -654,27 +653,4 @@
         return hashSet;
     }
 
-    /**
-     * @return creates a new alpha mask bitmap out of an existing bitmap
-     */
-    public static Bitmap convertToAlphaMask(Bitmap b, int applyAlpha) {
-        Bitmap a = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ALPHA_8);
-        Canvas c = new Canvas(a);
-        Paint paint = new Paint();
-        paint.setAlpha(applyAlpha);
-        c.drawBitmap(b, 0f, 0f, paint);
-        return a;
-    }
-
-    /**
-     * @return a new white 1x1 bitmap with ALPHA_8
-     */
-    public static Bitmap createOnePixBitmap() {
-        Bitmap a = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
-        Canvas c = new Canvas(a);
-        Paint paint = new Paint();
-        paint.setColor(Color.WHITE);
-        c.drawPaint(paint);
-        return a;
-    }
 }
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index ad1be7e..a65ea9b 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -111,7 +111,7 @@
      * sizes (landscape vs portrait).
      */
     private static class CacheDb extends SQLiteCacheHelper {
-        private static final int DB_VERSION = 8;
+        private static final int DB_VERSION = 9;
 
         private static final String TABLE_NAME = "shortcut_and_widget_previews";
         private static final String COLUMN_COMPONENT = "componentName";
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 767e332..a2270d6 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -52,8 +52,10 @@
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.widget.Toast;
+
 import com.android.launcher3.Launcher.CustomContentCallbacks;
 import com.android.launcher3.Launcher.LauncherOverlay;
+import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
 import com.android.launcher3.UninstallDropTarget.DropTargetSource;
 import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
 import com.android.launcher3.accessibility.OverviewAccessibilityDelegate;
@@ -75,6 +77,7 @@
 import com.android.launcher3.graphics.PreloadIconDrawable;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.ItemInfoMatcher;
@@ -85,6 +88,7 @@
 import com.android.launcher3.util.WallpaperOffsetInterpolator;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
@@ -300,8 +304,8 @@
     boolean mScrollInteractionBegan;
     boolean mStartedSendingScrollEvents;
     float mLastOverlayScroll = 0;
-    // Total over scrollX in the overlay direction.
-    private int mUnboundedScrollX;
+    boolean mOverlayShown = false;
+
     private boolean mForceDrawAdjacentPages = false;
     // Total over scrollX in the overlay direction.
     private float mOverlayTranslation;
@@ -599,12 +603,12 @@
             // In transposed layout, we add the QSB in the Grid. As workspace does not touch the
             // edges, we do not need a full width QSB.
             qsb = LayoutInflater.from(getContext())
-                    .inflate(R.layout.qsb_container,firstPage, false);
+                    .inflate(R.layout.search_container_workspace,firstPage, false);
         }
 
         CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, firstPage.getCountX(), 1);
         lp.canReorder = false;
-        if (!firstPage.addViewToCellLayout(qsb, 0, R.id.qsb_container, lp, true)) {
+        if (!firstPage.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true)) {
             Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout");
         }
     }
@@ -622,7 +626,7 @@
         }
 
         // Recycle the QSB widget
-        View qsb = findViewById(R.id.qsb_container);
+        View qsb = findViewById(R.id.search_container_workspace);
         if (qsb != null) {
             ((ViewGroup) qsb.getParent()).removeView(qsb);
         }
@@ -665,6 +669,10 @@
         newScreen.setOnLongClickListener(mLongClickListener);
         newScreen.setOnClickListener(mLauncher);
         newScreen.setSoundEffectsEnabled(false);
+
+        int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx;
+        newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, 0);
+
         mWorkspaceScreens.put(screenId, newScreen);
         mScreenOrder.add(insertIndex, screenId);
         addView(newScreen, insertIndex);
@@ -1321,18 +1329,10 @@
         onOverlayScrollChanged(0);
     }
 
-    @Override
-    protected int getUnboundedScrollX() {
-        if (isScrollingOverlay()) {
-            return mUnboundedScrollX;
-        }
-
-        return super.getUnboundedScrollX();
-    }
 
     private boolean isScrollingOverlay() {
         return mLauncherOverlay != null &&
-                ((mIsRtl && mUnboundedScrollX > mMaxScrollX) || (!mIsRtl && mUnboundedScrollX < 0));
+                ((mIsRtl && getUnboundedScrollX() > mMaxScrollX) || (!mIsRtl && getUnboundedScrollX() < 0));
     }
 
     @Override
@@ -1352,12 +1352,6 @@
     }
 
     @Override
-    public void scrollTo(int x, int y) {
-        mUnboundedScrollX = x;
-        super.scrollTo(x, y);
-    }
-
-    @Override
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
 
@@ -1410,7 +1404,7 @@
     @Override
     protected boolean shouldFlingForVelocity(int velocityX) {
         // When the overlay is moving, the fling or settle transition is controlled by the overlay.
-        return Float.compare(mOverlayTranslation, 0) == 0 &&
+        return Float.compare(Math.abs(mOverlayTranslation), 0) == 0 &&
                 super.shouldFlingForVelocity(velocityX);
     }
 
@@ -1420,6 +1414,20 @@
      * The overlay scroll is being controlled locally, just update our overlay effect
      */
     public void onOverlayScrollChanged(float scroll) {
+
+        if (Float.compare(scroll, 1f) == 0) {
+            if (!mOverlayShown) {
+                mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
+                        Action.Direction.LEFT, ContainerType.WORKSPACE, 0);
+            }
+            mOverlayShown = true;
+        } else if (Float.compare(scroll, 0f) == 0) {
+            if (mOverlayShown) {
+                mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
+                        Action.Direction.RIGHT, ContainerType.WORKSPACE, -1);
+            }
+            mOverlayShown = false;
+        }
         float offset = 0f;
         float slip = 0f;
 
@@ -1530,16 +1538,13 @@
     }
 
     @Override
-    protected void getEdgeVerticalPosition(int[] pos) {
-        View child = getChildAt(getPageCount() - 1);
-        pos[0] = child.getTop();
-        pos[1] = child.getBottom();
-    }
-
-    @Override
-    protected void notifyPageSwitchListener() {
-        super.notifyPageSwitchListener();
-
+    protected void notifyPageSwitchListener(int prevPage) {
+        super.notifyPageSwitchListener(prevPage);
+        if (prevPage != mCurrentPage) {
+            int swipeDirection = (prevPage < mCurrentPage) ? Action.Direction.RIGHT : Action.Direction.LEFT;
+            mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
+                    swipeDirection, ContainerType.WORKSPACE, prevPage);
+        }
         if (hasCustomContent() && getNextPage() == 0 && !mCustomContentShowing) {
             mCustomContentShowing = true;
             if (mCustomContentCallbacks != null) {
@@ -1634,16 +1639,21 @@
     }
 
     private void updatePageAlphaValues() {
-        if (mWorkspaceFadeInAdjacentScreens &&
-                !workspaceInModalState() &&
-                !mIsSwitchingState) {
+        if (!workspaceInModalState() && !mIsSwitchingState) {
             int screenCenter = getScrollX() + getViewportWidth() / 2;
             for (int i = numCustomPages(); i < getChildCount(); i++) {
                 CellLayout child = (CellLayout) getChildAt(i);
                 if (child != null) {
                     float scrollProgress = getScrollProgress(screenCenter, child, i);
                     float alpha = 1 - Math.abs(scrollProgress);
-                    child.getShortcutsAndWidgets().setAlpha(alpha);
+                    if (mWorkspaceFadeInAdjacentScreens) {
+                        child.getShortcutsAndWidgets().setAlpha(alpha);
+                    } else {
+                        // Pages that are off-screen aren't important for accessibility.
+                        child.getShortcutsAndWidgets().setImportantForAccessibility(
+                                alpha > 0 ? IMPORTANT_FOR_ACCESSIBILITY_AUTO
+                                        : IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+                    }
                 }
             }
         }
@@ -1889,13 +1899,20 @@
             return;
         }
 
+        ArrayList<Long> prevScreenOrder = (ArrayList<Long>) mScreenOrder.clone();
         mScreenOrder.clear();
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
             CellLayout cl = ((CellLayout) getChildAt(i));
             mScreenOrder.add(getIdForScreen(cl));
         }
-        mLauncher.getUserEventDispatcher().logOverviewReorder();
+
+        for (int i = 0; i < prevScreenOrder.size(); i++) {
+            if (mScreenOrder.get(i) != prevScreenOrder.get(i)) {
+                mLauncher.getUserEventDispatcher().logOverviewReorder();
+                break;
+            }
+        }
         LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
 
         // Re-enable auto layout transitions for page deletion.
@@ -2365,7 +2382,7 @@
                 fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,
                         postAnimationRunnable);
             } else {
-                fi.prepareCreate(v);
+                fi.prepareCreateAnimation(v);
                 fi.addItem(destInfo);
                 fi.addItem(sourceInfo);
             }
@@ -3974,8 +3991,9 @@
         }
     }
 
-    private void moveToScreen(int page, boolean animate) {
-        if (!workspaceInModalState()) {
+    void moveToDefaultScreen(boolean animate) {
+        int page = getDefaultPage();
+        if (!workspaceInModalState() && getNextPage() != page) {
             if (animate) {
                 snapToPage(page);
             } else {
@@ -3988,10 +4006,6 @@
         }
     }
 
-    void moveToDefaultScreen(boolean animate) {
-        moveToScreen(getDefaultPage(), animate);
-    }
-
     void moveToCustomContentScreen(boolean animate) {
         if (hasCustomContent()) {
             int ccIndex = getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID);
@@ -4068,7 +4082,7 @@
      * Used as a workaround to ensure that the AppWidgetService receives the
      * PACKAGE_ADDED broadcast before updating widgets.
      */
-    private class DeferredWidgetRefresh implements Runnable {
+    private class DeferredWidgetRefresh implements Runnable, ProviderChangedListener {
         private final ArrayList<LauncherAppWidgetInfo> mInfos;
         private final LauncherAppWidgetHost mHost;
         private final Handler mHandler;
@@ -4111,6 +4125,11 @@
                 }
             });
         }
+
+        @Override
+        public void notifyWidgetProvidersChanged() {
+            run();
+        }
     }
 
     private class StateTransitionListener extends AnimatorListenerAdapter
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index 8161219..b7c500f 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -50,8 +50,7 @@
         if ((host.getParent() instanceof DeepShortcutView)) {
             info.addAction(mActions.get(ADD_TO_WORKSPACE));
         } else if (host instanceof NotificationMainView) {
-            NotificationMainView notificationView = (NotificationMainView) host;
-            if (notificationView.canChildBeDismissed(notificationView)) {
+            if (((NotificationMainView) host).canChildBeDismissed()) {
                 info.addAction(mActions.get(DISMISS_NOTIFICATION));
             }
         }
@@ -88,8 +87,7 @@
             if (!(host instanceof NotificationMainView)) {
                 return false;
             }
-            NotificationMainView notificationView = (NotificationMainView) host;
-            notificationView.onChildDismissed(notificationView);
+            ((NotificationMainView) host).onChildDismissed();
             announceConfirmation(R.string.notification_dismissed);
             return true;
         }
diff --git a/src/com/android/launcher3/allapps/AllAppsCaretController.java b/src/com/android/launcher3/allapps/AllAppsCaretController.java
index 622322b..583b49f 100644
--- a/src/com/android/launcher3/allapps/AllAppsCaretController.java
+++ b/src/com/android/launcher3/allapps/AllAppsCaretController.java
@@ -22,13 +22,14 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.pageindicators.CaretDrawable;
+import com.android.launcher3.touch.SwipeDetector;
 
 public class AllAppsCaretController {
     // Determines when the caret should flip. Should be accessed via getThreshold()
     private static final float CARET_THRESHOLD = 0.015f;
     private static final float CARET_THRESHOLD_LAND = 0.5f;
     // The velocity at which the caret will peak (i.e. exhibit a 90 degree bend)
-    private static final float PEAK_VELOCITY = VerticalPullDetector.RELEASE_VELOCITY_PX_MS * .7f;
+    private static final float PEAK_VELOCITY = SwipeDetector.RELEASE_VELOCITY_PX_MS * .7f;
 
     private Launcher mLauncher;
 
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 47b68a2..0083d47 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -21,7 +21,6 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.InsetDrawable;
 import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.util.AttributeSet;
@@ -220,17 +219,16 @@
         });
 
         // Load the all apps recycler view
-        mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
+        mAppsRecyclerView = findViewById(R.id.apps_list_view);
         mAppsRecyclerView.setApps(mApps);
         mAppsRecyclerView.setLayoutManager(mLayoutManager);
         mAppsRecyclerView.setAdapter(mAdapter);
         mAppsRecyclerView.setHasFixedSize(true);
         if (FeatureFlags.LAUNCHER3_PHYSICS) {
             mAppsRecyclerView.setSpringAnimationHandler(mSpringAnimationHandler);
-            mAppsRecyclerView.addOnScrollListener(new SpringMotionOnScrollListener());
         }
 
-        mSearchContainer = findViewById(R.id.search_container);
+        mSearchContainer = findViewById(R.id.search_container_all_apps);
         mSearchUiManager = (SearchUiManager) mSearchContainer;
         mSearchUiManager.initialize(mApps, mAppsRecyclerView);
 
@@ -359,7 +357,7 @@
 
     @Override
     public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
-        targetParent.containerType = mAppsRecyclerView.getContainerType(v);
+        // This is filled in {@link AllAppsRecyclerView}
     }
 
     @Override
@@ -403,35 +401,4 @@
     public SpringAnimationHandler getSpringAnimationHandler() {
         return mSpringAnimationHandler;
     }
-
-    public class SpringMotionOnScrollListener extends RecyclerView.OnScrollListener {
-
-        private int mScrollState = RecyclerView.SCROLL_STATE_IDLE;
-
-        @Override
-        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-            if (mScrollState == RecyclerView.SCROLL_STATE_DRAGGING
-                    || (dx == 0 && dy == 0)) {
-                if (mSpringAnimationHandler.isRunning()){
-                    mSpringAnimationHandler.skipToEnd();
-                }
-                return;
-            }
-
-            int first = mLayoutManager.findFirstVisibleItemPosition();
-            int last = mLayoutManager.findLastVisibleItemPosition();
-
-            // We only show the spring animation when at the top or bottom, so we wait until the
-            // first or last row is visible to ensure that all animations run in sync.
-            if ((first == 0 && dy < 0) || (last == mAdapter.getItemCount() - 1 && dy > 0)) {
-                mSpringAnimationHandler.animateToFinalPosition(0);
-            }
-        }
-
-        @Override
-        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-            super.onScrollStateChanged(recyclerView, newState);
-            mScrollState = newState;
-        }
-    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 1054a56..ba4fbe0 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -481,19 +481,17 @@
          *     5 6 7 8 9
          */
         private int getAppPosition(int position, int numPredictedApps, int appsPerRow) {
-            int appPosition = position;
-            int numDividerViews = 1 + (numPredictedApps == 0 ? 0 : 1);
-
-            int allAppsStartAt = numDividerViews + numPredictedApps;
-            if (numDividerViews == 1 || position < allAppsStartAt) {
-                appPosition -= 1;
-            } else {
-                // We cannot assume that the predicted row will always be full.
-                int numPredictedAppsOffset = appsPerRow - numPredictedApps;
-                appPosition = position + numPredictedAppsOffset - numDividerViews;
+            if (position < numPredictedApps) {
+                // Predicted apps are first in the adapter.
+                return position;
             }
 
-            return appPosition;
+            // There is at most 1 divider view between the predicted apps and the alphabetical apps.
+            int numDividerViews = numPredictedApps == 0 ? 0 : 1;
+
+            // This offset takes into consideration an incomplete row of predicted apps.
+            int numPredictedAppsOffset = appsPerRow - numPredictedApps;
+            return position + numPredictedAppsOffset - numDividerViews;
         }
 
         /**
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 2b2fddc..331900c 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -15,12 +15,14 @@
  */
 package com.android.launcher3.allapps;
 
+import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
+import android.util.Property;
 import android.util.SparseIntArray;
 import android.view.MotionEvent;
 import android.view.View;
@@ -28,18 +30,23 @@
 import com.android.launcher3.BaseRecyclerView;
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.ItemInfo;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.SpringAnimationHandler;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.DrawableFactory;
+import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
+import com.android.launcher3.touch.OverScroll;
+import com.android.launcher3.touch.SwipeDetector;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 
 import java.util.List;
 
 /**
  * A RecyclerView with custom fast scroll support for the all apps view.
  */
-public class AllAppsRecyclerView extends BaseRecyclerView {
+public class AllAppsRecyclerView extends BaseRecyclerView implements LogContainerProvider {
 
     private AlphabeticalAppsList mApps;
     private AllAppsFastScrollHelper mFastScrollHelper;
@@ -54,6 +61,22 @@
     private int mEmptySearchBackgroundTopOffset;
 
     private SpringAnimationHandler mSpringAnimationHandler;
+    private OverScrollHelper mOverScrollHelper;
+    private SwipeDetector mPullDetector;
+
+    private float mContentTranslationY = 0;
+    public static final Property<AllAppsRecyclerView, Float> CONTENT_TRANS_Y =
+            new Property<AllAppsRecyclerView, Float>(Float.class, "appsRecyclerViewContentTransY") {
+                @Override
+                public Float get(AllAppsRecyclerView allAppsRecyclerView) {
+                    return allAppsRecyclerView.getContentTranslationY();
+                }
+
+                @Override
+                public void set(AllAppsRecyclerView allAppsRecyclerView, Float y) {
+                    allAppsRecyclerView.setContentTranslationY(y);
+                }
+            };
 
     public AllAppsRecyclerView(Context context) {
         this(context, null);
@@ -74,14 +97,28 @@
         addOnItemTouchListener(this);
         mEmptySearchBackgroundTopOffset = res.getDimensionPixelSize(
                 R.dimen.all_apps_empty_search_bg_top_offset);
+
+        mOverScrollHelper = new OverScrollHelper();
+        mPullDetector = new SwipeDetector(getContext(), mOverScrollHelper, SwipeDetector.VERTICAL);
+        mPullDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, true);
     }
 
     public void setSpringAnimationHandler(SpringAnimationHandler springAnimationHandler) {
-        mSpringAnimationHandler = springAnimationHandler;
+        if (FeatureFlags.LAUNCHER3_PHYSICS) {
+            mSpringAnimationHandler = springAnimationHandler;
+            addOnScrollListener(new SpringMotionOnScrollListener());
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) {
+        mPullDetector.onTouchEvent(ev);
+        return super.onInterceptTouchEvent(rv, ev) || mOverScrollHelper.isInOverScroll();
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent e) {
+        mPullDetector.onTouchEvent(e);
         if (FeatureFlags.LAUNCHER3_PHYSICS && mSpringAnimationHandler != null) {
             mSpringAnimationHandler.addMovement(e);
         }
@@ -168,6 +205,8 @@
 
     @Override
     public void onDraw(Canvas c) {
+        c.translate(0, mContentTranslationY);
+
         // Draw the background
         if (mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
             mEmptySearchBackground.draw(c);
@@ -176,6 +215,19 @@
         super.onDraw(c);
     }
 
+    public float getContentTranslationY() {
+        return mContentTranslationY;
+    }
+
+    /**
+     * Use this method instead of calling {@link #setTranslationY(float)}} directly to avoid drawing
+     * on top of other Views.
+     */
+    public void setContentTranslationY(float y) {
+        mContentTranslationY = y;
+        invalidate();
+    }
+
     @Override
     protected boolean verifyDrawable(Drawable who) {
         return who == mEmptySearchBackground || super.verifyDrawable(who);
@@ -186,9 +238,10 @@
         updateEmptySearchBackgroundBounds();
     }
 
-    public int getContainerType(View v) {
+    @Override
+    public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
         if (mApps.hasFilter()) {
-            return ContainerType.SEARCHRESULT;
+            targetParent.containerType = ContainerType.SEARCHRESULT;
         } else {
             if (v instanceof BubbleTextView) {
                 BubbleTextView icon = (BubbleTextView) v;
@@ -197,11 +250,13 @@
                     List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
                     AlphabeticalAppsList.AdapterItem item = items.get(position);
                     if (item.viewType == AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON) {
-                        return ContainerType.PREDICTION;
+                        targetParent.containerType = ContainerType.PREDICTION;
+                        target.predictedRank = item.rowAppIndex;
+                        return;
                     }
                 }
             }
-            return ContainerType.ALLAPPS;
+            targetParent.containerType = ContainerType.ALLAPPS;
         }
     }
 
@@ -434,4 +489,104 @@
                 y + mEmptySearchBackground.getIntrinsicHeight());
     }
 
+    private class SpringMotionOnScrollListener extends RecyclerView.OnScrollListener {
+
+        @Override
+        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+            if (mOverScrollHelper.isInOverScroll()) {
+                // OverScroll will handle animating the springs.
+                return;
+            }
+
+            // We only start the spring animation when we hit the top/bottom, to ensure
+            // that all of the animations start at the same time.
+            if (dy < 0 && !canScrollVertically(-1)) {
+                mSpringAnimationHandler.animateToFinalPosition(0, 1);
+            } else if (dy > 0 && !canScrollVertically(1)) {
+                mSpringAnimationHandler.animateToFinalPosition(0, -1);
+            }
+        }
+    }
+
+    private class OverScrollHelper implements SwipeDetector.Listener {
+
+        private static final float MAX_RELEASE_VELOCITY = 5000; // px / s
+        private static final float MAX_OVERSCROLL_PERCENTAGE = 0.07f;
+
+        private boolean mIsInOverScroll;
+
+        // We use this value to calculate the actual amount the user has overscrolled.
+        private float mFirstDisplacement = 0;
+
+        private boolean mAlreadyScrollingUp;
+        private int mFirstScrollYOnScrollUp;
+
+        @Override
+        public void onDragStart(boolean start) {
+        }
+
+        @Override
+        public boolean onDrag(float displacement, float velocity) {
+            boolean isScrollingUp = displacement > 0;
+            if (isScrollingUp) {
+                if (!mAlreadyScrollingUp) {
+                    mFirstScrollYOnScrollUp = getCurrentScrollY();
+                    mAlreadyScrollingUp = true;
+                }
+            } else {
+                mAlreadyScrollingUp = false;
+            }
+
+            // Only enter overscroll if the user is interacting with the RecyclerView directly
+            // and if one of the following criteria are met:
+            // - User scrolls down when they're already at the bottom.
+            // - User starts scrolling up, hits the top, and continues scrolling up.
+            mIsInOverScroll = !mScrollbar.isDraggingThumb() &&
+                    ((!canScrollVertically(1) && displacement < 0) ||
+                    (!canScrollVertically(-1) && isScrollingUp && mFirstScrollYOnScrollUp != 0));
+
+            if (mIsInOverScroll) {
+                if (Float.compare(mFirstDisplacement, 0) == 0) {
+                    // Because users can scroll before entering overscroll, we need to
+                    // subtract the amount where the user was not in overscroll.
+                    mFirstDisplacement = displacement;
+                }
+                float overscrollY = displacement - mFirstDisplacement;
+                setContentTranslationY(getDampedOverScroll(overscrollY));
+            }
+
+            return mIsInOverScroll;
+        }
+
+        @Override
+        public void onDragEnd(float velocity, boolean fling) {
+            float y = getContentTranslationY();
+            if (Float.compare(y, 0) != 0) {
+                if (FeatureFlags.LAUNCHER3_PHYSICS) {
+                    // We calculate our own velocity to give the springs the desired effect.
+                    velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY;
+                    // We want to negate the velocity because we are moving to 0 from -1 due to the
+                    // downward motion. (y-axis -1 is above 0).
+                    mSpringAnimationHandler.animateToPositionWithVelocity(0, -1, -velocity);
+                }
+
+                ObjectAnimator.ofFloat(AllAppsRecyclerView.this,
+                        AllAppsRecyclerView.CONTENT_TRANS_Y, 0)
+                        .setDuration(100)
+                        .start();
+            }
+            mIsInOverScroll = false;
+            mFirstDisplacement = 0;
+            mFirstScrollYOnScrollUp = 0;
+            mAlreadyScrollingUp = false;
+        }
+
+        public boolean isInOverScroll() {
+            return mIsInOverScroll;
+        }
+
+        private float getDampedOverScroll(float y) {
+            return OverScroll.dampedScroll(y, getHeight());
+        }
+    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 4d112c6..6896b37 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -25,7 +25,7 @@
 import com.android.launcher3.anim.SpringAnimationHandler;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.GradientView;
-import com.android.launcher3.graphics.ScrimView;
+import com.android.launcher3.touch.SwipeDetector;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.util.SystemUiController;
@@ -42,7 +42,7 @@
  * If release velocity < THRES1, snap according to either top or bottom depending on whether it's
  * closer to top or closer to the page indicator.
  */
-public class AllAppsTransitionController implements TouchController, VerticalPullDetector.Listener,
+public class AllAppsTransitionController implements TouchController, SwipeDetector.Listener,
          SearchUiManager.OnScrollRangeChangeListener {
 
     private static final String TAG = "AllAppsTrans";
@@ -52,8 +52,8 @@
     private final Interpolator mHotseatAccelInterpolator = new AccelerateInterpolator(1.5f);
     private final Interpolator mDecelInterpolator = new DecelerateInterpolator(3f);
     private final Interpolator mFastOutSlowInInterpolator = new FastOutSlowInInterpolator();
-    private final VerticalPullDetector.ScrollInterpolator mScrollInterpolator
-            = new VerticalPullDetector.ScrollInterpolator();
+    private final SwipeDetector.ScrollInterpolator mScrollInterpolator
+            = new SwipeDetector.ScrollInterpolator();
 
     private static final float PARALLAX_COEFFICIENT = .125f;
     private static final int SINGLE_FRAME_MS = 16;
@@ -69,7 +69,7 @@
     private float mStatusBarHeight;
 
     private final Launcher mLauncher;
-    private final VerticalPullDetector mDetector;
+    private final SwipeDetector mDetector;
     private final ArgbEvaluator mEvaluator;
     private final boolean mIsDarkTheme;
 
@@ -100,14 +100,12 @@
     private boolean mIsTranslateWithoutWorkspace = false;
     private AnimatorSet mDiscoBounceAnimation;
     private GradientView mGradientView;
-    private ScrimView mScrimView;
 
     private SpringAnimationHandler mSpringAnimationHandler;
 
     public AllAppsTransitionController(Launcher l) {
         mLauncher = l;
-        mDetector = new VerticalPullDetector(l);
-        mDetector.setListener(this);
+        mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
         mShiftRange = DEFAULT_SHIFT_RANGE;
         mProgress = 1f;
 
@@ -136,17 +134,17 @@
 
                 if (mDetector.isIdleState()) {
                     if (mLauncher.isAllAppsVisible()) {
-                        directionsToDetectScroll |= VerticalPullDetector.DIRECTION_DOWN;
+                        directionsToDetectScroll |= SwipeDetector.DIRECTION_NEGATIVE;
                     } else {
-                        directionsToDetectScroll |= VerticalPullDetector.DIRECTION_UP;
+                        directionsToDetectScroll |= SwipeDetector.DIRECTION_POSITIVE;
                     }
                 } else {
                     if (isInDisallowRecatchBottomZone()) {
-                        directionsToDetectScroll |= VerticalPullDetector.DIRECTION_UP;
+                        directionsToDetectScroll |= SwipeDetector.DIRECTION_POSITIVE;
                     } else if (isInDisallowRecatchTopZone()) {
-                        directionsToDetectScroll |= VerticalPullDetector.DIRECTION_DOWN;
+                        directionsToDetectScroll |= SwipeDetector.DIRECTION_NEGATIVE;
                     } else {
-                        directionsToDetectScroll |= VerticalPullDetector.DIRECTION_BOTH;
+                        directionsToDetectScroll |= SwipeDetector.DIRECTION_BOTH;
                         ignoreSlopWhenSettling = true;
                     }
                 }
@@ -228,7 +226,8 @@
                 }
                 mLauncher.showAppsView(true /* animated */, false /* updatePredictedApps */);
                 if (hasSpringAnimationHandler()) {
-                    mSpringAnimationHandler.animateToFinalPosition(0);
+                    // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
+                    mSpringAnimationHandler.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
                 }
             } else {
                 calculateDuration(velocity, Math.abs(mShiftRange - mAppsView.getTranslationY()));
@@ -301,13 +300,6 @@
             mGradientView.setVisibility(View.VISIBLE);
         }
         mGradientView.setProgress(progress);
-
-        // scrim
-        if (mScrimView == null) {
-            mScrimView = (ScrimView) mLauncher.findViewById(R.id.scrim_bg);
-            mScrimView.setVisibility(View.VISIBLE);
-        }
-        mScrimView.setProgress(progress);
     }
 
     /**
@@ -366,7 +358,7 @@
     }
 
     private void calculateDuration(float velocity, float disp) {
-        mAnimationDuration = mDetector.calculateDuration(velocity, disp / mShiftRange);
+        mAnimationDuration = SwipeDetector.calculateDuration(velocity, disp / mShiftRange);
     }
 
     public boolean animateToAllApps(AnimatorSet animationOut, long duration) {
diff --git a/src/com/android/launcher3/allapps/VerticalPullDetector.java b/src/com/android/launcher3/allapps/VerticalPullDetector.java
deleted file mode 100644
index 13c4f63..0000000
--- a/src/com/android/launcher3/allapps/VerticalPullDetector.java
+++ /dev/null
@@ -1,306 +0,0 @@
-package com.android.launcher3.allapps;
-
-import android.content.Context;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-import android.view.animation.Interpolator;
-
-/**
- * One dimensional scroll gesture detector for all apps container pull up interaction.
- * Client (e.g., AllAppsTransitionController) of this class can register a listener.
- * <p/>
- * Features that this gesture detector can support.
- */
-public class VerticalPullDetector {
-
-    private static final boolean DBG = false;
-    private static final String TAG = "VerticalPullDetector";
-
-    private final float mTouchSlop;
-
-    private int mScrollConditions;
-    public static final int DIRECTION_UP = 1 << 0;
-    public static final int DIRECTION_DOWN = 1 << 1;
-    public static final int DIRECTION_BOTH = DIRECTION_DOWN | DIRECTION_UP;
-
-    private static final float ANIMATION_DURATION = 1200;
-    private static final float FAST_FLING_PX_MS = 10;
-
-    /**
-     * The minimum release velocity in pixels per millisecond that triggers fling..
-     */
-    public static final float RELEASE_VELOCITY_PX_MS = 1.0f;
-
-    /**
-     * The time constant used to calculate dampening in the low-pass filter of scroll velocity.
-     * Cutoff frequency is set at 10 Hz.
-     */
-    public static final float SCROLL_VELOCITY_DAMPENING_RC = 1000f / (2f * (float) Math.PI * 10);
-
-    /* Scroll state, this is set to true during dragging and animation. */
-    private ScrollState mState = ScrollState.IDLE;
-
-    enum ScrollState {
-        IDLE,
-        DRAGGING,      // onDragStart, onDrag
-        SETTLING       // onDragEnd
-    }
-
-    //------------------- ScrollState transition diagram -----------------------------------
-    //
-    // IDLE ->      (mDisplacement > mTouchSlop) -> DRAGGING
-    // DRAGGING -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SETTLING
-    // SETTLING -> (MotionEvent#ACTION_DOWN) -> DRAGGING
-    // SETTLING -> (View settled) -> IDLE
-
-    private void setState(ScrollState newState) {
-        if (DBG) {
-            Log.d(TAG, "setState:" + mState + "->" + newState);
-        }
-        // onDragStart and onDragEnd is reported ONLY on state transition
-        if (newState == ScrollState.DRAGGING) {
-            initializeDragging();
-            if (mState == ScrollState.IDLE) {
-                reportDragStart(false /* recatch */);
-            } else if (mState == ScrollState.SETTLING) {
-                reportDragStart(true /* recatch */);
-            }
-        }
-        if (newState == ScrollState.SETTLING) {
-            reportDragEnd();
-        }
-
-        mState = newState;
-    }
-
-    public boolean isDraggingOrSettling() {
-        return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING;
-    }
-
-    /**
-     * There's no touch and there's no animation.
-     */
-    public boolean isIdleState() {
-        return mState == ScrollState.IDLE;
-    }
-
-    public boolean isSettlingState() {
-        return mState == ScrollState.SETTLING;
-    }
-
-    public boolean isDraggingState() {
-        return mState == ScrollState.DRAGGING;
-    }
-
-    private float mDownX;
-    private float mDownY;
-
-    private float mLastY;
-    private long mCurrentMillis;
-
-    private float mVelocity;
-    private float mLastDisplacement;
-    private float mDisplacementY;
-    private float mDisplacementX;
-
-    private float mSubtractDisplacement;
-    private boolean mIgnoreSlopWhenSettling;
-
-    /* Client of this gesture detector can register a callback. */
-    private Listener mListener;
-
-    public void setListener(Listener l) {
-        mListener = l;
-    }
-
-    public interface Listener {
-        void onDragStart(boolean start);
-
-        boolean onDrag(float displacement, float velocity);
-
-        void onDragEnd(float velocity, boolean fling);
-    }
-
-    public VerticalPullDetector(Context context) {
-        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-    }
-
-    public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
-        mScrollConditions = scrollDirectionFlags;
-        mIgnoreSlopWhenSettling = ignoreSlop;
-    }
-
-    private boolean shouldScrollStart() {
-        // reject cases where the slop condition is not met.
-        if (Math.abs(mDisplacementY) < mTouchSlop) {
-            return false;
-        }
-
-        // reject cases where the angle condition is not met.
-        float deltaY = Math.abs(mDisplacementY);
-        float deltaX = Math.max(Math.abs(mDisplacementX), 1);
-        if (deltaX > deltaY) {
-            return false;
-        }
-        // Check if the client is interested in scroll in current direction.
-        if (((mScrollConditions & DIRECTION_DOWN) > 0 && mDisplacementY > 0) ||
-                ((mScrollConditions & DIRECTION_UP) > 0 && mDisplacementY < 0)) {
-            return true;
-        }
-        return false;
-    }
-
-    public boolean onTouchEvent(MotionEvent ev) {
-        switch (ev.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                mDownX = ev.getX();
-                mDownY = ev.getY();
-                mLastDisplacement = 0;
-                mDisplacementY = 0;
-                mVelocity = 0;
-
-                if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
-                    setState(ScrollState.DRAGGING);
-                }
-                break;
-            case MotionEvent.ACTION_MOVE:
-                mDisplacementX = ev.getX() - mDownX;
-                mDisplacementY = ev.getY() - mDownY;
-                computeVelocity(ev);
-
-                // handle state and listener calls.
-                if (mState != ScrollState.DRAGGING && shouldScrollStart()) {
-                    setState(ScrollState.DRAGGING);
-                }
-                if (mState == ScrollState.DRAGGING) {
-                    reportDragging();
-                }
-                break;
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP:
-                // These are synthetic events and there is no need to update internal values.
-                if (mState == ScrollState.DRAGGING) {
-                    setState(ScrollState.SETTLING);
-                }
-                break;
-            default:
-                //TODO: add multi finger tracking by tracking active pointer.
-                break;
-        }
-        // Do house keeping.
-        mLastDisplacement = mDisplacementY;
-        mLastY = ev.getY();
-        return true;
-    }
-
-    public void finishedScrolling() {
-        setState(ScrollState.IDLE);
-    }
-
-    private boolean reportDragStart(boolean recatch) {
-        mListener.onDragStart(!recatch);
-        if (DBG) {
-            Log.d(TAG, "onDragStart recatch:" + recatch);
-        }
-        return true;
-    }
-
-    private void initializeDragging() {
-        if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
-            mSubtractDisplacement = 0;
-        }
-        if (mDisplacementY > 0) {
-            mSubtractDisplacement = mTouchSlop;
-        } else {
-            mSubtractDisplacement = -mTouchSlop;
-        }
-    }
-
-    private boolean reportDragging() {
-        float delta = mDisplacementY - mLastDisplacement;
-        if (delta != 0) {
-            if (DBG) {
-                Log.d(TAG, String.format("onDrag disp=%.1f, velocity=%.1f",
-                        mDisplacementY, mVelocity));
-            }
-
-            return mListener.onDrag(mDisplacementY - mSubtractDisplacement, mVelocity);
-        }
-        return true;
-    }
-
-    private void reportDragEnd() {
-        if (DBG) {
-            Log.d(TAG, String.format("onScrollEnd disp=%.1f, velocity=%.1f",
-                    mDisplacementY, mVelocity));
-        }
-        mListener.onDragEnd(mVelocity, Math.abs(mVelocity) > RELEASE_VELOCITY_PX_MS);
-
-    }
-
-    /**
-     * Computes the damped velocity using the two motion events and the previous velocity.
-     */
-    private float computeVelocity(MotionEvent to) {
-        return computeVelocity(to.getY() - mLastY, to.getEventTime());
-    }
-
-    public float computeVelocity(float delta, long currentMillis) {
-        long previousMillis = mCurrentMillis;
-        mCurrentMillis = currentMillis;
-
-        float deltaTimeMillis = mCurrentMillis - previousMillis;
-        float velocity = (deltaTimeMillis > 0) ? (delta / deltaTimeMillis) : 0;
-        if (Math.abs(mVelocity) < 0.001f) {
-            mVelocity = velocity;
-        } else {
-            float alpha = computeDampeningFactor(deltaTimeMillis);
-            mVelocity = interpolate(mVelocity, velocity, alpha);
-        }
-        return mVelocity;
-    }
-
-    /**
-     * Returns a time-dependent dampening factor using delta time.
-     */
-    private static float computeDampeningFactor(float deltaTime) {
-        return deltaTime / (SCROLL_VELOCITY_DAMPENING_RC + deltaTime);
-    }
-
-    /**
-     * Returns the linear interpolation between two values
-     */
-    private static float interpolate(float from, float to, float alpha) {
-        return (1.0f - alpha) * from + alpha * to;
-    }
-
-    public long calculateDuration(float velocity, float progressNeeded) {
-        // TODO: make these values constants after tuning.
-        float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity));
-        float travelDistance = Math.max(0.2f, progressNeeded);
-        long duration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance);
-        if (DBG) {
-            Log.d(TAG, String.format("calculateDuration=%d, v=%f, d=%f", duration, velocity, progressNeeded));
-        }
-        return duration;
-    }
-
-    public static class ScrollInterpolator implements Interpolator {
-
-        boolean mSteeper;
-
-        public void setVelocityAtZero(float velocity) {
-            mSteeper = velocity > FAST_FLING_PX_MS;
-        }
-
-        public float getInterpolation(float t) {
-            t -= 1.0f;
-            float output = t * t * t;
-            if (mSteeper) {
-                output *= t * t; // Make interpolation initial slope steeper
-            }
-            return output + 1;
-        }
-    }
-}
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 5cb12d5..39e2088 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -202,7 +202,8 @@
                 if (!dp.isVerticalBarLayout()) {
                     Rect insets = mLauncher.getDragLayer().getInsets();
                     int hotseatBottom = bottom - dp.hotseatBarBottomPaddingPx - insets.bottom;
-                    int searchTopMargin = insets.top + (mMinHeight - mSearchBoxHeight);
+                    int searchTopMargin = insets.top + (mMinHeight - mSearchBoxHeight)
+                            + ((MarginLayoutParams) getLayoutParams()).bottomMargin;
                     listener.onScrollRangeChanged(hotseatBottom - searchTopMargin);
                 } else {
                     listener.onScrollRangeChanged(bottom);
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index 4303302..cdbaf70 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -20,6 +20,7 @@
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.util.ComponentKey;
 
+import java.text.Collator;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -61,8 +62,9 @@
         // apps that don't match all of the words in the query.
         final String queryTextLower = query.toLowerCase();
         final ArrayList<ComponentKey> result = new ArrayList<>();
+        StringMatcher matcher = StringMatcher.getInstance();
         for (AppInfo info : mApps) {
-            if (matches(info, queryTextLower)) {
+            if (matches(info, queryTextLower, matcher)) {
                 result.add(info.toComponentKey());
             }
         }
@@ -70,6 +72,10 @@
     }
 
     public static boolean matches(AppInfo info, String query) {
+        return matches(info, query, StringMatcher.getInstance());
+    }
+
+    public static boolean matches(AppInfo info, String query, StringMatcher matcher) {
         int queryLength = query.length();
 
         String title = info.title.toString();
@@ -90,7 +96,7 @@
             nextType = i < (titleLength - 1) ?
                     Character.getType(title.codePointAt(i + 1)) : Character.UNASSIGNED;
             if (isBreak(thisType, lastType, nextType) &&
-                    title.substring(i, i + queryLength).equalsIgnoreCase(query)) {
+                    matcher.matches(query, title.substring(i, i + queryLength))) {
                 return true;
             }
         }
@@ -106,6 +112,13 @@
      *      4) Any capital character before a small character
      */
     private static boolean isBreak(int thisType, int prevType, int nextType) {
+        switch (prevType) {
+            case Character.UNASSIGNED:
+            case Character.SPACE_SEPARATOR:
+            case Character.LINE_SEPARATOR:
+            case Character.PARAGRAPH_SEPARATOR:
+                return true;
+        }
         switch (thisType) {
             case Character.UPPERCASE_LETTER:
                 if (nextType == Character.UPPERCASE_LETTER) {
@@ -136,4 +149,41 @@
                 return  prevType == Character.UNASSIGNED;
         }
     }
+
+    public static class StringMatcher {
+
+        private static final char MAX_UNICODE = '\uFFFF';
+
+        private final Collator mCollator;
+
+        StringMatcher() {
+            // On android N and above, Collator uses ICU implementation which has a much better
+            // support for non-latin locales.
+            mCollator = Collator.getInstance();
+            mCollator.setStrength(Collator.PRIMARY);
+            mCollator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
+        }
+
+        /**
+         * Returns true if {@param query} is a prefix of {@param target}
+         */
+        public boolean matches(String query, String target) {
+            switch (mCollator.compare(query, target)) {
+                case 0:
+                    return true;
+                case -1:
+                    // The target string can contain a modifier which would make it larger than
+                    // the query string (even though the length is same). If the query becomes
+                    // larger after appending a unicode character, it was originally a prefix of
+                    // the target string and hence should match.
+                    return mCollator.compare(query + MAX_UNICODE, target) > -1;
+                default:
+                    return false;
+            }
+        }
+
+        public static StringMatcher getInstance() {
+            return new StringMatcher();
+        }
+    }
 }
diff --git a/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java b/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
index 7c5fa1c..d01b26c 100644
--- a/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
+++ b/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
@@ -56,7 +56,7 @@
 
     @Override
     public boolean shouldRemoveElevationDuringAnimation() {
-        return true;
+        return false;
     }
 
     @Override
diff --git a/src/com/android/launcher3/anim/SpringAnimationHandler.java b/src/com/android/launcher3/anim/SpringAnimationHandler.java
index 038f826..3e58adc 100644
--- a/src/com/android/launcher3/anim/SpringAnimationHandler.java
+++ b/src/com/android/launcher3/anim/SpringAnimationHandler.java
@@ -111,22 +111,54 @@
         mShouldComputeVelocity = true;
     }
 
-    public void animateToFinalPosition(float position) {
-        if (DEBUG) Log.d(TAG, "animateToFinalPosition#computeVelocity=" + mShouldComputeVelocity);
+    public void animateToFinalPosition(float position, int startValue) {
+        animateToFinalPosition(position, startValue, mShouldComputeVelocity);
+    }
+
+    /**
+     * @param position The final animation position.
+     * @param startValue < 0 if scrolling from start to end; > 0 if scrolling from end to start
+     *                   The magnitude of the number changes how the spring will move.
+     * @param setVelocity If true, we set the velocity to {@link #mCurrentVelocity} before
+     *                    starting the animation.
+     */
+    private void animateToFinalPosition(float position, int startValue, boolean setVelocity) {
+        if (DEBUG) {
+            Log.d(TAG, "animateToFinalPosition#position=" + position + ", startValue=" + startValue);
+        }
 
         if (mShouldComputeVelocity) {
-            computeVelocity();
-            setStartVelocity(mCurrentVelocity);
+            mCurrentVelocity = computeVelocity();
         }
 
         int size = mAnimations.size();
         for (int i = 0; i < size; ++i) {
+            mAnimations.get(i).setStartValue(startValue);
+            if (setVelocity) {
+                mAnimations.get(i).setStartVelocity(mCurrentVelocity);
+            }
             mAnimations.get(i).animateToFinalPosition(position);
         }
 
         reset();
     }
 
+    /**
+     * Similar to {@link #animateToFinalPosition(float, int)}, but used in cases where we want to
+     * manually set the velocity.
+     */
+    public void animateToPositionWithVelocity(float position, int startValue, float velocity) {
+        if (DEBUG) {
+            Log.d(TAG, "animateToPosition#pos=" + position + ", start=" + startValue
+                    + ", velocity=" + velocity);
+        }
+
+        mCurrentVelocity = velocity;
+        mShouldComputeVelocity = false;
+        animateToFinalPosition(position, startValue, true);
+    }
+
+
     public boolean isRunning() {
         // All the animations run at the same time so we can just check the first one.
         return !mAnimations.isEmpty() && mAnimations.get(0).isRunning();
@@ -150,25 +182,20 @@
             mVelocityTracker = null;
         }
         mCurrentVelocity = 0;
+        mShouldComputeVelocity = false;
     }
 
-    private void setStartVelocity(float velocity) {
-        int size = mAnimations.size();
-        for (int i = 0; i < size; ++i) {
-            mAnimations.get(i).setStartVelocity(velocity);
-        }
-    }
 
-    private void computeVelocity() {
+    private float computeVelocity() {
         getVelocityTracker().computeCurrentVelocity(1000 /* millis */);
 
-        mCurrentVelocity = isVerticalDirection()
+        float velocity = isVerticalDirection()
                 ? getVelocityTracker().getYVelocity()
                 : getVelocityTracker().getXVelocity();
-        mCurrentVelocity *= VELOCITY_DAMPING_FACTOR;
-        mShouldComputeVelocity = false;
+        velocity *= VELOCITY_DAMPING_FACTOR;
 
-        if (DEBUG) Log.d(TAG, "computeVelocity=" + mCurrentVelocity);
+        if (DEBUG) Log.d(TAG, "computeVelocity=" + velocity);
+        return velocity;
     }
 
     private boolean isVerticalDirection() {
@@ -206,7 +233,6 @@
      */
     public static SpringAnimation forView(View view, FloatPropertyCompat property, float finalPos) {
         SpringAnimation spring = new SpringAnimation(view, property, finalPos);
-        spring.setStartValue(1f);
         spring.setSpring(new SpringForce(finalPos));
         return spring;
     }
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index 3efbbfb..4e00eae 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -16,15 +16,12 @@
 
 package com.android.launcher3.compat;
 
-import android.app.Activity;
-import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.UserHandle;
-import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -76,9 +73,6 @@
     public abstract boolean bindAppWidgetIdIfAllowed(
             int appWidgetId, AppWidgetProviderInfo info, Bundle options);
 
-    public abstract void startConfigActivity(AppWidgetProviderInfo info, int widgetId,
-            Activity activity, AppWidgetHost host, int requestCode);
-
     public abstract LauncherAppWidgetProviderInfo findProvider(
             ComponentName provider, UserHandle user);
 
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index f239f5c..cb3bd6c 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -16,24 +16,21 @@
 
 package com.android.launcher3.compat;
 
-import android.app.Activity;
-import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetProviderInfo;
-import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.support.annotation.Nullable;
-import android.widget.Toast;
 
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.PackageUserKey;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -49,6 +46,9 @@
 
     @Override
     public List<AppWidgetProviderInfo> getAllProviders(@Nullable PackageUserKey packageUser) {
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            return Collections.emptyList();
+        }
         if (packageUser == null) {
             ArrayList<AppWidgetProviderInfo> providers = new ArrayList<AppWidgetProviderInfo>();
             for (UserHandle user : mUserManager.getUserProfiles()) {
@@ -71,24 +71,20 @@
     @Override
     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
             Bundle options) {
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            return false;
+        }
         return mAppWidgetManager.bindAppWidgetIdIfAllowed(
                 appWidgetId, info.getProfile(), info.provider, options);
     }
 
     @Override
-    public void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity,
-            AppWidgetHost host, int requestCode) {
-        try {
-            host.startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, null);
-        } catch (ActivityNotFoundException | SecurityException e) {
-            Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
-        }
-    }
-
-    @Override
     public LauncherAppWidgetProviderInfo findProvider(ComponentName provider, UserHandle user) {
-        for (AppWidgetProviderInfo info : mAppWidgetManager
-                .getInstalledProvidersForProfile(user)) {
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            return null;
+        }
+        for (AppWidgetProviderInfo info :
+                getAllProviders(new PackageUserKey(provider.getPackageName(), user))) {
             if (info.provider.equals(provider)) {
                 return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
             }
@@ -99,6 +95,9 @@
     @Override
     public HashMap<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap() {
         HashMap<ComponentKey, AppWidgetProviderInfo> result = new HashMap<>();
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            return result;
+        }
         for (UserHandle user : mUserManager.getUserProfiles()) {
             for (AppWidgetProviderInfo info :
                     mAppWidgetManager.getInstalledProvidersForProfile(user)) {
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
index 1c48a13..44158ed 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
@@ -20,8 +20,10 @@
 import android.content.Context;
 import android.support.annotation.Nullable;
 
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.PackageUserKey;
 
+import java.util.Collections;
 import java.util.List;
 
 class AppWidgetManagerCompatVO extends AppWidgetManagerCompatVL {
@@ -32,6 +34,9 @@
 
     @Override
     public List<AppWidgetProviderInfo> getAllProviders(@Nullable PackageUserKey packageUser) {
+        if (FeatureFlags.GO_DISABLE_WIDGETS) {
+            return Collections.emptyList();
+        }
         if (packageUser == null) {
             return super.getAllProviders(null);
         }
diff --git a/src/com/android/launcher3/compat/WallpaperColorsCompat.java b/src/com/android/launcher3/compat/WallpaperColorsCompat.java
index 58d2a80..e25b9d9 100644
--- a/src/com/android/launcher3/compat/WallpaperColorsCompat.java
+++ b/src/com/android/launcher3/compat/WallpaperColorsCompat.java
@@ -21,6 +21,7 @@
 public class WallpaperColorsCompat {
 
     public static final int HINT_SUPPORTS_DARK_TEXT = 0x1;
+    public static final int HINT_SUPPORTS_DARK_THEME = 0x2;
 
     private final int mPrimaryColor;
     private final int mSecondaryColor;
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
new file mode 100644
index 0000000..9e0a3b3
--- /dev/null
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 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.config;
+
+/**
+ * Defines a set of flags used to control various launcher behaviors.
+ *
+ * All the flags should be defined here with appropriate default values. To override a value,
+ * redefine it in {@link FeatureFlags}.
+ *
+ * This class is kept package-private to prevent direct access.
+ */
+abstract class BaseFlags {
+
+    BaseFlags() {}
+
+    public static final boolean IS_DOGFOOD_BUILD = false;
+
+    // Custom flags go below this
+    public static boolean LAUNCHER3_DISABLE_ICON_NORMALIZATION = false;
+    public static boolean LAUNCHER3_LEGACY_FOLDER_ICON = false;
+    public static boolean LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW = false;
+    public static boolean LAUNCHER3_ALL_APPS_PULL_UP = true;
+    public static boolean LAUNCHER3_NEW_FOLDER_ANIMATION = true;
+    // When enabled allows to use any point on the fast scrollbar to start dragging.
+    public static final boolean LAUNCHER3_DIRECT_SCROLL = true;
+    // When enabled while all-apps open, the soft input will be set to adjust resize .
+    public static final boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = true;
+    // When enabled the promise icon is visible in all apps while installation an app.
+    public static final boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
+    // When enabled uses the AllAppsRadialGradientAndScrimDrawable for all apps
+    public static final boolean LAUNCHER3_GRADIENT_ALL_APPS = true;
+    // When enabled allows use of physics based motions in the Launcher.
+    public static final boolean LAUNCHER3_PHYSICS = true;
+    // When enabled allows use of spring motions on the icons.
+    public static final boolean LAUNCHER3_SPRING_ICONS = true;
+
+    // Feature flag to enable moving the QSB on the 0th screen of the workspace.
+    public static final boolean QSB_ON_FIRST_SCREEN = true;
+    // When enabled the all-apps icon is not added to the hotseat.
+    public static final boolean NO_ALL_APPS_ICON = true;
+    // When enabled fling down gesture on the first workspace triggers search.
+    public static final boolean PULLDOWN_SEARCH = false;
+    // When enabled the status bar may show dark icons based on the top of the wallpaper.
+    public static final boolean LIGHT_STATUS_BAR = false;
+    // When enabled icons are badged with the number of notifications associated with that app.
+    public static final boolean BADGE_ICONS = true;
+    // When enabled, icons not supporting {@link AdaptiveIconDrawable} will be wrapped in {@link FixedScaleDrawable}.
+    public static final boolean LEGACY_ICON_TREATMENT = true;
+    // When enabled, adaptive icons would have shadows baked when being stored to icon cache.
+    public static final boolean ADAPTIVE_ICON_SHADOW = true;
+    // When enabled, app discovery will be enabled if service is implemented
+    public static final boolean DISCOVERY_ENABLED = false;
+    // When enabled, the qsb will be moved to the hotseat.
+    public static final boolean QSB_IN_HOTSEAT = true;
+
+    // Features to control Launcher3Go behavior
+    public static final boolean GO_DISABLE_WIDGETS = false;
+}
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 01893bd..c843e72 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -16,14 +16,8 @@
 
 package com.android.launcher3.dragndrop;
 
-import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
-import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
-import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
-import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
-
 import android.annotation.TargetApi;
 import android.app.ActivityOptions;
-import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
 import android.content.ClipData;
 import android.content.ClipDescription;
@@ -45,8 +39,8 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.InstallShortcutReceiver;
 import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetHost;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -61,6 +55,11 @@
 import com.android.launcher3.widget.WidgetHostViewLoader;
 import com.android.launcher3.widget.WidgetImageView;
 
+import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
+import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
+import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
+import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
+
 @TargetApi(Build.VERSION_CODES.O)
 public class AddItemActivity extends BaseActivity implements OnLongClickListener, OnTouchListener {
 
@@ -78,7 +77,7 @@
     private LivePreviewWidgetCell mWidgetCell;
 
     // Widget request specific options.
-    private AppWidgetHost mAppWidgetHost;
+    private LauncherAppWidgetHost mAppWidgetHost;
     private AppWidgetManagerCompat mAppWidgetManager;
     private PendingAddWidgetInfo mPendingWidgetInfo;
     private int mPendingBindWidgetId;
@@ -212,7 +211,7 @@
         mWidgetCell.setPreview(PinItemDragListener.getPreview(mRequest));
 
         mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
-        mAppWidgetHost = new AppWidgetHost(this, Launcher.APPWIDGET_HOST_ID);
+        mAppWidgetHost = new LauncherAppWidgetHost(this);
 
         mPendingWidgetInfo = new PendingAddWidgetInfo(widgetInfo);
         mPendingWidgetInfo.spanX = Math.min(mIdp.numColumns, widgetInfo.spanX);
@@ -256,13 +255,8 @@
         }
 
         // request bind widget
-        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
-        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mPendingBindWidgetId);
-        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER,
-                mPendingWidgetInfo.componentName);
-        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
-                mRequest.getAppWidgetProviderInfo(this).getProfile());
-        startActivityForResult(intent, REQUEST_BIND_APPWIDGET);
+        mAppWidgetHost.startBindFlow(this, mPendingBindWidgetId,
+                mRequest.getAppWidgetProviderInfo(this), REQUEST_BIND_APPWIDGET);
     }
 
     private void acceptWidget(int widgetId) {
@@ -280,7 +274,7 @@
     }
 
     @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (requestCode == REQUEST_BIND_APPWIDGET) {
             int widgetId = data != null
                     ? data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mPendingBindWidgetId)
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 022b3b8..b6e38bb 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -16,23 +16,18 @@
 
 package com.android.launcher3.dragndrop;
 
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.FloatArrayEvaluator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.content.pm.LauncherActivityInfo;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.ColorFilter;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Point;
@@ -44,13 +39,11 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
-import android.support.animation.DynamicAnimation;
+import android.support.animation.FloatPropertyCompat;
 import android.support.animation.SpringAnimation;
 import android.support.animation.SpringForce;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
 
 import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.ItemInfo;
@@ -76,12 +69,16 @@
 import java.util.Arrays;
 import java.util.List;
 
-public class DragView extends FrameLayout {
+public class DragView extends View {
+    private static final ColorMatrix sTempMatrix1 = new ColorMatrix();
+    private static final ColorMatrix sTempMatrix2 = new ColorMatrix();
+
     public static final int COLOR_CHANGE_DURATION = 120;
     public static final int VIEW_ZOOM_DURATION = 150;
 
     @Thunk static float sDragAlpha = 1f;
 
+    private boolean mDrawBitmap = true;
     private Bitmap mBitmap;
     private Bitmap mCrossFadeBitmap;
     @Thunk Paint mPaint;
@@ -114,16 +111,11 @@
     private int mAnimatedShiftY;
 
     // Below variable only needed IF FeatureFlags.LAUNCHER3_SPRING_ICONS is {@code true}
-    private SpringAnimation mSpringX, mSpringY;
-    private ImageView mFgImageView, mBgImageView;
+    private Drawable mBgSpringDrawable, mFgSpringDrawable;
+    private SpringFloatValue mTranslateX, mTranslateY;
     private Path mScaledMaskPath;
     private Drawable mBadge;
-
-    // Following three values are fine tuned with motion ux designer
-    private final static int STIFFNESS = 4000;
-    private final static float DAMPENING_RATIO = 1f;
-    private final static int PARALLAX_MAX_IN_DP = 8;
-    private final int mDelta;
+    private ColorMatrixColorFilter mBaseFilter;
 
     /**
      * Construct the drag view.
@@ -193,12 +185,11 @@
 
         mBlurSizeOutline = getResources().getDimensionPixelSize(R.dimen.blur_size_medium_outline);
         setElevation(getResources().getDimension(R.dimen.drag_elevation));
-        setWillNotDraw(false);
-        mDelta = (int)(getResources().getDisplayMetrics().density * PARALLAX_MAX_IN_DP);
     }
 
     /**
-     * Initialize {@code #mIconDrawable} only if the icon type is app icon (not shortcut or folder).
+     * Initialize {@code #mIconDrawable} if the item can be represented using
+     * an {@link AdaptiveIconDrawable} or {@link FolderAdaptiveIcon}.
      */
     @TargetApi(Build.VERSION_CODES.O)
     public void setItemInfo(final ItemInfo info) {
@@ -206,7 +197,8 @@
             return;
         }
         if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
-                info.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                info.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
+                info.itemType != LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
             return;
         }
         // Load the adaptive icon on a background thread and add the view in ui thread.
@@ -216,51 +208,103 @@
             public void run() {
                 LauncherAppState appState = LauncherAppState.getInstance(mLauncher);
                 Object[] outObj = new Object[1];
-                Drawable dr = getFullDrawable(info, appState, outObj);
+                final Drawable dr = getFullDrawable(info, appState, outObj);
 
                 if (dr instanceof AdaptiveIconDrawable) {
                     int w = mBitmap.getWidth();
                     int h = mBitmap.getHeight();
-                    AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) dr;
-                    adaptiveIcon.setBounds(0, 0, w, h);
-                    float blurSizeOutline = mLauncher.getResources()
-                            .getDimension(R.dimen.blur_size_medium_outline);
-                    float normalizationScale = IconNormalizer.getInstance(mLauncher)
-                            .getScale(adaptiveIcon, null, null, null) * ((w - blurSizeOutline) / w);
+                    int blurMargin = (int) mLauncher.getResources()
+                            .getDimension(R.dimen.blur_size_medium_outline) / 2;
 
-                    final Path mask = getMaskPath(adaptiveIcon, normalizationScale);
-                    mFgImageView = setupImageView(adaptiveIcon.getForeground(), normalizationScale);
-                    mBgImageView = setupImageView(adaptiveIcon.getBackground(), normalizationScale);
-                    mSpringX = setupSpringAnimation(-w/4, w/4, DynamicAnimation.TRANSLATION_X);
-                    mSpringY = setupSpringAnimation(-h/4, h/4, DynamicAnimation.TRANSLATION_Y);
+                    Rect bounds = new Rect(0, 0, w, h);
+                    bounds.inset(blurMargin, blurMargin);
+                    Utilities.scaleRectAboutCenter(bounds,
+                            IconNormalizer.getInstance(mLauncher).getScale(dr, null, null, null));
+                    AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) dr;
+
+                    // Shrink very tiny bit so that the clip path is smaller than the original bitmap
+                    // that has anti aliased edges and shadows.
+                    Rect shrunkBounds = new Rect(bounds);
+                    Utilities.scaleRectAboutCenter(shrunkBounds, 0.98f);
+                    adaptiveIcon.setBounds(shrunkBounds);
+                    final Path mask = adaptiveIcon.getIconMask();
+
+                    mTranslateX = new SpringFloatValue(DragView.this,
+                            w * AdaptiveIconDrawable.getExtraInsetFraction());
+                    mTranslateY = new SpringFloatValue(DragView.this,
+                            h * AdaptiveIconDrawable.getExtraInsetFraction());
 
                     mBadge = getBadge(info, appState, outObj[0]);
-                    int blurMargin = (int) blurSizeOutline / 2;
-                    mBadge.setBounds(blurMargin, blurMargin, w - blurMargin, h - blurMargin);
+                    mBadge.setBounds(bounds);
+
+                    bounds.inset(
+                            (int) (-bounds.width() * AdaptiveIconDrawable.getExtraInsetFraction()),
+                            (int) (-bounds.height() * AdaptiveIconDrawable.getExtraInsetFraction())
+                    );
+                    mBgSpringDrawable = adaptiveIcon.getBackground();
+                    if (mBgSpringDrawable == null) {
+                        mBgSpringDrawable = new ColorDrawable(Color.TRANSPARENT);
+                    }
+                    mBgSpringDrawable.setBounds(bounds);
+                    mFgSpringDrawable = adaptiveIcon.getForeground();
+                    if (mFgSpringDrawable == null) {
+                        mFgSpringDrawable = new ColorDrawable(Color.TRANSPARENT);
+                    }
+                    mFgSpringDrawable.setBounds(bounds);
 
                     new Handler(Looper.getMainLooper()).post(new Runnable() {
                         @Override
                         public void run() {
                             // Assign the variable on the UI thread to avoid race conditions.
                             mScaledMaskPath = mask;
-                            addView(mBgImageView);
-                            addView(mFgImageView);
-                            setWillNotDraw(true);
+
+                            // Do not draw the background in case of folder as its translucent
+                            mDrawBitmap = !(dr instanceof FolderAdaptiveIcon);
 
                             if (info.isDisabled()) {
                                 FastBitmapDrawable d = new FastBitmapDrawable(null);
                                 d.setIsDisabled(true);
-                                ColorFilter cf = d.getColorFilter();
-                                mBgImageView.setColorFilter(cf);
-                                mFgImageView.setColorFilter(cf);
-                                mBadge.setColorFilter(cf);
+                                mBaseFilter = (ColorMatrixColorFilter) d.getColorFilter();
                             }
+                            updateColorFilter();
                         }
                     });
                 }
             }});
     }
 
+    @TargetApi(Build.VERSION_CODES.O)
+    private void updateColorFilter() {
+        if (mCurrentFilter == null) {
+            mPaint.setColorFilter(null);
+
+            if (mScaledMaskPath != null) {
+                mBgSpringDrawable.setColorFilter(mBaseFilter);
+                mBgSpringDrawable.setColorFilter(mBaseFilter);
+                mBadge.setColorFilter(mBaseFilter);
+            }
+        } else {
+            ColorMatrixColorFilter currentFilter = new ColorMatrixColorFilter(mCurrentFilter);
+            mPaint.setColorFilter(currentFilter);
+
+            if (mScaledMaskPath != null) {
+                if (mBaseFilter != null) {
+                    mBaseFilter.getColorMatrix(sTempMatrix1);
+                    sTempMatrix2.set(mCurrentFilter);
+                    sTempMatrix1.postConcat(sTempMatrix2);
+
+                    currentFilter = new ColorMatrixColorFilter(sTempMatrix1);
+                }
+
+                mBgSpringDrawable.setColorFilter(currentFilter);
+                mFgSpringDrawable.setColorFilter(currentFilter);
+                mBadge.setColorFilter(currentFilter);
+            }
+        }
+
+        invalidate();
+    }
+
     /**
      * Returns the full drawable for {@param info}.
      * @param outObj this is set to the internal data associated with {@param info},
@@ -291,6 +335,14 @@
                 return sm.getShortcutIconDrawable(si.get(0),
                         appState.getInvariantDeviceProfile().fillResIconDpi);
             }
+        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
+            FolderAdaptiveIcon icon =  FolderAdaptiveIcon.createFolderAdaptiveIcon(
+                    mLauncher, info.id, new Point(mBitmap.getWidth(), mBitmap.getHeight()));
+            if (icon == null) {
+                return null;
+            }
+            outObj[0] = icon;
+            return icon;
         } else {
             return null;
         }
@@ -318,84 +370,17 @@
             float insetFraction = (iconSize - badgeSize) / iconSize;
             return new InsetDrawable(new FastBitmapDrawable(badge),
                     insetFraction, insetFraction, 0, 0);
+        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
+            return ((FolderAdaptiveIcon) obj).getBadge();
         } else {
             return mLauncher.getPackageManager()
                     .getUserBadgedIcon(new FixedSizeEmptyDrawable(iconSize), info.user);
         }
     }
 
-    private ImageView setupImageView(Drawable drawable, float normalizationScale) {
-        FrameLayout.LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
-        ImageView imageViewOut = new ImageView(getContext());
-        imageViewOut.setLayoutParams(params);
-        imageViewOut.setScaleType(ImageView.ScaleType.FIT_XY);
-        imageViewOut.setScaleX(normalizationScale);
-        imageViewOut.setScaleY(normalizationScale);
-        imageViewOut.setImageDrawable(drawable);
-        return imageViewOut;
-    }
-
-    private SpringAnimation setupSpringAnimation(int minValue, int maxValue,
-            DynamicAnimation.ViewProperty property) {
-        SpringAnimation s = new SpringAnimation(mFgImageView, property, 0);
-        s.setMinValue(minValue).setMaxValue(maxValue);
-        s.setSpring(new SpringForce(0)
-                        .setDampingRatio(DAMPENING_RATIO)
-                        .setStiffness(STIFFNESS));
-        return s;
-    }
-
-    @TargetApi(Build.VERSION_CODES.O)
-    private Path getMaskPath(AdaptiveIconDrawable dr, float normalizationScale) {
-        Matrix m = new Matrix();
-        // Shrink very tiny bit so that the clip path is smaller than the original bitmap
-        // that has anti aliased edges and shadows.
-        float s = normalizationScale * .97f;
-        m.setScale(s, s, dr.getBounds().centerX(), dr.getBounds().centerY());
-        Path p = new Path();
-        dr.getIconMask().transform(m, p);
-        return p;
-    }
-
-    private void applySpring(int x, int y) {
-        if (mSpringX == null || mSpringY == null) {
-            return;
-        }
-        mSpringX.animateToFinalPosition(Utilities.boundToRange(x, -mDelta, mDelta));
-        mSpringY.animateToFinalPosition(Utilities.boundToRange(y, -mDelta, mDelta));
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        int w = right - left;
-        int h = bottom - top;
-        for (int i = 0; i < getChildCount(); i++) {
-            getChildAt(i).layout(-w / 4, -h / 4, w + w / 4, h + h / 4);
-        }
-    }
-
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int w = mBitmap.getWidth();
-        int h = mBitmap.getHeight();
-        setMeasuredDimension(w, h);
-        for (int i = 0; i < getChildCount(); i++) {
-            getChildAt(i).measure(w, h);
-        }
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        if (mScaledMaskPath != null) {
-            int cnt = canvas.save();
-            canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
-            canvas.clipPath(mScaledMaskPath);
-            super.dispatchDraw(canvas);
-            canvas.restoreToCount(cnt);
-            mBadge.draw(canvas);
-        } else {
-            super.dispatchDraw(canvas);
-        }
+        setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
     }
 
     /** Sets the scale of the view over the normal workspace icon size. */
@@ -439,43 +424,37 @@
         return mDragRegion;
     }
 
-    // Draws drag shadow for system DND.
-    @SuppressLint("WrongCall")
-    public void drawDragShadow(Canvas canvas) {
-        final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
-        canvas.scale(getScaleX(), getScaleY());
-        onDraw(canvas);
-        canvas.restoreToCount(saveCount);
-    }
-
-    // Provides drag shadow metrics for system DND.
-    public void provideDragShadowMetrics(Point size, Point touch) {
-        size.set((int)(mBitmap.getWidth() * getScaleX()), (int)(mBitmap.getHeight() * getScaleY()));
-
-        final float xGrowth = mBitmap.getWidth() * (getScaleX() - 1);
-        final float yGrowth = mBitmap.getHeight() * (getScaleY() - 1);
-        touch.set(
-                mRegistrationX + (int)Math.round(xGrowth / 2),
-                mRegistrationY + (int)Math.round(yGrowth / 2));
-    }
-
     @Override
     protected void onDraw(Canvas canvas) {
         mHasDrawn = true;
-        boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
-        if (crossFade) {
-            int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
-            mPaint.setAlpha(alpha);
+
+        if (mDrawBitmap) {
+            // Always draw the bitmap to mask anti aliasing due to clipPath
+            boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
+            if (crossFade) {
+                int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
+                mPaint.setAlpha(alpha);
+            }
+            canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
+            if (crossFade) {
+                mPaint.setAlpha((int) (255 * mCrossFadeProgress));
+                final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+                float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
+                float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
+                canvas.scale(sX, sY);
+                canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
+                canvas.restoreToCount(saveCount);
+            }
         }
-        canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
-        if (crossFade) {
-            mPaint.setAlpha((int) (255 * mCrossFadeProgress));
-            final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
-            float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
-            float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
-            canvas.scale(sX, sY);
-            canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
-            canvas.restoreToCount(saveCount);
+
+        if (mScaledMaskPath != null) {
+            int cnt = canvas.save();
+            canvas.clipPath(mScaledMaskPath);
+            mBgSpringDrawable.draw(canvas);
+            canvas.translate(mTranslateX.mValue, mTranslateY.mValue);
+            mFgSpringDrawable.draw(canvas);
+            canvas.restoreToCount(cnt);
+            mBadge.draw(canvas);
         }
     }
 
@@ -512,8 +491,7 @@
             animateFilterTo(m1.getArray());
         } else {
             if (mCurrentFilter == null) {
-                mPaint.setColorFilter(null);
-                invalidate();
+                updateColorFilter();
             } else {
                 animateFilterTo(new ColorMatrix().getArray());
             }
@@ -534,8 +512,7 @@
 
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
-                mPaint.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
-                invalidate();
+                updateColorFilter();
             }
         });
         mFilterAnimator.start();
@@ -590,8 +567,10 @@
      * @param touchY the y coordinate the user touched in DragLayer coordinates
      */
     public void move(int touchX, int touchY) {
-        if (touchX > 0 && touchY > 0 && mLastTouchX > 0 && mLastTouchY > 0) {
-            applySpring(mLastTouchX - touchX, mLastTouchY - touchY);
+        if (touchX > 0 && touchY > 0 && mLastTouchX > 0 && mLastTouchY > 0
+                && mScaledMaskPath != null) {
+            mTranslateX.animateToPos(mLastTouchX - touchX);
+            mTranslateY.animateToPos(mLastTouchY - touchY);
         }
         mLastTouchX = touchX;
         mLastTouchY = touchY;
@@ -642,6 +621,48 @@
         return mInitialScale;
     }
 
+    private static class SpringFloatValue {
+
+        private static final FloatPropertyCompat<SpringFloatValue> VALUE =
+                new FloatPropertyCompat<SpringFloatValue>("value") {
+                    @Override
+                    public float getValue(SpringFloatValue object) {
+                        return object.mValue;
+                    }
+
+                    @Override
+                    public void setValue(SpringFloatValue object, float value) {
+                        object.mValue = value;
+                        object.mView.invalidate();
+                    }
+                };
+
+        // Following three values are fine tuned with motion ux designer
+        private final static int STIFFNESS = 4000;
+        private final static float DAMPENING_RATIO = 1f;
+        private final static int PARALLAX_MAX_IN_DP = 8;
+
+        private final View mView;
+        private final SpringAnimation mSpring;
+        private final float mDelta;
+
+        private float mValue;
+
+        public SpringFloatValue(View view, float range) {
+            mView = view;
+            mSpring = new SpringAnimation(this, VALUE, 0)
+                    .setMinValue(-range).setMaxValue(range)
+                    .setSpring(new SpringForce(0)
+                            .setDampingRatio(DAMPENING_RATIO)
+                            .setStiffness(STIFFNESS));
+            mDelta = view.getResources().getDisplayMetrics().density * PARALLAX_MAX_IN_DP;
+        }
+
+        public void animateToPos(float value) {
+            mSpring.animateToFinalPosition(Utilities.boundToRange(value, -mDelta, mDelta));
+        }
+    }
+
     private static class FixedSizeEmptyDrawable extends ColorDrawable {
 
         private final int mSize;
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
new file mode 100644
index 0000000..c905460
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2017 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.dragndrop;
+
+import android.annotation.TargetApi;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.Log;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.R;
+import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.folder.PreviewBackground;
+import com.android.launcher3.util.Preconditions;
+
+import java.util.concurrent.Callable;
+
+/**
+ * {@link AdaptiveIconDrawable} representation of a {@link FolderIcon}
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public class FolderAdaptiveIcon extends AdaptiveIconDrawable {
+    private static final String TAG = "FolderAdaptiveIcon";
+
+    private final Drawable mBadge;
+    private final Path mMask;
+
+    private FolderAdaptiveIcon(Drawable bg, Drawable fg, Drawable badge, Path mask) {
+        super(bg, fg);
+        mBadge = badge;
+        mMask = mask;
+    }
+
+    @Override
+    public Path getIconMask() {
+        return mMask;
+    }
+
+    public Drawable getBadge() {
+        return mBadge;
+    }
+
+    public static FolderAdaptiveIcon createFolderAdaptiveIcon(
+            final Launcher launcher, final long folderId, Point dragViewSize) {
+        Preconditions.assertNonUiThread();
+        int margin = launcher.getResources()
+                .getDimensionPixelSize(R.dimen.blur_size_medium_outline);
+
+        // Allocate various bitmaps on the background thread, because why not!
+        final Bitmap badge = Bitmap.createBitmap(
+                dragViewSize.x - margin, dragViewSize.y - margin, Bitmap.Config.ARGB_8888);
+
+        // The bitmap for the preview is generated larger than needed to allow for the spring effect
+        float sizeScaleFactor = 1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction();
+        final Bitmap preview = Bitmap.createBitmap(
+                (int) (dragViewSize.x * sizeScaleFactor), (int) (dragViewSize.y * sizeScaleFactor),
+                Bitmap.Config.ARGB_8888);
+
+        // Create the actual drawable on the UI thread to avoid race conditions with
+        // FolderIcon draw pass
+        try {
+            return new MainThreadExecutor().submit(new Callable<FolderAdaptiveIcon>() {
+                @Override
+                public FolderAdaptiveIcon call() throws Exception {
+                    FolderIcon icon = launcher.findFolderIcon(folderId);
+                    return icon == null ? null : createDrawableOnUiThread(icon, badge, preview);
+                }
+            }).get();
+        } catch (Exception e) {
+            Log.e(TAG, "Unable to create folder icon", e);
+            return null;
+        }
+    }
+
+    /**
+     * Initializes various bitmaps on the UI thread and returns the final drawable.
+     */
+    private static FolderAdaptiveIcon createDrawableOnUiThread(FolderIcon icon,
+            Bitmap badgeBitmap, Bitmap previewBitmap) {
+        Preconditions.assertUIThread();
+        float margin = icon.getResources().getDimension(R.dimen.blur_size_medium_outline) / 2;
+
+        Canvas c = new Canvas();
+        PreviewBackground bg = icon.getFolderBackground();
+
+        // Initialize badge
+        c.setBitmap(badgeBitmap);
+        bg.drawShadow(c);
+        bg.drawBackgroundStroke(c);
+        icon.drawBadge(c);
+
+        // Initialize preview
+        float shiftFactor = AdaptiveIconDrawable.getExtraInsetFraction() /
+                (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
+        float previewShiftX = shiftFactor * previewBitmap.getWidth();
+        float previewShiftY = shiftFactor * previewBitmap.getHeight();
+
+        c.setBitmap(previewBitmap);
+        c.translate(previewShiftX, previewShiftY);
+        icon.getPreviewItemManager().draw(c);
+        c.setBitmap(null);
+
+        // Initialize mask
+        Path mask = new Path();
+        Matrix m = new Matrix();
+        m.setTranslate(margin, margin);
+        bg.getClipPath().transform(m, mask);
+
+        ShiftedBitmapDrawable badge = new ShiftedBitmapDrawable(badgeBitmap, margin, margin);
+        ShiftedBitmapDrawable foreground = new ShiftedBitmapDrawable(previewBitmap,
+                margin - previewShiftX, margin - previewShiftY);
+
+        return new FolderAdaptiveIcon(new ColorDrawable(bg.getBgColor()), foreground, badge, mask);
+    }
+
+    /**
+     * A simple drawable which draws a bitmap at a fixed position irrespective of the bounds
+     */
+    private static class ShiftedBitmapDrawable extends Drawable {
+
+        private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+        private final Bitmap mBitmap;
+        private final float mShiftX;
+        private final float mShiftY;
+
+        ShiftedBitmapDrawable(Bitmap bitmap, float shiftX, float shiftY) {
+            mBitmap = bitmap;
+            mShiftX = shiftX;
+            mShiftY = shiftY;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            canvas.drawBitmap(mBitmap, mShiftX, mShiftY, mPaint);
+        }
+
+        @Override
+        public void setAlpha(int i) { }
+
+        @Override
+        public void setColorFilter(ColorFilter colorFilter) {
+            mPaint.setColorFilter(colorFilter);
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.TRANSLUCENT;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java b/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
index de614f0..baedf90 100644
--- a/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
+++ b/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
@@ -50,19 +50,26 @@
     private static final float FIT_WEIGHT_S = 1.0f;
     private static final float FIT_WEIGHT_L = 10.0f;
 
+    public static final int MAIN_COLOR_LIGHT = 0xffb0b0b0;
+    public static final int SECONDARY_COLOR_LIGHT = 0xff9e9e9e;
+    public static final int MAIN_COLOR_DARK = 0xff212121;
+    public static final int SECONDARY_COLOR_DARK = 0xff000000;
+
     // Temporary variable to avoid allocations
     private float[] mTmpHSL = new float[3];
 
-    public @Nullable Pair<Integer, Integer> extractInto(WallpaperColorsCompat inWallpaperColors) {
+    public Pair<Integer, Integer> extractInto(WallpaperColorsCompat inWallpaperColors) {
         if (inWallpaperColors == null) {
-            return null;
+            return applyFallback(inWallpaperColors);
         }
 
         final List<Integer> mainColors = getMainColors(inWallpaperColors);
         final int mainColorsSize = mainColors.size();
+        final boolean supportsDarkText = (inWallpaperColors.getColorHints() &
+                WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT) != 0;
 
         if (mainColorsSize == 0) {
-            return null;
+            return applyFallback(inWallpaperColors);
         }
         // Tonal is not really a sort, it takes a color from the extracted
         // palette and finds a best fit amongst a collection of pre-defined
@@ -86,7 +93,7 @@
 
         // Fail if not found
         if (bestColor == null) {
-            return null;
+            return applyFallback(inWallpaperColors);
         }
 
         int colorValue = bestColor;
@@ -101,14 +108,14 @@
         TonalPalette palette = findTonalPalette(hsl[0], hsl[1]);
         if (palette == null) {
             Log.w(TAG, "Could not find a tonal palette!");
-            return null;
+            return applyFallback(inWallpaperColors);
         }
 
         // Figure out what's the main color index in the optimal palette
         int fitIndex = bestFit(palette, hsl[0], hsl[1], hsl[2]);
         if (fitIndex == -1) {
             Log.w(TAG, "Could not find best fit!");
-            return null;
+            return applyFallback(inWallpaperColors);
         }
 
         // Generate the 10 colors palette by offsetting each one of them
@@ -117,28 +124,48 @@
         float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f);
         float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f);
 
-        final int textInversionIndex = h.length - 3;
+        int primaryIndex = fitIndex;
+        int mainColor = getColorInt(primaryIndex, h, s, l);
 
-        int primaryIndex;
-        int secondaryIndex;
+        // We might want use the fallback in case the extracted color is brighter than our
+        // light fallback or darker than our dark fallback.
+        ColorUtils.colorToHSL(mainColor, mTmpHSL);
+        final float mainLuminosity = mTmpHSL[2];
+        ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
+        final float lightLuminosity = mTmpHSL[2];
+        if (mainLuminosity > lightLuminosity) {
+            return applyFallback(inWallpaperColors);
+        }
+        ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
+        final float darkLuminosity = mTmpHSL[2];
+        if (mainLuminosity < darkLuminosity) {
+            return applyFallback(inWallpaperColors);
+        }
 
         // Dark colors:
         // Stops at 4th color, only lighter if dark text is supported
-        if (fitIndex < 2) {
-            primaryIndex = 0;
-        } else if (fitIndex < textInversionIndex) {
-            primaryIndex = Math.min(fitIndex, 3);
-        } else {
+        if (supportsDarkText) {
             primaryIndex = h.length - 1;
+        } else if (fitIndex < 2) {
+            primaryIndex = 0;
+        } else {
+            primaryIndex = Math.min(fitIndex, 3);
         }
-        secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
-
-        int mainColor = getColorInt(primaryIndex, h, s, l);
+        int secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
         int secondaryColor = getColorInt(secondaryIndex, h, s, l);
 
         return new Pair<>(mainColor, secondaryColor);
     }
 
+    public static Pair<Integer, Integer> applyFallback(WallpaperColorsCompat inWallpaperColors) {
+        boolean light = inWallpaperColors != null
+                && (inWallpaperColors.getColorHints()
+                    & WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT)!= 0;
+        int innerColor = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK;
+        int outerColor = light ? SECONDARY_COLOR_LIGHT : SECONDARY_COLOR_DARK;
+        return new Pair<>(innerColor, outerColor);
+    }
+
     private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) {
         mTmpHSL[0] = fract(h[fitIndex]) * 360.0f;
         mTmpHSL[1] = s[fitIndex];
diff --git a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
index 512e89a..80a89e3 100644
--- a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
+++ b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
@@ -81,9 +81,9 @@
         mSupportsDarkText = wallpaperColors != null
                 ? (wallpaperColors.getColorHints()
                     & WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT) > 0 : false;
-        float[] hsl = new float[3];
-        ColorUtils.colorToHSL(mMainColor, hsl);
-        mIsDark = hsl[2] < 0.2f;
+        mIsDark = wallpaperColors != null
+                ? (wallpaperColors.getColorHints()
+                    & WallpaperColorsCompat.HINT_SUPPORTS_DARK_THEME) > 0 : false;
     }
 
     public void setOnThemeChangeListener(OnThemeChangeListener onThemeChangeListener) {
diff --git a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
index ff357c0..f25345e 100644
--- a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
@@ -1,15 +1,18 @@
 package com.android.launcher3.folder;
 
+
 public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
 
     static final int MAX_NUM_ITEMS_IN_PREVIEW = 4;
     private static final int MIN_NUM_ITEMS_IN_PREVIEW = 2;
-    private static final int MAX_NUM_ITEMS_PER_ROW = 2;
 
-    final float MIN_SCALE = 0.48f;
-    final float MAX_SCALE = 0.58f;
-    final float MAX_RADIUS_DILATION = 0.15f;
-    final float ITEM_RADIUS_SCALE_FACTOR = 1.33f;
+    private static final float MIN_SCALE = 0.48f;
+    private static final float MAX_SCALE = 0.58f;
+    private static final float MAX_RADIUS_DILATION = 0.15f;
+    private static final float ITEM_RADIUS_SCALE_FACTOR = 1.33f;
+
+    private static final int EXIT_INDEX = -2;
+    private static final int ENTER_INDEX = -3;
 
     private float[] mTmpPoint = new float[2];
 
@@ -31,21 +34,29 @@
     @Override
     public PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
             PreviewItemDrawingParams params) {
-
         float totalScale = scaleForItem(index, curNumItems);
         float transX;
         float transY;
         float overlayAlpha = 0;
 
-        // Items beyond those displayed in the preview are animated to the center
-        if (index >= MAX_NUM_ITEMS_IN_PREVIEW) {
-            transX = transY = mAvailableSpace / 2 - (mIconSize * totalScale) / 2;
+        if (index == getExitIndex()) {
+            // 0 1 * <-- Exit position (row 0, col 2)
+            // 2 3
+            getGridPosition(0, 2, mTmpPoint);
+        } else if (index == getEnterIndex()) {
+            // 0 1
+            // 2 3 * <-- Enter position (row 1, col 2)
+            getGridPosition(1, 2, mTmpPoint);
+        } else if (index >= MAX_NUM_ITEMS_IN_PREVIEW) {
+            // Items beyond those displayed in the preview are animated to the center
+            mTmpPoint[0] = mTmpPoint[1] = mAvailableSpace / 2 - (mIconSize * totalScale) / 2;
         } else {
             getPosition(index, curNumItems, mTmpPoint);
-            transX = mTmpPoint[0];
-            transY = mTmpPoint[1];
         }
 
+        transX = mTmpPoint[0];
+        transY = mTmpPoint[1];
+
         if (params == null) {
             params = new PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
         } else {
@@ -55,6 +66,27 @@
         return params;
     }
 
+    /**
+     * Builds a grid based on the positioning of the items when there are
+     * {@link #MAX_NUM_ITEMS_IN_PREVIEW} in the preview.
+     *
+     * Positions in the grid: 0 1  // 0 is row 0, col 1
+     *                        2 3  // 3 is row 1, col 1
+     */
+    private void getGridPosition(int row, int col, float[] result) {
+        // We use position 0 and 3 to calculate the x and y distances between items.
+        getPosition(0, 4, result);
+        float left = result[0];
+        float top = result[1];
+
+        getPosition(3, 4, result);
+        float dx = result[0] - left;
+        float dy = result[1] - top;
+
+        result[0] = left + (col * dx);
+        result[1] = top + (row * dy);
+    }
+
     private void getPosition(int index, int curNumItems, float[] result) {
         // The case of two items is homomorphic to the case of one.
         curNumItems = Math.max(curNumItems, 2);
@@ -127,4 +159,19 @@
     public boolean clipToBackground() {
         return true;
     }
+
+    @Override
+    public boolean hasEnterExitIndices() {
+        return true;
+    }
+
+    @Override
+    public int getExitIndex() {
+        return EXIT_INDEX;
+    }
+
+    @Override
+    public int getEnterIndex() {
+        return ENTER_INDEX;
+    }
 }
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 3c7c698..85792d4 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -791,12 +791,15 @@
         if (mFolderIcon != null) {
             mFolderIcon.setVisibility(View.VISIBLE);
             if (FeatureFlags.LAUNCHER3_NEW_FOLDER_ANIMATION) {
-                mFolderIcon.mFolderName.setTextVisibility(true);
                 mFolderIcon.setBackgroundVisible(true);
-                mFolderIcon.mBackground.fadeInBackgroundShadow();
+                mFolderIcon.mFolderName.setTextVisibility(true);
             }
             if (wasAnimated) {
-                mFolderIcon.mBackground.animateBackgroundStroke();
+                if (FeatureFlags.LAUNCHER3_NEW_FOLDER_ANIMATION) {
+                    mFolderIcon.mBackground.fadeInBackgroundShadow();
+                    mFolderIcon.mBackground.animateBackgroundStroke();
+                    mFolderIcon.onFolderClose(mContent.getCurrentPage());
+                }
                 if (mFolderIcon.hasBadge()) {
                     mFolderIcon.createBadgeScaleAnimator(0f, 1f).start();
                 }
@@ -818,6 +821,7 @@
         mSuppressFolderDeletion = false;
         clearDragInfo();
         mState = STATE_SMALL;
+        mContent.setCurrentPage(0);
     }
 
     public boolean acceptDrop(DragObject d) {
@@ -1280,7 +1284,7 @@
         };
         View finalChild = mContent.getLastItem();
         if (finalChild != null) {
-            mFolderIcon.performDestroyAnimation(finalChild, onCompleteRunnable);
+            mFolderIcon.performDestroyAnimation(onCompleteRunnable);
         } else {
             onCompleteRunnable.run();
         }
@@ -1355,8 +1359,11 @@
         }
         mContent.completePendingPageChanges();
 
-        if (d.dragInfo instanceof PendingAddShortcutInfo) {
-            PendingAddShortcutInfo pasi = (PendingAddShortcutInfo) d.dragInfo;
+        PendingAddShortcutInfo pasi = d.dragInfo instanceof PendingAddShortcutInfo
+                ? (PendingAddShortcutInfo) d.dragInfo : null;
+        ShortcutInfo pasiSi = pasi != null ? pasi.activityInfo.createShortcutInfo() : null;
+        if (pasi != null && pasiSi == null) {
+            // There is no ShortcutInfo, so we have to go through a configuration activity.
             pasi.container = mInfo.id;
             pasi.rank = mEmptyCellRank;
 
@@ -1366,7 +1373,9 @@
             mRearrangeOnClose = true;
         } else {
             final ShortcutInfo si;
-            if (d.dragInfo instanceof AppInfo) {
+            if (pasiSi != null) {
+                si = pasiSi;
+            } else if (d.dragInfo instanceof AppInfo) {
                 // Came from all apps -- make a copy.
                 si = ((AppInfo) d.dragInfo).makeShortcut();
             } else {
@@ -1513,18 +1522,17 @@
         return mItemsInReadingOrder;
     }
 
-    public List<BubbleTextView> getItemsOnCurrentPage() {
+    public List<BubbleTextView> getItemsOnPage(int page) {
         ArrayList<View> allItems = getItemsInReadingOrder();
-        int currentPage = mContent.getCurrentPage();
         int lastPage = mContent.getPageCount() - 1;
         int totalItemsInFolder = allItems.size();
         int itemsPerPage = mContent.itemsPerPage();
-        int numItemsOnCurrentPage = currentPage == lastPage
-                ? totalItemsInFolder - (itemsPerPage * currentPage)
+        int numItemsOnCurrentPage = page == lastPage
+                ? totalItemsInFolder - (itemsPerPage * page)
                 : itemsPerPage;
 
-        int startIndex = currentPage * itemsPerPage;
-        int endIndex = startIndex + numItemsOnCurrentPage;
+        int startIndex = page * itemsPerPage;
+        int endIndex = Math.min(startIndex + numItemsOnCurrentPage, allItems.size());
 
         List<BubbleTextView> itemsOnCurrentPage = new ArrayList<>(numItemsOnCurrentPage);
         for (int i = startIndex; i < endIndex; ++i) {
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 3648c60..69705d5 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -69,7 +69,8 @@
     private final int mDelay;
 
     private final TimeInterpolator mFolderInterpolator;
-    private final TimeInterpolator mLargeFolderPreviewItemInterpolator;
+    private final TimeInterpolator mLargeFolderPreviewItemOpenInterpolator;
+    private final TimeInterpolator mLargeFolderPreviewItemCloseInterpolator;
 
     private final PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
 
@@ -105,8 +106,10 @@
 
         mFolderInterpolator = AnimationUtils.loadInterpolator(mContext,
                 R.interpolator.folder_interpolator);
-        mLargeFolderPreviewItemInterpolator = AnimationUtils.loadInterpolator(mContext,
-                R.interpolator.large_folder_preview_item_interpolator);
+        mLargeFolderPreviewItemOpenInterpolator = AnimationUtils.loadInterpolator(mContext,
+                R.interpolator.large_folder_preview_item_open_interpolator);
+        mLargeFolderPreviewItemCloseInterpolator = AnimationUtils.loadInterpolator(mContext,
+                R.interpolator.large_folder_preview_item_close_interpolator);
     }
 
 
@@ -116,13 +119,14 @@
     public AnimatorSet getAnimator() {
         final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) mFolder.getLayoutParams();
         FolderIcon.PreviewLayoutRule rule = mFolderIcon.getLayoutRule();
-        final List<BubbleTextView> itemsInPreview = mFolderIcon.getItemsToDisplay();
+        final List<BubbleTextView> itemsInPreview = mFolderIcon.getPreviewItems();
 
         // Match position of the FolderIcon
         final Rect folderIconPos = new Rect();
         float scaleRelativeToDragLayer = mLauncher.getDragLayer()
                 .getDescendantRectRelativeToSelf(mFolderIcon, folderIconPos);
-        float initialSize = (mFolderIcon.mBackground.getRadius() * 2) * scaleRelativeToDragLayer;
+        int scaledRadius = mPreviewBackground.getScaledRadius();
+        float initialSize = (scaledRadius * 2) * scaleRelativeToDragLayer;
 
         // Match size/scale of icons in the preview
         float previewScale = rule.scaleForItem(0, itemsInPreview.size());
@@ -149,14 +153,9 @@
         final int paddingOffsetY = (int) ((mFolder.getPaddingTop() + mContent.getPaddingTop())
                 * initialScale);
 
-        // Background can have a scaled radius in drag and drop mode.
-        int radiusDiff = mFolderIcon.mBackground.getScaledRadius()
-                - mFolderIcon.mBackground.getRadius();
-
-        int initialX = folderIconPos.left + mFolderIcon.mBackground.getOffsetX() - paddingOffsetX
-                - previewItemOffsetX + radiusDiff;
-        int initialY = folderIconPos.top + mFolderIcon.mBackground.getOffsetY() - paddingOffsetY
-                + radiusDiff;
+        int initialX = folderIconPos.left + mPreviewBackground.getOffsetX() - paddingOffsetX
+                - previewItemOffsetX;
+        int initialY = folderIconPos.top + mPreviewBackground.getOffsetY() - paddingOffsetY;
         final float xDistance = initialX - lp.x;
         final float yDistance = initialY - lp.y;
 
@@ -181,10 +180,10 @@
         AnimatorSet a = LauncherAnimUtils.createAnimatorSet();
 
         // Initialize the Folder items' text.
-        PropertyResetListener colorResetListener = new PropertyResetListener(
+        PropertyResetListener colorResetListener = new PropertyResetListener<>(
                 BubbleTextView.TEXT_ALPHA_PROPERTY,
                 Color.alpha(Themes.getAttrColor(mContext, android.R.attr.textColorSecondary)));
-        for (BubbleTextView icon : mFolder.getItemsOnCurrentPage()) {
+        for (BubbleTextView icon : mFolder.getItemsOnPage(mFolder.mContent.getCurrentPage())) {
             if (mIsOpening) {
                 icon.setTextVisibility(false);
             }
@@ -198,13 +197,19 @@
         play(a, getAnimator(mFolder, SCALE_PROPERTY, initialScale, finalScale));
         play(a, getAnimator(mFolderBackground, "color", initialColor, finalColor));
         play(a, mFolderIcon.mFolderName.createTextAlphaAnimator(!mIsOpening));
-        play(a, new RoundedRectRevealOutlineProvider(initialRadius, finalRadius, startRect,
-                endRect).createRevealAnimator(mFolder, !mIsOpening));
+        RoundedRectRevealOutlineProvider outlineProvider = new RoundedRectRevealOutlineProvider(
+                initialRadius, finalRadius, startRect, endRect) {
+            @Override
+            public boolean shouldRemoveElevationDuringAnimation() {
+                return true;
+            }
+        };
+        play(a, outlineProvider.createRevealAnimator(mFolder, !mIsOpening));
 
         // Animate the elevation midway so that the shadow is not noticeable in the background.
         int midDuration = mDuration / 2;
         Animator z = getAnimator(mFolder, View.TRANSLATION_Z, -mFolder.getElevation(), 0);
-        play(a, z, midDuration, midDuration);
+        play(a, z, mIsOpening ? midDuration : 0, midDuration);
 
         a.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -224,18 +229,28 @@
             animator.setInterpolator(mFolderInterpolator);
         }
 
-        addPreviewItemAnimators(a, initialScale / scaleRelativeToDragLayer, previewItemOffsetX);
+        int radiusDiff = scaledRadius - mPreviewBackground.getRadius();
+        addPreviewItemAnimators(a, initialScale / scaleRelativeToDragLayer,
+                // Background can have a scaled radius in drag and drop mode, so we need to add the
+                // difference to keep the preview items centered.
+                previewItemOffsetX + radiusDiff, radiusDiff);
         return a;
     }
 
     /**
-     * Animate the items that are displayed in the preview.
+     * Animate the items on the current page.
      */
     private void addPreviewItemAnimators(AnimatorSet animatorSet, final float folderScale,
-            int previewItemOffsetX) {
+            int previewItemOffsetX, int previewItemOffsetY) {
         FolderIcon.PreviewLayoutRule rule = mFolderIcon.getLayoutRule();
-        final List<BubbleTextView> itemsInPreview = mFolderIcon.getItemsToDisplay();
+        boolean isOnFirstPage = mFolder.mContent.getCurrentPage() == 0;
+        final List<BubbleTextView> itemsInPreview = isOnFirstPage
+                ? mFolderIcon.getPreviewItems()
+                : mFolderIcon.getPreviewItemsOnPage(mFolder.mContent.getCurrentPage());
         final int numItemsInPreview = itemsInPreview.size();
+        final int numItemsInFirstPagePreview = isOnFirstPage
+                ? numItemsInPreview
+                : FolderIcon.NUM_ITEMS_IN_PREVIEW;
 
         TimeInterpolator previewItemInterpolator = getPreviewItemInterpolator();
 
@@ -248,8 +263,8 @@
             btvLp.isLockedToGrid = true;
             cwc.setupLp(btv);
 
-            // Match scale of icons in the preview.
-            float previewScale = rule.scaleForItem(i, numItemsInPreview);
+            // Match scale of icons in the preview of the items on the first page.
+            float previewScale = rule.scaleForItem(i, numItemsInFirstPagePreview);
             float previewSize = rule.getIconSize() * previewScale;
             float iconScale = previewSize / itemsInPreview.get(i).getIconSize();
 
@@ -260,14 +275,14 @@
             btv.setScaleY(scale);
 
             // Match positions of the icons in the folder with their positions in the preview
-            rule.computePreviewItemDrawingParams(i, numItemsInPreview, mTmpParams);
+            rule.computePreviewItemDrawingParams(i, numItemsInFirstPagePreview, mTmpParams);
             // The PreviewLayoutRule assumes that the icon size takes up the entire width so we
             // offset by the actual size.
             int iconOffsetX = (int) ((btvLp.width - btv.getIconSize()) * iconScale) / 2;
 
             final int previewPosX =
                     (int) ((mTmpParams.transX - iconOffsetX + previewItemOffsetX) / folderScale);
-            final int previewPosY = (int) (mTmpParams.transY / folderScale);
+            final int previewPosY = (int) ((mTmpParams.transY + previewItemOffsetY) / folderScale);
 
             final float xDistance = previewPosX - btvLp.x;
             final float yDistance = previewPosY - btvLp.y;
@@ -287,14 +302,15 @@
             if (mFolder.getItemCount() > FolderIcon.NUM_ITEMS_IN_PREVIEW) {
                 // These delays allows the preview items to move as part of the Folder's motion,
                 // and its only necessary for large folders because of differing interpolators.
+                int delay = mIsOpening ? mDelay : mDelay * 2;
                 if (mIsOpening) {
-                    translationX.setStartDelay(mDelay);
-                    translationY.setStartDelay(mDelay);
-                    scaleAnimator.setStartDelay(mDelay);
+                    translationX.setStartDelay(delay);
+                    translationY.setStartDelay(delay);
+                    scaleAnimator.setStartDelay(delay);
                 }
-                translationX.setDuration(translationX.getDuration() - mDelay);
-                translationY.setDuration(translationY.getDuration() - mDelay);
-                scaleAnimator.setDuration(scaleAnimator.getDuration() - mDelay);
+                translationX.setDuration(translationX.getDuration() - delay);
+                translationY.setDuration(translationY.getDuration() - delay);
+                scaleAnimator.setDuration(scaleAnimator.getDuration() - delay);
             }
 
             animatorSet.addListener(new AnimatorListenerAdapter() {
@@ -337,7 +353,9 @@
             // With larger folders, we want the preview items to reach their final positions faster
             // (when opening) and later (when closing) so that they appear aligned with the rest of
             // the folder items when they are both visible.
-            return mLargeFolderPreviewItemInterpolator;
+            return mIsOpening
+                    ? mLargeFolderPreviewItemOpenInterpolator
+                    : mLargeFolderPreviewItemCloseInterpolator;
         }
         return mFolderInterpolator;
     }
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 1cc285e..6533b04 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -37,7 +37,6 @@
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
-import android.widget.TextView;
 
 import com.android.launcher3.Alarm;
 import com.android.launcher3.AppInfo;
@@ -71,6 +70,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMATION_DURATION;
+
 /**
  * An icon that can appear on in the workspace representing an {@link Folder}.
  */
@@ -87,9 +88,7 @@
     private CheckLongPressHelper mLongPressHelper;
     private StylusEventHelper mStylusEventHelper;
 
-    private static final int DROP_IN_ANIMATION_DURATION = 400;
-    private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
-    private static final int FINAL_ITEM_ANIMATION_DURATION = 200;
+    static final int DROP_IN_ANIMATION_DURATION = 400;
 
     // Flag whether the folder should open itself when an item is dragged over is enabled.
     public static final boolean SPRING_LOADING_ENABLED = true;
@@ -99,27 +98,19 @@
 
     @Thunk BubbleTextView mFolderName;
 
-    // These variables are all associated with the drawing of the preview; they are stored
-    // as member variables for shared usage and to avoid computation on each frame
-    private float mIntrinsicIconSize = -1;
-    private int mTotalWidth = -1;
-    private int mPrevTopPadding = -1;
-
     PreviewBackground mBackground = new PreviewBackground();
     private boolean mBackgroundIsVisible = true;
 
-    private PreviewLayoutRule mPreviewLayoutRule;
+    FolderIconPreviewVerifier mPreviewVerifier;
+    PreviewLayoutRule mPreviewLayoutRule;
+    private PreviewItemManager mPreviewItemManager;
+    private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
 
     boolean mAnimating = false;
     private Rect mTempBounds = new Rect();
 
     private float mSlop;
 
-    FolderIconPreviewVerifier mPreviewVerifier;
-    private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
-    private ArrayList<PreviewItemDrawingParams> mDrawingParams = new ArrayList<>();
-    private Drawable mReferenceDrawable = null;
-
     private Alarm mOpenAlarm = new Alarm();
 
     private FolderBadgeInfo mBadgeInfo = new FolderBadgeInfo();
@@ -158,6 +149,7 @@
                 new StackFolderIconLayoutRule() :
                 new ClippedFolderIconLayoutRule();
         mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        mPreviewItemManager = new PreviewItemManager(this);
     }
 
     public static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
@@ -213,7 +205,7 @@
     private void setFolder(Folder folder) {
         mFolder = folder;
         mPreviewVerifier = new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv);
-        updateItemDrawingParams(false);
+        mPreviewItemManager.updateItemDrawingParams(false);
     }
 
     private boolean willAcceptItem(ItemInfo item) {
@@ -229,7 +221,15 @@
     }
 
     public void addItem(ShortcutInfo item) {
-        mInfo.add(item, true);
+        addItem(item, true);
+    }
+
+    public void addItem(ShortcutInfo item, boolean animate) {
+        mInfo.add(item, animate);
+    }
+
+    public void removeItem(ShortcutInfo item, boolean animate) {
+        mInfo.remove(item, animate);
     }
 
     public void onDragEnter(ItemInfo dragInfo) {
@@ -254,40 +254,28 @@
         }
     };
 
-    public Drawable prepareCreate(final View destView) {
-        Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
-        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
-                destView.getMeasuredWidth());
-        return animateDrawable;
+    public Drawable prepareCreateAnimation(final View destView) {
+        return mPreviewItemManager.prepareCreateAnimation(destView);
     }
 
     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 = prepareCreate(destView);
-
-        mReferenceDrawable = animateDrawable;
-
+        prepareCreateAnimation(destView);
         addItem(destInfo);
         // This will animate the first item from it's position as an icon into its
         // position as the first item in the preview
-        animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION, false, null);
+        mPreviewItemManager.createFirstItemAnimation(false /* reverse */, null)
+                .start();
 
         // This will animate the dragView (srcView) into the new folder
         onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable);
     }
 
-    public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) {
-        Drawable animateDrawable = ((TextView) finalView).getCompoundDrawables()[1];
-        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
-                finalView.getMeasuredWidth());
-
-        // This will animate the first item from it's position as an icon into its
-        // position as the first item in the preview
-        animateFirstItem(animateDrawable, FINAL_ITEM_ANIMATION_DURATION, true,
-                onCompleteRunnable);
+    public void performDestroyAnimation(Runnable onCompleteRunnable) {
+        // This will animate the final item in the preview to be full size.
+        mPreviewItemManager.createFirstItemAnimation(true /* reverse */, onCompleteRunnable)
+                .start();
     }
 
     public void onDragExit() {
@@ -324,13 +312,39 @@
                 workspace.resetTransitionTransform((CellLayout) getParent().getParent());
             }
 
+            boolean itemAdded = false;
+            if (index >= mPreviewLayoutRule.maxNumItems()
+                    && mPreviewLayoutRule.hasEnterExitIndices()) {
+                List<BubbleTextView> oldPreviewItems = getPreviewItemsOnPage(0);
+                addItem(item, false);
+                List<BubbleTextView> newPreviewItems = getPreviewItemsOnPage(0);
+
+                if (!oldPreviewItems.containsAll(newPreviewItems)) {
+                    for (int i = 0; i < newPreviewItems.size(); ++i) {
+                        if (newPreviewItems.get(i).getTag().equals(item)) {
+                            // If the item dropped is going to be in the preview, we update the
+                            // index here to reflect its position in the preview.
+                            index = i;
+                        }
+                    }
+                    mPreviewItemManager.onDrop(oldPreviewItems, newPreviewItems, item);
+                    itemAdded = true;
+                } else {
+                    removeItem(item, false);
+                }
+            }
+
+            if (!itemAdded) {
+                addItem(item);
+            }
+
             int[] center = new int[2];
             float scale = getLocalCenterForIndex(index, index + 1, center);
             center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]);
             center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]);
 
             to.offset(center[0] - animateView.getMeasuredWidth() / 2,
-                      center[1] - animateView.getMeasuredHeight() / 2);
+                    center[1] - animateView.getMeasuredHeight() / 2);
 
             float finalAlpha = index < mPreviewLayoutRule.maxNumItems() ? 0.5f : 0f;
 
@@ -339,15 +353,14 @@
                     1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
                     new DecelerateInterpolator(2), new AccelerateInterpolator(2),
                     postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
-            addItem(item);
+
             mFolder.hideItem(item);
 
-            final PreviewItemDrawingParams params = index < mDrawingParams.size() ?
-                    mDrawingParams.get(index) : null;
-            if (params != null) params.hidden = true;
+            if (!itemAdded) mPreviewItemManager.hidePreviewItem(index, true);
+            final int finalIndex = index;
             postDelayed(new Runnable() {
                 public void run() {
-                    if (params != null) params.hidden = false;
+                    mPreviewItemManager.hidePreviewItem(finalIndex, false);
                     mFolder.showItem(item);
                     invalidate();
                 }
@@ -369,25 +382,6 @@
         onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable);
     }
 
-    private void computePreviewDrawingParams(int drawableSize, int totalSize) {
-        if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize ||
-                mPrevTopPadding != getPaddingTop()) {
-            mIntrinsicIconSize = drawableSize;
-            mTotalWidth = totalSize;
-            mPrevTopPadding = getPaddingTop();
-
-            mBackground.setup(mLauncher, this, mTotalWidth, getPaddingTop());
-            mPreviewLayoutRule.init(mBackground.previewSize, mIntrinsicIconSize,
-                    Utilities.isRtl(getResources()));
-
-            updateItemDrawingParams(false);
-        }
-    }
-
-    private void computePreviewDrawingParams(Drawable d) {
-        computePreviewDrawingParams(d.getIntrinsicWidth(), getMeasuredWidth());
-    }
-
     public void setBadgeInfo(FolderBadgeInfo badgeInfo) {
         updateBadgeScale(mBadgeInfo.hasBadge(), badgeInfo.hasBadge());
         mBadgeInfo = badgeInfo;
@@ -421,56 +415,21 @@
     }
 
     private float getLocalCenterForIndex(int index, int curNumItems, int[] center) {
-        mTmpParams = computePreviewItemDrawingParams(
+        mTmpParams = mPreviewItemManager.computePreviewItemDrawingParams(
                 Math.min(mPreviewLayoutRule.maxNumItems(), index), curNumItems, mTmpParams);
 
         mTmpParams.transX += mBackground.basePreviewOffsetX;
         mTmpParams.transY += mBackground.basePreviewOffsetY;
-        float offsetX = mTmpParams.transX + (mTmpParams.scale * mIntrinsicIconSize) / 2;
-        float offsetY = mTmpParams.transY + (mTmpParams.scale * mIntrinsicIconSize) / 2;
+
+        float intrinsicIconSize = mPreviewItemManager.getIntrinsicIconSize();
+        float offsetX = mTmpParams.transX + (mTmpParams.scale * intrinsicIconSize) / 2;
+        float offsetY = mTmpParams.transY + (mTmpParams.scale * intrinsicIconSize) / 2;
 
         center[0] = Math.round(offsetX);
         center[1] = Math.round(offsetY);
         return mTmpParams.scale;
     }
 
-    PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
-            PreviewItemDrawingParams params) {
-        // We use an index of -1 to represent an icon on the workspace for the destroy and
-        // create animations
-        if (index == -1) {
-            return getFinalIconParams(params);
-        }
-        return mPreviewLayoutRule.computePreviewItemDrawingParams(index, curNumItems, params);
-    }
-
-    private PreviewItemDrawingParams getFinalIconParams(PreviewItemDrawingParams params) {
-        float iconSize = mLauncher.getDeviceProfile().iconSizePx;
-
-        final float scale = iconSize / mReferenceDrawable.getIntrinsicWidth();
-        final float trans = (mBackground.previewSize - iconSize) / 2;
-
-        params.update(trans, trans, scale);
-        return params;
-    }
-
-    private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
-        canvas.save(Canvas.MATRIX_SAVE_FLAG);
-        canvas.translate(params.transX, params.transY);
-        canvas.scale(params.scale, params.scale);
-        Drawable d = params.drawable;
-
-        if (d != null) {
-            Rect bounds = d.getBounds();
-            canvas.save();
-            canvas.translate(-bounds.left, -bounds.top);
-            canvas.scale(mIntrinsicIconSize / bounds.width(), mIntrinsicIconSize / bounds.height());
-            d.draw(canvas);
-            canvas.restore();
-        }
-        canvas.restore();
-    }
-
     public void setFolderBackground(PreviewBackground bg) {
         mBackground = bg;
         mBackground.setInvalidateDelegate(this);
@@ -481,15 +440,21 @@
         invalidate();
     }
 
+    public PreviewBackground getFolderBackground() {
+        return mBackground;
+    }
+
+    public PreviewItemManager getPreviewItemManager() {
+        return mPreviewItemManager;
+    }
+
     @Override
     protected void dispatchDraw(Canvas canvas) {
         super.dispatchDraw(canvas);
 
         if (!mBackgroundIsVisible) return;
 
-        if (mReferenceDrawable != null) {
-            computePreviewDrawingParams(mReferenceDrawable);
-        }
+        mPreviewItemManager.recomputePreviewDrawingParams();
 
         if (!mBackground.drawingDelegated()) {
             mBackground.drawBackground(canvas);
@@ -506,21 +471,11 @@
         } else {
             saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
             if (mPreviewLayoutRule.clipToBackground()) {
-                mBackground.clipCanvasSoftware(canvas, Region.Op.INTERSECT);
+                canvas.clipPath(mBackground.getClipPath(), Region.Op.INTERSECT);
             }
         }
 
-        // The items are drawn in coordinates relative to the preview offset
-        canvas.translate(mBackground.basePreviewOffsetX, mBackground.basePreviewOffsetY);
-
-        // The first item should be drawn last (ie. on top of later items)
-        for (int i = mDrawingParams.size() - 1; i >= 0; i--) {
-            PreviewItemDrawingParams p = mDrawingParams.get(i);
-            if (!p.hidden) {
-                drawPreviewItem(canvas, p);
-            }
-        }
-        canvas.translate(-mBackground.basePreviewOffsetX, -mBackground.basePreviewOffsetY);
+        mPreviewItemManager.draw(canvas);
 
         if (mPreviewLayoutRule.clipToBackground() && canvas.isHardwareAccelerated()) {
             mBackground.clipCanvasHardware(canvas);
@@ -531,6 +486,10 @@
             mBackground.drawBackgroundStroke(canvas);
         }
 
+        drawBadge(canvas);
+    }
+
+    public void drawBadge(Canvas canvas) {
         if ((mBadgeInfo != null && mBadgeInfo.hasBadge()) || mBadgeScale > 0) {
             int offsetX = mBackground.getOffsetX();
             int offsetY = mBackground.getOffsetY();
@@ -546,19 +505,6 @@
         }
     }
 
-    private void animateFirstItem(final Drawable d, int duration, final boolean reverse,
-            final Runnable onCompleteRunnable) {
-        FolderPreviewItemAnim anim;
-        if (!reverse) {
-            anim = new FolderPreviewItemAnim(this, mDrawingParams.get(0), -1, -1, 0, 2, duration,
-                    onCompleteRunnable);
-        } else {
-            anim = new FolderPreviewItemAnim(this, mDrawingParams.get(0), 0, 2, -1, -1, duration,
-                    onCompleteRunnable);
-        }
-        anim.start();
-    }
-
     public void setTextVisible(boolean visible) {
         if (visible) {
             mFolderName.setVisibility(VISIBLE);
@@ -571,15 +517,25 @@
         return mFolderName.getVisibility() == VISIBLE;
     }
 
-    public List<BubbleTextView> getItemsToDisplay() {
+    /**
+     * Returns the list of preview items displayed in the icon.
+     */
+    public List<BubbleTextView> getPreviewItems() {
+        return getPreviewItemsOnPage(0);
+    }
+
+    /**
+     * Returns the list of "preview items" on {@param page}.
+     */
+    public List<BubbleTextView> getPreviewItemsOnPage(int page) {
         mPreviewVerifier.setFolderInfo(mFolder.getInfo());
 
         List<BubbleTextView> itemsToDisplay = new ArrayList<>();
-        List<View> allItems = mFolder.getItemsInReadingOrder();
-        int numItems = allItems.size();
+        List<BubbleTextView> itemsOnPage = mFolder.getItemsOnPage(page);
+        int numItems = itemsOnPage.size();
         for (int rank = 0; rank < numItems; ++rank) {
-            if (mPreviewVerifier.isItemInPreview(rank)) {
-                itemsToDisplay.add((BubbleTextView) allItems.get(rank));
+            if (mPreviewVerifier.isItemInPreview(page, rank)) {
+                itemsToDisplay.add(itemsOnPage.get(rank));
             }
 
             if (itemsToDisplay.size() == FolderIcon.NUM_ITEMS_IN_PREVIEW) {
@@ -591,63 +547,12 @@
 
     @Override
     protected boolean verifyDrawable(@NonNull Drawable who) {
-        for (int i = 0; i < mDrawingParams.size(); i++) {
-            if (mDrawingParams.get(i).drawable == who) {
-                return true;
-            }
-        }
-        return super.verifyDrawable(who);
-    }
-
-    private void updateItemDrawingParams(boolean animate) {
-        List<BubbleTextView> items = getItemsToDisplay();
-        int nItemsInPreview = items.size();
-
-        int prevNumItems = mDrawingParams.size();
-
-        // We adjust the size of the list to match the number of items in the preview
-        while (nItemsInPreview < mDrawingParams.size()) {
-            mDrawingParams.remove(mDrawingParams.size() - 1);
-        }
-        while (nItemsInPreview > mDrawingParams.size()) {
-            mDrawingParams.add(new PreviewItemDrawingParams(0, 0, 0, 0));
-        }
-
-        for (int i = 0; i < mDrawingParams.size(); i++) {
-            PreviewItemDrawingParams p = mDrawingParams.get(i);
-            p.drawable = items.get(i).getCompoundDrawables()[1];
-
-            if (p.drawable != null && !mFolder.isOpen()) {
-                // Set the callback to FolderIcon as it is responsible to drawing the icon. The
-                // callback will be release when the folder is opened.
-                p.drawable.setCallback(this);
-            }
-
-            if (!animate || FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON) {
-                computePreviewItemDrawingParams(i, nItemsInPreview, p);
-                if (mReferenceDrawable == null) {
-                    mReferenceDrawable = p.drawable;
-                }
-            } else {
-                FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, i, prevNumItems, i,
-                        nItemsInPreview, DROP_IN_ANIMATION_DURATION, null);
-
-                if (p.anim != null) {
-                    if (p.anim.hasEqualFinalState(anim)) {
-                        // do nothing, let the current animation finish
-                        continue;
-                    }
-                    p.anim.cancel();
-                }
-                p.anim = anim;
-                p.anim.start();
-            }
-        }
+        return mPreviewItemManager.verifyDrawable(who) || super.verifyDrawable(who);
     }
 
     @Override
     public void onItemsChanged(boolean animate) {
-        updateItemDrawingParams(animate);
+        mPreviewItemManager.updateItemDrawingParams(animate);
         invalidate();
         requestLayout();
     }
@@ -790,13 +695,22 @@
         }
     }
 
+    public void onFolderClose(int currentPage) {
+        mPreviewItemManager.onFolderClose(currentPage);
+    }
+
     interface PreviewLayoutRule {
         PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
-            PreviewItemDrawingParams params);
+                PreviewItemDrawingParams params);
         void init(int availableSpace, float intrinsicIconSize, boolean rtl);
         float scaleForItem(int index, int totalNumItems);
         float getIconSize();
         int maxNumItems();
         boolean clipToBackground();
+
+        boolean hasEnterExitIndices();
+        int getExitIndex();
+        int getEnterIndex();
+
     }
 }
diff --git a/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java b/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java
index de962b0..d054a5d 100644
--- a/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java
+++ b/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java
@@ -41,20 +41,31 @@
 
     public void setFolderInfo(FolderInfo info) {
         int numItemsInFolder = info.contents.size();
+        FolderPagedView.calculateGridSize(numItemsInFolder, 0, 0, mMaxGridCountX,
+                mMaxGridCountY, mMaxItemsPerPage, mGridSize);
+        mGridCountX = mGridSize[0];
+
         mDisplayingUpperLeftQuadrant = FeatureFlags.LAUNCHER3_NEW_FOLDER_ANIMATION
                 && !FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON
                 && numItemsInFolder > FolderIcon.NUM_ITEMS_IN_PREVIEW;
-
-        if (mDisplayingUpperLeftQuadrant) {
-            FolderPagedView.calculateGridSize(info.contents.size(), 0, 0, mMaxGridCountX,
-                    mMaxGridCountY, mMaxItemsPerPage, mGridSize);
-            mGridCountX = mGridSize[0];
-        }
     }
 
+    /**
+     * Returns whether the item with {@param rank} is in the default Folder icon preview.
+     */
     public boolean isItemInPreview(int rank) {
-        if (mDisplayingUpperLeftQuadrant) {
-            // Returns true iff the icon is in the 2x2 upper left quadrant of the Folder.
+        return isItemInPreview(0, rank);
+    }
+
+    /**
+     * @param page The page the item is on.
+     * @param rank The rank of the item.
+     * @return True iff the icon is in the 2x2 upper left quadrant of the Folder.
+     */
+    public boolean isItemInPreview(int page, int rank) {
+        // First page items are laid out such that the first 4 items are always in the upper
+        // left quadrant. For all other pages, we need to check the row and col.
+        if (page > 0 || mDisplayingUpperLeftQuadrant) {
             int col = rank % mGridCountX;
             int row = rank / mGridCountX;
             return col < 2 && row < 2;
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index d0ac9f4..f4ac0a1 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -494,8 +494,8 @@
     }
 
     @Override
-    protected void notifyPageSwitchListener() {
-        super.notifyPageSwitchListener();
+    protected void notifyPageSwitchListener(int prevPage) {
+        super.notifyPageSwitchListener(prevPage);
         if (mFolder != null) {
             mFolder.updateTextViewFocus();
         }
@@ -701,10 +701,4 @@
     public int itemsPerPage() {
         return mMaxItemsPerPage;
     }
-
-    @Override
-    protected void getEdgeVerticalPosition(int[] pos) {
-        pos[0] = 0;
-        pos[1] = getViewportHeight();
-    }
 }
diff --git a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
index 0da7c5c..be075bc 100644
--- a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
+++ b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
@@ -25,16 +25,16 @@
  * Animates a Folder preview item.
  */
 class FolderPreviewItemAnim {
+
+    private static PreviewItemDrawingParams sTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+
     private ValueAnimator mValueAnimator;
 
     float finalScale;
     float finalTransX;
     float finalTransY;
 
-    private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
-
     /**
-     * @param folderIcon The FolderIcon this preview will be drawn in.
      * @param params layout params to animate
      * @param index0 original index of the item to be animated
      * @param items0 original number of items in the preview
@@ -43,20 +43,20 @@
      * @param duration duration in ms of the animation
      * @param onCompleteRunnable runnable to execute upon animation completion
      */
-    FolderPreviewItemAnim(final FolderIcon folderIcon, final PreviewItemDrawingParams params,
-            int index0, int items0, int index1, int items1, int duration,
-            final Runnable onCompleteRunnable) {
-        folderIcon.computePreviewItemDrawingParams(index1, items1, mTmpParams);
+    FolderPreviewItemAnim(final PreviewItemManager previewItemManager,
+            final PreviewItemDrawingParams params, int index0, int items0, int index1, int items1,
+            int duration, final Runnable onCompleteRunnable) {
+        previewItemManager.computePreviewItemDrawingParams(index1, items1, sTmpParams);
 
-        finalScale = mTmpParams.scale;
-        finalTransX = mTmpParams.transX;
-        finalTransY = mTmpParams.transY;
+        finalScale = sTmpParams.scale;
+        finalTransX = sTmpParams.transX;
+        finalTransY = sTmpParams.transY;
 
-        folderIcon.computePreviewItemDrawingParams(index0, items0, mTmpParams);
+        previewItemManager.computePreviewItemDrawingParams(index0, items0, sTmpParams);
 
-        final float scale0 = mTmpParams.scale;
-        final float transX0 = mTmpParams.transX;
-        final float transY0 = mTmpParams.transY;
+        final float scale0 = sTmpParams.scale;
+        final float transX0 = sTmpParams.transX;
+        final float transY0 = sTmpParams.transY;
 
         mValueAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
         mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@@ -66,7 +66,7 @@
                 params.transX = transX0 + progress * (finalTransX - transX0);
                 params.transY = transY0 + progress * (finalTransY - transY0);
                 params.scale = scale0 + progress * (finalScale - scale0);
-                folderIcon.invalidate();
+                previewItemManager.onParamsChanged();
             }
         });
         mValueAnimator.addListener(new AnimatorListenerAdapter() {
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 44ebbcd..eba5d98 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -88,7 +88,7 @@
     public boolean isClipping = true;
 
     // Drawing / animation configurations
-    private static final float ACCEPT_SCALE_FACTOR = 1.25f;
+    private static final float ACCEPT_SCALE_FACTOR = 1.20f;
     private static final float ACCEPT_COLOR_MULTIPLIER = 1.5f;
 
     // Expressed on a scale from 0 to 255.
@@ -195,19 +195,28 @@
         invalidate();
     }
 
+    public int getBgColor() {
+        int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
+        return ColorUtils.setAlphaComponent(mBgColor, alpha);
+    }
+
     public void drawBackground(Canvas canvas) {
         mPaint.setStyle(Paint.Style.FILL);
-        int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
-        mPaint.setColor(ColorUtils.setAlphaComponent(mBgColor, alpha));
+        mPaint.setColor(getBgColor());
 
         drawCircle(canvas, 0 /* deltaRadius */);
 
-        // Draw shadow.
+        drawShadow(canvas);
+    }
+
+    public void drawShadow(Canvas canvas) {
         if (mShadowShader == null) {
             return;
         }
+
         float radius = getScaledRadius();
         float shadowRadius = radius + mStrokeWidth;
+        mPaint.setStyle(Paint.Style.FILL);
         mPaint.setColor(Color.BLACK);
         int offsetX = getOffsetX();
         int offsetY = getOffsetY();
@@ -219,7 +228,7 @@
 
         } else {
             saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
-            clipCanvasSoftware(canvas, Region.Op.DIFFERENCE);
+            canvas.clipPath(getClipPath(), Region.Op.DIFFERENCE);
         }
 
         mShaderMatrix.setScale(shadowRadius, shadowRadius);
@@ -295,17 +304,17 @@
                 radius - deltaRadius, mPaint);
     }
 
-    // It is the callers responsibility to save and restore the canvas layers.
-    void clipCanvasSoftware(Canvas canvas, Region.Op op) {
+    public Path getClipPath() {
         mPath.reset();
         float r = getScaledRadius();
         mPath.addCircle(r + getOffsetX(), r + getOffsetY(), r, Path.Direction.CW);
-        canvas.clipPath(mPath, op);
+        return mPath;
     }
 
     // It is the callers responsibility to save and restore the canvas layers.
     void clipCanvasHardware(Canvas canvas) {
         mPaint.setColor(Color.BLACK);
+        mPaint.setStyle(Paint.Style.FILL);
         mPaint.setXfermode(mClipPorterDuffXfermode);
 
         float radius = getScaledRadius();
@@ -336,6 +345,7 @@
         }
 
         mDrawingDelegate = null;
+        isClipping = true;
         invalidate();
     }
 
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
new file mode 100644
index 0000000..2d979a6
--- /dev/null
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2017 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.folder;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION;
+
+/**
+ * Manages the drawing and animations of {@link PreviewItemDrawingParams} for a {@link FolderIcon}.
+ */
+public class PreviewItemManager {
+
+    private FolderIcon mIcon;
+
+    // These variables are all associated with the drawing of the preview; they are stored
+    // as member variables for shared usage and to avoid computation on each frame
+    private float mIntrinsicIconSize = -1;
+    private int mTotalWidth = -1;
+    private int mPrevTopPadding = -1;
+    private Drawable mReferenceDrawable = null;
+
+    // These hold the first page preview items
+    private ArrayList<PreviewItemDrawingParams> mFirstPageParams = new ArrayList<>();
+    // These hold the current page preview items. It is empty if the current page is the first page.
+    private ArrayList<PreviewItemDrawingParams> mCurrentPageParams = new ArrayList<>();
+
+    private float mCurrentPageItemsTransX = 0;
+    private boolean mShouldSlideInFirstPage;
+
+    static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
+    private static final int FINAL_ITEM_ANIMATION_DURATION = 200;
+
+    private static final int SLIDE_IN_FIRST_PAGE_ANIMATION_DURATION_DELAY = 100;
+    private static final int SLIDE_IN_FIRST_PAGE_ANIMATION_DURATION = 300;
+    private static final int ITEM_SLIDE_IN_OUT_DISTANCE_PX = 200;
+
+    public PreviewItemManager(FolderIcon icon) {
+        mIcon = icon;
+    }
+
+    /**
+     * @param reverse If true, animates the final item in the preview to be full size. If false,
+     *                animates the first item to its position in the preview.
+     */
+    public FolderPreviewItemAnim createFirstItemAnimation(final boolean reverse,
+            final Runnable onCompleteRunnable) {
+        return reverse
+                ? new FolderPreviewItemAnim(this, mFirstPageParams.get(0), 0, 2, -1, -1,
+                        FINAL_ITEM_ANIMATION_DURATION, onCompleteRunnable)
+                : new FolderPreviewItemAnim(this, mFirstPageParams.get(0), -1, -1, 0, 2,
+                        INITIAL_ITEM_ANIMATION_DURATION, onCompleteRunnable);
+    }
+
+    Drawable prepareCreateAnimation(final View destView) {
+        Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
+        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
+                destView.getMeasuredWidth());
+        mReferenceDrawable = animateDrawable;
+        return animateDrawable;
+    }
+
+    public void recomputePreviewDrawingParams() {
+        if (mReferenceDrawable != null) {
+            computePreviewDrawingParams(mReferenceDrawable.getIntrinsicWidth(),
+                    mIcon.getMeasuredWidth());
+        }
+    }
+
+    private void computePreviewDrawingParams(int drawableSize, int totalSize) {
+        if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize ||
+                mPrevTopPadding != mIcon.getPaddingTop()) {
+            mIntrinsicIconSize = drawableSize;
+            mTotalWidth = totalSize;
+            mPrevTopPadding = mIcon.getPaddingTop();
+
+            mIcon.mBackground.setup(mIcon.mLauncher, mIcon, mTotalWidth, mIcon.getPaddingTop());
+            mIcon.mPreviewLayoutRule.init(mIcon.mBackground.previewSize, mIntrinsicIconSize,
+                    Utilities.isRtl(mIcon.getResources()));
+
+            updateItemDrawingParams(false);
+        }
+    }
+
+    PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
+            PreviewItemDrawingParams params) {
+        // We use an index of -1 to represent an icon on the workspace for the destroy and
+        // create animations
+        if (index == -1) {
+            return getFinalIconParams(params);
+        }
+        return mIcon.mPreviewLayoutRule.computePreviewItemDrawingParams(index, curNumItems, params);
+    }
+
+    private PreviewItemDrawingParams getFinalIconParams(PreviewItemDrawingParams params) {
+        float iconSize = mIcon.mLauncher.getDeviceProfile().iconSizePx;
+
+        final float scale = iconSize / mReferenceDrawable.getIntrinsicWidth();
+        final float trans = (mIcon.mBackground.previewSize - iconSize) / 2;
+
+        params.update(trans, trans, scale);
+        return params;
+    }
+
+    public void drawParams(Canvas canvas, ArrayList<PreviewItemDrawingParams> params,
+            float transX) {
+        canvas.translate(transX, 0);
+        // The first item should be drawn last (ie. on top of later items)
+        for (int i = params.size() - 1; i >= 0; i--) {
+            PreviewItemDrawingParams p = params.get(i);
+            if (!p.hidden) {
+                drawPreviewItem(canvas, p);
+            }
+        }
+        canvas.translate(-transX, 0);
+    }
+
+    public void draw(Canvas canvas) {
+        // The items are drawn in coordinates relative to the preview offset
+        PreviewBackground bg = mIcon.getFolderBackground();
+        canvas.translate(bg.basePreviewOffsetX, bg.basePreviewOffsetY);
+
+        float firstPageItemsTransX = 0;
+        if (mShouldSlideInFirstPage) {
+            drawParams(canvas, mCurrentPageParams, mCurrentPageItemsTransX);
+
+            firstPageItemsTransX = -ITEM_SLIDE_IN_OUT_DISTANCE_PX + mCurrentPageItemsTransX;
+        }
+
+        drawParams(canvas, mFirstPageParams, firstPageItemsTransX);
+        canvas.translate(-bg.basePreviewOffsetX, -bg.basePreviewOffsetY);
+    }
+
+    public void onParamsChanged() {
+        mIcon.invalidate();
+    }
+
+    private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
+        canvas.save(Canvas.MATRIX_SAVE_FLAG);
+        canvas.translate(params.transX, params.transY);
+        canvas.scale(params.scale, params.scale);
+        Drawable d = params.drawable;
+
+        if (d != null) {
+            Rect bounds = d.getBounds();
+            canvas.save();
+            canvas.translate(-bounds.left, -bounds.top);
+            canvas.scale(mIntrinsicIconSize / bounds.width(), mIntrinsicIconSize / bounds.height());
+            d.draw(canvas);
+            canvas.restore();
+        }
+        canvas.restore();
+    }
+
+    public void hidePreviewItem(int index, boolean hidden) {
+        PreviewItemDrawingParams params = index < mFirstPageParams.size() ?
+                mFirstPageParams.get(index) : null;
+        if (params != null) {
+            params.hidden = hidden;
+        }
+    }
+
+    void buildParamsForPage(int page, ArrayList<PreviewItemDrawingParams> params, boolean animate) {
+        List<BubbleTextView> items = mIcon.getPreviewItemsOnPage(page);
+        int prevNumItems = params.size();
+
+        // We adjust the size of the list to match the number of items in the preview.
+        while (items.size() < params.size()) {
+            params.remove(params.size() - 1);
+        }
+        while (items.size() > params.size()) {
+            params.add(new PreviewItemDrawingParams(0, 0, 0, 0));
+        }
+
+        int numItemsInFirstPagePreview = page == 0 ? items.size() : FolderIcon.NUM_ITEMS_IN_PREVIEW;
+        for (int i = 0; i < params.size(); i++) {
+            PreviewItemDrawingParams p = params.get(i);
+            p.drawable = items.get(i).getCompoundDrawables()[1];
+
+            if (p.drawable != null && !mIcon.mFolder.isOpen()) {
+                // Set the callback to FolderIcon as it is responsible to drawing the icon. The
+                // callback will be released when the folder is opened.
+                p.drawable.setCallback(mIcon);
+            }
+
+            if (!animate || FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON) {
+                computePreviewItemDrawingParams(i, numItemsInFirstPagePreview, p);
+                if (mReferenceDrawable == null) {
+                    mReferenceDrawable = p.drawable;
+                }
+            } else {
+                FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, i, prevNumItems, i,
+                        numItemsInFirstPagePreview, DROP_IN_ANIMATION_DURATION, null);
+
+                if (p.anim != null) {
+                    if (p.anim.hasEqualFinalState(anim)) {
+                        // do nothing, let the current animation finish
+                        continue;
+                    }
+                    p.anim.cancel();
+                }
+                p.anim = anim;
+                p.anim.start();
+            }
+        }
+    }
+
+    void onFolderClose(int currentPage) {
+        // If we are not closing on the first page, we animate the current page preview items
+        // out, and animate the first page preview items in.
+        mShouldSlideInFirstPage = currentPage != 0;
+        if (mShouldSlideInFirstPage) {
+            mCurrentPageItemsTransX = 0;
+            buildParamsForPage(currentPage, mCurrentPageParams, false);
+            onParamsChanged();
+
+            ValueAnimator slideAnimator = ValueAnimator.ofFloat(0, ITEM_SLIDE_IN_OUT_DISTANCE_PX);
+            slideAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                    mCurrentPageItemsTransX = (float) valueAnimator.getAnimatedValue();
+                    onParamsChanged();
+                }
+            });
+            slideAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mCurrentPageParams.clear();
+                }
+            });
+            slideAnimator.setStartDelay(SLIDE_IN_FIRST_PAGE_ANIMATION_DURATION_DELAY);
+            slideAnimator.setDuration(SLIDE_IN_FIRST_PAGE_ANIMATION_DURATION);
+            slideAnimator.start();
+        }
+    }
+
+    void updateItemDrawingParams(boolean animate) {
+        buildParamsForPage(0, mFirstPageParams, animate);
+    }
+
+    boolean verifyDrawable(@NonNull Drawable who) {
+        for (int i = 0; i < mFirstPageParams.size(); i++) {
+            if (mFirstPageParams.get(i).drawable == who) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    float getIntrinsicIconSize() {
+        return mIntrinsicIconSize;
+    }
+
+    /**
+     * Handles the case where items in the preview are either:
+     *  - Moving into the preview
+     *  - Moving into a new position
+     *  - Moving out of the preview
+     *
+     * @param oldParams The list of items in the old preview.
+     * @param newParams The list of items in the new preview.
+     * @param dropped The item that was dropped onto the FolderIcon.
+     */
+    public void onDrop(List<BubbleTextView> oldParams, List<BubbleTextView> newParams,
+            ShortcutInfo dropped) {
+        int numItems = newParams.size();
+        final ArrayList<PreviewItemDrawingParams> params = mFirstPageParams;
+        buildParamsForPage(0, params, false);
+
+        // New preview items for items that are moving in (except for the dropped item).
+        List<BubbleTextView> moveIn = new ArrayList<>();
+        for (BubbleTextView btv : newParams) {
+            if (!oldParams.contains(btv) && !btv.getTag().equals(dropped)) {
+                moveIn.add(btv);
+            }
+        }
+        for (int i = 0; i < moveIn.size(); ++i) {
+            int prevIndex = newParams.indexOf(moveIn.get(i));
+            PreviewItemDrawingParams p = params.get(prevIndex);
+            computePreviewItemDrawingParams(prevIndex, numItems, p);
+            updateTransitionParam(p, moveIn.get(i), mIcon.mPreviewLayoutRule.getEnterIndex(),
+                    newParams.indexOf(moveIn.get(i)));
+        }
+
+        // Items that are moving into new positions within the preview.
+        for (int newIndex = 0; newIndex < newParams.size(); ++newIndex) {
+            int oldIndex = oldParams.indexOf(newParams.get(newIndex));
+            if (oldIndex >= 0 && newIndex != oldIndex) {
+                PreviewItemDrawingParams p = params.get(newIndex);
+                updateTransitionParam(p, newParams.get(newIndex), oldIndex, newIndex);
+            }
+        }
+
+        // Old preview items that need to be moved out.
+        List<BubbleTextView> moveOut = new ArrayList<>(oldParams);
+        moveOut.removeAll(newParams);
+        for (int i = 0; i < moveOut.size(); ++i) {
+            BubbleTextView item = moveOut.get(i);
+            int oldIndex = oldParams.indexOf(item);
+            PreviewItemDrawingParams p = computePreviewItemDrawingParams(oldIndex, numItems, null);
+            updateTransitionParam(p, item, oldIndex, mIcon.mPreviewLayoutRule.getExitIndex());
+            params.add(0, p); // We want these items first so that they are on drawn last.
+        }
+
+        for (int i = 0; i < params.size(); ++i) {
+            if (params.get(i).anim != null) {
+                params.get(i).anim.start();
+            }
+        }
+    }
+
+    private void updateTransitionParam(final PreviewItemDrawingParams p, BubbleTextView btv,
+            int prevIndex, int newIndex) {
+        p.drawable = btv.getCompoundDrawables()[1];
+        if (!mIcon.mFolder.isOpen()) {
+            // Set the callback to FolderIcon as it is responsible to drawing the icon. The
+            // callback will be released when the folder is opened.
+            p.drawable.setCallback(mIcon);
+        }
+
+        FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, prevIndex,
+                FolderIcon.NUM_ITEMS_IN_PREVIEW, newIndex, FolderIcon.NUM_ITEMS_IN_PREVIEW,
+                DROP_IN_ANIMATION_DURATION, null);
+        if (p.anim != null && !p.anim.hasEqualFinalState(anim)) {
+            p.anim.cancel();
+        }
+        p.anim = anim;
+    }
+}
diff --git a/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java b/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
index 138dc1c..7d10556 100644
--- a/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
@@ -97,4 +97,19 @@
     public boolean clipToBackground() {
         return false;
     }
+
+    @Override
+    public boolean hasEnterExitIndices() {
+        return false;
+    }
+
+    @Override
+    public int getExitIndex() {
+        throw new RuntimeException("hasEnterExitIndices not supported");
+    }
+
+    @Override
+    public int getEnterIndex() {
+        throw new RuntimeException("hasEnterExitIndices not supported");
+    }
 }
diff --git a/src/com/android/launcher3/graphics/GradientView.java b/src/com/android/launcher3/graphics/GradientView.java
index 9dd9504..678396d 100644
--- a/src/com/android/launcher3/graphics/GradientView.java
+++ b/src/com/android/launcher3/graphics/GradientView.java
@@ -18,13 +18,14 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.LinearGradient;
 import android.graphics.Paint;
 import android.graphics.RadialGradient;
 import android.graphics.RectF;
 import android.graphics.Shader;
+import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.animation.AccelerateInterpolator;
@@ -34,6 +35,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dynamicui.WallpaperColorInfo;
+import com.android.launcher3.util.Themes;
 
 /**
  * Draws a translucent radial gradient background from an initial state with progress 0.0 to a
@@ -42,44 +44,44 @@
 public class GradientView extends View implements WallpaperColorInfo.OnChangeListener {
 
     private static final int DEFAULT_COLOR = Color.WHITE;
-    private static final float GRADIENT_ALPHA_MASK_LENGTH_DP = 300;
+    private static final int ALPHA_MASK_HEIGHT_DP = 500;
+    private static final int ALPHA_MASK_WIDTH_DP = 2;
+    private static final int ALPHA_COLORS = 0xBF;
     private static final boolean DEBUG = false;
 
-    private final Bitmap mFinalGradientMask;
     private final Bitmap mAlphaGradientMask;
 
+    private boolean mShowScrim = true;
     private int mColor1 = DEFAULT_COLOR;
     private int mColor2 = DEFAULT_COLOR;
     private int mWidth;
     private int mHeight;
     private final RectF mAlphaMaskRect = new RectF();
     private final RectF mFinalMaskRect = new RectF();
-    private final Paint mPaint = new Paint();
+    private final Paint mPaintWithScrim = new Paint();
+    private final Paint mPaintNoScrim = new Paint();
     private float mProgress;
-    private final int mMaskHeight;
+    private final int mMaskHeight, mMaskWidth;
     private final Context mAppContext;
     private final Paint mDebugPaint = DEBUG ? new Paint() : null;
     private final Interpolator mAccelerator = new AccelerateInterpolator();
     private final float mAlphaStart;
     private final WallpaperColorInfo mWallpaperColorInfo;
+    private final int mScrimColor;
 
     public GradientView(Context context, AttributeSet attrs) {
         super(context, attrs);
         this.mAppContext = context.getApplicationContext();
-        this.mMaskHeight = Utilities.pxFromDp(GRADIENT_ALPHA_MASK_LENGTH_DP,
+        this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP,
+                mAppContext.getResources().getDisplayMetrics());
+        this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP,
                 mAppContext.getResources().getDisplayMetrics());
         Launcher launcher = Launcher.getLauncher(context);
         this.mAlphaStart = launcher.getDeviceProfile().isVerticalBarLayout() ? 0 : 100;
+        this.mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
         this.mWallpaperColorInfo = WallpaperColorInfo.getInstance(launcher);
         updateColors();
-
-        int finalAlpha = 0xBF;
-        mFinalGradientMask = Utilities.convertToAlphaMask(
-                Utilities.createOnePixBitmap(), finalAlpha);
-        Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(context.getResources(),
-                R.drawable.all_apps_alpha_mask);
-        mAlphaGradientMask = Utilities.convertToAlphaMask(
-                alphaMaskFromResource, finalAlpha);
+        mAlphaGradientMask = createDitheredAlphaMask();
     }
 
     @Override
@@ -101,8 +103,10 @@
     }
 
     private void updateColors() {
-        this.mColor1 = mWallpaperColorInfo.getMainColor();
-        this.mColor2 = mWallpaperColorInfo.getSecondaryColor();
+        this.mColor1 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getMainColor(),
+                ALPHA_COLORS);
+        this.mColor2 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getSecondaryColor(),
+                ALPHA_COLORS);
         if (mWidth + mHeight > 0) {
             createRadialShader();
         }
@@ -122,34 +126,53 @@
     private void createRadialShader() {
         final float gradientCenterY = 1.05f;
         float radius = Math.max(mHeight, mWidth) * gradientCenterY;
-
         float posScreenBottom = (radius - mHeight) / radius; // center lives below screen
-        RadialGradient shader = new RadialGradient(
+
+        RadialGradient shaderNoScrim = new RadialGradient(
                 mWidth * 0.5f,
                 mHeight * gradientCenterY,
                 radius,
                 new int[] {mColor1, mColor1, mColor2},
                 new float[] {0f, posScreenBottom, 1f},
                 Shader.TileMode.CLAMP);
-        mPaint.setShader(shader);
+        mPaintNoScrim.setShader(shaderNoScrim);
+
+        int color1 = ColorUtils.compositeColors(mScrimColor,mColor1);
+        int color2 = ColorUtils.compositeColors(mScrimColor,mColor2);
+        RadialGradient shaderWithScrim = new RadialGradient(
+                mWidth * 0.5f,
+                mHeight * gradientCenterY,
+                radius,
+                new int[] { color1, color1, color2 },
+                new float[] {0f, posScreenBottom, 1f},
+                Shader.TileMode.CLAMP);
+        mPaintWithScrim.setShader(shaderWithScrim);
     }
 
     public void setProgress(float progress) {
+        setProgress(progress, true);
+    }
+
+    public void setProgress(float progress, boolean showScrim) {
         this.mProgress = progress;
+        this.mShowScrim = showScrim;
         invalidate();
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
+        Paint paint = mShowScrim ? mPaintWithScrim : mPaintNoScrim;
+
         float head = 0.29f;
         float linearProgress = head + (mProgress * (1f - head));
         float startMaskY = (1f - linearProgress) * mHeight - mMaskHeight * linearProgress;
         float interpolatedAlpha = (255 - mAlphaStart) * mAccelerator.getInterpolation(mProgress);
-        mPaint.setAlpha((int) (mAlphaStart + interpolatedAlpha));
-        mAlphaMaskRect.set(0, startMaskY, mWidth, startMaskY + mMaskHeight);
-        mFinalMaskRect.set(0, startMaskY + mMaskHeight, mWidth, mHeight);
-        canvas.drawBitmap(mAlphaGradientMask, null, mAlphaMaskRect, mPaint);
-        canvas.drawBitmap(mFinalGradientMask, null, mFinalMaskRect, mPaint);
+        paint.setAlpha((int) (mAlphaStart + interpolatedAlpha));
+        float div = (float) Math.floor(startMaskY + mMaskHeight);
+        mAlphaMaskRect.set(0, startMaskY, mWidth, div);
+        mFinalMaskRect.set(0, div, mWidth, mHeight);
+        canvas.drawBitmap(mAlphaGradientMask, null, mAlphaMaskRect, paint);
+        canvas.drawRect(mFinalMaskRect, paint);
 
         if (DEBUG) {
             mDebugPaint.setColor(0xFF00FF00);
@@ -157,4 +180,20 @@
             canvas.drawLine(0, startMaskY + mMaskHeight, mWidth, startMaskY + mMaskHeight, mDebugPaint);
         }
     }
+
+    public Bitmap createDitheredAlphaMask() {
+        Bitmap dst = Bitmap.createBitmap(mMaskWidth, mMaskHeight, Bitmap.Config.ALPHA_8);
+        Canvas c = new Canvas(dst);
+        Paint paint = new Paint(Paint.DITHER_FLAG);
+        LinearGradient lg = new LinearGradient(0, 0, 0, mMaskHeight,
+                new int[]{
+                        0x00FFFFFF,
+                        ColorUtils.setAlphaComponent(Color.WHITE, (int) (0xFF * 0.95)),
+                        0xFFFFFFFF},
+                new float[]{0f, 0.8f, 1f},
+                Shader.TileMode.CLAMP);
+        paint.setShader(lg);
+        c.drawRect(0, 0, mMaskWidth, mMaskHeight, paint);
+        return dst;
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 830ca82..d955674 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -35,6 +35,7 @@
 import android.os.Build;
 import android.os.Process;
 import android.os.UserHandle;
+import android.support.annotation.Nullable;
 
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.IconCache;
@@ -45,6 +46,7 @@
 import com.android.launcher3.model.PackageItemInfo;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.util.Provider;
 
 /**
  * Helper methods for generating various launcher icons
@@ -315,14 +317,41 @@
 
     public static Bitmap createShortcutIcon(ShortcutInfoCompat shortcutInfo, Context context,
             boolean badged) {
+        return createShortcutIcon(shortcutInfo, context, badged, null);
+    }
+
+    public static Bitmap createShortcutIcon(ShortcutInfoCompat shortcutInfo, Context context,
+            final Bitmap fallbackIcon) {
+        Provider<Bitmap> fallbackIconProvider = new Provider<Bitmap>() {
+            @Override
+            public Bitmap get() {
+                // If the shortcut is pinned but no longer has an icon in the system,
+                // keep the current icon instead of reverting to the default icon.
+                return fallbackIcon;
+            }
+        };
+        return createShortcutIcon(shortcutInfo, context, true, fallbackIconProvider);
+    }
+
+    public static Bitmap createShortcutIcon(ShortcutInfoCompat shortcutInfo, Context context,
+            boolean badged, @Nullable Provider<Bitmap> fallbackIconProvider) {
         LauncherAppState app = LauncherAppState.getInstance(context);
         Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context)
                 .getShortcutIconDrawable(shortcutInfo,
                         app.getInvariantDeviceProfile().fillResIconDpi);
         IconCache cache = app.getIconCache();
-        Bitmap unbadgedBitmap = unbadgedDrawable == null
-                ? cache.getDefaultIcon(Process.myUserHandle())
-                : LauncherIcons.createScaledBitmapWithoutShadow(unbadgedDrawable, context, 0);
+        Bitmap unbadgedBitmap = null;
+        if (unbadgedDrawable != null) {
+            unbadgedBitmap = LauncherIcons.createScaledBitmapWithoutShadow(
+                    unbadgedDrawable, context, 0);
+        } else {
+            if (fallbackIconProvider != null) {
+                unbadgedBitmap = fallbackIconProvider.get();
+            }
+            if (unbadgedBitmap == null) {
+                unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle());
+            }
+        }
 
         if (!badged) {
             return unbadgedBitmap;
diff --git a/src/com/android/launcher3/graphics/ScrimView.java b/src/com/android/launcher3/graphics/ScrimView.java
deleted file mode 100644
index 6d1f30a..0000000
--- a/src/com/android/launcher3/graphics/ScrimView.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2017 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.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.support.v4.graphics.ColorUtils;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.Interpolator;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.Themes;
-
-public class ScrimView extends View {
-
-    private static final boolean DEBUG = false;
-
-    private static final int MASK_HEIGHT_DP = 300;
-    private static final float MASK_START_LENGTH_FACTOR = 1f;
-    private static final boolean APPLY_ALPHA = true;
-
-    private final Bitmap mFinalScrimMask;
-    private final Bitmap mAlphaScrimMask;
-
-    private final int mMaskHeight;
-    private int mVisibleHeight;
-    private final int mHeadStart;
-
-    private final RectF mAlphaMaskRect = new RectF();
-    private final RectF mFinalMaskRect = new RectF();
-    private final Paint mPaint = new Paint();
-    private float mProgress;
-    private final Interpolator mAccelerator = new AccelerateInterpolator();
-    private final Paint mDebugPaint = DEBUG ? new Paint() : null;
-    private final int mAlphaStart;
-
-    public ScrimView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mMaskHeight = Utilities.pxFromDp(MASK_HEIGHT_DP, getResources().getDisplayMetrics());
-        mHeadStart = (int) (mMaskHeight * MASK_START_LENGTH_FACTOR);
-        mAlphaStart = Launcher.getLauncher(context)
-                .getDeviceProfile().isVerticalBarLayout() ? 0 : 55;
-
-        int scrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
-        int scrimAlpha = Color.alpha(scrimColor);
-        mPaint.setColor(scrimColor);
-        mFinalScrimMask = Utilities.convertToAlphaMask(
-                Utilities.createOnePixBitmap(), scrimAlpha);
-        Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(getResources(),
-                R.drawable.all_apps_alpha_mask);
-        mAlphaScrimMask = Utilities.convertToAlphaMask(alphaMaskFromResource, scrimAlpha);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        int width = MeasureSpec.getSize(widthMeasureSpec);
-        mVisibleHeight = MeasureSpec.getSize(heightMeasureSpec);
-        setMeasuredDimension(width, mVisibleHeight * 2);
-        setProgress(mProgress);
-    }
-
-    public void setProgress(float progress) {
-        mProgress = progress;
-        float initialY = mVisibleHeight - mHeadStart;
-        float fullTranslationY = mVisibleHeight;
-        float linTranslationY = initialY - progress * fullTranslationY;
-        setTranslationY(linTranslationY);
-
-        if (APPLY_ALPHA) {
-            int alpha = mAlphaStart + (int) ((255f - mAlphaStart)
-                    * mAccelerator.getInterpolation(progress));
-            mPaint.setAlpha(alpha);
-            invalidate();
-        }
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        mAlphaMaskRect.set(0, 0, getWidth(), mMaskHeight);
-        mFinalMaskRect.set(0, mMaskHeight, getWidth(), getHeight());
-        canvas.drawBitmap(mAlphaScrimMask, null, mAlphaMaskRect, mPaint);
-        canvas.drawBitmap(mFinalScrimMask, null, mFinalMaskRect, mPaint);
-
-        if (DEBUG) {
-            mDebugPaint.setColor(0xFF0000FF);
-            canvas.drawLine(0, mAlphaMaskRect.top, getWidth(), mAlphaMaskRect.top, mDebugPaint);
-            canvas.drawLine(0, mAlphaMaskRect.bottom, getWidth(), mAlphaMaskRect.bottom, mDebugPaint);
-        }
-    }
-
-}
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
index fffea8e..60eeef5 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -53,27 +53,38 @@
     private final Canvas mCanvas;
     private final Paint mBlurPaint;
     private final Paint mDrawPaint;
+    private final BlurMaskFilter mDefaultBlurMaskFilter;
 
     private ShadowGenerator(Context context) {
         mIconSize = LauncherAppState.getIDP(context).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);
+        mDefaultBlurMaskFilter = new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL);
     }
 
     public synchronized Bitmap recreateIcon(Bitmap icon) {
+        return recreateIcon(icon, true, mDefaultBlurMaskFilter, AMBIENT_SHADOW_ALPHA,
+                KEY_SHADOW_ALPHA);
+    }
+
+    public synchronized Bitmap recreateIcon(Bitmap icon, boolean resize,
+            BlurMaskFilter blurMaskFilter, int ambientAlpha, int keyAlpha) {
+        int width = resize ? mIconSize : icon.getWidth();
+        int height = resize ? mIconSize : icon.getHeight();
         int[] offset = new int[2];
+
+        mBlurPaint.setMaskFilter(blurMaskFilter);
         Bitmap shadow = icon.extractAlpha(mBlurPaint, offset);
-        Bitmap result = Bitmap.createBitmap(mIconSize, mIconSize, Config.ARGB_8888);
+        Bitmap result = Bitmap.createBitmap(width, height, Config.ARGB_8888);
         mCanvas.setBitmap(result);
 
         // Draw ambient shadow
-        mDrawPaint.setAlpha(AMBIENT_SHADOW_ALPHA);
+        mDrawPaint.setAlpha(ambientAlpha);
         mCanvas.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);
 
         // Draw key shadow
-        mDrawPaint.setAlpha(KEY_SHADOW_ALPHA);
+        mDrawPaint.setAlpha(keyAlpha);
         mCanvas.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize, mDrawPaint);
 
         // Draw the icon
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 329b7d5..ebb69c4 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.UninstallDropTarget;
+import com.android.launcher3.userevent.nano.LauncherLogExtensions.TargetExtension;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
@@ -66,8 +67,14 @@
     }
 
     public static String getActionStr(Action action) {
+        String str = "";
         switch (action.type) {
-            case Action.Type.TOUCH: return getFieldName(action.touch, Action.Touch.class);
+            case Action.Type.TOUCH:
+                str += getFieldName(action.touch, Action.Touch.class);
+                if (action.touch == Action.Touch.SWIPE) {
+                    str += " direction=" + getFieldName(action.dir, Action.Direction.class);
+                }
+                return str;
             case Action.Type.COMMAND: return getFieldName(action.command, Action.Command.class);
             default: return UNKNOWN;
         }
@@ -153,6 +160,13 @@
         return t;
     }
 
+    public static Target newTarget(int targetType, TargetExtension extension) {
+        Target t = new Target();
+        t.type = targetType;
+        t.extension = extension;
+        return t;
+    }
+
     public static Target newTarget(int targetType) {
         Target t = new Target();
         t.type = targetType;
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index edbb88c..d5c6515 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.os.SystemClock;
 import android.support.annotation.Nullable;
 import android.util.Log;
@@ -35,11 +36,10 @@
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.LogConfig;
 
-import java.util.List;
 import java.util.Locale;
+import java.util.UUID;
 
 import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
 import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
@@ -62,13 +62,21 @@
     private static final String TAG = "UserEvent";
     private static final boolean IS_VERBOSE =
             FeatureFlags.IS_DOGFOOD_BUILD && Utilities.isPropertyEnabled(LogConfig.USEREVENT);
+    private static final String UUID_STORAGE = "uuid";
 
     public static UserEventDispatcher newInstance(Context context, boolean isInLandscapeMode,
             boolean isInMultiWindowMode) {
+        SharedPreferences sharedPrefs = Utilities.getDevicePrefs(context);
+        String uuidStr = sharedPrefs.getString(UUID_STORAGE, null);
+        if (uuidStr == null) {
+            uuidStr = UUID.randomUUID().toString();
+            sharedPrefs.edit().putString(UUID_STORAGE, uuidStr).apply();
+        }
         UserEventDispatcher ued = Utilities.getOverrideObject(UserEventDispatcher.class,
                 context.getApplicationContext(), R.string.user_event_dispatcher_class);
         ued.mIsInLandscapeMode = isInLandscapeMode;
         ued.mIsInMultiWindowMode = isInMultiWindowMode;
+        ued.mUuidStr = uuidStr;
         return ued;
     }
 
@@ -116,9 +124,7 @@
     private long mActionDurationMillis;
     private boolean mIsInMultiWindowMode;
     private boolean mIsInLandscapeMode;
-
-    // Used for filling in predictedRank on {@link Target}s.
-    private List<ComponentKey> mPredictedApps;
+    private String mUuidStr;
 
     //                      APP_ICON    SHORTCUT    WIDGET
     // --------------------------------------------------------------
@@ -127,32 +133,11 @@
     // intentHash                       required
     // --------------------------------------------------------------
 
-    protected LauncherEvent createLauncherEvent(View v, int intentHashCode, ComponentName cn) {
-        LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
-                newItemTarget(v), newTarget(Target.Type.CONTAINER));
-
-        // TODO: make idx percolate up the view hierarchy if needed.
-        int idx = 0;
-        if (fillInLogContainerData(event, v)) {
-            ItemInfo itemInfo = (ItemInfo) v.getTag();
-            event.srcTarget[idx].intentHash = intentHashCode;
-            if (cn != null) {
-                event.srcTarget[idx].packageNameHash = cn.getPackageName().hashCode();
-                event.srcTarget[idx].componentHash = cn.hashCode();
-                if (mPredictedApps != null) {
-                    event.srcTarget[idx].predictedRank = mPredictedApps.indexOf(
-                            new ComponentKey(cn, itemInfo.user));
-                }
-            }
-        }
-        return event;
-    }
-
     /**
      * Fills in the container data on the given event if the given view is not null.
      * @return whether container data was added.
      */
-    private boolean fillInLogContainerData(LauncherEvent event, @Nullable View v) {
+    protected boolean fillInLogContainerData(LauncherEvent event, @Nullable View v) {
         // Fill in grid(x,y), pageIndex of the child and container type of the parent
         LogContainerProvider provider = getLaunchProviderRecursive(v);
         if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
@@ -164,20 +149,31 @@
     }
 
     public void logAppLaunch(View v, Intent intent) {
-        LauncherEvent ev = createLauncherEvent(v, intent.hashCode(), intent.getComponent());
-        if (ev == null) {
-            return;
+        LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
+                newItemTarget(v), newTarget(Target.Type.CONTAINER));
+
+        if (fillInLogContainerData(event, v)) {
+            fillIntentInfo(event.srcTarget[0], intent);
         }
-        dispatchUserEvent(ev, intent);
+        dispatchUserEvent(event, intent);
+    }
+
+    protected void fillIntentInfo(Target target, Intent intent) {
+        target.intentHash = intent.hashCode();
+        ComponentName cn = intent.getComponent();
+        if (cn != null) {
+            target.packageNameHash = (mUuidStr + cn.getPackageName()).hashCode();
+            target.componentHash = (mUuidStr + cn.flattenToString()).hashCode();
+        }
     }
 
     public void logNotificationLaunch(View v, PendingIntent intent) {
-        ComponentName dummyComponent = new ComponentName(intent.getCreatorPackage(), "--dummy--");
-        LauncherEvent ev = createLauncherEvent(v, intent.hashCode(), dummyComponent);
-        if (ev == null) {
-            return;
+        LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
+                newItemTarget(v), newTarget(Target.Type.CONTAINER));
+        if (fillInLogContainerData(event, v)) {
+            event.srcTarget[0].packageNameHash = (mUuidStr + intent.getCreatorPackage()).hashCode();
         }
-        dispatchUserEvent(ev, null);
+        dispatchUserEvent(event, null);
     }
 
     public void logActionCommand(int command, int containerType) {
@@ -262,10 +258,6 @@
         resetElapsedContainerMillis();
     }
 
-    public void setPredictedApps(List<ComponentKey> predictedApps) {
-        mPredictedApps = predictedApps;
-    }
-
     /* Currently we are only interested in whether this event happens or not and don't
     * care about which screen moves to where. */
     public void logOverviewReorder() {
@@ -337,7 +329,10 @@
     }
 
     private static String getTargetsStr(Target[] targets) {
-        return "child:" + LoggerUtils.getTargetStr(targets[0]) +
-                (targets.length > 1 ? "\tparent:" + LoggerUtils.getTargetStr(targets[1]) : "");
+        String result = "child:" + LoggerUtils.getTargetStr(targets[0]);
+        for (int i = 1; i < targets.length; i++) {
+            result += "\tparent:" + LoggerUtils.getTargetStr(targets[i]);
+        }
+        return result;
     }
 }
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 1a2c04d..bc7da9b 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -184,9 +184,13 @@
                 icon = LauncherIcons.createIconBitmap(
                         BitmapFactory.decodeByteArray(data, 0, data.length), mContext);
             } catch (Exception e) {
+                Log.e(TAG, "Failed to load icon for info " + info, e);
                 return null;
             }
         }
+        if (icon == null) {
+            Log.e(TAG, "Failed to load icon for info " + info);
+        }
         return icon;
     }
 
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index bb2d0b6..c56325a 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -24,8 +24,8 @@
 import android.content.IntentFilter;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.PackageInstaller;
+import android.graphics.Bitmap;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.Trace;
@@ -66,6 +66,7 @@
 import com.android.launcher3.util.ManagedProfileHeuristic;
 import com.android.launcher3.util.MultiHashMap;
 import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.Provider;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -459,8 +460,18 @@
                                         continue;
                                     }
                                     info = new ShortcutInfo(pinnedShortcut, context);
+                                    final ShortcutInfo finalInfo = info;
+                                    Provider<Bitmap> fallbackIconProvider = new Provider<Bitmap>() {
+                                        @Override
+                                        public Bitmap get() {
+                                            // If the pinned deep shortcut is no longer published,
+                                            // use the last saved icon instead of the default.
+                                            return c.loadIcon(finalInfo);
+                                        }
+                                    };
                                     info.iconBitmap = LauncherIcons
-                                            .createShortcutIcon(pinnedShortcut, context);
+                                            .createShortcutIcon(pinnedShortcut, context,
+                                                    true /* badged */, fallbackIconProvider);
                                     if (pmHelper.isAppSuspended(
                                             pinnedShortcut.getPackage(), info.user)) {
                                         info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
@@ -537,6 +548,11 @@
                             break;
 
                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+                            if (FeatureFlags.GO_DISABLE_WIDGETS) {
+                                c.markDeleted("Only legacy shortcuts can have null package");
+                                continue;
+                            }
+                            // Follow through
                         case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
                             // Read all Launcher-specific widget details
                             boolean customWidget = c.itemType ==
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 6f32585..17cc238 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -85,10 +85,10 @@
                     removedShortcutInfos.addAll(shortcutInfos);
                     continue;
                 }
-                for (ShortcutInfo shortcutInfo : shortcutInfos) {
+                for (final ShortcutInfo shortcutInfo : shortcutInfos) {
                     shortcutInfo.updateFromDeepShortcutInfo(fullDetails, context);
-                    shortcutInfo.iconBitmap =
-                            LauncherIcons.createShortcutIcon(fullDetails, context);
+                    shortcutInfo.iconBitmap = LauncherIcons.createShortcutIcon(fullDetails, context,
+                            shortcutInfo.iconBitmap);
                     updatedShortcutInfos.add(shortcutInfo);
                 }
             }
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 5682006..802771f 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -85,7 +85,8 @@
                     }
                     si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
                     si.updateFromDeepShortcutInfo(shortcut, context);
-                    si.iconBitmap = LauncherIcons.createShortcutIcon(shortcut, context);
+                    si.iconBitmap = LauncherIcons.createShortcutIcon(shortcut, context,
+                            si.iconBitmap);
                 } else {
                     si.isDisabled |= ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
                 }
diff --git a/src/com/android/launcher3/notification/FlingAnimationUtils.java b/src/com/android/launcher3/notification/FlingAnimationUtils.java
deleted file mode 100644
index a1f7e49..0000000
--- a/src/com/android/launcher3/notification/FlingAnimationUtils.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (C) 2017 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.notification;
-
-import android.animation.Animator;
-import android.content.Context;
-import android.view.ViewPropertyAnimator;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
-
-/**
- * Utility class to calculate general fling animation when the finger is released.
- *
- * This class was copied from com.android.systemui.statusbar.
- */
-public class FlingAnimationUtils {
-
-    private static final float LINEAR_OUT_SLOW_IN_X2 = 0.35f;
-    private static final float LINEAR_OUT_SLOW_IN_X2_MAX = 0.68f;
-    private static final float LINEAR_OUT_FASTER_IN_X2 = 0.5f;
-    private static final float LINEAR_OUT_FASTER_IN_Y2_MIN = 0.4f;
-    private static final float LINEAR_OUT_FASTER_IN_Y2_MAX = 0.5f;
-    private static final float MIN_VELOCITY_DP_PER_SECOND = 250;
-    private static final float HIGH_VELOCITY_DP_PER_SECOND = 3000;
-
-    private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 0.75f;
-    private final float mSpeedUpFactor;
-    private final float mY2;
-
-    private float mMinVelocityPxPerSecond;
-    private float mMaxLengthSeconds;
-    private float mHighVelocityPxPerSecond;
-    private float mLinearOutSlowInX2;
-
-    private AnimatorProperties mAnimatorProperties = new AnimatorProperties();
-    private PathInterpolator mInterpolator;
-    private float mCachedStartGradient = -1;
-    private float mCachedVelocityFactor = -1;
-
-    public FlingAnimationUtils(Context ctx, float maxLengthSeconds) {
-        this(ctx, maxLengthSeconds, 0.0f);
-    }
-
-    /**
-     * @param maxLengthSeconds the longest duration an animation can become in seconds
-     * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
-     *                      the end of the animation. 0 means it's at the beginning and no
-     *                      acceleration will take place.
-     */
-    public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor) {
-        this(ctx, maxLengthSeconds, speedUpFactor, -1.0f, 1.0f);
-    }
-
-    /**
-     * @param maxLengthSeconds the longest duration an animation can become in seconds
-     * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
-     *                      the end of the animation. 0 means it's at the beginning and no
-     *                      acceleration will take place.
-     * @param x2 the x value to take for the second point of the bezier spline. If a value below 0
-     *           is provided, the value is automatically calculated.
-     * @param y2 the y value to take for the second point of the bezier spline
-     */
-    public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor, float x2,
-            float y2) {
-        mMaxLengthSeconds = maxLengthSeconds;
-        mSpeedUpFactor = speedUpFactor;
-        if (x2 < 0) {
-            mLinearOutSlowInX2 = interpolate(LINEAR_OUT_SLOW_IN_X2,
-                    LINEAR_OUT_SLOW_IN_X2_MAX,
-                    mSpeedUpFactor);
-        } else {
-            mLinearOutSlowInX2 = x2;
-        }
-        mY2 = y2;
-
-        mMinVelocityPxPerSecond
-                = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
-        mHighVelocityPxPerSecond
-                = HIGH_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
-    }
-
-    private static float interpolate(float start, float end, float amount) {
-        return start * (1.0f - amount) + end * amount;
-    }
-
-    /**
-     * Applies the interpolator and length to the animator, such that the fling animation is
-     * consistent with the finger motion.
-     *
-     * @param animator the animator to apply
-     * @param currValue the current value
-     * @param endValue the end value of the animator
-     * @param velocity the current velocity of the motion
-     */
-    public void apply(Animator animator, float currValue, float endValue, float velocity) {
-        apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
-    }
-
-    /**
-     * Applies the interpolator and length to the animator, such that the fling animation is
-     * consistent with the finger motion.
-     *
-     * @param animator the animator to apply
-     * @param currValue the current value
-     * @param endValue the end value of the animator
-     * @param velocity the current velocity of the motion
-     */
-    public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
-            float velocity) {
-        apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
-    }
-
-    /**
-     * Applies the interpolator and length to the animator, such that the fling animation is
-     * consistent with the finger motion.
-     *
-     * @param animator the animator to apply
-     * @param currValue the current value
-     * @param endValue the end value of the animator
-     * @param velocity the current velocity of the motion
-     * @param maxDistance the maximum distance for this interaction; the maximum animation length
-     *                    gets multiplied by the ratio between the actual distance and this value
-     */
-    public void apply(Animator animator, float currValue, float endValue, float velocity,
-            float maxDistance) {
-        AnimatorProperties properties = getProperties(currValue, endValue, velocity,
-                maxDistance);
-        animator.setDuration(properties.duration);
-        animator.setInterpolator(properties.interpolator);
-    }
-
-    /**
-     * Applies the interpolator and length to the animator, such that the fling animation is
-     * consistent with the finger motion.
-     *
-     * @param animator the animator to apply
-     * @param currValue the current value
-     * @param endValue the end value of the animator
-     * @param velocity the current velocity of the motion
-     * @param maxDistance the maximum distance for this interaction; the maximum animation length
-     *                    gets multiplied by the ratio between the actual distance and this value
-     */
-    public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
-            float velocity, float maxDistance) {
-        AnimatorProperties properties = getProperties(currValue, endValue, velocity,
-                maxDistance);
-        animator.setDuration(properties.duration);
-        animator.setInterpolator(properties.interpolator);
-    }
-
-    private AnimatorProperties getProperties(float currValue,
-            float endValue, float velocity, float maxDistance) {
-        float maxLengthSeconds = (float) (mMaxLengthSeconds
-                * Math.sqrt(Math.abs(endValue - currValue) / maxDistance));
-        float diff = Math.abs(endValue - currValue);
-        float velAbs = Math.abs(velocity);
-        float velocityFactor = mSpeedUpFactor == 0.0f
-                ? 1.0f : Math.min(velAbs / HIGH_VELOCITY_DP_PER_SECOND, 1.0f);
-        float startGradient = interpolate(LINEAR_OUT_SLOW_IN_START_GRADIENT,
-                mY2 / mLinearOutSlowInX2, velocityFactor);
-        float durationSeconds = startGradient * diff / velAbs;
-        Interpolator slowInInterpolator = getInterpolator(startGradient, velocityFactor);
-        if (durationSeconds <= maxLengthSeconds) {
-            mAnimatorProperties.interpolator = slowInInterpolator;
-        } else if (velAbs >= mMinVelocityPxPerSecond) {
-
-            // Cross fade between fast-out-slow-in and linear interpolator with current velocity.
-            durationSeconds = maxLengthSeconds;
-            VelocityInterpolator velocityInterpolator
-                    = new VelocityInterpolator(durationSeconds, velAbs, diff);
-            InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
-                    velocityInterpolator, slowInInterpolator, Interpolators.LINEAR_OUT_SLOW_IN);
-            mAnimatorProperties.interpolator = superInterpolator;
-        } else {
-
-            // Just use a normal interpolator which doesn't take the velocity into account.
-            durationSeconds = maxLengthSeconds;
-            mAnimatorProperties.interpolator = Interpolators.FAST_OUT_SLOW_IN;
-        }
-        mAnimatorProperties.duration = (long) (durationSeconds * 1000);
-        return mAnimatorProperties;
-    }
-
-    private Interpolator getInterpolator(float startGradient, float velocityFactor) {
-        if (startGradient != mCachedStartGradient
-                || velocityFactor != mCachedVelocityFactor) {
-            float speedup = mSpeedUpFactor * (1.0f - velocityFactor);
-            mInterpolator = new PathInterpolator(speedup,
-                    speedup * startGradient,
-                    mLinearOutSlowInX2, mY2);
-            mCachedStartGradient = startGradient;
-            mCachedVelocityFactor = velocityFactor;
-        }
-        return mInterpolator;
-    }
-
-    /**
-     * Applies the interpolator and length to the animator, such that the fling animation is
-     * consistent with the finger motion for the case when the animation is making something
-     * disappear.
-     *
-     * @param animator the animator to apply
-     * @param currValue the current value
-     * @param endValue the end value of the animator
-     * @param velocity the current velocity of the motion
-     * @param maxDistance the maximum distance for this interaction; the maximum animation length
-     *                    gets multiplied by the ratio between the actual distance and this value
-     */
-    public void applyDismissing(Animator animator, float currValue, float endValue,
-            float velocity, float maxDistance) {
-        AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
-                maxDistance);
-        animator.setDuration(properties.duration);
-        animator.setInterpolator(properties.interpolator);
-    }
-
-    /**
-     * Applies the interpolator and length to the animator, such that the fling animation is
-     * consistent with the finger motion for the case when the animation is making something
-     * disappear.
-     *
-     * @param animator the animator to apply
-     * @param currValue the current value
-     * @param endValue the end value of the animator
-     * @param velocity the current velocity of the motion
-     * @param maxDistance the maximum distance for this interaction; the maximum animation length
-     *                    gets multiplied by the ratio between the actual distance and this value
-     */
-    public void applyDismissing(ViewPropertyAnimator animator, float currValue, float endValue,
-            float velocity, float maxDistance) {
-        AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
-                maxDistance);
-        animator.setDuration(properties.duration);
-        animator.setInterpolator(properties.interpolator);
-    }
-
-    private AnimatorProperties getDismissingProperties(float currValue, float endValue,
-            float velocity, float maxDistance) {
-        float maxLengthSeconds = (float) (mMaxLengthSeconds
-                * Math.pow(Math.abs(endValue - currValue) / maxDistance, 0.5f));
-        float diff = Math.abs(endValue - currValue);
-        float velAbs = Math.abs(velocity);
-        float y2 = calculateLinearOutFasterInY2(velAbs);
-
-        float startGradient = y2 / LINEAR_OUT_FASTER_IN_X2;
-        Interpolator mLinearOutFasterIn = new PathInterpolator(0, 0, LINEAR_OUT_FASTER_IN_X2, y2);
-        float durationSeconds = startGradient * diff / velAbs;
-        if (durationSeconds <= maxLengthSeconds) {
-            mAnimatorProperties.interpolator = mLinearOutFasterIn;
-        } else if (velAbs >= mMinVelocityPxPerSecond) {
-
-            // Cross fade between linear-out-faster-in and linear interpolator with current
-            // velocity.
-            durationSeconds = maxLengthSeconds;
-            VelocityInterpolator velocityInterpolator
-                    = new VelocityInterpolator(durationSeconds, velAbs, diff);
-            InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
-                    velocityInterpolator, mLinearOutFasterIn, Interpolators.LINEAR_OUT_SLOW_IN);
-            mAnimatorProperties.interpolator = superInterpolator;
-        } else {
-
-            // Just use a normal interpolator which doesn't take the velocity into account.
-            durationSeconds = maxLengthSeconds;
-            mAnimatorProperties.interpolator = Interpolators.FAST_OUT_LINEAR_IN;
-        }
-        mAnimatorProperties.duration = (long) (durationSeconds * 1000);
-        return mAnimatorProperties;
-    }
-
-    /**
-     * Calculates the y2 control point for a linear-out-faster-in path interpolator depending on the
-     * velocity. The faster the velocity, the more "linear" the interpolator gets.
-     *
-     * @param velocity the velocity of the gesture.
-     * @return the y2 control point for a cubic bezier path interpolator
-     */
-    private float calculateLinearOutFasterInY2(float velocity) {
-        float t = (velocity - mMinVelocityPxPerSecond)
-                / (mHighVelocityPxPerSecond - mMinVelocityPxPerSecond);
-        t = Math.max(0, Math.min(1, t));
-        return (1 - t) * LINEAR_OUT_FASTER_IN_Y2_MIN + t * LINEAR_OUT_FASTER_IN_Y2_MAX;
-    }
-
-    /**
-     * @return the minimum velocity a gesture needs to have to be considered a fling
-     */
-    public float getMinVelocityPxPerSecond() {
-        return mMinVelocityPxPerSecond;
-    }
-
-    /**
-     * An interpolator which interpolates two interpolators with an interpolator.
-     */
-    private static final class InterpolatorInterpolator implements Interpolator {
-
-        private Interpolator mInterpolator1;
-        private Interpolator mInterpolator2;
-        private Interpolator mCrossfader;
-
-        InterpolatorInterpolator(Interpolator interpolator1, Interpolator interpolator2,
-                Interpolator crossfader) {
-            mInterpolator1 = interpolator1;
-            mInterpolator2 = interpolator2;
-            mCrossfader = crossfader;
-        }
-
-        @Override
-        public float getInterpolation(float input) {
-            float t = mCrossfader.getInterpolation(input);
-            return (1 - t) * mInterpolator1.getInterpolation(input)
-                    + t * mInterpolator2.getInterpolation(input);
-        }
-    }
-
-    /**
-     * An interpolator which interpolates with a fixed velocity.
-     */
-    private static final class VelocityInterpolator implements Interpolator {
-
-        private float mDurationSeconds;
-        private float mVelocity;
-        private float mDiff;
-
-        private VelocityInterpolator(float durationSeconds, float velocity, float diff) {
-            mDurationSeconds = durationSeconds;
-            mVelocity = velocity;
-            mDiff = diff;
-        }
-
-        @Override
-        public float getInterpolation(float input) {
-            float time = input * mDurationSeconds;
-            return time * mVelocity / mDiff;
-        }
-    }
-
-    private static class AnimatorProperties {
-        Interpolator interpolator;
-        long duration;
-    }
-
-}
diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java
index b83c9b9..2455eab 100644
--- a/src/com/android/launcher3/notification/NotificationFooterLayout.java
+++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java
@@ -206,7 +206,10 @@
                     @Override
                     public void onAnimationEnd(Animator animation) {
                         ((ViewGroup) getParent()).findViewById(R.id.divider).setVisibility(GONE);
-                        ((ViewGroup) getParent()).removeView(NotificationFooterLayout.this);
+                        // Keep view around because gutter is aligned to it, but remove height to
+                        // both hide the view and keep calculations correct for last dismissal.
+                        getLayoutParams().height = 0;
+                        requestLayout();
                     }
                 });
                 collapseFooter.start();
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index 0b08ef8..78c64d7 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -17,6 +17,8 @@
 package com.android.launcher3.notification;
 
 import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.app.Notification;
 import android.content.Context;
 import android.graphics.Rect;
@@ -28,11 +30,14 @@
 import android.widget.TextView;
 
 import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.R;
+import com.android.launcher3.anim.PropertyResetListener;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.graphics.IconPalette;
 import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
 import com.android.launcher3.popup.PopupItemView;
+import com.android.launcher3.touch.SwipeDetector;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.Themes;
 
@@ -48,10 +53,11 @@
 
     private static final Rect sTempRect = new Rect();
 
+    private TextView mHeaderText;
     private TextView mHeaderCount;
     private NotificationMainView mMainView;
     private NotificationFooterLayout mFooter;
-    private SwipeHelper mSwipeHelper;
+    private SwipeDetector mSwipeDetector;
     private boolean mAnimatingNextIcon;
     private int mNotificationHeaderTextColor = Notification.COLOR_DEFAULT;
 
@@ -70,11 +76,14 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mHeaderCount = (TextView) findViewById(R.id.notification_count);
-        mMainView = (NotificationMainView) findViewById(R.id.main_view);
-        mFooter = (NotificationFooterLayout) findViewById(R.id.footer);
-        mSwipeHelper = new SwipeHelper(SwipeHelper.X, mMainView, getContext());
-        mSwipeHelper.setDisableHardwareLayers(true);
+        mHeaderText = findViewById(R.id.notification_text);
+        mHeaderCount = findViewById(R.id.notification_count);
+        mMainView = findViewById(R.id.main_view);
+        mFooter = findViewById(R.id.footer);
+
+        mSwipeDetector = new SwipeDetector(getContext(), mMainView, SwipeDetector.HORIZONTAL);
+        mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
+        mMainView.setSwipeDetector(mSwipeDetector);
     }
 
     public NotificationMainView getMainView() {
@@ -87,6 +96,8 @@
     }
 
     public Animator animateHeightRemoval(int heightToRemove, boolean shouldRemoveFromTop) {
+        AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+
         Rect startRect = new Rect(mPillRect);
         Rect endRect = new Rect(mPillRect);
         if (shouldRemoveFromTop) {
@@ -94,8 +105,18 @@
         } else {
             endRect.bottom -= heightToRemove;
         }
-        return new RoundedRectRevealOutlineProvider(getBackgroundRadius(), getBackgroundRadius(),
-                startRect, endRect, mRoundedCorners).createRevealAnimator(this, false);
+        anim.play(new RoundedRectRevealOutlineProvider(getBackgroundRadius(), getBackgroundRadius(),
+                startRect, endRect, mRoundedCorners).createRevealAnimator(this, false));
+
+        View bottomGutter = findViewById(R.id.gutter_bottom);
+        if (bottomGutter != null && bottomGutter.getVisibility() == VISIBLE) {
+            Animator translateGutter = ObjectAnimator.ofFloat(bottomGutter, TRANSLATION_Y,
+                    -heightToRemove);
+            translateGutter.addListener(new PropertyResetListener<>(TRANSLATION_Y, 0f));
+            anim.play(translateGutter);
+        }
+
+        return anim;
     }
 
     public void updateHeader(int notificationCount, @Nullable IconPalette palette) {
@@ -106,6 +127,7 @@
                         IconPalette.resolveContrastColor(getContext(), palette.dominantColor,
                                 Themes.getAttrColor(getContext(), R.attr.popupColorPrimary));
             }
+            mHeaderText.setTextColor(mNotificationHeaderTextColor);
             mHeaderCount.setTextColor(mNotificationHeaderTextColor);
         }
     }
@@ -117,7 +139,8 @@
             return false;
         }
         getParent().requestDisallowInterceptTouchEvent(true);
-        return mSwipeHelper.onInterceptTouchEvent(ev);
+        mSwipeDetector.onTouchEvent(ev);
+        return mSwipeDetector.isDraggingOrSettling();
     }
 
     @Override
@@ -126,7 +149,7 @@
             // The notification hasn't been populated yet.
             return false;
         }
-        return mSwipeHelper.onTouchEvent(ev) || super.onTouchEvent(ev);
+        return mSwipeDetector.onTouchEvent(ev) || super.onTouchEvent(ev);
     }
 
     public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) {
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index baaa66a..73d89aa 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -28,6 +28,7 @@
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.Pair;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.config.FeatureFlags;
@@ -47,6 +48,8 @@
 @TargetApi(Build.VERSION_CODES.O)
 public class NotificationListener extends NotificationListenerService {
 
+    public static final String TAG = "NotificationListener";
+
     private static final int MSG_NOTIFICATION_POSTED = 1;
     private static final int MSG_NOTIFICATION_REMOVED = 2;
     private static final int MSG_NOTIFICATION_FULL_REFRESH = 3;
@@ -71,9 +74,19 @@
                     mUiHandler.obtainMessage(message.what, message.obj).sendToTarget();
                     break;
                 case MSG_NOTIFICATION_FULL_REFRESH:
-                    final List<StatusBarNotification> activeNotifications = sIsConnected
-                            ? filterNotifications(getActiveNotifications())
-                            : new ArrayList<StatusBarNotification>();
+                    List<StatusBarNotification> activeNotifications;
+                    if (sIsConnected) {
+                        try {
+                            activeNotifications =  filterNotifications(getActiveNotifications());
+                        } catch (SecurityException ex) {
+                            Log.e(TAG, "SecurityException: failed to fetch notifications");
+                            activeNotifications = new ArrayList<StatusBarNotification>();
+
+                        }
+                    } else {
+                        activeNotifications = new ArrayList<StatusBarNotification>();
+                    }
+
                     mUiHandler.obtainMessage(message.what, activeNotifications).sendToTarget();
                     break;
             }
@@ -127,8 +140,9 @@
         }
         sNotificationsChangedListener = listener;
 
-        if (sNotificationListenerInstance != null) {
-            sNotificationListenerInstance.onNotificationFullRefresh();
+        NotificationListener notificationListener = getInstanceIfConnected();
+        if (notificationListener != null) {
+            notificationListener.onNotificationFullRefresh();
         }
     }
 
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index 9b8dd64..5aff28d 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -23,15 +23,17 @@
 import android.graphics.drawable.RippleDrawable;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
+import com.android.launcher3.touch.OverScroll;
+import com.android.launcher3.touch.SwipeDetector;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.Themes;
 
@@ -39,7 +41,7 @@
  * A {@link android.widget.FrameLayout} that contains a single notification,
  * e.g. icon + title + text.
  */
-public class NotificationMainView extends FrameLayout implements SwipeHelper.Callback {
+public class NotificationMainView extends FrameLayout implements SwipeDetector.Listener {
 
     private NotificationInfo mNotificationInfo;
     private ViewGroup mTextAndBackground;
@@ -47,6 +49,8 @@
     private TextView mTitleView;
     private TextView mTextView;
 
+    private SwipeDetector mSwipeDetector;
+
     public NotificationMainView(Context context) {
         this(context, null, 0);
     }
@@ -78,6 +82,10 @@
         applyNotificationInfo(mainNotification, iconView, false);
     }
 
+    public void setSwipeDetector(SwipeDetector swipeDetector) {
+        mSwipeDetector = swipeDetector;
+    }
+
     /**
      * Sets the content of this view, animating it after a new icon shifts up if necessary.
      */
@@ -113,29 +121,11 @@
     }
 
 
-    // SwipeHelper.Callback's
-
-    @Override
-    public View getChildAtPosition(MotionEvent ev) {
-        return this;
-    }
-
-    @Override
-    public boolean canChildBeDismissed(View v) {
+    public boolean canChildBeDismissed() {
         return mNotificationInfo != null && mNotificationInfo.dismissable;
     }
 
-    @Override
-    public boolean isAntiFalsingNeeded() {
-        return false;
-    }
-
-    @Override
-    public void onBeginDrag(View v) {
-    }
-
-    @Override
-    public void onChildDismissed(View v) {
+    public void onChildDismissed() {
         Launcher launcher = Launcher.getLauncher(getContext());
         launcher.getPopupDataProvider().cancelNotification(
                 mNotificationInfo.notificationKey);
@@ -145,22 +135,55 @@
                 LauncherLogProto.ItemType.NOTIFICATION);
     }
 
+    // SwipeDetector.Listener's
     @Override
-    public void onDragCancelled(View v) {
-    }
+    public void onDragStart(boolean start) { }
+
 
     @Override
-    public void onChildSnappedBack(View animView, float targetLeft) {
-    }
-
-    @Override
-    public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
-        // Don't fade out.
+    public boolean onDrag(float displacement, float velocity) {
+        setTranslationX(canChildBeDismissed()
+                ? displacement : OverScroll.dampedScroll(displacement, getWidth()));
+        animate().cancel();
         return true;
     }
 
     @Override
-    public float getFalsingThresholdFactor() {
-        return 1;
+    public void onDragEnd(float velocity, boolean fling) {
+        final boolean willExit;
+        final float endTranslation;
+
+        if (!canChildBeDismissed()) {
+            willExit = false;
+            endTranslation = 0;
+        } else if (fling) {
+            willExit = true;
+            endTranslation = velocity < 0 ? - getWidth() : getWidth();
+        } else if (Math.abs(getTranslationX()) > getWidth() / 2) {
+            willExit = true;
+            endTranslation = (getTranslationX() < 0 ? -getWidth() : getWidth());
+        } else {
+            willExit = false;
+            endTranslation = 0;
+        }
+
+        SwipeDetector.ScrollInterpolator interpolator = new SwipeDetector.ScrollInterpolator();
+        interpolator.setVelocityAtZero(velocity);
+
+        long duration = SwipeDetector.calculateDuration(velocity,
+                (endTranslation - getTranslationX()) / getWidth());
+        animate()
+                .setDuration(duration)
+                .setInterpolator(interpolator)
+                .translationX(endTranslation)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        mSwipeDetector.finishedScrolling();
+                        if (willExit) {
+                            onChildDismissed();
+                        }
+                    }
+                }).start();
     }
 }
diff --git a/src/com/android/launcher3/notification/SwipeHelper.java b/src/com/android/launcher3/notification/SwipeHelper.java
deleted file mode 100644
index ebbe5fc..0000000
--- a/src/com/android/launcher3/notification/SwipeHelper.java
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * Copyright (C) 2017 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.notification;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.graphics.RectF;
-import android.os.Handler;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.accessibility.AccessibilityEvent;
-import com.android.launcher3.R;
-
-/**
- * This class was copied from com.android.systemui.
- */
-public class SwipeHelper {
-    private static final String TAG = "SwipeHelper";
-    private static final boolean DEBUG_INVALIDATE = false;
-    private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
-    private static final boolean CONSTRAIN_SWIPE = true;
-    private static final boolean FADE_OUT_DURING_SWIPE = true;
-    private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
-
-    public static final int X = 0;
-    public static final int Y = 1;
-
-    private static final float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
-    private static final int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
-    private static final int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
-    private static final int MAX_DISMISS_VELOCITY = 4000; // dp/sec
-    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
-
-    static final float SWIPE_PROGRESS_FADE_END = 0.5f; // fraction of thumbnail width
-                                                // beyond which swipe progress->0
-    private float mMinSwipeProgress = 0f;
-    private float mMaxSwipeProgress = 1f;
-
-    private final FlingAnimationUtils mFlingAnimationUtils;
-    private float mPagingTouchSlop;
-    private final Callback mCallback;
-    private final Handler mHandler;
-    private final int mSwipeDirection;
-    private final VelocityTracker mVelocityTracker;
-
-    private float mInitialTouchPos;
-    private float mPerpendicularInitialTouchPos;
-    private boolean mDragging;
-    private boolean mSnappingChild;
-    private View mCurrView;
-    private boolean mCanCurrViewBeDimissed;
-    private float mDensityScale;
-    private float mTranslation = 0;
-
-    private boolean mLongPressSent;
-    private LongPressListener mLongPressListener;
-    private Runnable mWatchLongPress;
-    private final long mLongPressTimeout;
-
-    final private int[] mTmpPos = new int[2];
-    private final int mFalsingThreshold;
-    private boolean mTouchAboveFalsingThreshold;
-    private boolean mDisableHwLayers;
-
-    private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
-
-    public SwipeHelper(int swipeDirection, Callback callback, Context context) {
-        mCallback = callback;
-        mHandler = new Handler();
-        mSwipeDirection = swipeDirection;
-        mVelocityTracker = VelocityTracker.obtain();
-        mDensityScale =  context.getResources().getDisplayMetrics().density;
-        mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
-
-        mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press!
-        mFalsingThreshold = context.getResources().getDimensionPixelSize(
-                R.dimen.swipe_helper_falsing_threshold);
-        mFlingAnimationUtils = new FlingAnimationUtils(context, getMaxEscapeAnimDuration() / 1000f);
-    }
-
-    public void setLongPressListener(LongPressListener listener) {
-        mLongPressListener = listener;
-    }
-
-    public void setDensityScale(float densityScale) {
-        mDensityScale = densityScale;
-    }
-
-    public void setPagingTouchSlop(float pagingTouchSlop) {
-        mPagingTouchSlop = pagingTouchSlop;
-    }
-
-    public void setDisableHardwareLayers(boolean disableHwLayers) {
-        mDisableHwLayers = disableHwLayers;
-    }
-
-    private float getPos(MotionEvent ev) {
-        return mSwipeDirection == X ? ev.getX() : ev.getY();
-    }
-
-    private float getPerpendicularPos(MotionEvent ev) {
-        return mSwipeDirection == X ? ev.getY() : ev.getX();
-    }
-
-    protected float getTranslation(View v) {
-        return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
-    }
-
-    private float getVelocity(VelocityTracker vt) {
-        return mSwipeDirection == X ? vt.getXVelocity() :
-                vt.getYVelocity();
-    }
-
-    protected ObjectAnimator createTranslationAnimation(View v, float newPos) {
-        ObjectAnimator anim = ObjectAnimator.ofFloat(v,
-                mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
-        return anim;
-    }
-
-    private float getPerpendicularVelocity(VelocityTracker vt) {
-        return mSwipeDirection == X ? vt.getYVelocity() :
-                vt.getXVelocity();
-    }
-
-    protected Animator getViewTranslationAnimator(View v, float target,
-            AnimatorUpdateListener listener) {
-        ObjectAnimator anim = createTranslationAnimation(v, target);
-        if (listener != null) {
-            anim.addUpdateListener(listener);
-        }
-        return anim;
-    }
-
-    protected void setTranslation(View v, float translate) {
-        if (v == null) {
-            return;
-        }
-        if (mSwipeDirection == X) {
-            v.setTranslationX(translate);
-        } else {
-            v.setTranslationY(translate);
-        }
-    }
-
-    protected float getSize(View v) {
-        return mSwipeDirection == X ? v.getMeasuredWidth() :
-                v.getMeasuredHeight();
-    }
-
-    public void setMinSwipeProgress(float minSwipeProgress) {
-        mMinSwipeProgress = minSwipeProgress;
-    }
-
-    public void setMaxSwipeProgress(float maxSwipeProgress) {
-        mMaxSwipeProgress = maxSwipeProgress;
-    }
-
-    private float getSwipeProgressForOffset(View view, float translation) {
-        float viewSize = getSize(view);
-        float result = Math.abs(translation / viewSize);
-        return Math.min(Math.max(mMinSwipeProgress, result), mMaxSwipeProgress);
-    }
-
-    private float getSwipeAlpha(float progress) {
-        return Math.min(0, Math.max(1, progress / SWIPE_PROGRESS_FADE_END));
-    }
-
-    private void updateSwipeProgressFromOffset(View animView, boolean dismissable) {
-        updateSwipeProgressFromOffset(animView, dismissable, getTranslation(animView));
-    }
-
-    private void updateSwipeProgressFromOffset(View animView, boolean dismissable,
-            float translation) {
-        float swipeProgress = getSwipeProgressForOffset(animView, translation);
-        if (!mCallback.updateSwipeProgress(animView, dismissable, swipeProgress)) {
-            if (FADE_OUT_DURING_SWIPE && dismissable) {
-                float alpha = swipeProgress;
-                if (!mDisableHwLayers) {
-                    if (alpha != 0f && alpha != 1f) {
-                        animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-                    } else {
-                        animView.setLayerType(View.LAYER_TYPE_NONE, null);
-                    }
-                }
-                animView.setAlpha(getSwipeAlpha(swipeProgress));
-            }
-        }
-        invalidateGlobalRegion(animView);
-    }
-
-    // invalidate the view's own bounds all the way up the view hierarchy
-    public static void invalidateGlobalRegion(View view) {
-        invalidateGlobalRegion(
-                view,
-                new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
-    }
-
-    // invalidate a rectangle relative to the view's coordinate system all the way up the view
-    // hierarchy
-    public static void invalidateGlobalRegion(View view, RectF childBounds) {
-        //childBounds.offset(view.getTranslationX(), view.getTranslationY());
-        if (DEBUG_INVALIDATE)
-            Log.v(TAG, "-------------");
-        while (view.getParent() != null && view.getParent() instanceof View) {
-            view = (View) view.getParent();
-            view.getMatrix().mapRect(childBounds);
-            view.invalidate((int) Math.floor(childBounds.left),
-                    (int) Math.floor(childBounds.top),
-                    (int) Math.ceil(childBounds.right),
-                    (int) Math.ceil(childBounds.bottom));
-            if (DEBUG_INVALIDATE) {
-                Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
-                        + "," + (int) Math.floor(childBounds.top)
-                        + "," + (int) Math.ceil(childBounds.right)
-                        + "," + (int) Math.ceil(childBounds.bottom));
-            }
-        }
-    }
-
-    public void removeLongPressCallback() {
-        if (mWatchLongPress != null) {
-            mHandler.removeCallbacks(mWatchLongPress);
-            mWatchLongPress = null;
-        }
-    }
-
-    public boolean onInterceptTouchEvent(final MotionEvent ev) {
-        final int action = ev.getAction();
-
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                mTouchAboveFalsingThreshold = false;
-                mDragging = false;
-                mSnappingChild = false;
-                mLongPressSent = false;
-                mVelocityTracker.clear();
-                mCurrView = mCallback.getChildAtPosition(ev);
-
-                if (mCurrView != null) {
-                    onDownUpdate(mCurrView);
-                    mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
-                    mVelocityTracker.addMovement(ev);
-                    mInitialTouchPos = getPos(ev);
-                    mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
-                    mTranslation = getTranslation(mCurrView);
-                    if (mLongPressListener != null) {
-                        if (mWatchLongPress == null) {
-                            mWatchLongPress = new Runnable() {
-                                @Override
-                                public void run() {
-                                    if (mCurrView != null && !mLongPressSent) {
-                                        mLongPressSent = true;
-                                        mCurrView.sendAccessibilityEvent(
-                                                AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
-                                        mCurrView.getLocationOnScreen(mTmpPos);
-                                        final int x = (int) ev.getRawX() - mTmpPos[0];
-                                        final int y = (int) ev.getRawY() - mTmpPos[1];
-                                        mLongPressListener.onLongPress(mCurrView, x, y);
-                                    }
-                                }
-                            };
-                        }
-                        mHandler.postDelayed(mWatchLongPress, mLongPressTimeout);
-                    }
-                }
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                if (mCurrView != null && !mLongPressSent) {
-                    mVelocityTracker.addMovement(ev);
-                    float pos = getPos(ev);
-                    float perpendicularPos = getPerpendicularPos(ev);
-                    float delta = pos - mInitialTouchPos;
-                    float deltaPerpendicular = perpendicularPos - mPerpendicularInitialTouchPos;
-                    if (Math.abs(delta) > mPagingTouchSlop
-                            && Math.abs(delta) > Math.abs(deltaPerpendicular)) {
-                        mCallback.onBeginDrag(mCurrView);
-                        mDragging = true;
-                        mInitialTouchPos = getPos(ev);
-                        mTranslation = getTranslation(mCurrView);
-                        removeLongPressCallback();
-                    }
-                }
-                break;
-
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                final boolean captured = (mDragging || mLongPressSent);
-                mDragging = false;
-                mCurrView = null;
-                mLongPressSent = false;
-                removeLongPressCallback();
-                if (captured) return true;
-                break;
-        }
-        return mDragging || mLongPressSent;
-    }
-
-    /**
-     * @param view The view to be dismissed
-     * @param velocity The desired pixels/second speed at which the view should move
-     * @param useAccelerateInterpolator Should an accelerating Interpolator be used
-     */
-    public void dismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
-        dismissChild(view, velocity, null /* endAction */, 0 /* delay */,
-                useAccelerateInterpolator, 0 /* fixedDuration */, false /* isDismissAll */);
-    }
-
-    /**
-     * @param animView The view to be dismissed
-     * @param velocity The desired pixels/second speed at which the view should move
-     * @param endAction The action to perform at the end
-     * @param delay The delay after which we should start
-     * @param useAccelerateInterpolator Should an accelerating Interpolator be used
-     * @param fixedDuration If not 0, this exact duration will be taken
-     */
-    public void dismissChild(final View animView, float velocity, final Runnable endAction,
-            long delay, boolean useAccelerateInterpolator, long fixedDuration,
-            boolean isDismissAll) {
-        final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
-        float newPos;
-        boolean isLayoutRtl = animView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-
-        // if we use the Menu to dismiss an item in landscape, animate up
-        boolean animateUpForMenu = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll)
-                && mSwipeDirection == Y;
-        // if the language is rtl we prefer swiping to the left
-        boolean animateLeftForRtl = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll)
-                && isLayoutRtl;
-        boolean animateLeft = velocity < 0
-                || (velocity == 0 && getTranslation(animView) < 0 && !isDismissAll);
-
-        if (animateLeft || animateLeftForRtl || animateUpForMenu) {
-            newPos = -getSize(animView);
-        } else {
-            newPos = getSize(animView);
-        }
-        long duration;
-        if (fixedDuration == 0) {
-            duration = MAX_ESCAPE_ANIMATION_DURATION;
-            if (velocity != 0) {
-                duration = Math.min(duration,
-                        (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
-                                .abs(velocity))
-                );
-            } else {
-                duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
-            }
-        } else {
-            duration = fixedDuration;
-        }
-
-        if (!mDisableHwLayers) {
-            animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-        }
-        AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-            public void onAnimationUpdate(ValueAnimator animation) {
-                onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
-            }
-        };
-
-        Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
-        if (anim == null) {
-            return;
-        }
-        if (useAccelerateInterpolator) {
-            anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
-            anim.setDuration(duration);
-        } else {
-            mFlingAnimationUtils.applyDismissing(anim, getTranslation(animView),
-                    newPos, velocity, getSize(animView));
-        }
-        if (delay > 0) {
-            anim.setStartDelay(delay);
-        }
-        anim.addListener(new AnimatorListenerAdapter() {
-            private boolean mCancelled;
-
-            public void onAnimationCancel(Animator animation) {
-                mCancelled = true;
-            }
-
-            public void onAnimationEnd(Animator animation) {
-                updateSwipeProgressFromOffset(animView, canBeDismissed);
-                mDismissPendingMap.remove(animView);
-                if (!mCancelled) {
-                    mCallback.onChildDismissed(animView);
-                }
-                if (endAction != null) {
-                    endAction.run();
-                }
-                if (!mDisableHwLayers) {
-                    animView.setLayerType(View.LAYER_TYPE_NONE, null);
-                }
-            }
-        });
-
-        prepareDismissAnimation(animView, anim);
-        mDismissPendingMap.put(animView, anim);
-        anim.start();
-    }
-
-    /**
-     * Called to update the dismiss animation.
-     */
-    protected void prepareDismissAnimation(View view, Animator anim) {
-        // Do nothing
-    }
-
-    public void snapChild(final View animView, final float targetLeft, float velocity) {
-        final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
-        AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-            public void onAnimationUpdate(ValueAnimator animation) {
-                onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
-            }
-        };
-
-        Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
-        if (anim == null) {
-            return;
-        }
-        int duration = SNAP_ANIM_LEN;
-        anim.setDuration(duration);
-        anim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationEnd(Animator animator) {
-                mSnappingChild = false;
-                updateSwipeProgressFromOffset(animView, canBeDismissed);
-                mCallback.onChildSnappedBack(animView, targetLeft);
-            }
-        });
-        prepareSnapBackAnimation(animView, anim);
-        mSnappingChild = true;
-        anim.start();
-    }
-
-    /**
-     * Called to update the snap back animation.
-     */
-    protected void prepareSnapBackAnimation(View view, Animator anim) {
-        // Do nothing
-    }
-
-    /**
-     * Called when there's a down event.
-     */
-    public void onDownUpdate(View currView) {
-        // Do nothing
-    }
-
-    /**
-     * Called on a move event.
-     */
-    protected void onMoveUpdate(View view, float totalTranslation, float delta) {
-        // Do nothing
-    }
-
-    /**
-     * Called in {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)} when the current
-     * view is being animated to dismiss or snap.
-     */
-    public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
-        updateSwipeProgressFromOffset(animView, canBeDismissed, value);
-    }
-
-    private void snapChildInstantly(final View view) {
-        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
-        setTranslation(view, 0);
-        updateSwipeProgressFromOffset(view, canAnimViewBeDismissed);
-    }
-
-    /**
-     * Called when a view is updated to be non-dismissable, if the view was being dismissed before
-     * the update this will handle snapping it back into place.
-     *
-     * @param view the view to snap if necessary.
-     * @param animate whether to animate the snap or not.
-     * @param targetLeft the target to snap to.
-     */
-    public void snapChildIfNeeded(final View view, boolean animate, float targetLeft) {
-        if ((mDragging && mCurrView == view) || mSnappingChild) {
-            return;
-        }
-        boolean needToSnap = false;
-        Animator dismissPendingAnim = mDismissPendingMap.get(view);
-        if (dismissPendingAnim != null) {
-            needToSnap = true;
-            dismissPendingAnim.cancel();
-        } else if (getTranslation(view) != 0) {
-            needToSnap = true;
-        }
-        if (needToSnap) {
-            if (animate) {
-                snapChild(view, targetLeft, 0.0f /* velocity */);
-            } else {
-                snapChildInstantly(view);
-            }
-        }
-    }
-
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (mLongPressSent) {
-            return true;
-        }
-
-        if (!mDragging) {
-            if (mCallback.getChildAtPosition(ev) != null) {
-
-                // We are dragging directly over a card, make sure that we also catch the gesture
-                // even if nobody else wants the touch event.
-                onInterceptTouchEvent(ev);
-                 return true;
-            } else {
-
-                // We are not doing anything, make sure the long press callback
-                // is not still ticking like a bomb waiting to go off.
-                removeLongPressCallback();
-                return false;
-            }
-        }
-
-        mVelocityTracker.addMovement(ev);
-        final int action = ev.getAction();
-        switch (action) {
-            case MotionEvent.ACTION_OUTSIDE:
-            case MotionEvent.ACTION_MOVE:
-                if (mCurrView != null) {
-                    float delta = getPos(ev) - mInitialTouchPos;
-                    float absDelta = Math.abs(delta);
-                    if (absDelta >= getFalsingThreshold()) {
-                        mTouchAboveFalsingThreshold = true;
-                    }
-                    // don't let items that can't be dismissed be dragged more than
-                    // maxScrollDistance
-                    if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
-                        float size = getSize(mCurrView);
-                        float maxScrollDistance = 0.25f * size;
-                        if (absDelta >= size) {
-                            delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
-                        } else {
-                            delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
-                        }
-                    }
-
-                    setTranslation(mCurrView, mTranslation + delta);
-                    updateSwipeProgressFromOffset(mCurrView, mCanCurrViewBeDimissed);
-                    onMoveUpdate(mCurrView, mTranslation + delta, delta);
-                }
-                break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                if (mCurrView == null) {
-                    break;
-                }
-                mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, getMaxVelocity());
-                float velocity = getVelocity(mVelocityTracker);
-
-                if (!handleUpEvent(ev, mCurrView, velocity, getTranslation(mCurrView))) {
-                    if (isDismissGesture(ev)) {
-                        // flingadingy
-                        dismissChild(mCurrView, velocity,
-                                !swipedFastEnough() /* useAccelerateInterpolator */);
-                    } else {
-                        // snappity
-                        mCallback.onDragCancelled(mCurrView);
-                        snapChild(mCurrView, 0 /* leftTarget */, velocity);
-                    }
-                    mCurrView = null;
-                }
-                mDragging = false;
-                break;
-        }
-        return true;
-    }
-
-    private int getFalsingThreshold() {
-        float factor = mCallback.getFalsingThresholdFactor();
-        return (int) (mFalsingThreshold * factor);
-    }
-
-    private float getMaxVelocity() {
-        return MAX_DISMISS_VELOCITY * mDensityScale;
-    }
-
-    protected float getEscapeVelocity() {
-        return getUnscaledEscapeVelocity() * mDensityScale;
-    }
-
-    protected float getUnscaledEscapeVelocity() {
-        return SWIPE_ESCAPE_VELOCITY;
-    }
-
-    protected long getMaxEscapeAnimDuration() {
-        return MAX_ESCAPE_ANIMATION_DURATION;
-    }
-
-    protected boolean swipedFarEnough() {
-        float translation = getTranslation(mCurrView);
-        return DISMISS_IF_SWIPED_FAR_ENOUGH && Math.abs(translation) > 0.4 * getSize(mCurrView);
-    }
-
-    protected boolean isDismissGesture(MotionEvent ev) {
-        boolean falsingDetected = mCallback.isAntiFalsingNeeded() && !mTouchAboveFalsingThreshold;
-        return !falsingDetected && (swipedFastEnough() || swipedFarEnough())
-                && ev.getActionMasked() == MotionEvent.ACTION_UP
-                && mCallback.canChildBeDismissed(mCurrView);
-    }
-
-    protected boolean swipedFastEnough() {
-        float velocity = getVelocity(mVelocityTracker);
-        float translation = getTranslation(mCurrView);
-        boolean ret = (Math.abs(velocity) > getEscapeVelocity())
-                && (velocity > 0) == (translation > 0);
-        return ret;
-    }
-
-    protected boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
-            float translation) {
-        return false;
-    }
-
-    public interface Callback {
-        View getChildAtPosition(MotionEvent ev);
-
-        boolean canChildBeDismissed(View v);
-
-        boolean isAntiFalsingNeeded();
-
-        void onBeginDrag(View v);
-
-        void onChildDismissed(View v);
-
-        void onDragCancelled(View v);
-
-        /**
-         * Called when the child is snapped to a position.
-         *
-         * @param animView the view that was snapped.
-         * @param targetLeft the left position the view was snapped to.
-         */
-        void onChildSnappedBack(View animView, float targetLeft);
-
-        /**
-         * Updates the swipe progress on a child.
-         *
-         * @return if true, prevents the default alpha fading.
-         */
-        boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress);
-
-        /**
-         * @return The factor the falsing threshold should be multiplied with
-         */
-        float getFalsingThresholdFactor();
-    }
-
-    /**
-     * Equivalent to View.OnLongClickListener with coordinates
-     */
-    public interface LongPressListener {
-        /**
-         * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
-         * @return whether the longpress was handled
-         */
-        boolean onLongPress(View v, int x, int y);
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
index 8bcb979..682d5a9 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
@@ -57,7 +57,7 @@
     protected void onDraw(Canvas canvas) {
         Rect drawableBounds = getCaretDrawable().getBounds();
         int count = canvas.save();
-        canvas.translate(getWidth() - drawableBounds.width(),
+        canvas.translate((getWidth() - drawableBounds.width()) / 2,
                 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 6b992fc..29834d7 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
@@ -21,7 +21,9 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dynamicui.ExtractedColors;
+import com.android.launcher3.dynamicui.WallpaperColorInfo;
 
 /**
  * A PageIndicator that briefly shows a fraction of a line when moving between pages.
@@ -128,6 +130,10 @@
         mLauncher = Launcher.getLauncher(context);
         mLineHeight = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_line_height);
         setCaretDrawable(new CaretDrawable(context));
+
+        boolean darkText = WallpaperColorInfo.getInstance(context).supportsDarkText();
+        mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
+        mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE);
     }
 
     @Override
@@ -219,6 +225,9 @@
      * - mostly opaque black if the hotseat is black (ignoring alpha)
      */
     public void updateColor(ExtractedColors extractedColors) {
+        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+            return;
+        }
         int originalLineAlpha = mLinePaint.getAlpha();
         int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX);
         if (color != Color.TRANSPARENT) {
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 77375fa..c3e2d8b 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
 import android.content.Context;
@@ -43,7 +44,6 @@
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AccelerateDecelerateInterpolator;
-import android.widget.FrameLayout;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BubbleTextView;
@@ -53,7 +53,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
@@ -118,6 +117,7 @@
     private boolean mIsLeftAligned;
     protected boolean mIsAboveIcon;
     private View mArrow;
+    private int mGravity;
 
     protected Animator mOpenCloseAnimator;
     private boolean mDeferContainerRemoval;
@@ -285,9 +285,11 @@
                 int roundedCorners = ROUNDED_TOP_CORNERS | ROUNDED_BOTTOM_CORNERS;
                 if (shouldUnroundTopCorners) {
                     roundedCorners &= ~ROUNDED_TOP_CORNERS;
+                    mNotificationItemView.findViewById(R.id.gutter_top).setVisibility(VISIBLE);
                 }
                 if (shouldUnroundBottomCorners) {
                     roundedCorners &= ~ROUNDED_BOTTOM_CORNERS;
+                    mNotificationItemView.findViewById(R.id.gutter_bottom).setVisibility(VISIBLE);
                 }
                 int backgroundColor = Themes.getAttrColor(mLauncher, R.attr.popupColorTertiary);
                 mNotificationItemView.setBackgroundWithCorners(backgroundColor, roundedCorners);
@@ -308,9 +310,15 @@
                 }
                 if (itemTypeToPopulate != PopupPopulator.Item.SYSTEM_SHORTCUT_ICON
                         && numNotifications > 0) {
+                    int prevHeight = item.getLayoutParams().height;
                     // Condense shortcuts height when there are notifications.
                     item.getLayoutParams().height = res.getDimensionPixelSize(
                             R.dimen.bg_popup_item_condensed_height);
+                    if (item instanceof DeepShortcutView) {
+                        float iconScale = (float) item.getLayoutParams().height / prevHeight;
+                        ((DeepShortcutView) item).getIconView().setScaleX(iconScale);
+                        ((DeepShortcutView) item).getIconView().setScaleY(iconScale);
+                    }
                 }
                 mShortcutsItemView.addShortcutView(item, itemTypeToPopulate);
                 if (shouldUnroundBottomCorners) {
@@ -320,8 +328,7 @@
                 addView(item);
             }
         }
-        int backgroundColor = Themes.getAttrColor(mLauncher, mNotificationItemView == null
-                ? R.attr.popupColorPrimary : R.attr.popupColorSecondary);
+        int backgroundColor = Themes.getAttrColor(mLauncher, R.attr.popupColorPrimary);
         mShortcutsItemView.setBackgroundWithCorners(backgroundColor, shortcutsItemRoundedCorners);
         if (numNotifications > 0) {
             mShortcutsItemView.hideShortcuts(mIsAboveIcon, MAX_SHORTCUTS_IF_NOTIFICATIONS);
@@ -347,6 +354,8 @@
 
         final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
         final Resources res = getResources();
+        final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
+        final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
 
         // Rectangular reveal.
         int itemsTotalHeight = 0;
@@ -360,8 +369,13 @@
         mEndRect.set(0, top, getMeasuredWidth(), top + itemsTotalHeight);
         final ValueAnimator revealAnim = new RoundedRectRevealOutlineProvider
                 (radius, radius, mStartRect, mEndRect).createRevealAnimator(this, false);
-        revealAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
-        revealAnim.setInterpolator(new AccelerateDecelerateInterpolator());
+        revealAnim.setDuration(revealDuration);
+        revealAnim.setInterpolator(revealInterpolator);
+
+        Animator fadeIn = ObjectAnimator.ofFloat(this, ALPHA, 0, 1);
+        fadeIn.setDuration(revealDuration);
+        fadeIn.setInterpolator(revealInterpolator);
+        openAnim.play(fadeIn);
 
         // Animate the arrow.
         mArrow.setScaleX(0);
@@ -385,6 +399,29 @@
         openAnim.start();
     }
 
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        enforceContainedWithinScreen(l, r);
+
+    }
+
+    private void enforceContainedWithinScreen(int left, int right) {
+        DragLayer dragLayer = mLauncher.getDragLayer();
+        if (getTranslationX() + left < 0 ||
+                getTranslationX() + right > dragLayer.getWidth()) {
+            // If we are still off screen, center horizontally too.
+            mGravity |= Gravity.CENTER_HORIZONTAL;
+        }
+
+        if (Gravity.isHorizontal(mGravity)) {
+            setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2);
+        }
+        if (Gravity.isVertical(mGravity)) {
+            setY(dragLayer.getHeight() / 2 - getMeasuredHeight() / 2);
+        }
+    }
+
     /**
      * Returns the point at which the center of the arrow merges with the first popup item.
      */
@@ -476,9 +513,10 @@
         }
         y -= insets.top;
 
-        if (y < dragLayer.getTop() || y + height > dragLayer.getBottom()) {
+        mGravity = 0;
+        if (y + height > dragLayer.getBottom() - insets.bottom) {
             // The container is opening off the screen, so just center it in the drag layer instead.
-            ((FrameLayout.LayoutParams) getLayoutParams()).gravity = Gravity.CENTER_VERTICAL;
+            mGravity = Gravity.CENTER_VERTICAL;
             // Put the container next to the icon, preferring the right side in ltr (left in rtl).
             int rightSide = leftAlignedX + iconWidth - insets.left;
             int leftSide = rightAlignedX - iconWidth - insets.left;
@@ -502,18 +540,8 @@
             mIsAboveIcon = true;
         }
 
-        if (x < dragLayer.getLeft() || x + width > dragLayer.getRight()) {
-            // If we are still off screen, center horizontally too.
-            ((FrameLayout.LayoutParams) getLayoutParams()).gravity |= Gravity.CENTER_HORIZONTAL;
-        }
-
-        int gravity = ((FrameLayout.LayoutParams) getLayoutParams()).gravity;
-        if (!Gravity.isHorizontal(gravity)) {
-            setX(x);
-        }
-        if (!Gravity.isVertical(gravity)) {
-            setY(y);
-        }
+        setX(x);
+        setY(y);
     }
 
     private boolean isAlignedWithStart() {
@@ -541,7 +569,7 @@
         }
 
         View arrowView = new View(getContext());
-        if (Gravity.isVertical(((FrameLayout.LayoutParams) getLayoutParams()).gravity)) {
+        if (Gravity.isVertical(mGravity)) {
             // This is only true if there wasn't room for the container next to the icon,
             // so we centered it instead. In that case we don't want to show the arrow.
             arrowView.setVisibility(INVISIBLE);
@@ -845,10 +873,8 @@
 
         final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
         final Resources res = getResources();
-
-        // Animate the arrow.
-        Animator arrowScale = createArrowScaleAnim(0).setDuration(res.getInteger(
-                R.integer.config_popupArrowOpenDuration));
+        final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
+        final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
 
         // Rectangular reveal (reversed).
         int itemsTotalHeight = 0;
@@ -864,11 +890,19 @@
         }
         final ValueAnimator revealAnim = new RoundedRectRevealOutlineProvider(
                 radius, radius, mStartRect, mEndRect).createRevealAnimator(this, true);
-        revealAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
-        revealAnim.setInterpolator(new AccelerateDecelerateInterpolator());
+        revealAnim.setDuration(revealDuration);
+        revealAnim.setInterpolator(revealInterpolator);
+        closeAnim.play(revealAnim);
+
+        Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0);
+        fadeOut.setDuration(revealDuration);
+        fadeOut.setInterpolator(revealInterpolator);
+        closeAnim.play(fadeOut);
 
         // Animate original icon's text back in.
-        closeAnim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */));
+        Animator fadeText = mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */);
+        fadeText.setDuration(revealDuration);
+        closeAnim.play(fadeText);
 
         closeAnim.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -882,7 +916,6 @@
             }
         });
         mOpenCloseAnimator = closeAnim;
-        closeAnim.playSequentially(arrowScale, revealAnim);
         closeAnim.start();
         mOriginalIcon.forceHideBadge(false);
     }
@@ -897,9 +930,7 @@
         }
         mIsOpen = false;
         mDeferContainerRemoval = false;
-        boolean isInHotseat = ((ItemInfo) mOriginalIcon.getTag()).container
-                == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
-        mOriginalIcon.setTextVisibility(!isInHotseat);
+        mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible());
         mOriginalIcon.forceHideBadge(false);
         mLauncher.getDragController().removeDragListener(this);
         mLauncher.getDragLayer().removeView(this);
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 00e2644..5230160 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -134,7 +134,7 @@
     }
 
     public static void setPending(Context context, boolean isPending) {
-        FileLog.d(TAG, "Restore data received through full backup");
+        FileLog.d(TAG, "Restore data received through full backup " + isPending);
         Utilities.getPrefs(context).edit().putBoolean(RESTORE_TASK_PENDING, isPending).commit();
     }
 }
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index 4dc3c1c..d26f9f6 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -39,12 +39,14 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
 
 /**
  * A frame layout which contains a QSB. This internally uses fragment to bind the view, which
  * allows it to contain the logic for {@link Fragment#startActivityForResult(Intent, int)}.
+ *
+ * Note: AppWidgetManagerCompat can be disabled using FeatureFlags. In QSB, we should use
+ * AppWidgetManager directly, so that it keeps working in that case.
  */
 public class QsbContainerView extends FrameLayout {
 
@@ -106,7 +108,7 @@
                 return QsbWidgetHostView.getDefaultView(container);
             }
 
-            AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(activity);
+            AppWidgetManager widgetManager = AppWidgetManager.getInstance(activity);
             InvariantDeviceProfile idp = LauncherAppState.getIDP(activity);
 
             Bundle opts = new Bundle();
@@ -129,7 +131,8 @@
                 }
 
                 widgetId = mQsbWidgetHost.allocateAppWidgetId();
-                isWidgetBound = widgetManager.bindAppWidgetIdIfAllowed(widgetId, mWidgetInfo, opts);
+                isWidgetBound = widgetManager.bindAppWidgetIdIfAllowed(
+                        widgetId, mWidgetInfo.getProfile(), mWidgetInfo.provider, opts);
                 if (!isWidgetBound) {
                     mQsbWidgetHost.deleteAppWidgetId(widgetId);
                     widgetId = -1;
diff --git a/src/com/android/launcher3/shortcuts/ShortcutsItemView.java b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
index 8785a56..b4fa04e 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
@@ -24,7 +24,6 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -35,6 +34,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.R;
+import com.android.launcher3.anim.PropertyListBuilder;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
@@ -144,18 +144,8 @@
             if (mSystemShortcutIcons == null) {
                 mSystemShortcutIcons = (LinearLayout) mLauncher.getLayoutInflater().inflate(
                         R.layout.system_shortcut_icons, mContent, false);
-
-                View divider = LayoutInflater.from(getContext()).inflate(
-                        R.layout.horizontal_divider, this, false);
-
                 boolean iconsAreBelowShortcuts = mShortcutsLayout.getChildCount() > 0;
-                if (iconsAreBelowShortcuts) {
-                    mContent.addView(divider);
-                    mContent.addView(mSystemShortcutIcons);
-                } else {
-                    mContent.addView(divider, 0);
-                    mContent.addView(mSystemShortcutIcons, 0);
-                }
+                mContent.addView(mSystemShortcutIcons, iconsAreBelowShortcuts ? -1 : 0);
             }
             mSystemShortcutIcons.addView(shortcutView, index);
         } else {
@@ -280,6 +270,9 @@
             // Make sure the text and icon stay centered in the shortcut.
             animation.play(translateYFrom(shortcut.getBubbleText(), heightDiff / 2 * fromDir));
             animation.play(translateYFrom(shortcut.getIconView(), heightDiff / 2 * fromDir));
+            // Scale icons back up to full size.
+            animation.play(LauncherAnimUtils.ofPropertyValuesHolder(shortcut.getIconView(),
+                    new PropertyListBuilder().scale(1f).build()));
         }
         return animation;
     }
diff --git a/src/com/android/launcher3/touch/OverScroll.java b/src/com/android/launcher3/touch/OverScroll.java
new file mode 100644
index 0000000..dc801ec
--- /dev/null
+++ b/src/com/android/launcher3/touch/OverScroll.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 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.touch;
+
+/**
+ * Utility methods for overscroll damping and related effect.
+ */
+public class OverScroll {
+
+    private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
+
+    /**
+     * This curve determines how the effect of scrolling over the limits of the page diminishes
+     * as the user pulls further and further from the bounds
+     *
+     * @param f The percentage of how much the user has overscrolled.
+     * @return A transformed percentage based on the influence curve.
+     */
+    private static float overScrollInfluenceCurve(float f) {
+        f -= 1.0f;
+        return f * f * f + 1.0f;
+    }
+
+    /**
+     * @param amount The original amount overscrolled.
+     * @param max The maximum amount that the View can overscroll.
+     * @return The dampened overscroll amount.
+     */
+    public static int dampedScroll(float amount, int max) {
+        if (Float.compare(amount, 0) == 0) return 0;
+
+        float f = amount / max;
+        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
+
+        // Clamp this factor, f, to -1 < f < 1
+        if (Math.abs(f) >= 1) {
+            f /= Math.abs(f);
+        }
+
+        return Math.round(OVERSCROLL_DAMP_FACTOR * f * max);
+    }
+}
diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
new file mode 100644
index 0000000..be4648e
--- /dev/null
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2017 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.touch;
+
+import static android.view.MotionEvent.INVALID_POINTER_ID;
+import android.content.Context;
+import android.graphics.PointF;
+import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+import android.view.animation.Interpolator;
+
+/**
+ * One dimensional scroll/drag/swipe gesture detector.
+ *
+ * Definition of swipe is different from android system in that this detector handles
+ * 'swipe to dismiss', 'swiping up/down a container' but also keeps scrolling state before
+ * swipe action happens
+ */
+public class SwipeDetector {
+
+    private static final boolean DBG = false;
+    private static final String TAG = "SwipeDetector";
+
+    private int mScrollConditions;
+    public static final int DIRECTION_POSITIVE = 1 << 0;
+    public static final int DIRECTION_NEGATIVE = 1 << 1;
+    public static final int DIRECTION_BOTH = DIRECTION_NEGATIVE | DIRECTION_POSITIVE;
+
+    private static final float ANIMATION_DURATION = 1200;
+    private static final float FAST_FLING_PX_MS = 10;
+
+    protected int mActivePointerId = INVALID_POINTER_ID;
+
+    /**
+     * The minimum release velocity in pixels per millisecond that triggers fling..
+     */
+    public static final float RELEASE_VELOCITY_PX_MS = 1.0f;
+
+    /**
+     * The time constant used to calculate dampening in the low-pass filter of scroll velocity.
+     * Cutoff frequency is set at 10 Hz.
+     */
+    public static final float SCROLL_VELOCITY_DAMPENING_RC = 1000f / (2f * (float) Math.PI * 10);
+
+    /* Scroll state, this is set to true during dragging and animation. */
+    private ScrollState mState = ScrollState.IDLE;
+
+    enum ScrollState {
+        IDLE,
+        DRAGGING,      // onDragStart, onDrag
+        SETTLING       // onDragEnd
+    }
+
+    public static abstract class Direction {
+
+        abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint);
+
+        /**
+         * Distance in pixels a touch can wander before we think the user is scrolling.
+         */
+        abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos);
+    }
+
+    public static final Direction VERTICAL = new Direction() {
+
+        @Override
+        float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) {
+            return ev.getY(pointerIndex) - refPoint.y;
+        }
+
+        @Override
+        float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos) {
+            return Math.abs(ev.getX(pointerIndex) - downPos.x);
+        }
+    };
+
+    public static final Direction HORIZONTAL = new Direction() {
+
+        @Override
+        float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) {
+            return ev.getX(pointerIndex) - refPoint.x;
+        }
+
+        @Override
+        float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos) {
+            return Math.abs(ev.getY(pointerIndex) - downPos.y);
+        }
+    };
+
+    //------------------- ScrollState transition diagram -----------------------------------
+    //
+    // IDLE ->      (mDisplacement > mTouchSlop) -> DRAGGING
+    // DRAGGING -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SETTLING
+    // SETTLING -> (MotionEvent#ACTION_DOWN) -> DRAGGING
+    // SETTLING -> (View settled) -> IDLE
+
+    private void setState(ScrollState newState) {
+        if (DBG) {
+            Log.d(TAG, "setState:" + mState + "->" + newState);
+        }
+        // onDragStart and onDragEnd is reported ONLY on state transition
+        if (newState == ScrollState.DRAGGING) {
+            initializeDragging();
+            if (mState == ScrollState.IDLE) {
+                reportDragStart(false /* recatch */);
+            } else if (mState == ScrollState.SETTLING) {
+                reportDragStart(true /* recatch */);
+            }
+        }
+        if (newState == ScrollState.SETTLING) {
+            reportDragEnd();
+        }
+
+        mState = newState;
+    }
+
+    public boolean isDraggingOrSettling() {
+        return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING;
+    }
+
+    /**
+     * There's no touch and there's no animation.
+     */
+    public boolean isIdleState() {
+        return mState == ScrollState.IDLE;
+    }
+
+    public boolean isSettlingState() {
+        return mState == ScrollState.SETTLING;
+    }
+
+    public boolean isDraggingState() {
+        return mState == ScrollState.DRAGGING;
+    }
+
+    private final PointF mDownPos = new PointF();
+    private final PointF mLastPos = new PointF();
+    private final Direction mDir;
+
+    private final float mTouchSlop;
+
+    /* Client of this gesture detector can register a callback. */
+    private final Listener mListener;
+
+    private long mCurrentMillis;
+
+    private float mVelocity;
+    private float mLastDisplacement;
+    private float mDisplacement;
+
+    private float mSubtractDisplacement;
+    private boolean mIgnoreSlopWhenSettling;
+
+    public interface Listener {
+        void onDragStart(boolean start);
+
+        boolean onDrag(float displacement, float velocity);
+
+        void onDragEnd(float velocity, boolean fling);
+    }
+
+    public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) {
+        this(ViewConfiguration.get(context).getScaledTouchSlop(), l, dir);
+    }
+
+    @VisibleForTesting
+    protected SwipeDetector(float touchSlope, @NonNull Listener l, @NonNull Direction dir) {
+        mTouchSlop = touchSlope;
+        mListener = l;
+        mDir = dir;
+    }
+
+    public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
+        mScrollConditions = scrollDirectionFlags;
+        mIgnoreSlopWhenSettling = ignoreSlop;
+    }
+
+    private boolean shouldScrollStart(MotionEvent ev, int pointerIndex) {
+        // reject cases where the angle or slop condition is not met.
+        if (Math.max(mDir.getActiveTouchSlop(ev, pointerIndex, mDownPos), mTouchSlop)
+                > Math.abs(mDisplacement)) {
+            return false;
+        }
+
+        // Check if the client is interested in scroll in current direction.
+        if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDisplacement > 0) ||
+                ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDisplacement < 0)) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean onTouchEvent(MotionEvent ev) {
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mActivePointerId = ev.getPointerId(0);
+                mDownPos.set(ev.getX(), ev.getY());
+                mLastPos.set(mDownPos);
+                mLastDisplacement = 0;
+                mDisplacement = 0;
+                mVelocity = 0;
+
+                if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
+                    setState(ScrollState.DRAGGING);
+                }
+                break;
+            //case MotionEvent.ACTION_POINTER_DOWN:
+            case MotionEvent.ACTION_POINTER_UP:
+                int ptrIdx = ev.getActionIndex();
+                int ptrId = ev.getPointerId(ptrIdx);
+                if (ptrId == mActivePointerId) {
+                    final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
+                    mDownPos.set(
+                            ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
+                            ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
+                    mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
+                    mActivePointerId = ev.getPointerId(newPointerIdx);
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                int pointerIndex = ev.findPointerIndex(mActivePointerId);
+                if (pointerIndex == INVALID_POINTER_ID) {
+                    break;
+                }
+                mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos);
+                computeVelocity(mDir.getDisplacement(ev, pointerIndex, mLastPos),
+                        ev.getEventTime());
+
+                // handle state and listener calls.
+                if (mState != ScrollState.DRAGGING && shouldScrollStart(ev, pointerIndex)) {
+                    setState(ScrollState.DRAGGING);
+                }
+                if (mState == ScrollState.DRAGGING) {
+                    reportDragging();
+                }
+                mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
+                break;
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                // These are synthetic events and there is no need to update internal values.
+                if (mState == ScrollState.DRAGGING) {
+                    setState(ScrollState.SETTLING);
+                }
+                break;
+            default:
+                break;
+        }
+        return true;
+    }
+
+    public void finishedScrolling() {
+        setState(ScrollState.IDLE);
+    }
+
+    private boolean reportDragStart(boolean recatch) {
+        mListener.onDragStart(!recatch);
+        if (DBG) {
+            Log.d(TAG, "onDragStart recatch:" + recatch);
+        }
+        return true;
+    }
+
+    private void initializeDragging() {
+        if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
+            mSubtractDisplacement = 0;
+        }
+        if (mDisplacement > 0) {
+            mSubtractDisplacement = mTouchSlop;
+        } else {
+            mSubtractDisplacement = -mTouchSlop;
+        }
+    }
+
+    private boolean reportDragging() {
+        if (mDisplacement != mLastDisplacement) {
+            if (DBG) {
+                Log.d(TAG, String.format("onDrag disp=%.1f, velocity=%.1f",
+                        mDisplacement, mVelocity));
+            }
+
+            mLastDisplacement = mDisplacement;
+            return mListener.onDrag(mDisplacement - mSubtractDisplacement, mVelocity);
+        }
+        return true;
+    }
+
+    private void reportDragEnd() {
+        if (DBG) {
+            Log.d(TAG, String.format("onScrollEnd disp=%.1f, velocity=%.1f",
+                    mDisplacement, mVelocity));
+        }
+        mListener.onDragEnd(mVelocity, Math.abs(mVelocity) > RELEASE_VELOCITY_PX_MS);
+
+    }
+
+    /**
+     * Computes the damped velocity.
+     */
+    public float computeVelocity(float delta, long currentMillis) {
+        long previousMillis = mCurrentMillis;
+        mCurrentMillis = currentMillis;
+
+        float deltaTimeMillis = mCurrentMillis - previousMillis;
+        float velocity = (deltaTimeMillis > 0) ? (delta / deltaTimeMillis) : 0;
+        if (Math.abs(mVelocity) < 0.001f) {
+            mVelocity = velocity;
+        } else {
+            float alpha = computeDampeningFactor(deltaTimeMillis);
+            mVelocity = interpolate(mVelocity, velocity, alpha);
+        }
+        return mVelocity;
+    }
+
+    /**
+     * Returns a time-dependent dampening factor using delta time.
+     */
+    private static float computeDampeningFactor(float deltaTime) {
+        return deltaTime / (SCROLL_VELOCITY_DAMPENING_RC + deltaTime);
+    }
+
+    /**
+     * Returns the linear interpolation between two values
+     */
+    private static float interpolate(float from, float to, float alpha) {
+        return (1.0f - alpha) * from + alpha * to;
+    }
+
+    public static long calculateDuration(float velocity, float progressNeeded) {
+        // TODO: make these values constants after tuning.
+        float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity));
+        float travelDistance = Math.max(0.2f, progressNeeded);
+        long duration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance);
+        if (DBG) {
+            Log.d(TAG, String.format("calculateDuration=%d, v=%f, d=%f", duration, velocity, progressNeeded));
+        }
+        return duration;
+    }
+
+    public static class ScrollInterpolator implements Interpolator {
+
+        boolean mSteeper;
+
+        public void setVelocityAtZero(float velocity) {
+            mSteeper = velocity > FAST_FLING_PX_MS;
+        }
+
+        public float getInterpolation(float t) {
+            t -= 1.0f;
+            float output = t * t * t;
+            if (mSteeper) {
+                output *= t * t; // Make interpolation initial slope steeper
+            }
+            return output + 1;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/LauncherEdgeEffect.java b/src/com/android/launcher3/util/LauncherEdgeEffect.java
deleted file mode 100644
index 3e3b255..0000000
--- a/src/com/android/launcher3/util/LauncherEdgeEffect.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.util;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-
-/**
- * This class differs from the framework {@link android.widget.EdgeEffect}:
- *   1) It does not use PorterDuffXfermode
- *   2) The width to radius factor is smaller (0.5 instead of 0.75)
- */
-public class LauncherEdgeEffect {
-
-    // Time it will take the effect to fully recede in ms
-    private static final int RECEDE_TIME = 600;
-
-    // Time it will take before a pulled glow begins receding in ms
-    private static final int PULL_TIME = 167;
-
-    // Time it will take in ms for a pulled glow to decay to partial strength before release
-    private static final int PULL_DECAY_TIME = 2000;
-
-    private static final float MAX_ALPHA = 0.5f;
-
-    private static final float MAX_GLOW_SCALE = 2.f;
-
-    private static final float PULL_GLOW_BEGIN = 0.f;
-
-    // Minimum velocity that will be absorbed
-    private static final int MIN_VELOCITY = 100;
-    // Maximum velocity, clamps at this value
-    private static final int MAX_VELOCITY = 10000;
-
-    private static final float EPSILON = 0.001f;
-
-    private static final double ANGLE = Math.PI / 6;
-    private static final float SIN = (float) Math.sin(ANGLE);
-    private static final float COS = (float) Math.cos(ANGLE);
-
-    private float mGlowAlpha;
-    private float mGlowScaleY;
-
-    private float mGlowAlphaStart;
-    private float mGlowAlphaFinish;
-    private float mGlowScaleYStart;
-    private float mGlowScaleYFinish;
-
-    private long mStartTime;
-    private float mDuration;
-
-    private final Interpolator mInterpolator;
-
-    private static final int STATE_IDLE = 0;
-    private static final int STATE_PULL = 1;
-    private static final int STATE_ABSORB = 2;
-    private static final int STATE_RECEDE = 3;
-    private static final int STATE_PULL_DECAY = 4;
-
-    private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f;
-
-    private static final int VELOCITY_GLOW_FACTOR = 6;
-
-    private int mState = STATE_IDLE;
-
-    private float mPullDistance;
-
-    private final Rect mBounds = new Rect();
-    private final Paint mPaint = new Paint();
-    private float mRadius;
-    private float mBaseGlowScale;
-    private float mDisplacement = 0.5f;
-    private float mTargetDisplacement = 0.5f;
-
-    /**
-     * Construct a new EdgeEffect with a theme appropriate for the provided context.
-     */
-    public LauncherEdgeEffect() {
-        mPaint.setAntiAlias(true);
-        mPaint.setStyle(Paint.Style.FILL);
-        mInterpolator = new DecelerateInterpolator();
-    }
-
-    /**
-     * Set the size of this edge effect in pixels.
-     *
-     * @param width Effect width in pixels
-     * @param height Effect height in pixels
-     */
-    public void setSize(int width, int height) {
-        final float r = width * 0.5f / SIN;
-        final float y = COS * r;
-        final float h = r - y;
-        final float or = height * 0.75f / SIN;
-        final float oy = COS * or;
-        final float oh = or - oy;
-
-        mRadius = r;
-        mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f;
-
-        mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));
-    }
-
-    /**
-     * Reports if this EdgeEffect's animation is finished. If this method returns false
-     * after a call to {@link #draw(Canvas)} the host widget should schedule another
-     * drawing pass to continue the animation.
-     *
-     * @return true if animation is finished, false if drawing should continue on the next frame.
-     */
-    public boolean isFinished() {
-        return mState == STATE_IDLE;
-    }
-
-    /**
-     * Immediately finish the current animation.
-     * After this call {@link #isFinished()} will return true.
-     */
-    public void finish() {
-        mState = STATE_IDLE;
-    }
-
-    /**
-     * A view should call this when content is pulled away from an edge by the user.
-     * This will update the state of the current visual effect and its associated animation.
-     * The host view should always {@link android.view.View#invalidate()} after this
-     * and draw the results accordingly.
-     *
-     * <p>Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement
-     * of the pull point is known.</p>
-     *
-     * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
-     *                      1.f (full length of the view) or negative values to express change
-     *                      back toward the edge reached to initiate the effect.
-     */
-    public void onPull(float deltaDistance) {
-        onPull(deltaDistance, 0.5f);
-    }
-
-    /**
-     * A view should call this when content is pulled away from an edge by the user.
-     * This will update the state of the current visual effect and its associated animation.
-     * The host view should always {@link android.view.View#invalidate()} after this
-     * and draw the results accordingly.
-     *
-     * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
-     *                      1.f (full length of the view) or negative values to express change
-     *                      back toward the edge reached to initiate the effect.
-     * @param displacement The displacement from the starting side of the effect of the point
-     *                     initiating the pull. In the case of touch this is the finger position.
-     *                     Values may be from 0-1.
-     */
-    public void onPull(float deltaDistance, float displacement) {
-        final long now = AnimationUtils.currentAnimationTimeMillis();
-        mTargetDisplacement = displacement;
-        if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) {
-            return;
-        }
-        if (mState != STATE_PULL) {
-            mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY);
-        }
-        mState = STATE_PULL;
-
-        mStartTime = now;
-        mDuration = PULL_TIME;
-
-        mPullDistance += deltaDistance;
-
-        final float absdd = Math.abs(deltaDistance);
-        mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,
-                mGlowAlpha + (absdd * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
-
-        if (mPullDistance == 0) {
-            mGlowScaleY = mGlowScaleYStart = 0;
-        } else {
-            final float scale = (float) (Math.max(0, 1 - 1 /
-                    Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3d) / 0.7d);
-
-            mGlowScaleY = mGlowScaleYStart = scale;
-        }
-
-        mGlowAlphaFinish = mGlowAlpha;
-        mGlowScaleYFinish = mGlowScaleY;
-    }
-
-    /**
-     * Call when the object is released after being pulled.
-     * This will begin the "decay" phase of the effect. After calling this method
-     * the host view should {@link android.view.View#invalidate()} and thereby
-     * draw the results accordingly.
-     */
-    public void onRelease() {
-        mPullDistance = 0;
-
-        if (mState != STATE_PULL && mState != STATE_PULL_DECAY) {
-            return;
-        }
-
-        mState = STATE_RECEDE;
-        mGlowAlphaStart = mGlowAlpha;
-        mGlowScaleYStart = mGlowScaleY;
-
-        mGlowAlphaFinish = 0.f;
-        mGlowScaleYFinish = 0.f;
-
-        mStartTime = AnimationUtils.currentAnimationTimeMillis();
-        mDuration = RECEDE_TIME;
-    }
-
-    /**
-     * Call when the effect absorbs an impact at the given velocity.
-     * Used when a fling reaches the scroll boundary.
-     *
-     * <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller},
-     * the method <code>getCurrVelocity</code> will provide a reasonable approximation
-     * to use here.</p>
-     *
-     * @param velocity Velocity at impact in pixels per second.
-     */
-    public void onAbsorb(int velocity) {
-        mState = STATE_ABSORB;
-        velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY);
-
-        mStartTime = AnimationUtils.currentAnimationTimeMillis();
-        mDuration = 0.15f + (velocity * 0.02f);
-
-        // The glow depends more on the velocity, and therefore starts out
-        // nearly invisible.
-        mGlowAlphaStart = 0.3f;
-        mGlowScaleYStart = Math.max(mGlowScaleY, 0.f);
-
-
-        // Growth for the size of the glow should be quadratic to properly
-        // respond
-        // to a user's scrolling speed. The faster the scrolling speed, the more
-        // intense the effect should be for both the size and the saturation.
-        mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f);
-        // Alpha should change for the glow as well as size.
-        mGlowAlphaFinish = Math.max(
-                mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA));
-        mTargetDisplacement = 0.5f;
-    }
-
-    /**
-     * Set the color of this edge effect in argb.
-     *
-     * @param color Color in argb
-     */
-    public void setColor(int color) {
-        mPaint.setColor(color);
-    }
-
-    /**
-     * Return the color of this edge effect in argb.
-     * @return The color of this edge effect in argb
-     */
-    public int getColor() {
-        return mPaint.getColor();
-    }
-
-    /**
-     * Draw into the provided canvas. Assumes that the canvas has been rotated
-     * accordingly and the size has been set. The effect will be drawn the full
-     * width of X=0 to X=width, beginning from Y=0 and extending to some factor <
-     * 1.f of height.
-     *
-     * @param canvas Canvas to draw into
-     * @return true if drawing should continue beyond this frame to continue the
-     *         animation
-     */
-    public boolean draw(Canvas canvas) {
-        update();
-
-        final float centerX = mBounds.centerX();
-        final float centerY = mBounds.height() - mRadius;
-
-        canvas.scale(1.f, Math.min(mGlowScaleY, 1.f) * mBaseGlowScale, centerX, 0);
-
-        final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f;
-        float translateX = mBounds.width() * displacement / 2;
-        mPaint.setAlpha((int) (0xff * mGlowAlpha));
-        canvas.drawCircle(centerX + translateX, centerY, mRadius, mPaint);
-
-        boolean oneLastFrame = false;
-        if (mState == STATE_RECEDE && mGlowScaleY == 0) {
-            mState = STATE_IDLE;
-            oneLastFrame = true;
-        }
-
-        return mState != STATE_IDLE || oneLastFrame;
-    }
-
-    /**
-     * Return the maximum height that the edge effect will be drawn at given the original
-     * {@link #setSize(int, int) input size}.
-     * @return The maximum height of the edge effect
-     */
-    public int getMaxHeight() {
-        return (int) (mBounds.height() * MAX_GLOW_SCALE + 0.5f);
-    }
-
-    private void update() {
-        final long time = AnimationUtils.currentAnimationTimeMillis();
-        final float t = Math.min((time - mStartTime) / mDuration, 1.f);
-
-        final float interp = mInterpolator.getInterpolation(t);
-
-        mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp;
-        mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp;
-        mDisplacement = (mDisplacement + mTargetDisplacement) / 2;
-
-        if (t >= 1.f - EPSILON) {
-            switch (mState) {
-                case STATE_ABSORB:
-                    mState = STATE_RECEDE;
-                    mStartTime = AnimationUtils.currentAnimationTimeMillis();
-                    mDuration = RECEDE_TIME;
-
-                    mGlowAlphaStart = mGlowAlpha;
-                    mGlowScaleYStart = mGlowScaleY;
-
-                    // After absorb, the glow should fade to nothing.
-                    mGlowAlphaFinish = 0.f;
-                    mGlowScaleYFinish = 0.f;
-                    break;
-                case STATE_PULL:
-                    mState = STATE_PULL_DECAY;
-                    mStartTime = AnimationUtils.currentAnimationTimeMillis();
-                    mDuration = PULL_DECAY_TIME;
-
-                    mGlowAlphaStart = mGlowAlpha;
-                    mGlowScaleYStart = mGlowScaleY;
-
-                    // After pull, the glow should fade to nothing.
-                    mGlowAlphaFinish = 0.f;
-                    mGlowScaleYFinish = 0.f;
-                    break;
-                case STATE_PULL_DECAY:
-                    mState = STATE_RECEDE;
-                    break;
-                case STATE_RECEDE:
-                    mState = STATE_IDLE;
-                    break;
-            }
-        }
-    }
-}
diff --git a/src/com/android/launcher3/views/ButtonPreference.java b/src/com/android/launcher3/views/ButtonPreference.java
new file mode 100644
index 0000000..4697e25
--- /dev/null
+++ b/src/com/android/launcher3/views/ButtonPreference.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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.views;
+
+import android.content.Context;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Extension of {@link Preference} which makes the widget layout clickable.
+ *
+ * @see #setWidgetLayoutResource(int)
+ */
+public class ButtonPreference extends Preference {
+
+    private View.OnClickListener mClickListener;
+
+    public ButtonPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public ButtonPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public ButtonPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public ButtonPreference(Context context) {
+        super(context);
+    }
+
+    public void setButtonOnClickListener(View.OnClickListener clickListener) {
+        if (mClickListener != clickListener) {
+            mClickListener = clickListener;
+            notifyChanged();
+        }
+    }
+
+    @Override
+    protected void onBindView(View view) {
+        super.onBindView(view);
+
+        ViewGroup widgetFrame = view.findViewById(android.R.id.widget_frame);
+        if (widgetFrame != null) {
+            View button = widgetFrame.getChildAt(0);
+            if (button != null) {
+                button.setOnClickListener(mClickListener);
+            }
+            widgetFrame.setVisibility(
+                    (mClickListener == null || button == null) ? View.GONE : View.VISIBLE);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index c0b5fe1..c8203f7 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -23,6 +23,7 @@
 import android.graphics.Region;
 import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
+import android.widget.TextView;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
@@ -50,13 +51,12 @@
 
     @Override
     public void onDraw(Canvas canvas) {
-        // If text is transparent, don't draw any shadow
-        int alpha = Color.alpha(getCurrentTextColor());
-        if (alpha == 0) {
-            getPaint().clearShadowLayer();
+        // If text is transparent or shadow alpha is 0, don't draw any shadow
+        if (mShadowInfo.skipDoubleShadow(this)) {
             super.onDraw(canvas);
             return;
         }
+        int alpha = Color.alpha(getCurrentTextColor());
 
         // We enhance the shadow by drawing the shadow twice
         getPaint().setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0,
@@ -97,5 +97,25 @@
             keyShadowColor = a.getColor(R.styleable.ShadowInfo_keyShadowColor, 0);
             a.recycle();
         }
+
+        public boolean skipDoubleShadow(TextView textView) {
+            int textAlpha = Color.alpha(textView.getCurrentTextColor());
+            int keyShadowAlpha = Color.alpha(keyShadowColor);
+            int ambientShadowAlpha = Color.alpha(ambientShadowColor);
+            if (textAlpha == 0 || (keyShadowAlpha == 0 && ambientShadowAlpha == 0)) {
+                textView.getPaint().clearShadowLayer();
+                return true;
+            } else if (ambientShadowAlpha > 0) {
+                textView.getPaint().setShadowLayer(ambientShadowBlur, 0, 0,
+                        ColorUtils.setAlphaComponent(ambientShadowColor, textAlpha));
+                return true;
+            } else if (keyShadowAlpha > 0) {
+                textView.getPaint().setShadowLayer(keyShadowBlur, 0.0f, keyShadowOffset,
+                        ColorUtils.setAlphaComponent(keyShadowColor, textAlpha));
+                return true;
+            } else {
+                return false;
+            }
+        }
     }
 }
diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
index e8f13a1..62b6903 100644
--- a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.widget;
 
-import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.compat.ShortcutConfigActivityInfo;
 
diff --git a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
index 629f30c..5387be8 100644
--- a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
+++ b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
@@ -15,10 +15,8 @@
  */
 package com.android.launcher3.widget;
 
-import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
-import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -26,7 +24,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppWidgetInfo;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.util.PendingRequestArgs;
 
 /**
@@ -56,15 +53,8 @@
 
     public void startBindFlow(Launcher launcher, int appWidgetId, ItemInfo info, int requestCode) {
         launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info));
-
-        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
-        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
-        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, mProviderInfo.provider);
-        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
-                mProviderInfo.getProfile());
-        // TODO: we need to make sure that this accounts for the options bundle.
-        // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
-        launcher.startActivityForResult(intent, requestCode);
+        launcher.getAppWidgetHost()
+                .startBindFlow(launcher, appWidgetId, mProviderInfo, requestCode);
     }
 
     /**
@@ -85,9 +75,7 @@
             return false;
         }
         launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info));
-
-        AppWidgetManagerCompat.getInstance(launcher).startConfigActivity(
-                mProviderInfo, appWidgetId, launcher, launcher.getAppWidgetHost(), requestCode);
+        launcher.getAppWidgetHost().startConfigActivity(launcher, appWidgetId, requestCode);
         return true;
     }
 
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index fff3472..0b4bf62 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -40,14 +40,16 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.VerticalPullDetector;
+import com.android.launcher3.touch.SwipeDetector;
 import com.android.launcher3.anim.PropertyListBuilder;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.graphics.GradientView;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TouchController;
 
 import java.util.List;
@@ -56,7 +58,7 @@
  * Bottom sheet for the "Widgets" system shortcut in the long-press popup.
  */
 public class WidgetsBottomSheet extends AbstractFloatingView implements Insettable, TouchController,
-        VerticalPullDetector.Listener, View.OnClickListener, View.OnLongClickListener,
+        SwipeDetector.Listener, View.OnClickListener, View.OnLongClickListener,
         DragController.DragListener {
 
     private int mTranslationYOpen;
@@ -67,9 +69,10 @@
     private ItemInfo mOriginalItemInfo;
     private ObjectAnimator mOpenCloseAnimator;
     private Interpolator mFastOutSlowInInterpolator;
-    private VerticalPullDetector.ScrollInterpolator mScrollInterpolator;
+    private SwipeDetector.ScrollInterpolator mScrollInterpolator;
     private Rect mInsets;
-    private VerticalPullDetector mVerticalPullDetector;
+    private SwipeDetector mSwipeDetector;
+    private GradientView mGradientBackground;
 
     public WidgetsBottomSheet(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -82,10 +85,10 @@
         mOpenCloseAnimator = LauncherAnimUtils.ofPropertyValuesHolder(this);
         mFastOutSlowInInterpolator =
                 AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
-        mScrollInterpolator = new VerticalPullDetector.ScrollInterpolator();
+        mScrollInterpolator = new SwipeDetector.ScrollInterpolator();
         mInsets = new Rect();
-        mVerticalPullDetector = new VerticalPullDetector(context);
-        mVerticalPullDetector.setListener(this);
+        mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL);
+        mGradientBackground = (GradientView) mLauncher.findViewById(R.id.gradient_bg);
     }
 
     @Override
@@ -178,15 +181,17 @@
             return;
         }
         mIsOpen = true;
+        boolean isSheetDark = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
         mLauncher.getSystemUiController().updateUiState(
-                SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, SystemUiController.FLAG_LIGHT_NAV);
+                SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET,
+                isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV);
         if (animate) {
             mOpenCloseAnimator.setValues(new PropertyListBuilder()
                     .translationY(mTranslationYOpen).build());
             mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    mVerticalPullDetector.finishedScrolling();
+                    mSwipeDetector.finishedScrolling();
                 }
             });
             mOpenCloseAnimator.setInterpolator(mFastOutSlowInInterpolator);
@@ -208,13 +213,13 @@
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     mIsOpen = false;
-                    mVerticalPullDetector.finishedScrolling();
+                    mSwipeDetector.finishedScrolling();
                     ((ViewGroup) getParent()).removeView(WidgetsBottomSheet.this);
                     mLauncher.getSystemUiController().updateUiState(
                             SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
                 }
             });
-            mOpenCloseAnimator.setInterpolator(mVerticalPullDetector.isIdleState()
+            mOpenCloseAnimator.setInterpolator(mSwipeDetector.isIdleState()
                     ? mFastOutSlowInInterpolator : mScrollInterpolator);
             mOpenCloseAnimator.start();
         } else {
@@ -253,7 +258,7 @@
                 getPaddingRight() + rightInset, getPaddingBottom() + bottomInset);
     }
 
-    /* VerticalPullDetector.Listener */
+    /* SwipeDetector.Listener */
 
     @Override
     public void onDragStart(boolean start) {
@@ -267,15 +272,24 @@
     }
 
     @Override
+    public void setTranslationY(float translationY) {
+        super.setTranslationY(translationY);
+        if (mGradientBackground == null) return;
+        float p = (mTranslationYClosed - translationY) / mTranslationYRange;
+        boolean showScrim = p <= 0;
+        mGradientBackground.setProgress(p, showScrim);
+    }
+
+    @Override
     public void onDragEnd(float velocity, boolean fling) {
         if ((fling && velocity > 0) || getTranslationY() > (mTranslationYRange) / 2) {
             mScrollInterpolator.setVelocityAtZero(velocity);
-            mOpenCloseAnimator.setDuration(mVerticalPullDetector.calculateDuration(velocity,
+            mOpenCloseAnimator.setDuration(SwipeDetector.calculateDuration(velocity,
                     (mTranslationYClosed - getTranslationY()) / mTranslationYRange));
             close(true);
         } else {
             mIsOpen = false;
-            mOpenCloseAnimator.setDuration(mVerticalPullDetector.calculateDuration(velocity,
+            mOpenCloseAnimator.setDuration(SwipeDetector.calculateDuration(velocity,
                     (getTranslationY() - mTranslationYOpen) / mTranslationYRange));
             open(true);
         }
@@ -283,17 +297,17 @@
 
     @Override
     public boolean onControllerTouchEvent(MotionEvent ev) {
-        return mVerticalPullDetector.onTouchEvent(ev);
+        return mSwipeDetector.onTouchEvent(ev);
     }
 
     @Override
     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-        int directionsToDetectScroll = mVerticalPullDetector.isIdleState() ?
-                VerticalPullDetector.DIRECTION_DOWN : 0;
-        mVerticalPullDetector.setDetectableScrollConditions(
+        int directionsToDetectScroll = mSwipeDetector.isIdleState() ?
+                SwipeDetector.DIRECTION_NEGATIVE : 0;
+        mSwipeDetector.setDetectableScrollConditions(
                 directionsToDetectScroll, false);
-        mVerticalPullDetector.onTouchEvent(ev);
-        return mVerticalPullDetector.isDraggingOrSettling();
+        mSwipeDetector.onTouchEvent(ev);
+        return mSwipeDetector.isDraggingOrSettling();
     }
 
     /* DragListener */
diff --git a/src_flags/com/android/launcher3/config/FeatureFlags.java b/src_flags/com/android/launcher3/config/FeatureFlags.java
index 42a110c..3ffb6c9 100644
--- a/src_flags/com/android/launcher3/config/FeatureFlags.java
+++ b/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -19,48 +19,7 @@
 /**
  * Defines a set of flags used to control various launcher behaviors
  */
-public final class FeatureFlags {
-
-    public static final boolean IS_DOGFOOD_BUILD = true;
+public final class FeatureFlags extends BaseFlags {
 
     private FeatureFlags() {}
-
-    // Custom flags go below this
-    public static boolean LAUNCHER3_DISABLE_ICON_NORMALIZATION = false;
-    public static boolean LAUNCHER3_LEGACY_FOLDER_ICON = false;
-    public static boolean LAUNCHER3_USE_SYSTEM_DRAG_DRIVER = true;
-    public static boolean LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW = false;
-    public static boolean LAUNCHER3_ALL_APPS_PULL_UP = true;
-    public static boolean LAUNCHER3_NEW_FOLDER_ANIMATION = true;
-    // When enabled allows to use any point on the fast scrollbar to start dragging.
-    public static boolean LAUNCHER3_DIRECT_SCROLL = true;
-    // When enabled while all-apps open, the soft input will be set to adjust resize .
-    public static boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = true;
-    // When enabled the promise icon is visible in all apps while installation an app.
-    public static boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
-    // When enabled uses the AllAppsRadialGradientAndScrimDrawable for all apps
-    public static boolean LAUNCHER3_GRADIENT_ALL_APPS = true;
-    // When enabled allows use of physics based motions in the Launcher.
-    public static boolean LAUNCHER3_PHYSICS = true;
-    // When enabled allows use of spring motions on the icons.
-    public static boolean LAUNCHER3_SPRING_ICONS = true;
-
-    // Feature flag to enable moving the QSB on the 0th screen of the workspace.
-    public static final boolean QSB_ON_FIRST_SCREEN = true;
-    // When enabled the all-apps icon is not added to the hotseat.
-    public static final boolean NO_ALL_APPS_ICON = true;
-    // When enabled fling down gesture on the first workspace triggers search.
-    public static final boolean PULLDOWN_SEARCH = false;
-    // When enabled the status bar may show dark icons based on the top of the wallpaper.
-    public static final boolean LIGHT_STATUS_BAR = false;
-    // When enabled icons are badged with the number of notifications associated with that app.
-    public static final boolean BADGE_ICONS = true;
-    // When enabled, icons not supporting {@link AdaptiveIconDrawable} will be wrapped in {@link FixedScaleDrawable}.
-    public static final boolean LEGACY_ICON_TREATMENT = true;
-    // When enabled, adaptive icons would have shadows baked when being stored to icon cache.
-    public static final boolean ADAPTIVE_ICON_SHADOW = true;
-    // When enabled, app discovery will be enabled if service is implemented
-    public static final boolean DISCOVERY_ENABLED = false;
-    // When enabled, the qsb will be moved to the hotseat.
-    public static final boolean QSB_IN_HOTSEAT = true;
 }
diff --git a/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java b/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
index 58dc0c4..26ec69b 100644
--- a/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
+++ b/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
@@ -19,6 +19,7 @@
 import android.test.InstrumentationTestCase;
 
 import com.android.launcher3.AppInfo;
+import com.android.launcher3.Utilities;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -75,6 +76,25 @@
         assertTrue(mAlgorithm.matches(getInfo("电子邮件"), "电子"));
         assertFalse(mAlgorithm.matches(getInfo("电子邮件"), "子"));
         assertFalse(mAlgorithm.matches(getInfo("电子邮件"), "邮件"));
+
+        assertFalse(mAlgorithm.matches(getInfo("Bot"), "ba"));
+        assertFalse(mAlgorithm.matches(getInfo("bot"), "ba"));
+    }
+
+    public void testMatchesVN() {
+        if (!Utilities.ATLEAST_NOUGAT) {
+            return;
+        }
+        assertTrue(mAlgorithm.matches(getInfo("다운로드"), "다"));
+        assertTrue(mAlgorithm.matches(getInfo("드라이브"), "드"));
+        assertTrue(mAlgorithm.matches(getInfo("다운로드 드라이브"), "ㄷ"));
+        assertTrue(mAlgorithm.matches(getInfo("운로 드라이브"), "ㄷ"));
+        assertTrue(mAlgorithm.matches(getInfo("abc"), "åbç"));
+        assertTrue(mAlgorithm.matches(getInfo("Alpha"), "ål"));
+
+        assertFalse(mAlgorithm.matches(getInfo("다운로드 드라이브"), "ㄷㄷ"));
+        assertFalse(mAlgorithm.matches(getInfo("로드라이브"), "ㄷ"));
+        assertFalse(mAlgorithm.matches(getInfo("abc"), "åç"));
     }
 
     private AppInfo getInfo(String title) {
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 29f738b..5858e13 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -47,11 +47,8 @@
     }
 
     private int getCount(SQLiteDatabase db, String sql) {
-        Cursor c = db.rawQuery(sql, null);
-        try {
+        try (Cursor c = db.rawQuery(sql, null)) {
             return c.getCount();
-        } finally {
-            c.getCount();
         }
     }
 
@@ -59,7 +56,7 @@
 
         private final long mProfileId;
 
-        public MyDatabaseHelper(long profileId) {
+        MyDatabaseHelper(long profileId) {
             super(getContext(), null, null);
             mProfileId = profileId;
         }
diff --git a/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java b/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
new file mode 100644
index 0000000..80d6341
--- /dev/null
+++ b/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2017 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.testcomponent;
+
+import android.graphics.Point;
+import android.util.Pair;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility class to generate MotionEvent event sequences for testing touch gesture detectors.
+ */
+public class TouchEventGenerator {
+
+    /**
+     * Amount of time between two generated events.
+     */
+    private static final long TIME_INCREMENT_MS = 20L;
+
+    /**
+     * Id of the fake device generating the events.
+     */
+    private static final int DEVICE_ID = 2104;
+
+    /**
+     * The fingers currently present on the emulated touch screen.
+     */
+    private Map<Integer, Point> mFingers;
+
+    /**
+     * Initial event time for the current sequence.
+     */
+    private long mInitialTime;
+
+    /**
+     * Time of the last generated event.
+     */
+    private long mLastEventTime;
+
+    /**
+     * Time of the next event.
+     */
+    private long mTime;
+
+    /**
+     * Receives the generated events.
+     */
+    public interface Listener {
+
+        /**
+         * Called when an event was generated.
+         */
+        void onTouchEvent(MotionEvent event);
+    }
+    private final Listener mListener;
+
+    public TouchEventGenerator(Listener listener) {
+        mListener = listener;
+        mFingers = new HashMap<Integer, Point>();
+    }
+
+    /**
+     * Adds a finger on the touchscreen.
+     */
+    public TouchEventGenerator put(int id, int x, int y, long ms) {
+        checkFingerExistence(id, false);
+        boolean isInitialDown = mFingers.isEmpty();
+        mFingers.put(id, new Point(x, y));
+        int action;
+        if (isInitialDown) {
+            action = MotionEvent.ACTION_DOWN;
+        } else {
+            action = MotionEvent.ACTION_POINTER_DOWN;
+            // Set the id of the changed pointer.
+            action |= id << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+        }
+        generateEvent(action, ms);
+        return this;
+    }
+
+    /**
+     * Adds a finger on the touchscreen after advancing default time interval.
+     */
+    public TouchEventGenerator put(int id, int x, int y) {
+        return put(id, x, y, TIME_INCREMENT_MS);
+    }
+
+    /**
+     * Adjusts the position of a finger for an upcoming move event.
+     *
+     * @see #move(long ms)
+     */
+    public TouchEventGenerator position(int id, int x, int y) {
+        checkFingerExistence(id, true);
+        mFingers.get(id).set(x, y);
+        return this;
+    }
+
+    /**
+     * Commits the finger position changes of {@link #position(int, int, int)} by generating a move
+     * event.
+     *
+     * @see #position(int, int, int)
+     */
+    public TouchEventGenerator move(long ms) {
+        generateEvent(MotionEvent.ACTION_MOVE, ms);
+        return this;
+    }
+
+    /**
+     * Commits the finger position changes of {@link #position(int, int, int)} by generating a move
+     * event after advancing the default time interval.
+     *
+     * @see #position(int, int, int)
+     */
+    public TouchEventGenerator move() {
+        return move(TIME_INCREMENT_MS);
+    }
+
+    /**
+     * Moves a single finger on the touchscreen.
+     */
+    public TouchEventGenerator move(int id, int x, int y, long ms) {
+        return position(id, x, y).move(ms);
+    }
+
+    /**
+     * Moves a single finger on the touchscreen after advancing default time interval.
+     */
+    public TouchEventGenerator move(int id, int x, int y) {
+        return move(id, x, y, TIME_INCREMENT_MS);
+    }
+
+    /**
+     * Removes an existing finger from the touchscreen.
+     */
+    public TouchEventGenerator lift(int id, long ms) {
+        checkFingerExistence(id, true);
+        boolean isFinalUp = mFingers.size() == 1;
+        int action;
+        if (isFinalUp) {
+            action = MotionEvent.ACTION_UP;
+        } else {
+            action = MotionEvent.ACTION_POINTER_UP;
+            // Set the id of the changed pointer.
+            action |= id << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+        }
+        generateEvent(action, ms);
+        mFingers.remove(id);
+        return this;
+    }
+
+    /**
+     * Removes a finger from the touchscreen.
+     */
+    public TouchEventGenerator lift(int id, int x, int y, long ms) {
+        checkFingerExistence(id, true);
+        mFingers.get(id).set(x, y);
+        return lift(id, ms);
+    }
+
+    /**
+     * Removes an existing finger from the touchscreen after advancing default time interval.
+     */
+    public TouchEventGenerator lift(int id) {
+        return lift(id, TIME_INCREMENT_MS);
+    }
+
+    /**
+     * Cancels an ongoing sequence.
+     */
+    public TouchEventGenerator cancel(long ms) {
+        generateEvent(MotionEvent.ACTION_CANCEL, ms);
+        mFingers.clear();
+        return this;
+    }
+
+    /**
+     * Cancels an ongoing sequence.
+     */
+    public TouchEventGenerator cancel() {
+        return cancel(TIME_INCREMENT_MS);
+    }
+
+    private void checkFingerExistence(int id, boolean shouldExist) {
+        if (shouldExist != mFingers.containsKey(id)) {
+            throw new IllegalArgumentException(
+                    shouldExist ? "Finger does not exist" : "Finger already exists");
+        }
+    }
+
+    private void generateEvent(int action, long ms) {
+        mTime = mLastEventTime + ms;
+        Pair<PointerProperties[], PointerCoords[]> state = getFingerState();
+        MotionEvent event = MotionEvent.obtain(
+                mInitialTime,
+                mTime,
+                action,
+                state.first.length,
+                state.first,
+                state.second,
+                0 /* metaState */,
+                0 /* buttonState */,
+                1.0f /* xPrecision */,
+                1.0f /* yPrecision */,
+                DEVICE_ID,
+                0 /* edgeFlags */,
+                InputDevice.SOURCE_TOUCHSCREEN,
+                0 /* flags */);
+        mListener.onTouchEvent(event);
+        if (action == MotionEvent.ACTION_UP) {
+            resetTime();
+        }
+        event.recycle();
+        mLastEventTime = mTime;
+    }
+
+    /**
+     * Returns the description of the fingers' state expected by MotionEvent.
+     */
+    private Pair<PointerProperties[], PointerCoords[]> getFingerState() {
+        int nFingers = mFingers.size();
+        PointerProperties[] properties = new PointerProperties[nFingers];
+        PointerCoords[] coordinates = new PointerCoords[nFingers];
+
+        int index = 0;
+        for (Map.Entry<Integer, Point> entry : mFingers.entrySet()) {
+            int id = entry.getKey();
+            Point location = entry.getValue();
+
+            PointerProperties property = new PointerProperties();
+            property.id = id;
+            property.toolType = MotionEvent.TOOL_TYPE_FINGER;
+            properties[index] = property;
+
+            PointerCoords coordinate = new PointerCoords();
+            coordinate.x = location.x;
+            coordinate.y = location.y;
+            coordinate.pressure = 1.0f;
+            coordinates[index] = coordinate;
+
+            index++;
+        }
+
+        return new Pair<MotionEvent.PointerProperties[], MotionEvent.PointerCoords[]>(
+                properties, coordinates);
+    }
+
+    /**
+     * Resets the time references for a new sequence.
+     */
+    private void resetTime() {
+        mInitialTime = 0L;
+        mLastEventTime = -1L;
+        mTime = 0L;
+    }
+}
diff --git a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
new file mode 100644
index 0000000..ff83131
--- /dev/null
+++ b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 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.touch;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.testcomponent.TouchEventGenerator;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SwipeDetectorTest {
+
+    private static final String TAG = SwipeDetectorTest.class.getSimpleName();
+    public static void L(String s, Object... parts) {
+        Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts));
+    }
+
+    private TouchEventGenerator mGenerator;
+    private SwipeDetector mDetector;
+    private int mTouchSlop;
+
+    @Mock
+    private SwipeDetector.Listener mMockListener;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mGenerator = new TouchEventGenerator(new TouchEventGenerator.Listener() {
+            @Override
+            public void onTouchEvent(MotionEvent event) {
+                mDetector.onTouchEvent(event);
+            }
+        });
+
+        mDetector = new SwipeDetector(mTouchSlop, mMockListener, SwipeDetector.VERTICAL);
+        mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
+        mTouchSlop = ViewConfiguration.get(InstrumentationRegistry.getTargetContext())
+                .getScaledTouchSlop();
+        L("mTouchSlop=", mTouchSlop);
+    }
+
+    @Test
+    public void testDragStart_vertical() throws Exception {
+        mGenerator.put(0, 100, 100);
+        mGenerator.move(0, 100, 100 + mTouchSlop);
+        // TODO: actually calculate the following parameters and do exact value checks.
+        verify(mMockListener).onDragStart(anyBoolean());
+    }
+
+    @Test
+    public void testDragStart_failed() throws Exception {
+        mGenerator.put(0, 100, 100);
+        mGenerator.move(0, 100 + mTouchSlop, 100);
+        // TODO: actually calculate the following parameters and do exact value checks.
+        verify(mMockListener, never()).onDragStart(anyBoolean());
+    }
+
+    @Test
+    public void testDragStart_horizontal() throws Exception {
+        mDetector = new SwipeDetector(mTouchSlop, mMockListener, SwipeDetector.HORIZONTAL);
+        mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
+
+        mGenerator.put(0, 100, 100);
+        mGenerator.move(0, 100 + mTouchSlop, 100);
+        // TODO: actually calculate the following parameters and do exact value checks.
+        verify(mMockListener).onDragStart(anyBoolean());
+    }
+
+    @Test
+    public void testDrag() throws Exception {
+        mGenerator.put(0, 100, 100);
+        mGenerator.move(0, 100, 100 + mTouchSlop);
+        // TODO: actually calculate the following parameters and do exact value checks.
+        verify(mMockListener).onDrag(anyFloat(), anyFloat());
+    }
+
+    @Test
+    public void testDragEnd() throws Exception {
+        mGenerator.put(0, 100, 100);
+        mGenerator.move(0, 100, 100 + mTouchSlop);
+        mGenerator.move(0, 100, 100 + mTouchSlop * 2);
+        mGenerator.lift(0);
+        // TODO: actually calculate the following parameters and do exact value checks.
+        verify(mMockListener).onDragEnd(anyFloat(), anyBoolean());
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 97f7b50..221fed1 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -28,6 +28,7 @@
 import android.test.suitebuilder.annotation.LargeTest;
 
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetHost;
 import com.android.launcher3.LauncherAppWidgetHostView;
 import com.android.launcher3.LauncherAppWidgetInfo;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -285,7 +286,7 @@
             pendingInfo.minSpanY = item.minSpanY;
             Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(mTargetContext, pendingInfo);
 
-            AppWidgetHost host = new AppWidgetHost(mTargetContext, Launcher.APPWIDGET_HOST_ID);
+            AppWidgetHost host = new LauncherAppWidgetHost(mTargetContext);
             int widgetId = host.allocateAppWidgetId();
             if (!mWidgetManager.bindAppWidgetIdIfAllowed(widgetId, info, options)) {
                 host.deleteAppWidgetId(widgetId);