Merge "Polish animation when icon returns to Folder." into ub-launcher3-master
diff --git a/Android.mk b/Android.mk
index d41e184..4cc5e42 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,7 +26,6 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-v4 \
     android-support-v7-recyclerview \
-    android-support-v7-palette \
     android-support-dynamic-animation
 
 LOCAL_SRC_FILES := \
@@ -72,7 +71,6 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-v4 \
     android-support-v7-recyclerview \
-    android-support-v7-palette \
     android-support-dynamic-animation
 
 LOCAL_SRC_FILES := \
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 94098e1..bb03f50 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -81,12 +81,6 @@
             </intent-filter>
         </receiver>
 
-        <service android:name="com.android.launcher3.dynamicui.ColorExtractionService"
-            android:exported="false"
-            android:process=":wallpaper_chooser"
-            android:permission="android.permission.BIND_JOB_SERVICE">
-        </service>
-
         <service
             android:name="com.android.launcher3.compat.WallpaperManagerCompatVL$ColorExtractionService"
             android:exported="false"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7d65bdc..23bddf6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -70,7 +70,7 @@
             android:launchMode="singleTask"
             android:clearTaskOnLaunch="true"
             android:stateNotNeeded="true"
-            android:windowSoftInputMode="adjustPan|stateUnchanged"
+            android:windowSoftInputMode="adjustPan"
             android:screenOrientation="nosensor"
             android:configChanges="keyboard|keyboardHidden|navigation"
             android:resizeableActivity="true"
diff --git a/build.gradle b/build.gradle
index 886ccac..2376146 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,12 +13,12 @@
 apply plugin: 'com.google.protobuf'
 
 android {
-    compileSdkVersion 26
-    buildToolsVersion '26.0.0'
+    compileSdkVersion 27
+    buildToolsVersion '27.0.0'
 
     defaultConfig {
         minSdkVersion 21
-        targetSdkVersion 26
+        targetSdkVersion 27
         versionCode 1
         versionName "1.0"
 
@@ -86,12 +86,11 @@
     jcenter()
 }
 
-final String SUPPORT_LIBS_VERSION = '26.0.0-SNAPSHOT'
+final String SUPPORT_LIBS_VERSION = '27.0.0-SNAPSHOT'
 dependencies {
     compile "com.android.support:support-v4:${SUPPORT_LIBS_VERSION}"
     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-7'
 
     testCompile 'junit:junit:4.12'
diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml
index ed8e0ad..fbaf981 100644
--- a/go/AndroidManifest.xml
+++ b/go/AndroidManifest.xml
@@ -42,7 +42,7 @@
             android:excludeFromRecents="true"
             android:autoRemoveFromRecents="true"
             android:label="@string/action_add_to_workspace"
-            tools:merge="override" >
+            tools:node="replace" >
             <intent-filter>
                 <action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
             </intent-filter>
diff --git a/go/res/values/dimens.xml b/go/res/values/dimens.xml
new file mode 100644
index 0000000..f1b1053
--- /dev/null
+++ b/go/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?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>
+    <!-- Dynamic Grid -->
+    <dimen name="dynamic_grid_hotseat_size">60dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/go/res/xml/device_profiles.xml b/go/res/xml/device_profiles.xml
index 094fc74..487c026 100644
--- a/go/res/xml/device_profiles.xml
+++ b/go/res/xml/device_profiles.xml
@@ -25,7 +25,7 @@
         launcher:numColumns="4"
         launcher:numFolderRows="4"
         launcher:numFolderColumns="4"
-        launcher:iconSize="56"
+        launcher:iconSize="60"
         launcher:iconTextSize="14.0"
         launcher:defaultLayoutId="@xml/default_workspace_4x4"
         />
diff --git a/proguard.flags b/proguard.flags
index 51abcca..a315cdc 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -86,13 +86,15 @@
   public <init>(...);
 }
 
+# The support library contains references to newer platform versions.
+# Don't warn about those in case this app is linking against an older
+# platform version.  We know about them, and they are safe.
+-dontwarn android.support.**
+
 # Proguard will strip methods required for talkback to properly scroll to
 # next row when focus is on the last item of last row when using a RecyclerView
 # Keep optimized and shrunk proguard to prevent issues like this when using
 # support jar.
-#-keep,allowoptimization,allowshrinking class android.support.** {
-#  *;
-#}
 -keep class android.support.v7.widget.RecyclerView { *; }
 
 -keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** {
diff --git a/res/layout/app_widget_resize_frame.xml b/res/layout/app_widget_resize_frame.xml
index 874fecc..12561b6 100644
--- a/res/layout/app_widget_resize_frame.xml
+++ b/res/layout/app_widget_resize_frame.xml
@@ -21,42 +21,47 @@
     android:background="@drawable/widget_resize_shadow"
     android:foreground="@drawable/widget_resize_frame"
     android:foregroundTint="?attr/workspaceTextColor"
-    android:padding="0dp" >
+    android:padding="0dp">
 
-    <!-- Left -->
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="left|center_vertical"
-        android:layout_marginLeft="@dimen/widget_handle_margin"
-        android:src="@drawable/ic_widget_resize_handle"
-        android:tint="?attr/workspaceTextColor" />
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
 
-    <!-- Top -->
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|center_horizontal"
-        android:layout_marginTop="@dimen/widget_handle_margin"
-        android:src="@drawable/ic_widget_resize_handle"
-        android:tint="?attr/workspaceTextColor" />
+        <!-- Left -->
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="left|center_vertical"
+            android:layout_marginLeft="@dimen/widget_handle_margin"
+            android:src="@drawable/ic_widget_resize_handle"
+            android:tint="?attr/workspaceTextColor" />
 
-    <!-- Right -->
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="right|center_vertical"
-        android:layout_marginRight="@dimen/widget_handle_margin"
-        android:src="@drawable/ic_widget_resize_handle"
-        android:tint="?attr/workspaceTextColor" />
+        <!-- Top -->
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal"
+            android:layout_marginTop="@dimen/widget_handle_margin"
+            android:src="@drawable/ic_widget_resize_handle"
+            android:tint="?attr/workspaceTextColor" />
 
-    <!-- Bottom -->
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom|center_horizontal"
-        android:layout_marginBottom="@dimen/widget_handle_margin"
-        android:src="@drawable/ic_widget_resize_handle"
-        android:tint="?attr/workspaceTextColor" />
+        <!-- Right -->
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="right|center_vertical"
+            android:layout_marginRight="@dimen/widget_handle_margin"
+            android:src="@drawable/ic_widget_resize_handle"
+            android:tint="?attr/workspaceTextColor" />
 
+        <!-- Bottom -->
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom|center_horizontal"
+            android:layout_marginBottom="@dimen/widget_handle_margin"
+            android:src="@drawable/ic_widget_resize_handle"
+            android:tint="?attr/workspaceTextColor" />
+
+    </FrameLayout>
 </com.android.launcher3.AppWidgetResizeFrame>
\ No newline at end of file
diff --git a/res/layout/gradient_bg.xml b/res/layout/gradient_bg.xml
index db448d7..6c6626c 100644
--- a/res/layout/gradient_bg.xml
+++ b/res/layout/gradient_bg.xml
@@ -20,5 +20,4 @@
     android:id="@+id/gradient_bg"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:visibility="gone"
     launcher:layout_ignoreInsets="true" />
\ No newline at end of file
diff --git a/res/layout/search_container_all_apps.xml b/res/layout/search_container_all_apps.xml
index c430521..fc07002 100644
--- a/res/layout/search_container_all_apps.xml
+++ b/res/layout/search_container_all_apps.xml
@@ -19,11 +19,11 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/all_apps_search_bar_height"
     android:layout_gravity="center|top"
+    android:layout_marginBottom="-8dp"
     android:gravity="center|bottom"
-    android:saveEnabled="false"
     android:paddingLeft="@dimen/dynamic_grid_edge_margin"
     android:paddingRight="@dimen/dynamic_grid_edge_margin"
-    android:layout_marginBottom="-8dp" >
+    android:saveEnabled="false" >
 
     <!--
       Note: The following relation should always be true so that the shadows are aligned properly
@@ -45,6 +45,7 @@
         android:imeOptions="actionSearch|flagNoExtractUi"
         android:inputType="text|textNoSuggestions|textCapWords"
         android:maxLines="1"
+        android:saveEnabled="false"
         android:scrollHorizontally="true"
         android:singleLine="true"
         android:textColor="?android:attr/textColorSecondary"
diff --git a/res/layout/zzz_dummy_widget.xml b/res/layout/zzz_dummy_widget.xml
deleted file mode 100644
index a0fa8fc..0000000
--- a/res/layout/zzz_dummy_widget.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="horizontal">
-
-    <FrameLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:background="#ffff0000" />
-
-    <FrameLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:background="#ff00ff00" />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index a79c2d4..5a776a6 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Verwyder"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleer"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Programinligting"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Installeer"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installeer kortpaaie"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Laat \'n program toe om kortpaaie by te voeg sonder gebruikerinmenging."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lees Tuis-instellings en -kortpaaie"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index c7d2958..5225dba 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ጫን"</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>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index a15bb76..5f2d58d 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"تثبيت"</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>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index b583865..4fa86d2 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Inform. o aplikaciji"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečica"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Dozvoljava aplikaciji da dodaje prečice bez intervencije korisnika."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"čitanje podešavanja i prečica na početnom ekranu"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index eae036e..1d7797d 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Усталяваць"</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>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 8ef3df8..b429492 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталиране"</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>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index b6c4226..897a8db 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ইনস্টল করুন"</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>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 773fe4a..b062b88 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Informacije o aplikaciji"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliraj prečice"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Dopušta aplikaciji dodavanje prečica bez posredovanja korisnika."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"čitaj postavke na početnom ekranu i prečice"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index acaf997..008531a 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Suprimeix"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstal·la"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Dades de l\'aplicació"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instal·la"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instal·la dreceres"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet que una aplicació afegeixi dreceres sense la intervenció de l\'usuari."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"llegeix la configuració i les dreceres de la pantalla d\'inici"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index db7f7bb..7cd71c2 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Odstranit"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstalovat"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"O aplikaci"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Nainstalovat"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalace zástupce"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Umožňuje aplikaci přidat zástupce bez zásahu uživatele."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"čtení nastavení a odkazů plochy"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 8e54486..9a91bc4 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Fjern"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Afinstaller"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Appinfo"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installere genveje"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Tillader, at en app tilføjer genveje uden brugerens indgriben."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"læs indstillinger og genveje for startskærmen"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index b32cdf4..6bc0875 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Entfernen"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstallieren"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App-Details"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Installieren"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Verknüpfungen installieren"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ermöglicht einer App das Hinzufügen von Verknüpfungen ohne Eingreifen des Nutzers"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Einstellungen und Verknüpfungen auf dem Startbildschirm lesen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 421907f..cdb255d 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Εγκατάσταση"</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>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index b4823f3..afd6757 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"read Home settings and shortcuts"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index b4823f3..afd6757 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"read Home settings and shortcuts"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index b4823f3..afd6757 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"read Home settings and shortcuts"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index af22e0b..05f1e06 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Información de app"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación agregue accesos directos sin que el usuario intervenga."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"leer configuración y accesos directos de la pantalla principal"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index cd80b378..e7e1cf8 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Datos de aplicación"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación añada accesos directos sin intervención del usuario."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"leer información de accesos directos y de ajustes de la pantalla de inicio"</string>
@@ -85,7 +84,7 @@
     <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>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para aplicaciones nuevas"</string>
     <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>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index d911ac4..ccc85a3 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Eemalda"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalli"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Rakenduse teave"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Installimine"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installi otseteed"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Võimaldab rakendusel lisada otseteid kasutaja sekkumiseta."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"loe avaekraani seadeid ja otseteid"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index aaaf0d8..8051b85 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"نصب"</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>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 7b09da0..5e05bbe 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Poista"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Poista asennus"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Sovelluksen tiedot"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Asenna"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"asenna pikakuvakkeita"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Antaa sovelluksen lisätä pikakuvakkeita itsenäisesti ilman käyttäjän valintaa."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lue aloitusruudun asetuksia ja pikakuvakkeita"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 9768320..da403a0 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -24,7 +24,7 @@
     <string name="work_folder_name" msgid="3753320833950115786">"Travail"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"L\'application n\'est pas installée."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Application indisponible"</string>
-    <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'application téléchargée est désactivée en mode sécurisé."</string>
+    <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'application téléchargée est désactivée en mode sans échec."</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets désactivés en mode sans échec"</string>
     <string name="shortcut_not_available" msgid="2536503539825726397">"Le raccourci n\'est pas disponible"</string>
     <string name="home_screen" msgid="806512411299847073">"Écran d\'accueil"</string>
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Supprimer"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Détails de l\'appli"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lire les paramètres et les raccourcis de la page d\'accueil"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index fde0c60..bc98cd2 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Supprimer"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Infos sur l\'appli"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permettre à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lire les paramètres et les raccourcis de l\'écran d\'accueil"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index bdc79f2..54f9604 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Eliminar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da aplicación"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atallos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a unha aplicación engadir atallos sen intervención do usuario."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ler a configuración e os atallos da pantalla de inicio"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 68a9e86..9734781 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ઇન્સ્ટૉલ કરો"</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>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 24f9997..f533015 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info o aplikaciji"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečaca"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji omogućuje dodavanje prečaca bez intervencije korisnika."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"čitanje postavki početnog zaslona i prečaca"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 94907eb..e38da35 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Törlés"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Eltávolítás"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Alkalmazásinformáció"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Telepítés"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"parancsikonok telepítése"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Lehetővé teszi egy alkalmazás számára, hogy felhasználói beavatkozás nélkül adjon hozzá parancsikonokat."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Főoldal beállításainak és parancsikonjainak beolvasása"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 44b337d..4901dc5 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Տեղադրել"</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>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index da9a683..5112223 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Hapus"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstal"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info aplikasi"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instal"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"memasang pintasan"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Mengizinkan aplikasi menambahkan pintasan tanpa campur tangan pengguna."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"membaca setelan dan pintasan layar Utama"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 40c26d7..e1b04e2 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Fjarlægja"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Fjarlægja"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Forritsupplýsingar"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Setja upp"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"setja upp flýtileiðir"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Leyfir forriti að bæta við flýtileiðum án íhlutunar notanda."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lesa stillingar og flýtileiðir heimaskjás"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index c1d97d9..a22a4ce 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Rimuovi"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Disinstalla"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Informazioni app"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Installa"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"aggiunta di scorciatoie"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Consente a un\'app di aggiungere scorciatoie automaticamente."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lettura di impostazioni e scorciatoie in Home"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index d1595b9..d7905b4 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"התקנה"</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>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index eb1b8aa0..4b6c3ef 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"インストール"</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>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 297b964..ec60583 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ინსტალაცია"</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>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 6818162..115b752 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</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>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index e72b2ec..9040811 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ដំឡើង"</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>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index df3b80a..4156a21 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</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>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 1630ddd..d9d8da6 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"설치"</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>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index a0635d4..0808214 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Орнотуу"</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>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 759c732..c1a1e71 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ຕິດຕັ້ງ"</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>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index ad1aa6d..ca45583 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ištrinti"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Pašalinti"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Programos inform."</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Įdiegti"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"įdiegti sparčiuosius klavišus"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Programai leidžiama pridėti sparčiuosius klavišus be naudotojo įsikišimo."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"skaityti pagrindinio puslapio nustatymus ir sparčiuosius klavišus"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 1b99b1e..7a4903a 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Noņemt"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Atinstalēt"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Par lietotni"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instalēt"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalēt saīsnes"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ļauj lietotnei pievienot saīsnes, nejautājot lietotājam."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lasīt sākuma ekrāna iestatījumus un saīsnes"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index a4b967b..0aaed62 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</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>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index c18b119..299fc45 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്‌റ്റാൾ ചെയ്യുക"</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>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 3fad545..8921c77 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Суулгах"</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>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index fabe15d..ca9a402 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करा"</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>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 0874387..6aeac8b 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Alih keluar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Nyahpasang"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Maklumat apl"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Pasang"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"pasang pintasan"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Membenarkan apl menambah pintasan tanpa campur tangan pengguna."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"baca tetapan dan pintasan Laman Utama"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 3ad2cc8..0a6276b 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Fjern"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstaller"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info om appen"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installere snarveier"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Gir apper tillatelse til å legge til snarveier uten innblanding fra brukeren."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lese startsideinnstillinger og -snarveier"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 776d672..41e43a7 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</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>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index b1d3efd..525f2f6 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -28,9 +28,9 @@
     <string name="safemode_widget_error" msgid="4863470563535682004">"ਵਿਜੇਟ ਸੁਰੱਖਿਅਤ ਮੋਡ ਵਿੱਚ ਅਸਮਰਥਿਤ"</string>
     <string name="shortcut_not_available" msgid="2536503539825726397">"ਸ਼ਾਰਟਕੱਟ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="home_screen" msgid="806512411299847073">"ਹੋਮ ਸਕ੍ਰੀਨ"</string>
-    <string name="custom_actions" msgid="3747508247759093328">"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ ਕਾਰਵਾਈਆਂ"</string>
+    <string name="custom_actions" msgid="3747508247759093328">"ਵਿਉਂਂਤੀ ਕਾਰਵਾਈਆਂ"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ਇੱਕ ਵਿਜੇਟ ਚੁਣਨ ਲਈ ਛੋਹਵੋT &amp; ਹੋਲਡ ਕਰੋ।"</string>
-    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ਡਬਲ ਟੈਪ ਕਰੋ &amp; ਇੱਕ ਵਿਜੇਟ ਚੁਣਨ ਲਈ ਹੋਲਡ ਕਰੋ ਜਾਂ ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"</string>
+    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ਇੱਕ ਵਿਜੇਟ ਚੁਣਨ ਲਈ ਜਾਂ ਵਿਉਂਂਤੀ ਕਾਰਵਾਈਆਂ ਵਰਤਣ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ਚੌੜਾਈ ਅਤੇ %2$d ਲੰਬਾਈ"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"ਹੱਥੀਂ ਰੱਖਣ ਲਈ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾਈ ਰੱਖੋ"</string>
@@ -45,17 +45,16 @@
     <string name="all_apps_button_label" msgid="8130441508702294465">"ਐਪ ਸੂਚੀ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ਹੋਮ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ਹਟਾਓ"</string>
-    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ਸਥਾਪਨਾ ਰੱਦ ਕਰੋ"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ਅਣਸਥਾਪਤ ਕਰੋ"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ਐਪ ਜਾਣਕਾਰੀ"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
-    <string name="permlab_install_shortcut" msgid="5632423390354674437">"ਸ਼ਾਰਟਕੱਟ ਇੰਸਟੌਲ ਕਰੋ"</string>
-    <string name="permdesc_install_shortcut" msgid="923466509822011139">"ਇੱਕ ਐਪ ਨੂੰ ਉਪਭੋਗਤਾ ਦੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਸ਼ਾਰਟਕੱਟ ਜੋੜਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ਸਥਾਪਤ ਕਰੋ"</string>
+    <string name="permlab_install_shortcut" msgid="5632423390354674437">"ਸ਼ਾਰਟਕੱਟ ਸਥਾਪਤ ਕਰੋ"</string>
+    <string name="permdesc_install_shortcut" msgid="923466509822011139">"ਇੱਕ ਐਪ ਨੂੰ ਵਰਤੋਂਕਾਰ ਦੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਸ਼ਾਰਟਕੱਟ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਪੜ੍ਹੋ"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"ਐਪ ਨੂੰ ਹੋਮ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਲਿਖੋ"</string>
     <string name="permdesc_write_settings" msgid="5440712911516509985">"ਐਪ ਨੂੰ ਹੋਮ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਬਦਲਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
-    <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਫੋਨ ਕਾਲਾਂ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਹੈ"</string>
+    <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਫ਼ੋਨ ਕਾਲਾਂ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਹੈ"</string>
     <string name="gadget_error_text" msgid="6081085226050792095">"ਵਿਜੇਟ ਲੋਡ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"ਸਥਾਪਤ ਕਰੋ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ਇਹ ਇੱਕ ਸਿਸਟਮ ਐਪ ਹੈ ਅਤੇ ਇਸਨੂੰ ਅਣਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
@@ -86,22 +85,22 @@
     <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>
-    <string name="icon_shape_override_label" msgid="2977264953998281004">"ਆਈਕਨ ਦੀ ਆਕ੍ਰਿਤੀ ਬਦਲੋ"</string>
+    <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>
-    <string name="icon_shape_override_progress" msgid="3461735694970239908">"ਆਈਕਨ ਦੀ ਆਕ੍ਰਿਤੀ ਵਿੱਚ ਤਬਦੀਲੀਆਂ ਨੂੰ ਲਾਗੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+    <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>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"ਇਹ ਐਪ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</string>
-    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ਇਸ ਆਈਕਨ ਲਈ ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ। ਤੁਸੀਂ ਇਸਨੂੰ ਹਟਾ ਸਕਦੇ ਹੋ ਜਾਂ ਐਪ ਖੋਜ ਸਕਦੇ ਹੋ ਅਤੇ ਇਸਨੂੰ ਮੈਨੂਅਲੀ ਸਥਾਪਤ ਕਰ ਸਕਦੇ ਹੋ।"</string>
+    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ਇਸ ਪ੍ਰਤੀਕ ਲਈ ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ। ਤੁਸੀਂ ਇਸਨੂੰ ਹਟਾ ਸਕਦੇ ਹੋ ਜਾਂ ਐਪ ਖੋਜ ਸਕਦੇ ਹੋ ਅਤੇ ਇਸਨੂੰ ਮੈਨੂਅਲੀ ਸਥਾਪਤ ਕਰ ਸਕਦੇ ਹੋ।"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ਡਾਉਨਲੋਡ ਹੋਰ ਰਿਹਾ ਹੈ, <xliff:g id="PROGRESS">%2$s</xliff:g> ਸੰਪੂਰਣ"</string>
-    <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ਸਥਾਪਿਤ ਕਰਨ ਦੀ ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ"</string>
+    <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ਸਥਾਪਤ ਕਰਨ ਦੀ ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ਵਿਜੇਟ"</string>
-    <string name="action_add_to_workspace" msgid="8902165848117513641">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜੋ"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ਆਈਟਮ ਨੂੰ ਇੱਥੇ ਮੂਵ ਕਰੋ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ਆਈਟਮ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"</string>
     <string name="item_removed" msgid="851119963877842327">"ਅਈਟਮ ਹਟਾਈ ਗਈ"</string>
@@ -110,8 +109,8 @@
     <string name="move_to_position" msgid="6750008980455459790">"ਸਥਿਤੀ <xliff:g id="NUMBER">%1$s</xliff:g> ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
     <string name="move_to_hotseat_position" msgid="6295412897075147808">"ਮਨਪਸੰਦ ਸਥਿਤੀ <xliff:g id="NUMBER">%1$s</xliff:g> ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
     <string name="item_moved" msgid="4606538322571412879">"ਆਈਟਮ ਮੂਵ ਕੀਤੀ ਗਈ"</string>
-    <string name="add_to_folder" msgid="9040534766770853243">"ਇਸ ਫੋਲਡਰ ਵਿੱਚ ਜੋੜੋ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ਦੇ ਨਾਲ ਫੋਲਡਰ ਵਿੱਚ ਜੋੜੋ"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ਇਸ ਫੋਲਡਰ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ਦੇ ਨਾਲ ਫੋਲਡਰ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="added_to_folder" msgid="4793259502305558003">"ਆਈਟਮ ਨੂੰ ਫੋਲਡਰ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"</string>
     <string name="create_folder_with" msgid="4050141361160214248">"ਇਸਦੇ ਨਾਲ ਫੋਲਡਰ ਬਣਾਓ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"ਫੋਲਡਰ ਬਣਾਇਆ ਗਿਆ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 486a94e..2a01d04 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Usuń"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstaluj"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"O aplikacji"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Zainstaluj"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalowanie skrótów"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Pozwala aplikacji dodawać skróty bez interwencji użytkownika."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"odczytywanie ustawień i skrótów na ekranie głównym"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 1916b20..ee4bf08 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remover"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Inf. da aplicação"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a uma aplicação adicionar atalhos sem a intervenção do utilizador."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ler definições e atalhos do Ecrã Principal"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 4a09cd5..b550f6f 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remover"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Informações do app"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que um app adicione atalhos sem intervenção do usuário."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ler configurações e atalhos da tela inicial"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 43ce4c8..9cf1cc6 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Eliminați"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Dezinstalați"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Informații aplicație"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instalați"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalează comenzi rapide"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite unei aplicații să adauge comenzi rapide fără intervenția utilizatorului."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"citește setări și comenzi rapide pentru ecranul de pornire"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 8bf71d6..bfd014e 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Установить"</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>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index fbdf5bf..349b7ca 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ස්ථාපනය කරන්න"</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>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 4268bad..ba84811 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Odstrániť"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinštalovať"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info o aplikácii"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Inštalovať"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"inštalovať odkazy"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Povoľuje aplikácii pridať odkazy bez zásahu používateľa."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"čítanie nastavení a odkazov plochy"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index c7abd88..c317c0e 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Odstrani"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odstrani"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Podatki o aplikaciji"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Namesti"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"namestitev bližnjic"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji dovoli dodajanje bližnjic brez posredovanja uporabnika."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"branje nastavitev in bližnjic na začetnem zaslonu"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 7b3a909..ed07912 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Hiqe"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Çinstalo"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Informacion mbi aplikacionin"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instalo"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalo shkurtore"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Lejon një aplikacion të shtojë shkurtore pa ndërhyrjen e përdoruesit."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lexo cilësimet dhe shkurtoret e ekranit bazë"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 76f28e0..f40366f 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</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>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 354d709..ff6b4e8 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ta bort"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstallera"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info om appen"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Installera"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installera genvägar"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Tillåter att en app lägger till genvägar utan åtgärd från användaren."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"läsa inställningar och genvägar för startsidan"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index eb2845d..2f0bbf7 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ondoa"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ondoa"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Maelezo ya programu"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Sakinisha"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"kuweka njia za mkato"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Huruhusu programu kuongeza njia za mkato bila mtumiaji kuingilia kati."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"soma mipangilio ya Mwanzo na njia za mkato"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index c3401aa..5d72030 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"நிறுவு"</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>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 79314e1..4db5352 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ఇన్‌స్టాల్ చేయండి"</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>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 10c0fa2..ae5aeb5 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ติดตั้ง"</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>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 3a328aa..11f13b0 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Alisin"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"I-uninstall"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Impormasyon ng app"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"I-install"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"i-install ang mga shortcut"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Pinapayagan ang isang app na magdagdag ng mga shortcut nang walang panghihimasok ng user."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"basahin ang mga setting at shortcut ng Home"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 5c2d681..f19cd78 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Kaldır"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Yüklemeyi kaldır"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Uygulama bilgileri"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Yükle"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"kısayolları yükle"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Uygulamaya, kullanıcı müdahalesi olmadan kısayol ekleme izni verir."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Ana ekran ayarlarını ve kısayollarını oku"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 8cb05ea..08f1575 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Установити"</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>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 6011d51..99b8c80 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"انسٹال کریں"</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>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index d289642..5167670 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Olib tashlash"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"O‘chirib tashlash"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Ilova haqida"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"O‘rnatish"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"yorliqlar yaratish"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ilovalarga foydalanuvchidan so‘ramasdan yorliqlar qo‘shishga ruxsat beradi."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Uy sozlamalari va yorliqlarini o‘qish"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index b06646d..c0e1454 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Xóa"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Gỡ cài đặt"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Thông tin ứng dụng"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Cài đặt"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"cài đặt lối tắt"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Cho phép ứng dụng thêm lối tắt mà không cần sự can thiệp của người dùng."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"đọc cài đặt và lối tắt trên Màn hình chính"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 47e5506..2342133 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"安装"</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>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index c5e09c5..f87ff7f 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</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>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index ae8df09..814a6e4 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -47,8 +47,7 @@
     <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>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</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>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 65e2561..35fa1c7 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -47,8 +47,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Susa"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Khipha"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Ulwazi lohlelo lokusebenza"</string>
-    <!-- no translation found for install_drop_target_label (2539096853673231757) -->
-    <skip />
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Faka"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"faka izinqamuleli"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ivumela uhlelo lokusebenza ukufaka izinqamuleli ngaphandle kokungenelela komsebenzisi."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"funda izilungiselelo zokuthi Ikhaya nezinqamuleli"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 68b628f..e87397b 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -123,6 +123,7 @@
         <attr name="iconTextSize" format="float" />
 
         <attr name="defaultLayoutId" format="reference" />
+        <attr name="demoModeLayoutId" format="reference" />
     </declare-styleable>
 
     <declare-styleable name="CellLayout">
@@ -143,4 +144,19 @@
     <declare-styleable name="RecyclerViewFastScroller">
         <attr name="canThumbDetach" format="boolean" />
     </declare-styleable>
+
+    <declare-styleable name="CustomAppWidgetProviderInfo">
+        <attr name="providerId" format="integer" />
+
+        <attr name="android:label" />
+        <attr name="android:initialLayout" />
+        <attr name="android:icon" />
+        <attr name="android:previewImage" />
+        <attr name="android:resizeMode" />
+
+        <attr name="numRows" />
+        <attr name="numColumns" />
+        <attr name="numMinRows" format="integer" />
+        <attr name="numMinColumns" format="integer" />
+    </declare-styleable>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b1f9d63..481199e 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -54,7 +54,6 @@
     <dimen name="vert_drop_target_horizontal_gap">14dp</dimen>
 
 <!-- App Widget resize frame -->
-    <dimen name="default_widget_padding">8dp</dimen>
     <dimen name="widget_handle_margin">13dp</dimen>
     <dimen name="resize_frame_background_padding">24dp</dimen>
 
@@ -233,8 +232,4 @@
     <dimen name="horizontal_ellipsis_offset">19dp</dimen>
     <dimen name="popup_item_divider_height">0.5dp</dimen>
     <dimen name="swipe_helper_falsing_threshold">70dp</dimen>
-
-<!-- Other -->
-    <!-- Approximates the system status bar height. Not guaranteed to be always be correct. -->
-    <dimen name="status_bar_height">24dp</dimen>
 </resources>
diff --git a/res/xml/custom_widgets.xml b/res/xml/custom_widgets.xml
new file mode 100644
index 0000000..4b54386
--- /dev/null
+++ b/res/xml/custom_widgets.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<widgets>
+    <!-- Sample widget definition
+        <widget
+            android:label="My custom widget"
+            android:initialLayout="@layout/sample_widget_layout"
+            android:icon="@drawable/ic_launcher_home"
+            android:resizeMode="horizontal|vertical"
+            launcher:numRows="2"
+            launcher:numColumns="3"
+            launcher:numMinRows="1"
+            launcher:numMinColumns="2"
+            launcher:providerId="1" />
+    -->
+</widgets>
\ No newline at end of file
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 597e937..4996818 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -25,6 +25,8 @@
 import android.widget.LinearLayout;
 
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.util.TouchController;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -32,18 +34,20 @@
 /**
  * Base class for a View which shows a floating UI on top of the launcher UI.
  */
-public abstract class AbstractFloatingView extends LinearLayout {
+public abstract class AbstractFloatingView extends LinearLayout implements TouchController {
 
     @IntDef(flag = true, value = {
             TYPE_FOLDER,
             TYPE_POPUP_CONTAINER_WITH_ARROW,
-            TYPE_WIDGETS_BOTTOM_SHEET
+            TYPE_WIDGETS_BOTTOM_SHEET,
+            TYPE_WIDGET_RESIZE_FRAME
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FloatingViewType {}
     public static final int TYPE_FOLDER = 1 << 0;
     public static final int TYPE_POPUP_CONTAINER_WITH_ARROW = 1 << 1;
     public static final int TYPE_WIDGETS_BOTTOM_SHEET = 1 << 2;
+    public static final int TYPE_WIDGET_RESIZE_FRAME = 1 << 3;
 
     protected boolean mIsOpen;
 
@@ -72,21 +76,7 @@
 
     protected abstract void handleClose(boolean animate);
 
-    /**
-     * If the view is current handling keyboard, return the active target, null otherwise
-     */
-    public ExtendedEditText getActiveTextView() {
-        return null;
-    }
-
-
-    /**
-     * Any additional view (outside of this container) where touch should be allowed while this
-     * view is visible.
-     */
-    public View getExtendedTouchView() {
-        return null;
-    }
+    public abstract void logActionCommand(int command);
 
     public final boolean isOpen() {
         return mIsOpen;
@@ -97,6 +87,16 @@
 
     protected abstract boolean isOfType(@FloatingViewType int type);
 
+    public void onBackPressed() {
+        logActionCommand(Action.Command.BACK);
+        close(true);
+    }
+
+    @Override
+    public boolean onControllerTouchEvent(MotionEvent ev) {
+        return false;
+    }
+
     protected static <T extends AbstractFloatingView> T getOpenView(
             Launcher launcher, @FloatingViewType int type) {
         DragLayer dragLayer = launcher.getDragLayer();
@@ -139,8 +139,6 @@
 
     public static AbstractFloatingView getTopOpenView(Launcher launcher) {
         return getOpenView(launcher, TYPE_FOLDER | TYPE_POPUP_CONTAINER_WITH_ARROW
-                | TYPE_WIDGETS_BOTTOM_SHEET);
+                | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME);
     }
-
-    public abstract int getLogContainerType();
 }
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index 3da1996..7d2f753 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -19,6 +19,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherActivityInfo;
 import android.os.UserHandle;
 
@@ -31,6 +32,10 @@
  */
 public class AppInfo extends ItemInfoWithIcon {
 
+    public static final int FLAG_SYSTEM_UNKNOWN = 0;
+    public static final int FLAG_SYSTEM_YES = 1 << 0;
+    public static final int FLAG_SYSTEM_NO = 1 << 1;
+
     /**
      * The intent used to start the application.
      */
@@ -43,6 +48,11 @@
      */
     public int isDisabled = ShortcutInfo.DEFAULT;
 
+    /**
+     * Stores if the app is a system app or not.
+     */
+    public int isSystemApp;
+
     public AppInfo() {
         itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
     }
@@ -71,6 +81,10 @@
         }
 
         intent = makeLaunchIntent(info);
+
+        isSystemApp = (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0
+                ? FLAG_SYSTEM_NO : FLAG_SYSTEM_YES;
+
     }
 
     public AppInfo(AppInfo info) {
@@ -79,6 +93,7 @@
         title = Utilities.trim(info.title);
         intent = new Intent(info.intent);
         isDisabled = info.isDisabled;
+        isSystemApp = info.isSystemApp;
     }
 
     @Override
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index a486a3a..1e95333 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -8,22 +8,19 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
-import android.widget.FrameLayout;
+import android.view.ViewGroup;
 
 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.util.FocusLogic;
-import com.android.launcher3.util.TouchController;
 
-public class AppWidgetResizeFrame extends FrameLayout
-        implements View.OnKeyListener, TouchController {
+public class AppWidgetResizeFrame extends AbstractFloatingView implements View.OnKeyListener {
     private static final int SNAP_DURATION = 150;
     private static final float DIMMED_HANDLE_ALPHA = 0f;
     private static final float RESIZE_THRESHOLD = 0.66f;
@@ -109,12 +106,28 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
+        ViewGroup content = (ViewGroup) getChildAt(0);
         for (int i = 0; i < HANDLE_COUNT; i ++) {
-            mDragHandles[i] = getChildAt(i);
+            mDragHandles[i] = content.getChildAt(i);
         }
     }
 
-    public void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout,
+    public static void showForWidget(LauncherAppWidgetHostView widget, CellLayout cellLayout) {
+        Launcher launcher = Launcher.getLauncher(cellLayout.getContext());
+        AbstractFloatingView.closeAllOpenViews(launcher);
+
+        DragLayer dl = launcher.getDragLayer();
+        AppWidgetResizeFrame frame = (AppWidgetResizeFrame) launcher.getLayoutInflater()
+                .inflate(R.layout.app_widget_resize_frame, dl, false);
+        frame.setupForWidget(widget, cellLayout, dl);
+        ((DragLayer.LayoutParams) frame.getLayoutParams()).customPosition = true;
+
+        dl.addView(frame);
+        frame.mIsOpen = true;
+        frame.snapToWidget(false);
+    }
+
+    private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout,
             DragLayer dragLayer) {
         mCellLayout = cellLayout;
         mWidgetView = widgetView;
@@ -126,14 +139,8 @@
         mMinHSpan = info.minSpanX;
         mMinVSpan = info.minSpanY;
 
-        if (!info.isCustomWidget) {
-            mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(getContext(),
-                    widgetView.getAppWidgetInfo().provider, null);
-        } else {
-            Resources r = getContext().getResources();
-            int padding = r.getDimensionPixelSize(R.dimen.default_widget_padding);
-            mWidgetPadding = new Rect(padding, padding, padding, padding);
-        }
+        mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(getContext(),
+                widgetView.getAppWidgetInfo().provider, null);
 
         if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
             mDragHandles[INDEX_TOP].setVisibility(GONE);
@@ -391,7 +398,7 @@
         out.bottom = out.top + height;
     }
 
-    public void snapToWidget(boolean animate) {
+    private void snapToWidget(boolean animate) {
         getSnappedRectRelativeToDragLayer(sTmpRect);
         int newWidth = sTmpRect.width();
         int newHeight = sTmpRect.height();
@@ -455,7 +462,7 @@
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         // Clear the frame and give focus to the widget host view when a directional key is pressed.
         if (FocusLogic.shouldConsume(keyCode)) {
-            mDragLayer.clearResizeFrame();
+            close(false);
             mWidgetView.requestFocus();
             return true;
         }
@@ -505,9 +512,25 @@
         if (ev.getAction() == MotionEvent.ACTION_DOWN && handleTouchDown(ev)) {
             return true;
         }
+        close(false);
         return false;
     }
 
+    @Override
+    protected void handleClose(boolean animate) {
+        mDragLayer.removeView(this);
+    }
+
+    @Override
+    public void logActionCommand(int command) {
+        // TODO: Log this case.
+    }
+
+    @Override
+    protected boolean isOfType(int type) {
+        return (type & TYPE_WIDGET_RESIZE_FRAME) != 0;
+    }
+
     /**
      * A mutable class for describing the range of two int values.
      */
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index d82579b..162aa08 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -28,7 +28,9 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.Process;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -433,8 +435,10 @@
                 return -1;
             }
 
-            mValues.put(LauncherSettings.Favorites.ICON,
-                    Utilities.flattenBitmap(LauncherIcons.createIconBitmap(icon, mContext)));
+            // Auto installs should always support the current platform version.
+            mValues.put(LauncherSettings.Favorites.ICON, Utilities.flattenBitmap(
+                    LauncherIcons.createBadgedIconBitmap(
+                            icon, Process.myUserHandle(), mContext, Build.VERSION.SDK_INT)));
             mValues.put(Favorites.ICON_PACKAGE, mIconRes.getResourcePackageName(iconId));
             mValues.put(Favorites.ICON_RESOURCE, mIconRes.getResourceName(iconId));
 
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index ac842f9..485125e 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -496,11 +496,17 @@
     public PreloadIconDrawable applyProgressLevel(int progressLevel) {
         if (getTag() instanceof ItemInfoWithIcon) {
             ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
-            setContentDescription(progressLevel > 0
-                    ? getContext().getString(R.string.app_downloading_title, info.title,
-                    NumberFormat.getPercentInstance().format(progressLevel * 0.01))
-                    : getContext().getString(R.string.app_waiting_download_title, info.title));
-
+            if (progressLevel >= 100) {
+                setContentDescription(info.contentDescription != null
+                        ? info.contentDescription : "");
+            } else if (progressLevel > 0) {
+                setContentDescription(getContext()
+                        .getString(R.string.app_downloading_title, info.title,
+                                NumberFormat.getPercentInstance().format(progressLevel * 0.01)));
+            } else {
+                setContentDescription(getContext()
+                        .getString(R.string.app_waiting_download_title, info.title));
+            }
             if (mIcon != null) {
                 final PreloadIconDrawable preloadDrawable;
                 if (mIcon instanceof PreloadIconDrawable) {
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 632e490..3759300 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -178,7 +178,7 @@
 
     @Override
     public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
-        mActive = supportsDrop(dragObject.dragSource, dragObject.dragInfo);
+        mActive = supportsDrop(dragObject.dragInfo);
         mDrawable.setColorFilter(null);
         if (mCurrentColorAnim != null) {
             mCurrentColorAnim.cancel();
@@ -194,10 +194,10 @@
 
     @Override
     public final boolean acceptDrop(DragObject dragObject) {
-        return supportsDrop(dragObject.dragSource, dragObject.dragInfo);
+        return supportsDrop(dragObject.dragInfo);
     }
 
-    protected abstract boolean supportsDrop(DragSource source, ItemInfo info);
+    protected abstract boolean supportsDrop(ItemInfo info);
 
     @Override
     public boolean isDropEnabled() {
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index f835748..d92b934 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -355,10 +355,6 @@
         mShortcutsAndWidgets.setLayerType(hasLayer ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, sPaint);
     }
 
-    public void buildHardwareLayer() {
-        mShortcutsAndWidgets.buildLayer();
-    }
-
     public void setCellDimensions(int width, int height) {
         mFixedCellWidth = mCellWidth = width;
         mFixedCellHeight = mCellHeight = height;
diff --git a/src/com/android/launcher3/CustomAppWidget.java b/src/com/android/launcher3/CustomAppWidget.java
deleted file mode 100644
index 1b4ed79..0000000
--- a/src/com/android/launcher3/CustomAppWidget.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.android.launcher3;
-
-public interface CustomAppWidget {
-    public String getLabel();
-    public int getPreviewImage();
-    public int getIcon();
-    public int getWidgetLayout();
-
-    public int getSpanX();
-    public int getSpanY();
-    public int getMinSpanX();
-    public int getMinSpanY();
-    public int getResizeMode();
-}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 4dcb64f..fdd4f34 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -46,7 +46,7 @@
     @Override
     public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
         super.onDragStart(dragObject, options);
-        setTextBasedOnDragSource(dragObject.dragSource);
+        setTextBasedOnDragSource(dragObject.dragInfo);
     }
 
     /** @return true for items that should have a "Remove" action in accessibility. */
@@ -57,16 +57,16 @@
     }
 
     @Override
-    protected boolean supportsDrop(DragSource source, ItemInfo info) {
+    protected boolean supportsDrop(ItemInfo info) {
         return true;
     }
 
     /**
-     * Set the drop target's text to either "Remove" or "Cancel" depending on the drag source.
+     * Set the drop target's text to either "Remove" or "Cancel" depending on the drag item.
      */
-    public void setTextBasedOnDragSource(DragSource dragSource) {
+    private void setTextBasedOnDragSource(ItemInfo item) {
         if (!TextUtils.isEmpty(mText)) {
-            mText = getResources().getString(dragSource.supportsDeleteDropTarget()
+            mText = getResources().getString(item.id != ItemInfo.NO_ID
                     ? R.string.remove_drop_target_label
                     : android.R.string.cancel);
             requestLayout();
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index dec0a92..8f7e882 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -277,8 +277,12 @@
         DeviceProfile profile = new DeviceProfile(context, inv, mwSize, mwSize, mwSize.x, mwSize.y,
                 isLandscape);
 
-        // Hide labels on the workspace.
-        profile.adjustToHideWorkspaceLabels();
+        // If there isn't enough vertical cell padding with the labels displayed, hide the labels.
+        float workspaceCellPaddingY = profile.getCellSize().y - profile.iconSizePx
+                - iconDrawablePaddingPx - profile.iconTextSizePx;
+        if (workspaceCellPaddingY < profile.iconDrawablePaddingPx * 2) {
+            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.
@@ -350,9 +354,18 @@
         iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale);
         iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale);
 
-        cellWidthPx = iconSizePx + iconDrawablePaddingPx;
         cellHeightPx = iconSizePx + iconDrawablePaddingPx
                 + Utilities.calculateTextHeight(iconTextSizePx);
+        int cellYPadding = (getCellSize().y - cellHeightPx) / 2;
+        if (iconDrawablePaddingPx > cellYPadding && !isVerticalBarLayout()
+                && !inMultiWindowMode()) {
+            // Ensures that the label is closer to its corresponding icon. This is not an issue
+            // with vertical bar layout or multi-window mode since the issue is handled separately
+            // with their calls to {@link #adjustToHideWorkspaceLabels}.
+            cellHeightPx -= (iconDrawablePaddingPx - cellYPadding);
+            iconDrawablePaddingPx = cellYPadding;
+        }
+        cellWidthPx = iconSizePx + iconDrawablePaddingPx;
 
         // All apps
         allAppsIconTextSizePx = iconTextSizePx;
@@ -755,11 +768,14 @@
         return new int[] { padding.left - mInsets.left, padding.right + mInsets.left};
     }
 
+    public boolean inMultiWindowMode() {
+        return this != inv.landscapeProfile && this != inv.portraitProfile;
+    }
+
     public boolean shouldIgnoreLongPressToOverview(float touchX) {
-        boolean inMultiWindowMode = this != inv.landscapeProfile && this != inv.portraitProfile;
         boolean touchedLhsEdge = mInsets.left == 0 && touchX < edgeMarginPx;
         boolean touchedRhsEdge = mInsets.right == 0 && touchX > (widthPx - edgeMarginPx);
-        return !inMultiWindowMode && (touchedLhsEdge || touchedRhsEdge);
+        return !inMultiWindowMode() && (touchedLhsEdge || touchedRhsEdge);
     }
 
     private static Context getContext(Context c, int orientation) {
diff --git a/src/com/android/launcher3/DragSource.java b/src/com/android/launcher3/DragSource.java
index dcd8f58..c6106c2 100644
--- a/src/com/android/launcher3/DragSource.java
+++ b/src/com/android/launcher3/DragSource.java
@@ -27,22 +27,6 @@
 public interface DragSource extends LogContainerProvider {
 
     /**
-     * @return whether items dragged from this source supports 'App Info'
-     */
-    boolean supportsAppInfoDropTarget();
-
-    /**
-     * @return whether items dragged from this source supports 'Delete' drop target (e.g. to remove
-     * a shortcut.) If this returns false, the drop target will say "Cancel" instead of "Remove."
-     */
-    boolean supportsDeleteDropTarget();
-
-    /*
-     * @return the scale of the icons over the workspace icon size
-     */
-    float getIntrinsicIconScaleFactor();
-
-    /**
      * A callback made back to the source after an item from this source has been dropped on a
      * DropTarget.
      */
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index 596aa8f..403c8b8 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -16,12 +16,16 @@
 package com.android.launcher3;
 
 import android.content.Context;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.DragEvent;
 import android.view.KeyEvent;
+import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 
+import com.android.launcher3.util.UiThreadHelper;
+
 
 /**
  * The edit text that reports back when the back key has been pressed.
@@ -102,8 +106,7 @@
     }
 
     public void dispatchBackKey() {
-        ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE))
-                .hideSoftInputFromWindow(getWindowToken(), 0);
+        UiThreadHelper.hideKeyboardAsync(getContext(), getWindowToken());
         if (mBackKeyListener != null) {
             mBackKeyListener.onBackKey();
         }
@@ -121,4 +124,17 @@
     public boolean isSuggestionsEnabled() {
         return !mForceDisableSuggestions && super.isSuggestionsEnabled();
     }
+
+    public void reset() {
+        if (!TextUtils.isEmpty(getText())) {
+            setText("");
+        }
+        if (isFocused()) {
+            View nextFocus = focusSearch(View.FOCUS_DOWN);
+            if (nextFocus != null) {
+                nextFocus.requestFocus();
+            }
+        }
+        UiThreadHelper.hideKeyboardAsync(getContext(), getWindowToken());
+    }
 }
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index 3cbc989..cea7e43 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -24,6 +24,7 @@
 import android.view.ViewPropertyAnimator;
 import android.view.ViewTreeObserver;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.TraceHelper;
 
 /*
  *  This is a helper class that listens to updates from the corresponding animation.
@@ -71,15 +72,12 @@
         if (sGlobalDrawListener != null) {
             view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener);
         }
+
+        TraceHelper.beginSection("TICK");
         sGlobalDrawListener = new ViewTreeObserver.OnDrawListener() {
-                private long mTime = System.currentTimeMillis();
                 public void onDraw() {
                     sGlobalFrameCounter++;
-                    if (DEBUG) {
-                        long newTime = System.currentTimeMillis();
-                        Log.d(TAG, "TICK " + (newTime - mTime));
-                        mTime = newTime;
-                    }
+                    TraceHelper.partitionSection("TICK", "Frame drawn");
                 }
             };
         view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener);
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index af3abeb..09f9e82 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -16,16 +16,9 @@
 
 package com.android.launcher3;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ArgbEvaluator;
-import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Color;
 import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -35,11 +28,9 @@
 import android.widget.TextView;
 
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dynamicui.ExtractedColors;
 import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.util.Themes;
 
 public class Hotseat extends FrameLayout
         implements UserEventDispatcher.LogContainerProvider {
@@ -51,12 +42,6 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private final boolean mHasVerticalHotseat;
 
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private int mBackgroundColor;
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private ColorDrawable mBackground;
-    private ValueAnimator mBackgroundColorAnimator;
-
     public Hotseat(Context context) {
         this(context, null);
     }
@@ -69,12 +54,6 @@
         super(context, attrs, defStyle);
         mLauncher = Launcher.getLauncher(context);
         mHasVerticalHotseat = mLauncher.getDeviceProfile().isVerticalBarLayout();
-        mBackgroundColor = ColorUtils.setAlphaComponent(
-                Themes.getAttrColor(context, android.R.attr.colorPrimary), 0);
-        mBackground = new ColorDrawable(mBackgroundColor);
-        if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-            setBackground(mBackground);
-        }
     }
 
     public CellLayout getLayout() {
@@ -149,7 +128,6 @@
             allAppsButton.setOnKeyListener(new HotseatIconKeyEventListener());
             if (mLauncher != null) {
                 mLauncher.setAllAppsButton(allAppsButton);
-                allAppsButton.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
                 allAppsButton.setOnClickListener(mLauncher);
                 allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler);
             }
@@ -178,49 +156,4 @@
         target.gridY = info.cellY;
         targetParent.containerType = ContainerType.HOTSEAT;
     }
-
-    public void updateColor(ExtractedColors extractedColors, boolean animate) {
-        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-            // not hotseat visible
-            return;
-        }
-        if (!mHasVerticalHotseat) {
-            int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX);
-            if (mBackgroundColorAnimator != null) {
-                mBackgroundColorAnimator.cancel();
-            }
-            if (!animate) {
-                setBackgroundColor(color);
-            } else {
-                mBackgroundColorAnimator = ValueAnimator.ofInt(mBackgroundColor, color);
-                mBackgroundColorAnimator.setEvaluator(new ArgbEvaluator());
-                mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                    @Override
-                    public void onAnimationUpdate(ValueAnimator animation) {
-                        mBackground.setColor((Integer) animation.getAnimatedValue());
-                    }
-                });
-                mBackgroundColorAnimator.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        mBackgroundColorAnimator = null;
-                    }
-                });
-                mBackgroundColorAnimator.start();
-            }
-            mBackgroundColor = color;
-        }
-    }
-
-    public void setBackgroundTransparent(boolean enable) {
-        if (enable) {
-            mBackground.setAlpha(0);
-        } else {
-            mBackground.setAlpha(255);
-        }
-    }
-
-    public int getBackgroundDrawableColor() {
-        return mBackgroundColor;
-    }
 }
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 6f86954..573e8a2 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -123,7 +123,7 @@
     }
 
     private Drawable getFullResDefaultActivityIcon() {
-        return getFullResIcon(Resources.getSystem(), Utilities.isAtLeastO() ?
+        return getFullResIcon(Resources.getSystem(), Utilities.ATLEAST_OREO ?
                 android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon);
     }
 
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index f919dd0..eb6a704 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -99,8 +99,8 @@
     }
 
     @Override
-    protected boolean supportsDrop(DragSource source, ItemInfo info) {
-        return source.supportsAppInfoDropTarget() && supportsDrop(getContext(), info);
+    protected boolean supportsDrop(ItemInfo info) {
+        return supportsDrop(getContext(), info);
     }
 
     public static boolean supportsDrop(Context context, ItemInfo info) {
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index d7bebd1..7a43198 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -85,7 +85,9 @@
      * Number of icons inside the hotseat area.
      */
     public int numHotseatIcons;
+
     int defaultLayoutId;
+    int demoModeLayoutId;
 
     public DeviceProfile landscapeProfile;
     public DeviceProfile portraitProfile;
@@ -99,11 +101,11 @@
         this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns,
                 p.numFolderRows, p.numFolderColumns, p.minAllAppsPredictionColumns,
                 p.iconSize, p.landscapeIconSize, p.iconTextSize, p.numHotseatIcons,
-                p.defaultLayoutId);
+                p.defaultLayoutId, p.demoModeLayoutId);
     }
 
     InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, int maapc,
-            float is, float lis, float its, int hs, int dlId) {
+            float is, float lis, float its, int hs, int dlId, int dmlId) {
         name = n;
         minWidthDps = w;
         minHeightDps = h;
@@ -117,6 +119,7 @@
         iconTextSize = its;
         numHotseatIcons = hs;
         defaultLayoutId = dlId;
+        demoModeLayoutId = dmlId;
     }
 
     @TargetApi(23)
@@ -144,6 +147,7 @@
         numColumns = closestProfile.numColumns;
         numHotseatIcons = closestProfile.numHotseatIcons;
         defaultLayoutId = closestProfile.defaultLayoutId;
+        demoModeLayoutId = closestProfile.demoModeLayoutId;
         numFolderRows = closestProfile.numFolderRows;
         numFolderColumns = closestProfile.numFolderColumns;
         minAllAppsPredictionColumns = closestProfile.minAllAppsPredictionColumns;
@@ -208,7 +212,8 @@
                             a.getFloat(R.styleable.InvariantDeviceProfile_landscapeIconSize, iconSize),
                             a.getFloat(R.styleable.InvariantDeviceProfile_iconTextSize, 0),
                             a.getInt(R.styleable.InvariantDeviceProfile_numHotseatIcons, numColumns),
-                            a.getResourceId(R.styleable.InvariantDeviceProfile_defaultLayoutId, 0)));
+                            a.getResourceId(R.styleable.InvariantDeviceProfile_defaultLayoutId, 0),
+                            a.getResourceId(R.styleable.InvariantDeviceProfile_demoModeLayoutId, 0)));
                     a.recycle();
                 }
             }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c22a04a..ba31926 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -16,6 +16,9 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_APPS;
+import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_WIDGETS;
+
 import android.Manifest;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -53,8 +56,6 @@
 import android.os.Handler;
 import android.os.Process;
 import android.os.StrictMode;
-import android.os.SystemClock;
-import android.os.Trace;
 import android.os.UserHandle;
 import android.support.annotation.Nullable;
 import android.text.Selection;
@@ -73,7 +74,6 @@
 import android.view.View;
 import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -91,13 +91,13 @@
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.LauncherAppsCompatVO;
+import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.PinItemDragListener;
-import com.android.launcher3.dynamicui.ExtractedColors;
 import com.android.launcher3.dynamicui.WallpaperColorInfo;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
@@ -118,7 +118,6 @@
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
 import com.android.launcher3.util.ActivityResultInfo;
-import com.android.launcher3.util.RunnableWithId;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.ComponentKeyMapper;
 import com.android.launcher3.util.ItemInfoMatcher;
@@ -126,30 +125,30 @@
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.PendingRequestArgs;
+import com.android.launcher3.util.RunnableWithId;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.TestingUtils;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.TraceHelper;
+import com.android.launcher3.util.UiThreadHelper;
 import com.android.launcher3.util.ViewOnDrawExecutor;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
 import com.android.launcher3.widget.WidgetAddFlowHandler;
 import com.android.launcher3.widget.WidgetHostViewLoader;
 import com.android.launcher3.widget.WidgetsContainerView;
+import com.android.launcher3.widget.custom.CustomWidgetParser;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Executor;
 
-import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_APPS;
-import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_WIDGETS;
-
 /**
  * Default launcher application.
  */
@@ -161,9 +160,7 @@
     public static final String TAG = "Launcher";
     static final boolean LOGD = false;
 
-    static final boolean DEBUG_WIDGETS = false;
     static final boolean DEBUG_STRICT_MODE = false;
-    static final boolean DEBUG_RESUME_TIME = false;
 
     private static final int REQUEST_CREATE_SHORTCUT = 1;
     private static final int REQUEST_CREATE_APPWIDGET = 5;
@@ -222,8 +219,6 @@
     private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
     @Thunk static final int NEW_APPS_ANIMATION_DELAY = 500;
 
-    private final ExtractedColors mExtractedColors = new ExtractedColors();
-
     @Thunk Workspace mWorkspace;
     private View mLauncherView;
     @Thunk DragLayer mDragLayer;
@@ -251,6 +246,10 @@
     // Main container view and the model for the widget tray screen.
     @Thunk WidgetsContainerView mWidgetsView;
 
+    // We need to store the orientation Launcher was created with, due to a bug (b/64916689)
+    // that results in widgets being inflated in the wrong orientation.
+    private int mOrientation;
+
     // We set the state in both onCreate and then onNewIntent in some cases, which causes both
     // scroll issues (because the workspace may not have been measured yet) and extra work.
     // Instead, just save the state that we need to restore Launcher to, and commit it in onResume.
@@ -279,8 +278,6 @@
 
     private PopupDataProvider mPopupDataProvider;
 
-    private View.OnTouchListener mHapticFeedbackTouchListener;
-
     // Determines how long to wait after a rotation before restoring the screen orientation to
     // match the sensor state.
     private static final int RESTORE_SCREEN_ORIENTATION_DELAY = 500;
@@ -296,28 +293,11 @@
     // the press state and keep this reference to reset the press state when we return to launcher.
     private BubbleTextView mWaitingForResume;
 
-    protected static final HashMap<String, CustomAppWidget> sCustomAppWidgets =
-        new HashMap<>();
-
-    static {
-        if (TestingUtils.ENABLE_CUSTOM_WIDGET_TEST) {
-            TestingUtils.addDummyWidget(sCustomAppWidgets);
-        }
-    }
-
     // Exiting spring loaded mode happens with a delay. This runnable object triggers the
     // state transition. If another state transition happened during this delay,
     // simply unregister this runnable.
     private Runnable mExitSpringLoadedModeRunnable;
 
-    @Thunk final Runnable mBuildLayersRunnable = new Runnable() {
-        public void run() {
-            if (mWorkspace != null) {
-                mWorkspace.buildPageHardwareLayers();
-            }
-        }
-    };
-
     // Activity result which needs to be processed after workspace has loaded.
     private ActivityResultInfo mPendingActivityResult;
     /**
@@ -358,9 +338,7 @@
                     .penaltyDeath()
                     .build());
         }
-        if (LauncherAppState.PROFILE_STARTUP) {
-            Trace.beginSection("Launcher-onCreate");
-        }
+        TraceHelper.beginSection("Launcher-onCreate");
 
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.preOnCreate();
@@ -371,6 +349,7 @@
         overrideTheme(wallpaperColorInfo.isDark(), wallpaperColorInfo.supportsDarkText());
 
         super.onCreate(savedInstanceState);
+        TraceHelper.partitionSection("Launcher-onCreate", "super call");
 
         LauncherAppState app = LauncherAppState.getInstance(this);
 
@@ -383,6 +362,7 @@
             mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
         }
 
+        mOrientation = getResources().getConfiguration().orientation;
         mSharedPrefs = Utilities.getPrefs(this);
         mIsSafeModeEnabled = getPackageManager().isSafeMode();
         mModel = app.setLauncher(this);
@@ -411,7 +391,6 @@
 
         setupViews();
         mDeviceProfile.layout(this, false /* notifyListeners */);
-        loadExtractedColorsAndColorItems();
 
         mPopupDataProvider = new PopupDataProvider(this);
 
@@ -420,10 +399,6 @@
 
         restoreState(savedInstanceState);
 
-        if (LauncherAppState.PROFILE_STARTUP) {
-            Trace.endSection();
-        }
-
         // We only load the page synchronously if the user rotates (or triggers a
         // configuration change) while launcher is in the foreground
         int currentScreen = PagedView.INVALID_RESTORE_PAGE;
@@ -478,6 +453,8 @@
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onCreate(savedInstanceState);
         }
+
+        TraceHelper.endSection("Launcher-onCreate");
     }
 
     @Override
@@ -499,27 +476,12 @@
     }
 
     @Override
-    public void onExtractedColorsChanged() {
-        loadExtractedColorsAndColorItems();
-        mExtractedColors.notifyChange();
-    }
-
-    @Override
     public void onAppWidgetHostReset() {
         if (mAppWidgetHost != null) {
             mAppWidgetHost.startListening();
         }
     }
 
-    private void loadExtractedColorsAndColorItems() {
-        // TODO: do this in pre-N as well, once the extraction part is complete.
-        if (Utilities.ATLEAST_NOUGAT) {
-            mExtractedColors.load(this);
-            mHotseat.updateColor(mExtractedColors, !mPaused);
-            mWorkspace.getPageIndicator().updateColor(mExtractedColors);
-        }
-    }
-
     private LauncherCallbacks mLauncherCallbacks;
 
     public void onPostCreate(Bundle savedInstanceState) {
@@ -892,34 +854,23 @@
 
     @Override
     protected void onResume() {
-        long startTime = 0;
-        if (DEBUG_RESUME_TIME) {
-            startTime = System.currentTimeMillis();
-            Log.v(TAG, "Launcher.onResume()");
-        }
-
+        TraceHelper.beginSection("ON_RESUME");
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.preOnResume();
         }
-
         super.onResume();
+        TraceHelper.partitionSection("ON_RESUME", "superCall");
+
         getUserEventDispatcher().resetElapsedSessionMillis();
 
         // Restore the previous launcher state
         if (mOnResumeState == State.WORKSPACE) {
             showWorkspace(false);
         } else if (mOnResumeState == State.APPS) {
-            boolean launchedFromApp = (mWaitingForResume != null);
-            // Don't update the predicted apps if the user is returning to launcher in the apps
-            // view after launching an app, as they may be depending on the UI to be static to
-            // switch to another app, otherwise, if it was
-            showAppsView(false /* animated */, !launchedFromApp /* updatePredictedApps */);
+            showAppsView(false /* animated */);
         } else if (mOnResumeState == State.WIDGETS) {
             showWidgetsView(false, false);
         }
-        if (mOnResumeState != State.APPS) {
-            tryAndUpdatePredictedApps();
-        }
         mOnResumeState = State.NONE;
 
         mPaused = false;
@@ -931,19 +882,10 @@
         if (mBindOnResumeCallbacks.size() > 0) {
             // We might have postponed some bind calls until onResume (see waitUntilResume) --
             // execute them here
-            long startTimeCallbacks = 0;
-            if (DEBUG_RESUME_TIME) {
-                startTimeCallbacks = System.currentTimeMillis();
-            }
-
             for (int i = 0; i < mBindOnResumeCallbacks.size(); i++) {
                 mBindOnResumeCallbacks.get(i).run();
             }
             mBindOnResumeCallbacks.clear();
-            if (DEBUG_RESUME_TIME) {
-                Log.d(TAG, "Time spent processing callbacks in onResume: " +
-                    (System.currentTimeMillis() - startTimeCallbacks));
-            }
         }
         if (mOnResumeCallbacks.size() > 0) {
             for (int i = 0; i < mOnResumeCallbacks.size(); i++) {
@@ -959,20 +901,7 @@
             mWaitingForResume.setStayPressed(false);
         }
 
-        // It is possible that widgets can receive updates while launcher is not in the foreground.
-        // Consequently, the widgets will be inflated in the orientation of the foreground activity
-        // (framework issue). On resuming, we ensure that any widgets are inflated for the current
-        // orientation.
-        if (!isWorkspaceLoading()) {
-            getWorkspace().reinflateWidgetsIfNecessary();
-        }
-
-        if (DEBUG_RESUME_TIME) {
-            Log.d(TAG, "Time spent in onResume: " + (System.currentTimeMillis() - startTime));
-        }
-
         updateInteraction(Workspace.State.NORMAL, mWorkspace.getState());
-        mWorkspace.onResume();
 
         // Process any items that were added while Launcher was away.
         InstallShortcutReceiver.disableAndFlushInstallQueue(
@@ -988,6 +917,9 @@
             mLauncherCallbacks.onResume();
         }
 
+        clearTypedText();
+
+        TraceHelper.endSection("ON_RESUME");
     }
 
     @Override
@@ -1050,7 +982,7 @@
             // On O and above we there is always some setting present settings (add icon to
             // home screen or icon badging). On earlier APIs we will have the allow rotation
             // setting, on devices with a locked orientation,
-            return Utilities.isAtLeastO() || !getResources().getBoolean(R.bool.allow_rotation);
+            return Utilities.ATLEAST_OREO || !getResources().getBoolean(R.bool.allow_rotation);
         }
     }
 
@@ -1117,9 +1049,6 @@
                 // Close any open floating view
                 AbstractFloatingView.closeAllOpenViews(this);
 
-                // Stop resizing any widgets
-                mWorkspace.exitWidgetResizeMode();
-
                 // Show the overview mode if we are on the workspace
                 if (mState == State.WORKSPACE && !mWorkspace.isInOverviewMode() &&
                         !mWorkspace.isSwitchingState()) {
@@ -1234,7 +1163,6 @@
                 onClickWallpaperPicker(view);
             }
         }.attachTo(wallpaperButton);
-        wallpaperButton.setOnTouchListener(getHapticFeedbackTouchListener());
 
         // Bind widget button actions
         mWidgetsButton = findViewById(R.id.widget_button);
@@ -1244,7 +1172,6 @@
                 onClickAddWidgetButton(view);
             }
         }.attachTo(mWidgetsButton);
-        mWidgetsButton.setOnTouchListener(getHapticFeedbackTouchListener());
 
         // Bind settings actions
         View settingsButton = findViewById(R.id.settings_button);
@@ -1256,7 +1183,6 @@
                     onClickSettingsButton(view);
                 }
             }.attachTo(settingsButton);
-            settingsButton.setOnTouchListener(getHapticFeedbackTouchListener());
         } else {
             settingsButton.setVisibility(View.GONE);
         }
@@ -1322,7 +1248,7 @@
         CellLayout layout = getCellLayout(container, screenId);
 
         ShortcutInfo info = null;
-        if (Utilities.isAtLeastO()) {
+        if (Utilities.ATLEAST_OREO) {
             info = LauncherAppsCompatVO.createShortcutInfoFromPinItemRequest(
                     this, LauncherAppsCompatVO.getPinItemRequest(data), 0);
         }
@@ -1408,17 +1334,13 @@
             appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(appWidgetId);
         }
 
-        if (appWidgetInfo.isCustomWidget) {
-            appWidgetId = LauncherAppWidgetInfo.CUSTOM_WIDGET_ID;
-        }
-
         LauncherAppWidgetInfo launcherInfo;
         launcherInfo = new LauncherAppWidgetInfo(appWidgetId, appWidgetInfo.provider);
         launcherInfo.spanX = itemInfo.spanX;
         launcherInfo.spanY = itemInfo.spanY;
         launcherInfo.minSpanX = itemInfo.minSpanX;
         launcherInfo.minSpanY = itemInfo.minSpanY;
-        launcherInfo.user = appWidgetInfo.getUser();
+        launcherInfo.user = appWidgetInfo.getProfile();
 
         getModelWriter().addItemToDatabase(launcherInfo,
                 itemInfo.container, itemInfo.screenId, itemInfo.cellX, itemInfo.cellY);
@@ -1444,8 +1366,6 @@
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
             if (Intent.ACTION_SCREEN_OFF.equals(action)) {
-                mDragLayer.clearResizeFrame();
-
                 // Reset AllApps to its initial state only if we are not in the middle of
                 // processing a multi-step drop
                 if (mAppsView != null && mWidgetsView != null && mPendingRequestArgs == null) {
@@ -1500,44 +1420,6 @@
         }
     }
 
-    public void onWindowVisibilityChanged(int visibility) {
-        // The following code used to be in onResume, but it turns out onResume is called when
-        // you're in All Apps and click home to go to the workspace. onWindowVisibilityChanged
-        // is a more appropriate event to handle
-        if (visibility == View.VISIBLE) {
-            if (!mWorkspaceLoading) {
-                final ViewTreeObserver observer = mWorkspace.getViewTreeObserver();
-                // We want to let Launcher draw itself at least once before we force it to build
-                // layers on all the workspace pages, so that transitioning to Launcher from other
-                // apps is nice and speedy.
-                observer.addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
-                    private boolean mStarted = false;
-                    public void onDraw() {
-                        if (mStarted) return;
-                        mStarted = true;
-                        // We delay the layer building a bit in order to give
-                        // other message processing a time to run.  In particular
-                        // this avoids a delay in hiding the IME if it was
-                        // currently shown, because doing that may involve
-                        // some communication back with the app.
-                        mWorkspace.postDelayed(mBuildLayersRunnable, 500);
-                        final ViewTreeObserver.OnDrawListener listener = this;
-                        mWorkspace.post(new Runnable() {
-                            public void run() {
-                                if (mWorkspace != null &&
-                                        mWorkspace.getViewTreeObserver() != null) {
-                                    mWorkspace.getViewTreeObserver().
-                                            removeOnDrawListener(listener);
-                                }
-                            }
-                        });
-                    }
-                });
-            }
-            clearTypedText();
-        }
-    }
-
     public DragLayer getDragLayer() {
         return mDragLayer;
     }
@@ -1582,12 +1464,11 @@
         return mSharedPrefs;
     }
 
+    public int getOrientation() { return mOrientation; }
+
     @Override
     protected void onNewIntent(Intent intent) {
-        long startTime = 0;
-        if (DEBUG_RESUME_TIME) {
-            startTime = System.currentTimeMillis();
-        }
+        TraceHelper.beginSection("NEW_INTENT");
         super.onNewIntent(intent);
 
         boolean alreadyOnHome = mHasFocus && ((intent.getFlags() &
@@ -1608,17 +1489,9 @@
             // Note: There should be at most one log per method call. This is enforced implicitly
             // by using if-else statements.
             UserEventDispatcher ued = getUserEventDispatcher();
-
-            // TODO: Log this case.
-            mWorkspace.exitWidgetResizeMode();
-
             AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(this);
-            if (topOpenView instanceof PopupContainerWithArrow) {
-                ued.logActionCommand(Action.Command.HOME_INTENT,
-                        topOpenView.getExtendedTouchView(), ContainerType.DEEPSHORTCUTS);
-            } else if (topOpenView instanceof Folder) {
-                ued.logActionCommand(Action.Command.HOME_INTENT,
-                            ((Folder) topOpenView).getFolderIcon(), ContainerType.FOLDER);
+            if (topOpenView != null) {
+                topOpenView.logActionCommand(Action.Command.HOME_INTENT);
             } else if (alreadyOnHome) {
                 ued.logActionCommand(Action.Command.HOME_INTENT,
                         mWorkspace.getState().containerType, mWorkspace.getCurrentPage());
@@ -1638,9 +1511,7 @@
 
             final View v = getWindow().peekDecorView();
             if (v != null && v.getWindowToken() != null) {
-                InputMethodManager imm = (InputMethodManager) getSystemService(
-                        INPUT_METHOD_SERVICE);
-                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
+                UiThreadHelper.hideKeyboardAsync(this, v.getWindowToken());
             }
 
             // Reset the apps view
@@ -1684,9 +1555,7 @@
             }
         }
 
-        if (DEBUG_RESUME_TIME) {
-            Log.d(TAG, "Time spent in onNewIntent: " + (System.currentTimeMillis() - startTime));
-        }
+        TraceHelper.endSection("NEW_INTENT");
     }
 
     @Override
@@ -1727,7 +1596,6 @@
         super.onDestroy();
 
         unregisterReceiver(mReceiver);
-        mWorkspace.removeCallbacks(mBuildLayersRunnable);
         mWorkspace.removeFolderListeners();
 
         // Stop callbacks from LauncherModel
@@ -1968,7 +1836,7 @@
      */
     private void addAppWidgetFromDrop(PendingAddWidgetInfo info) {
         AppWidgetHostView hostView = info.boundWidget;
-        int appWidgetId;
+        final int appWidgetId;
         WidgetAddFlowHandler addFlowHandler = info.getHandler();
         if (hostView != null) {
             // In the case where we've prebound the widget, we remove it from the DragLayer
@@ -1985,7 +1853,13 @@
         } else {
             // In this case, we either need to start an activity to get permission to bind
             // the widget, or we need to start an activity to configure the widget, or both.
-            appWidgetId = getAppWidgetHost().allocateAppWidgetId();
+            if (FeatureFlags.ENABLE_CUSTOM_WIDGETS &&
+                    info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET) {
+                appWidgetId = CustomWidgetParser.getWidgetIdForCustomProvider(
+                        this, info.componentName);
+            } else {
+                appWidgetId = getAppWidgetHost().allocateAppWidgetId();
+            }
             Bundle options = info.bindOptions;
 
             boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
@@ -2094,18 +1968,7 @@
         UserEventDispatcher ued = getUserEventDispatcher();
         AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
         if (topView != null) {
-            if (topView.getActiveTextView() != null) {
-                topView.getActiveTextView().dispatchBackKey();
-            } else {
-                if (topView instanceof PopupContainerWithArrow) {
-                    ued.logActionCommand(Action.Command.BACK,
-                            topView.getExtendedTouchView(), ContainerType.DEEPSHORTCUTS);
-                } else if (topView instanceof Folder) {
-                    ued.logActionCommand(Action.Command.BACK,
-                            ((Folder) topView).getFolderIcon(), ContainerType.FOLDER);
-                }
-                topView.close(true);
-            }
+            topView.onBackPressed();
         } else if (isAppsViewVisible()) {
             ued.logActionCommand(Action.Command.BACK, ContainerType.ALLAPPS);
             showWorkspace(true);
@@ -2116,9 +1979,6 @@
             ued.logActionCommand(Action.Command.BACK, ContainerType.OVERVIEW);
             showWorkspace(true);
         } else {
-            // TODO: Log this case.
-            mWorkspace.exitWidgetResizeMode();
-
             // Back button is a no-op here, but give at least some feedback for the button press
             mWorkspace.showOutlinesTemporarily();
         }
@@ -2232,7 +2092,7 @@
         if (!isAppsViewVisible()) {
             getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
                     ControlType.ALL_APPS_BUTTON);
-            showAppsView(true /* animated */, true /* updatePredictedApps */);
+            showAppsView(true /* animated */);
         } else {
             showWorkspace(true);
         }
@@ -2427,22 +2287,6 @@
         startActivity(intent, getActivityLaunchOptions(v));
     }
 
-    public View.OnTouchListener getHapticFeedbackTouchListener() {
-        if (mHapticFeedbackTouchListener == null) {
-            mHapticFeedbackTouchListener = new View.OnTouchListener() {
-                @SuppressLint("ClickableViewAccessibility")
-                @Override
-                public boolean onTouch(View v, MotionEvent event) {
-                    if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
-                        v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
-                    }
-                    return false;
-                }
-            };
-        }
-        return mHapticFeedbackTouchListener;
-    }
-
     @Override
     public void onAccessibilityStateChanged(boolean enabled) {
         mDragLayer.onAccessibilityStateChanged(enabled);
@@ -2813,11 +2657,8 @@
     /**
      * Shows the apps view.
      */
-    public void showAppsView(boolean animated, boolean updatePredictedApps) {
+    public void showAppsView(boolean animated) {
         markAppsViewShown();
-        if (updatePredictedApps) {
-            tryAndUpdatePredictedApps();
-        }
         showAppsOrWidgets(State.APPS, animated);
     }
 
@@ -2937,7 +2778,7 @@
 
     public void exitSpringLoadedDragMode() {
         if (mState == State.APPS_SPRING_LOADED) {
-            showAppsView(true /* animated */, false /* updatePredictedApps */);
+            showAppsView(true /* animated */);
         } else if (mState == State.WIDGETS_SPRING_LOADED) {
             showWidgetsView(true, false);
         } else if (mState == State.WORKSPACE_SPRING_LOADED) {
@@ -2945,19 +2786,6 @@
         }
     }
 
-    /**
-     * Updates the set of predicted apps if it hasn't been updated since the last time Launcher was
-     * resumed.
-     */
-    public void tryAndUpdatePredictedApps() {
-        if (mLauncherCallbacks != null) {
-            List<ComponentKeyMapper<AppInfo>> apps = mLauncherCallbacks.getPredictedApps();
-            if (apps != null) {
-                mAppsView.setPredictedApps(apps);
-            }
-        }
-    }
-
     @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
         final boolean result = super.dispatchPopulateAccessibilityEvent(event);
@@ -3063,10 +2891,7 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void startBinding() {
-        if (LauncherAppState.PROFILE_STARTUP) {
-            Trace.beginSection("Starting page bind");
-        }
-
+        TraceHelper.beginSection("startBinding");
         AbstractFloatingView.closeAllOpenViews(this);
 
         setWorkspaceLoading(true);
@@ -3078,9 +2903,7 @@
         if (mHotseat != null) {
             mHotseat.resetLayout();
         }
-        if (LauncherAppState.PROFILE_STARTUP) {
-            Trace.endSection();
-        }
+        TraceHelper.endSection("startBinding");
     }
 
     @Override
@@ -3192,7 +3015,8 @@
                             (FolderInfo) item);
                     break;
                 }
-                case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: {
+                case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+                case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: {
                     view = inflateAppWidget((LauncherAppWidgetInfo) item);
                     if (view == null) {
                         continue;
@@ -3283,10 +3107,7 @@
             return view;
         }
 
-        final long start = DEBUG_WIDGETS ? SystemClock.uptimeMillis() : 0;
-        if (DEBUG_WIDGETS) {
-            Log.d(TAG, "bindAppWidget: " + item);
-        }
+        TraceHelper.beginSection("BIND_WIDGET");
 
         final LauncherAppWidgetProviderInfo appWidgetInfo;
 
@@ -3304,11 +3125,9 @@
         if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) &&
                 (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) {
             if (appWidgetInfo == null) {
-                if (DEBUG_WIDGETS) {
-                    Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
-                            + " belongs to component " + item.providerName
-                            + ", as the provider is null");
-                }
+                Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
+                        + " belongs to component " + item.providerName
+                        + ", as the provider is null");
                 getModelWriter().deleteItemFromDatabase(item);
                 return null;
             }
@@ -3369,11 +3188,6 @@
 
         final AppWidgetHostView view;
         if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
-            if (DEBUG_WIDGETS) {
-                Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component "
-                        + appWidgetInfo.provider);
-            }
-
             // Verify that we own the widget
             if (appWidgetInfo == null) {
                 FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId);
@@ -3389,10 +3203,7 @@
         }
         prepareAppWidget(view, item);
 
-        if (DEBUG_WIDGETS) {
-            Log.d(TAG, "bound widget id="+item.appWidgetId+" in "
-                    + (SystemClock.uptimeMillis()-start) + "ms");
-        }
+        TraceHelper.endSection("BIND_WIDGET", "id=" + item.appWidgetId);
         return view;
     }
 
@@ -3414,7 +3225,10 @@
             info.pendingItemInfo = null;
         }
 
-        mWorkspace.reinflateWidgetsIfNecessary();
+        if (((PendingAppWidgetHostView) view).isReinflateIfNeeded()) {
+            view.reinflate();
+        }
+
         getModelWriter().updateItemInDatabase(info);
         return info;
     }
@@ -3478,9 +3292,7 @@
         if (waitUntilResume(r)) {
             return;
         }
-        if (LauncherAppState.PROFILE_STARTUP) {
-            Trace.beginSection("Page bind completed");
-        }
+        TraceHelper.beginSection("finishBindingItems");
         mWorkspace.restoreInstanceStateForRemainingPages();
 
         setWorkspaceLoading(false);
@@ -3499,9 +3311,7 @@
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.finishBindingItems(false);
         }
-        if (LauncherAppState.PROFILE_STARTUP) {
-            Trace.endSection();
-        }
+        TraceHelper.endSection("finishBindingItems");
     }
 
     private boolean canRunNewAppsAnimation() {
@@ -3693,7 +3503,6 @@
         // Update AllApps
         if (mAppsView != null) {
             mAppsView.removeApps(appInfos);
-            tryAndUpdatePredictedApps();
         }
     }
 
@@ -3771,7 +3580,8 @@
     }
 
     private boolean shouldShowDiscoveryBounce() {
-        return mState == State.WORKSPACE && !mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false);
+        UserManagerCompat um = UserManagerCompat.getInstance(this);
+        return mState == State.WORKSPACE && !mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false) && !um.isDemoUser();
     }
 
     /**
@@ -3856,7 +3666,7 @@
             switch (keyCode) {
                 case KeyEvent.KEYCODE_A:
                     if (mState == State.WORKSPACE) {
-                        showAppsView(true, true);
+                        showAppsView(true);
                         return true;
                     }
                     break;
@@ -3882,14 +3692,6 @@
         return super.onKeyShortcut(keyCode, event);
     }
 
-    public static CustomAppWidget getCustomAppWidget(String name) {
-        return sCustomAppWidgets.get(name);
-    }
-
-    public static HashMap<String, CustomAppWidget> getCustomAppWidgets() {
-        return sCustomAppWidgets;
-    }
-
     public static Launcher getLauncher(Context context) {
         if (context instanceof Launcher) {
             return (Launcher) context;
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 1ffe41b..dfb30fd 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -28,7 +28,6 @@
 import com.android.launcher3.compat.PackageInstallerCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dynamicui.ExtractionUtils;
 import com.android.launcher3.notification.NotificationListener;
 import com.android.launcher3.util.ConfigMonitor;
 import com.android.launcher3.util.Preconditions;
@@ -42,8 +41,6 @@
 
 public class LauncherAppState {
 
-    public static final boolean PROFILE_STARTUP = FeatureFlags.IS_DOGFOOD_BUILD;
-
     // We do not need any synchronization for this variable as its only written on UI thread.
     private static LauncherAppState INSTANCE;
 
@@ -111,18 +108,11 @@
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
-        // For extracting colors from the wallpaper
-        if (Utilities.ATLEAST_NOUGAT) {
-            // TODO: add a broadcast entry to the manifest for pre-N.
-            filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
-        }
 
         mContext.registerReceiver(mModel, filter);
         UserManagerCompat.getInstance(mContext).enableAndResetCache();
         new ConfigMonitor(mContext).register();
 
-        ExtractionUtils.startColorExtractionServiceIfNecessary(mContext);
-
         if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) {
             mNotificationBadgingObserver = null;
         } else {
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 5573c5c..70440fa 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -116,13 +116,12 @@
 
     public AppWidgetHostView createView(Context context, int appWidgetId,
             LauncherAppWidgetProviderInfo appWidget) {
-        if (appWidget.isCustomWidget) {
+        if (appWidget.isCustomWidget()) {
             LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
             LayoutInflater inflater = (LayoutInflater)
                     context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             inflater.inflate(appWidget.initialLayout, lahv);
             lahv.setAppWidget(0, appWidget);
-            lahv.updateLastInflationOrientation();
             return lahv;
         } else {
             try {
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index c7b7782..6f953e5 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -19,6 +19,7 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Handler;
@@ -58,10 +59,14 @@
 
     private final CheckLongPressHelper mLongPressHelper;
     private final StylusEventHelper mStylusEventHelper;
-    private final Context mContext;
+    private final Launcher mLauncher;
+
+    private static final int DONT_REINFLATE = 0;
+    private static final int REINFLATE_ON_RESUME = 1;
+    private static final int REINFLATE_ON_CONFIG_CHANGE = 2;
 
     @ViewDebug.ExportedProperty(category = "launcher")
-    private int mPreviousOrientation;
+    private int mReinflateStatus;
 
     private float mSlop;
 
@@ -85,14 +90,14 @@
 
     public LauncherAppWidgetHostView(Context context) {
         super(context);
-        mContext = context;
+        mLauncher = Launcher.getLauncher(context);
         mLongPressHelper = new CheckLongPressHelper(this, this);
         mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
         mInflater = LayoutInflater.from(context);
-        setAccessibilityDelegate(Launcher.getLauncher(context).getAccessibilityDelegate());
+        setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
         setBackgroundResource(R.drawable.widget_internal_focus_bg);
 
-        if (Utilities.isAtLeastO()) {
+        if (Utilities.ATLEAST_OREO) {
             setExecutor(Utilities.THREAD_POOL_EXECUTOR);
         }
     }
@@ -112,18 +117,28 @@
         return mInflater.inflate(R.layout.appwidget_error, this, false);
     }
 
-    public void updateLastInflationOrientation() {
-        mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
-    }
-
     @Override
     public void updateAppWidget(RemoteViews remoteViews) {
-        // Store the orientation in which the widget was inflated
-        updateLastInflationOrientation();
         super.updateAppWidget(remoteViews);
 
         // The provider info or the views might have changed.
         checkIfAutoAdvance();
+
+        // It is possible that widgets can receive updates while launcher is not in the foreground.
+        // Consequently, the widgets will be inflated for the orientation of the foreground activity
+        // (framework issue). On resuming, we ensure that any widgets are inflated for the current
+        // orientation.
+        if (mReinflateStatus == DONT_REINFLATE && !isSameOrientation()) {
+            mReinflateStatus = REINFLATE_ON_RESUME;
+            if (!mLauncher.waitUntilResume(new ReInflateRunnable())) {
+                mReinflateStatus = REINFLATE_ON_CONFIG_CHANGE;
+            }
+        }
+    }
+
+    private boolean isSameOrientation() {
+        return mLauncher.getResources().getConfiguration().orientation ==
+                mLauncher.getOrientation();
     }
 
     private boolean checkScrollableRecursively(ViewGroup viewGroup) {
@@ -142,15 +157,6 @@
         return false;
     }
 
-    public boolean isReinflateRequired() {
-        // Re-inflate is required if the orientation has changed since last inflated.
-        int orientation = mContext.getResources().getConfiguration().orientation;
-        if (mPreviousOrientation != orientation) {
-           return true;
-       }
-       return false;
-    }
-
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         // Just in case the previous long press hasn't been cleared, we make sure to start fresh
         // on touch down.
@@ -474,4 +480,45 @@
     public PointF getTranslationForCentering() {
         return mTranslationForCentering;
     }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        if (mReinflateStatus == REINFLATE_ON_CONFIG_CHANGE) {
+            // We are finally in the same orientation
+            reinflateIfNecessary();
+        }
+    }
+
+    private void reinflateIfNecessary() {
+        if (!isSameOrientation()) {
+            // We cannot reinflate yet, wait until next config change
+            mReinflateStatus = REINFLATE_ON_CONFIG_CHANGE;
+            return;
+        }
+
+        mReinflateStatus = DONT_REINFLATE;
+        if (isAttachedToWindow()) {
+            LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
+            reinflate();
+        }
+    }
+
+    public void reinflate() {
+        LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
+        // Remove and rebind the current widget (which was inflated in the wrong
+        // orientation), but don't delete it from the database
+        mLauncher.removeItem(this, info, false  /* deleteFromDb */);
+        mLauncher.bindAppWidget(info);
+    }
+
+    private class ReInflateRunnable implements Runnable {
+        @Override
+        public void run() {
+            if (mReinflateStatus == REINFLATE_ON_RESUME) {
+                reinflateIfNecessary();
+            }
+        }
+    }
 }
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index 6f23e56..051846c 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -71,7 +71,7 @@
     /**
      * Indicates that this is a locally defined widget and hence has no system allocated id.
      */
-    static final int CUSTOM_WIDGET_ID = -100;
+    public static final int CUSTOM_WIDGET_ID = -100;
 
     /**
      * Identifier for this widget when talking with
@@ -104,15 +104,15 @@
     private boolean mHasNotifiedInitialWidgetSizeChanged;
 
     public LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) {
-        if (appWidgetId == CUSTOM_WIDGET_ID) {
+        this.appWidgetId = appWidgetId;
+        this.providerName = providerName;
+
+        if (isCustomWidget()) {
             itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
         } else {
             itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
         }
 
-        this.appWidgetId = appWidgetId;
-        this.providerName = providerName;
-
         // Since the widget isn't instantiated yet, we don't know these values. Set them to -1
         // to indicate that they should be calculated based on the layout and minWidth/minHeight
         spanX = -1;
@@ -128,7 +128,7 @@
     }
 
     public boolean isCustomWidget() {
-        return appWidgetId == CUSTOM_WIDGET_ID;
+        return appWidgetId <= CUSTOM_WIDGET_ID;
     }
 
     @Override
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index 6cb703b..c713992 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -2,15 +2,11 @@
 
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.os.Parcel;
-import android.os.Process;
-import android.os.UserHandle;
 
 /**
  * This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords
@@ -20,7 +16,7 @@
  */
 public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo {
 
-    public boolean isCustomWidget = false;
+    public static final String CLS_CUSTOM_WIDGET_PREFIX = "#custom-widget-";
 
     public int spanX;
     public int spanY;
@@ -48,22 +44,12 @@
         return launcherInfo;
     }
 
-    private LauncherAppWidgetProviderInfo(Parcel in) {
+    protected LauncherAppWidgetProviderInfo() {}
+
+    protected LauncherAppWidgetProviderInfo(Parcel in) {
         super(in);
     }
 
-    public LauncherAppWidgetProviderInfo(Context context, CustomAppWidget widget) {
-        isCustomWidget = true;
-
-        provider = new ComponentName(context, widget.getClass().getName());
-        icon = widget.getIcon();
-        label = widget.getLabel();
-        previewImage = widget.getPreviewImage();
-        initialLayout = widget.getWidgetLayout();
-        resizeMode = widget.getResizeMode();
-        initSpans(context);
-    }
-
     public void initSpans(Context context) {
         InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
 
@@ -97,34 +83,15 @@
     }
 
     public String getLabel(PackageManager packageManager) {
-        if (isCustomWidget) {
-            return Utilities.trim(label);
-        }
         return super.loadLabel(packageManager);
     }
 
-    public Drawable getIcon(Context context, IconCache cache) {
-        if (isCustomWidget) {
-            return cache.getFullResIcon(provider.getPackageName(), icon);
-        }
-        return super.loadIcon(context, LauncherAppState.getIDP(context).fillResIconDpi);
+    public Point getMinSpans() {
+        return new Point((resizeMode & RESIZE_HORIZONTAL) != 0 ? minSpanX : -1,
+                (resizeMode & RESIZE_VERTICAL) != 0 ? minSpanY : -1);
     }
 
-    public String toString(PackageManager pm) {
-        if (isCustomWidget) {
-            return "WidgetProviderInfo(" + provider + ")";
-        }
-        return String.format("WidgetProviderInfo provider:%s package:%s short:%s label:%s",
-                provider.toString(), provider.getPackageName(), provider.getShortClassName(), getLabel(pm));
-    }
-
-    public Point getMinSpans(InvariantDeviceProfile idp, Context context) {
-        return new Point(
-                (resizeMode & RESIZE_HORIZONTAL) != 0 ? minSpanX : -1,
-                        (resizeMode & RESIZE_VERTICAL) != 0 ? minSpanY : -1);
-    }
-
-    public UserHandle getUser() {
-        return isCustomWidget ? Process.myUserHandle() : getProfile();
+    public boolean isCustomWidget() {
+        return provider.getClassName().startsWith(CLS_CUSTOM_WIDGET_PREFIX);
     }
  }
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index d1e2b62..2c9a23f 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -19,14 +19,10 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.Menu;
-import android.view.View;
-
-import com.android.launcher3.util.ComponentKeyMapper;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * LauncherCallbacks is an interface used to extend the Launcher activity. It includes many hooks
@@ -87,5 +83,4 @@
      */
     boolean shouldMoveToDefaultScreenOnHomeIntent();
     boolean hasSettings();
-    List<ComponentKeyMapper<AppInfo>> getPredictedApps();
 }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index a906b00..74a5bac 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -37,7 +37,6 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
 import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.dynamicui.ExtractionUtils;
 import com.android.launcher3.graphics.LauncherIcons;
 import com.android.launcher3.model.AddWorkspaceItemsTask;
 import com.android.launcher3.model.BgDataModel;
@@ -406,8 +405,6 @@
                     enqueueModelUpdateTask(new UserLockStateChangedTask(user));
                 }
             }
-        } else if (Intent.ACTION_WALLPAPER_CHANGED.equals(action)) {
-            ExtractionUtils.startColorExtractionServiceIfNecessary(context);
         }
     }
 
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index dc83f36..25a698b 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -55,7 +55,6 @@
 import com.android.launcher3.LauncherSettings.WorkspaceScreens;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dynamicui.ExtractionUtils;
 import com.android.launcher3.graphics.IconShapeOverride;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.DbDowngradeHelper;
@@ -149,9 +148,6 @@
      */
     protected synchronized void createDbIfNotExists() {
         if (mOpenHelper == null) {
-            if (LauncherAppState.PROFILE_STARTUP) {
-                Trace.beginSection("Opening workspace DB");
-            }
             mOpenHelper = new DatabaseHelper(getContext(), mListenerHandler);
 
             if (RestoreDbTask.isPending(getContext())) {
@@ -162,10 +158,6 @@
                 // executed again.
                 RestoreDbTask.setPending(getContext(), false);
             }
-
-            if (LauncherAppState.PROFILE_STARTUP) {
-                Trace.endSection();
-            }
         }
     }
 
@@ -372,19 +364,6 @@
         createDbIfNotExists();
 
         switch (method) {
-            case LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID: {
-                String extractedColors = extras.getString(
-                        LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS);
-                int wallpaperId = extras.getInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID);
-                Utilities.getPrefs(getContext()).edit()
-                        .putString(ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, extractedColors)
-                        .putInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, wallpaperId)
-                        .apply();
-                mListenerHandler.sendEmptyMessage(ChangeListenerWrapper.MSG_EXTRACTED_COLORS_CHANGED);
-                Bundle result = new Bundle();
-                result.putString(LauncherSettings.Settings.EXTRA_VALUE, extractedColors);
-                return result;
-            }
             case LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG: {
                 clearFlagEmptyDbCreated();
                 return null;
@@ -552,7 +531,14 @@
     }
 
     private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) {
-        int defaultLayout = LauncherAppState.getIDP(getContext()).defaultLayoutId;
+        InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext());
+        int defaultLayout = idp.defaultLayoutId;
+
+        UserManagerCompat um = UserManagerCompat.getInstance(getContext());
+        if (um.isDemoUser() && idp.demoModeLayoutId != 0) {
+            defaultLayout = idp.demoModeLayoutId;
+        }
+
         return new DefaultLayoutParser(getContext(), widgetHost,
                 mOpenHelper, getContext().getResources(), defaultLayout);
     }
@@ -1153,8 +1139,7 @@
     private static class ChangeListenerWrapper implements Handler.Callback {
 
         private static final int MSG_LAUNCHER_PROVIDER_CHANGED = 1;
-        private static final int MSG_EXTRACTED_COLORS_CHANGED = 2;
-        private static final int MSG_APP_WIDGET_HOST_RESET = 3;
+        private static final int MSG_APP_WIDGET_HOST_RESET = 2;
 
         private LauncherProviderChangeListener mListener;
 
@@ -1165,9 +1150,6 @@
                     case MSG_LAUNCHER_PROVIDER_CHANGED:
                         mListener.onLauncherProviderChanged();
                         break;
-                    case MSG_EXTRACTED_COLORS_CHANGED:
-                        mListener.onExtractedColorsChanged();
-                        break;
                     case MSG_APP_WIDGET_HOST_RESET:
                         mListener.onAppWidgetHostReset();
                         break;
diff --git a/src/com/android/launcher3/LauncherProviderChangeListener.java b/src/com/android/launcher3/LauncherProviderChangeListener.java
index 7044812..0243088 100644
--- a/src/com/android/launcher3/LauncherProviderChangeListener.java
+++ b/src/com/android/launcher3/LauncherProviderChangeListener.java
@@ -9,7 +9,5 @@
 
     void onLauncherProviderChanged();
 
-    void onExtractedColorsChanged();
-
     void onAppWidgetHostReset();
 }
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 87f62eb..3b337ef 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -304,11 +304,6 @@
 
         public static final String METHOD_LOAD_DEFAULT_FAVORITES = "load_default_favorites";
 
-        public static final String METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID =
-                "set_extracted_colors_and_wallpaper_id_setting";
-        public static final String EXTRA_EXTRACTED_COLORS = "extra_extractedColors";
-        public static final String EXTRA_WALLPAPER_ID = "extra_wallpaperId";
-
         public static final String METHOD_REMOVE_GHOST_WIDGETS = "remove_ghost_widgets";
 
         public static final String EXTRA_VALUE = "value";
diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java
index de424ab..b86d413 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/PendingAppWidgetHostView.java
@@ -110,9 +110,7 @@
         mClickListener = l;
     }
 
-    @Override
-    public boolean isReinflateRequired() {
-        // Re inflate is required any time the widget restore status changes
+    public boolean isReinflateIfNeeded() {
         return mStartState != mInfo.restoreStatus;
     }
 
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index 8caba75..edb7ff5 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -59,7 +59,7 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (!isEnabled(context) || !Utilities.isAtLeastO()) {
+        if (!isEnabled(context) || !Utilities.ATLEAST_OREO) {
             // User has decided to not add icons on homescreen.
             return;
         }
@@ -92,7 +92,7 @@
     }
 
     public static void applyDefaultUserPrefs(final Context context) {
-        if (!Utilities.isAtLeastO()) {
+        if (!Utilities.ATLEAST_OREO) {
             return;
         }
         SharedPreferences prefs = Utilities.getPrefs(context);
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index 5bdc1f5..d40ac8f 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -94,7 +94,7 @@
 
             ButtonPreference iconBadgingPref =
                     (ButtonPreference) findPreference(ICON_BADGING_PREFERENCE_KEY);
-            if (!Utilities.isAtLeastO()) {
+            if (!Utilities.ATLEAST_OREO) {
                 getPreferenceScreen().removePreference(
                         findPreference(SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY));
                 getPreferenceScreen().removePreference(iconBadgingPref);
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 84d6a9b..3f7de06 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -21,6 +21,7 @@
 public class UninstallDropTarget extends ButtonDropTarget {
 
     private static final String TAG = "UninstallDropTarget";
+    private static Boolean sUninstallDisabled;
 
     public UninstallDropTarget(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -43,18 +44,27 @@
     }
 
     @Override
-    protected boolean supportsDrop(DragSource source, ItemInfo info) {
+    protected boolean supportsDrop(ItemInfo info) {
         return supportsDrop(getContext(), info);
     }
 
     public static boolean supportsDrop(Context context, ItemInfo info) {
-        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        Bundle restrictions = userManager.getUserRestrictions();
-        if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
-                || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
+        if (sUninstallDisabled == null) {
+            UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+            Bundle restrictions = userManager.getUserRestrictions();
+            sUninstallDisabled = restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
+                    || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false);
+        }
+        if (sUninstallDisabled) {
             return false;
         }
 
+        if (info instanceof AppInfo) {
+            AppInfo appInfo = (AppInfo) info;
+            if (appInfo.isSystemApp != AppInfo.FLAG_SYSTEM_UNKNOWN) {
+                return (appInfo.isSystemApp & AppInfo.FLAG_SYSTEM_NO) != 0;
+            }
+        }
         return getUninstallTarget(context, info) != null;
     }
 
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 3aa2db0..7167778 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -83,15 +83,17 @@
     private static final Matrix sMatrix = new Matrix();
     private static final Matrix sInverseMatrix = new Matrix();
 
-    public static boolean isAtLeastO() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
-    }
+    public static final boolean ATLEAST_OREO_MR1 =
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1;
+
+    public static final boolean ATLEAST_OREO =
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
 
     public static final boolean ATLEAST_NOUGAT_MR1 =
-        Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1;
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1;
 
     public static final boolean ATLEAST_NOUGAT =
-        Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
 
     public static final boolean ATLEAST_MARSHMALLOW =
             Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
@@ -307,6 +309,9 @@
         float highScore = -1;
         int bestHue = -1;
 
+        int[] pixels = new int[samples];
+        int pixelCount = 0;
+
         for (int y = 0; y < height; y += sampleStride) {
             for (int x = 0; x < width; x += sampleStride) {
                 int argb = bitmap.getPixel(x, y);
@@ -324,6 +329,9 @@
                     // Defensively avoid array bounds violations.
                     continue;
                 }
+                if (pixelCount < samples) {
+                    pixels[pixelCount++] = rgb;
+                }
                 float score = hsv[1] * hsv[2];
                 hueScoreHistogram[hue] += score;
                 if (hueScoreHistogram[hue] > highScore) {
@@ -333,31 +341,29 @@
             }
         }
 
-        SparseArray<Float> rgbScores = new SparseArray<Float>();
+        SparseArray<Float> rgbScores = new SparseArray<>();
         int bestColor = 0xff000000;
         highScore = -1;
         // Go back over the RGB colors that match the winning hue,
         // creating a histogram of weighted s*v scores, for up to 100*100 [s,v] buckets.
         // The highest-scoring RGB color wins.
-        for (int y = 0; y < height; y += sampleStride) {
-            for (int x = 0; x < width; x += sampleStride) {
-                int rgb = bitmap.getPixel(x, y) | 0xff000000;
-                Color.colorToHSV(rgb, hsv);
-                int hue = (int) hsv[0];
-                if (hue == bestHue) {
-                    float s = hsv[1];
-                    float v = hsv[2];
-                    int bucket = (int) (s * 100) + (int) (v * 10000);
-                    // Score by cumulative saturation * value.
-                    float score = s * v;
-                    Float oldTotal = rgbScores.get(bucket);
-                    float newTotal = oldTotal == null ? score : oldTotal + score;
-                    rgbScores.put(bucket, newTotal);
-                    if (newTotal > highScore) {
-                        highScore = newTotal;
-                        // All the colors in the winning bucket are very similar. Last in wins.
-                        bestColor = rgb;
-                    }
+        for (int i = 0; i < pixelCount; i++) {
+            int rgb = pixels[i];
+            Color.colorToHSV(rgb, hsv);
+            int hue = (int) hsv[0];
+            if (hue == bestHue) {
+                float s = hsv[1];
+                float v = hsv[2];
+                int bucket = (int) (s * 100) + (int) (v * 10000);
+                // Score by cumulative saturation * value.
+                float score = s * v;
+                Float oldTotal = rgbScores.get(bucket);
+                float newTotal = oldTotal == null ? score : oldTotal + score;
+                rgbScores.put(bucket, newTotal);
+                if (newTotal > highScore) {
+                    highScore = newTotal;
+                    // All the colors in the winning bucket are very similar. Last in wins.
+                    bestColor = rgb;
                 }
             }
         }
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index a65ea9b..f150c89 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -22,7 +22,6 @@
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
-import android.os.Build;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.UserHandle;
@@ -412,7 +411,8 @@
 
             // Draw icon in the center.
             try {
-                Drawable icon = info.getIcon(launcher, mIconCache);
+                Drawable icon =
+                        mIconCache.getFullResIcon(info.provider.getPackageName(), info.icon);
                 if (icon != null) {
                     int appIconSize = launcher.getDeviceProfile().iconSizePx;
                     int iconSize = (int) Math.min(appIconSize * scale,
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 59437f6..95f7484 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -228,7 +228,6 @@
     private State mState = State.NORMAL;
     private boolean mIsSwitchingState = false;
 
-    boolean mAnimatingViewIntoPlace = false;
     boolean mChildrenLayersEnabled = true;
 
     private boolean mStripScreensOnPageStopMoving = false;
@@ -252,8 +251,6 @@
     private boolean mAddToExistingFolderOnDrop = false;
     private float mMaxDistanceForFolderCreation;
 
-    private final Canvas mCanvas = new Canvas();
-
     // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
     private float mXDown;
     private float mYDown;
@@ -351,12 +348,9 @@
     /**
      * Estimates the size of an item using spans: hSpan, vSpan.
      *
-     * @param springLoaded True if we are in spring loaded mode.
-     * @param unscaledSize True if caller wants to return the unscaled size
      * @return MAX_VALUE for each dimension if unsuccessful.
      */
-    public int[] estimateItemSize(ItemInfo itemInfo, boolean springLoaded, boolean unscaledSize) {
-        float shrinkFactor = mLauncher.getDeviceProfile().workspaceSpringLoadShrinkFactor;
+    public int[] estimateItemSize(ItemInfo itemInfo) {
         int[] size = new int[2];
         if (getChildCount() > 0) {
             // Use the first page to estimate the child position
@@ -373,15 +367,10 @@
             size[0] = r.width();
             size[1] = r.height();
 
-            if (isWidget && unscaledSize) {
+            if (isWidget) {
                 size[0] /= scale;
                 size[1] /= scale;
             }
-
-            if (springLoaded) {
-                size[0] *= shrinkFactor;
-                size[1] *= shrinkFactor;
-            }
             return size;
         } else {
             size[0] = Integer.MAX_VALUE;
@@ -408,11 +397,15 @@
         }
 
         if (mOutlineProvider != null) {
-            // The outline is used to visualize where the item will land if dropped
-            mOutlineProvider.generateDragOutline(mCanvas);
+            if (dragObject.dragView != null) {
+                Bitmap preview = dragObject.dragView.getPreviewBitmap();
+
+                // The outline is used to visualize where the item will land if dropped
+                mOutlineProvider.generateDragOutline(preview);
+            }
         }
 
-        updateChildrenLayersEnabled(false);
+        updateChildrenLayersEnabled();
         mLauncher.lockScreenOrientation();
         mLauncher.onInteractionBegin();
         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
@@ -465,7 +458,7 @@
             removeExtraEmptyScreen(true, mDragSourceInternal != null);
         }
 
-        updateChildrenLayersEnabled(false);
+        updateChildrenLayersEnabled();
         mLauncher.unlockScreenOrientation(false);
 
         // Re-enable any Un/InstallShortcutReceiver and now process any queued items
@@ -1022,10 +1015,6 @@
                 || (mTransitionProgress > FINISHED_SWITCHING_STATE_TRANSITION_PROGRESS);
     }
 
-    protected void onWindowVisibilityChanged (int visibility) {
-        mLauncher.onWindowVisibilityChanged(visibility);
-    }
-
     @Override
     public boolean dispatchUnhandledMove(View focused, int direction) {
         if (workspaceInModalState() || !isFinishedSwitchingState()) {
@@ -1054,30 +1043,6 @@
         return super.onInterceptTouchEvent(ev);
     }
 
-    protected void reinflateWidgetsIfNecessary() {
-        final int clCount = getChildCount();
-        for (int i = 0; i < clCount; i++) {
-            CellLayout cl = (CellLayout) getChildAt(i);
-            ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets();
-            final int itemCount = swc.getChildCount();
-            for (int j = 0; j < itemCount; j++) {
-                View v = swc.getChildAt(j);
-
-                if (v instanceof LauncherAppWidgetHostView
-                        && v.getTag() instanceof LauncherAppWidgetInfo) {
-                    LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
-                    LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) v;
-                    if (lahv.isReinflateRequired()) {
-                        // Remove and rebind the current widget (which was inflated in the wrong
-                        // orientation), but don't delete it from the database
-                        mLauncher.removeItem(lahv, info, false  /* deleteFromDb */);
-                        mLauncher.bindAppWidget(info);
-                    }
-                }
-            }
-        }
-    }
-
     @Override
     protected void determineScrollingStart(MotionEvent ev) {
         if (!isFinishedSwitchingState()) return;
@@ -1115,12 +1080,12 @@
 
     protected void onPageBeginTransition() {
         super.onPageBeginTransition();
-        updateChildrenLayersEnabled(false);
+        updateChildrenLayersEnabled();
     }
 
     protected void onPageEndTransition() {
         super.onPageEndTransition();
-        updateChildrenLayersEnabled(false);
+        updateChildrenLayersEnabled();
 
         if (mDragController.isDragging()) {
             if (workspaceInModalState()) {
@@ -1465,10 +1430,6 @@
         mWallpaperOffset.setWindowToken(null);
     }
 
-    protected void onResume() {
-        mWallpaperOffset.onResume();
-    }
-
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         if (mUnlockWallpaperFromDefaultPageOnLayout) {
@@ -1500,9 +1461,9 @@
         return mState == State.NORMAL || mState == State.SPRING_LOADED;
     }
 
-    @Thunk void updateChildrenLayersEnabled(boolean force) {
+    private void updateChildrenLayersEnabled() {
         boolean small = mState == State.OVERVIEW || mIsSwitchingState;
-        boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageInTransition();
+        boolean enableChildrenLayers = small || isPageInTransition();
 
         if (enableChildrenLayers != mChildrenLayersEnabled) {
             mChildrenLayersEnabled = enableChildrenLayers;
@@ -1568,19 +1529,6 @@
         }
     }
 
-    public void buildPageHardwareLayers() {
-        // force layers to be enabled just for the call to buildLayer
-        updateChildrenLayersEnabled(true);
-        if (getWindowToken() != null) {
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                CellLayout cl = (CellLayout) getChildAt(i);
-                cl.buildHardwareLayer();
-            }
-        }
-        updateChildrenLayersEnabled(false);
-    }
-
     protected void onWallpaperTap(MotionEvent ev) {
         final int[] position = mTempXY;
         getLocationOnScreen(position);
@@ -1599,11 +1547,6 @@
         mOutlineProvider = outlineProvider;
     }
 
-    public void exitWidgetResizeMode() {
-        DragLayer dragLayer = mLauncher.getDragLayer();
-        dragLayer.clearResizeFrame();
-    }
-
     public void onStartReordering() {
         super.onStartReordering();
         // Reordering handles its own animations, disable the automatic ones.
@@ -1779,12 +1722,12 @@
         }
         invalidate(); // This will call dispatchDraw(), which calls getVisiblePages().
 
-        updateChildrenLayersEnabled(false);
+        updateChildrenLayersEnabled();
     }
 
     public void onEndStateTransition() {
         mIsSwitchingState = false;
-        updateChildrenLayersEnabled(false);
+        updateChildrenLayersEnabled();
         mForceDrawAdjacentPages = false;
         mTransitionProgress = 1;
     }
@@ -1833,7 +1776,7 @@
         mOutlineProvider = previewProvider;
 
         // The drag bitmap follows the touch point around on the screen
-        final Bitmap b = previewProvider.createDragBitmap(mCanvas);
+        final Bitmap b = previewProvider.createDragBitmap();
         int halfPadding = previewProvider.previewPadding / 2;
 
         float scale = previewProvider.getScaleAndPosition(b, mTempXY);
@@ -1880,8 +1823,7 @@
 
         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source,
                 dragObject, dragVisualizeOffset, dragRect, scale, dragOptions);
-        dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
-        b.recycle();
+        dv.setIntrinsicIconScaleFactor(dragOptions.intrinsicIconScaleFactor);
         return dv;
     }
 
@@ -1893,6 +1835,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean acceptDrop(DragObject d) {
         // If it's an external drop (e.g. from All Apps), check if it should be accepted
         CellLayout dropTargetLayout = mDropToLayout;
@@ -2244,8 +2187,7 @@
                             mDelayedResizeRunnable = new Runnable() {
                                 public void run() {
                                     if (!isPageInTransition()) {
-                                        DragLayer dragLayer = mLauncher.getDragLayer();
-                                        dragLayer.addResizeFrame(hostView, cellLayout);
+                                        AppWidgetResizeFrame.showForWidget(hostView, cellLayout);
                                     }
                                 }
                             };
@@ -2269,16 +2211,6 @@
             }
 
             final CellLayout parent = (CellLayout) cell.getParent().getParent();
-            // Prepare it to be animated into its new position
-            // This must be called after the view has been re-parented
-            final Runnable onCompleteRunnable = new Runnable() {
-                @Override
-                public void run() {
-                    mAnimatingViewIntoPlace = false;
-                    updateChildrenLayersEnabled(false);
-                }
-            };
-            mAnimatingViewIntoPlace = true;
             if (d.dragView.hasDrawn()) {
                 if (droppedOnOriginalCellDuringTransition) {
                     // Animate the item to its original position, while simultaneously exiting
@@ -2297,12 +2229,11 @@
                 if (isWidget) {
                     int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :
                             ANIMATE_INTO_POSITION_AND_DISAPPEAR;
-                    animateWidgetDrop(info, parent, d.dragView,
-                            onCompleteRunnable, animationType, cell, false);
+                    animateWidgetDrop(info, parent, d.dragView, null, animationType, cell, false);
                 } else {
                     int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;
                     mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,
-                            onCompleteRunnable, this);
+                            null, this);
                 }
             } else {
                 d.deferDragViewCleanupPostAnimation = false;
@@ -2992,7 +2923,7 @@
     }
 
     public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
-        int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo, false, true);
+        int[] unScaledSize = estimateItemSize(widgetInfo);
         int visibility = layout.getVisibility();
         layout.setVisibility(VISIBLE);
 
@@ -3000,12 +2931,9 @@
         int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);
         Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],
                 Bitmap.Config.ARGB_8888);
-        mCanvas.setBitmap(b);
-
         layout.measure(width, height);
         layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);
-        layout.draw(mCanvas);
-        mCanvas.setBitmap(null);
+        layout.draw(new Canvas(b));
         layout.setVisibility(visibility);
         return b;
     }
@@ -3157,7 +3085,7 @@
 
         // hardware layers on children are enabled on startup, but should be disabled until
         // needed
-        updateChildrenLayersEnabled(false);
+        updateChildrenLayersEnabled();
     }
 
     /**
@@ -3256,21 +3184,6 @@
         }
     }
 
-    @Override
-    public float getIntrinsicIconScaleFactor() {
-        return 1f;
-    }
-
-    @Override
-    public boolean supportsAppInfoDropTarget() {
-        return true;
-    }
-
-    @Override
-    public boolean supportsDeleteDropTarget() {
-        return true;
-    }
-
     public boolean isDropEnabled() {
         return true;
     }
@@ -3641,7 +3554,7 @@
                         .getInstance(mLauncher).findProvider(item.providerName, item.user);
             } else {
                 widgetInfo = AppWidgetManagerCompat.getInstance(mLauncher)
-                        .getAppWidgetInfo(item.appWidgetId);
+                        .getLauncherAppWidgetInfo(item.appWidgetId);
             }
 
             if (widgetInfo != null) {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 4eba5c6..d63ae41 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -115,13 +115,6 @@
     }
 
     /**
-     * Sets the current set of predicted apps.
-     */
-    public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
-        mApps.setPredictedApps(apps);
-    }
-
-    /**
      * Sets the current set of apps.
      */
     public void setApps(List<AppInfo> apps) {
@@ -290,24 +283,12 @@
                 dragController.removeDragListener(this);
             }
         });
-        mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions());
-        return false;
-    }
 
-    @Override
-    public boolean supportsAppInfoDropTarget() {
-        return true;
-    }
-
-    @Override
-    public boolean supportsDeleteDropTarget() {
-        return false;
-    }
-
-    @Override
-    public float getIntrinsicIconScaleFactor() {
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        return (float) grid.allAppsIconSizePx / grid.iconSizePx;
+        DragOptions options = new DragOptions();
+        options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx;
+        mLauncher.getWorkspace().beginDragShared(v, this, options);
+        return false;
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 3364c61..b844ba3 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -6,14 +6,11 @@
 import android.animation.AnimatorSet;
 import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
-import android.graphics.Color;
 import android.support.animation.SpringAnimation;
-import android.support.v4.graphics.ColorUtils;
 import android.support.v4.view.animation.FastOutSlowInInterpolator;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
 import com.android.launcher3.AbstractFloatingView;
@@ -46,12 +43,8 @@
 public class AllAppsTransitionController implements TouchController, SwipeDetector.Listener,
          SearchUiManager.OnScrollRangeChangeListener {
 
-    private static final String TAG = "AllAppsTrans";
-    private static final boolean DBG = false;
-
     private final Interpolator mWorkspaceAccelnterpolator = new AccelerateInterpolator(2f);
     private final Interpolator mHotseatAccelInterpolator = new AccelerateInterpolator(1.5f);
-    private final Interpolator mDecelInterpolator = new DecelerateInterpolator(3f);
     private final Interpolator mFastOutSlowInInterpolator = new FastOutSlowInInterpolator();
     private final SwipeDetector.ScrollInterpolator mScrollInterpolator
             = new SwipeDetector.ScrollInterpolator();
@@ -60,10 +53,8 @@
     private static final int SINGLE_FRAME_MS = 16;
 
     private AllAppsContainerView mAppsView;
-    private int mAllAppsBackgroundColor;
     private Workspace mWorkspace;
     private Hotseat mHotseat;
-    private int mHotseatBackgroundColor;
 
     private AllAppsCaretController mCaretController;
 
@@ -112,7 +103,6 @@
         mProgress = 1f;
 
         mEvaluator = new ArgbEvaluator();
-        mAllAppsBackgroundColor = Themes.getAttrColor(l, android.R.attr.colorPrimary);
         mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
     }
 
@@ -226,7 +216,7 @@
                             Action.Direction.UP,
                             containerType);
                 }
-                mLauncher.showAppsView(true /* animated */, false /* updatePredictedApps */);
+                mLauncher.showAppsView(true /* animated */);
                 if (hasSpringAnimationHandler()) {
                     mSpringAnimationHandler.add(mSearchSpring, true /* setDefaultValues */);
                     // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
@@ -249,7 +239,7 @@
                             Action.Direction.UP,
                             containerType);
                 }
-                mLauncher.showAppsView(true, /* animated */ false /* updatePredictedApps */);
+                mLauncher.showAppsView(true /* animated */);
             }
         }
     }
@@ -266,29 +256,13 @@
             // Initialize values that should not change until #onDragEnd
             mStatusBarHeight = mLauncher.getDragLayer().getInsets().top;
             mHotseat.setVisibility(View.VISIBLE);
-            mHotseatBackgroundColor = mHotseat.getBackgroundDrawableColor();
-            mHotseat.setBackgroundTransparent(true /* transparent */);
-            if (!mLauncher.isAllAppsVisible()) {
-                mLauncher.tryAndUpdatePredictedApps();
-                mAppsView.setVisibility(View.VISIBLE);
-                if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-                    mAppsView.setRevealDrawableColor(mHotseatBackgroundColor);
-                }
-            }
+            mAppsView.setVisibility(View.VISIBLE);
         }
     }
 
     private void updateLightStatusBar(float shift) {
-        // Do not modify status bar on landscape as all apps is not full bleed.
-        if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS
-                && mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-            return;
-        }
-
         // Use a light system UI (dark icons) if all apps is behind at least half of the status bar.
-        boolean forceChange = FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS ?
-                shift <= mShiftRange / 4 :
-                shift <= mStatusBarHeight / 2;
+        boolean forceChange = shift <= mShiftRange / 4;
         if (forceChange) {
             mLauncher.getSystemUiController().updateUiState(
                     SystemUiController.UI_STATE_ALL_APPS, !mIsDarkTheme);
@@ -301,8 +275,7 @@
     private void updateAllAppsBg(float progress) {
         // gradient
         if (mGradientView == null) {
-            mGradientView = (GradientView) mLauncher.findViewById(R.id.gradient_bg);
-            mGradientView.setVisibility(View.VISIBLE);
+            mGradientView = mLauncher.findViewById(R.id.gradient_bg);
         }
         mGradientView.setProgress(progress);
     }
@@ -320,17 +293,7 @@
         float workspaceAlpha = mWorkspaceAccelnterpolator.getInterpolation(workspaceHotseatAlpha);
         float hotseatAlpha = mHotseatAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
 
-        int color = (Integer) mEvaluator.evaluate(mDecelInterpolator.getInterpolation(alpha),
-                mHotseatBackgroundColor, mAllAppsBackgroundColor);
-        int bgAlpha = Color.alpha((int) mEvaluator.evaluate(alpha,
-                mHotseatBackgroundColor, mAllAppsBackgroundColor));
-
-        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-            updateAllAppsBg(alpha);
-        } else {
-            mAppsView.setRevealDrawableColor(ColorUtils.setAlphaComponent(color, bgAlpha));
-        }
-
+        updateAllAppsBg(alpha);
         mAppsView.getContentView().setAlpha(alpha);
         mAppsView.setTranslationY(shiftCurrent);
 
@@ -530,7 +493,6 @@
 
     public void finishPullDown() {
         mAppsView.setVisibility(View.INVISIBLE);
-        mHotseat.setBackgroundTransparent(false /* transparent */);
         mHotseat.setVisibility(View.VISIBLE);
         mAppsView.reset();
         if (hasSpringAnimationHandler()) {
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 6bbe3ea..f0b650b 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -362,9 +362,12 @@
         int size = apps.size();
         for (int i = 0; i < size; ++i) {
             AppInfo info = apps.get(i);
-            AdapterItem appItem = AdapterItem.asPredictedApp(i, "", info, i);
-            appItem.rowAppIndex = i;
-            mAdapterItems.set(i, appItem);
+            AdapterItem orgItem = mAdapterItems.get(i);
+            AdapterItem newItem = AdapterItem.asPredictedApp(orgItem.position, "", info,
+                    orgItem.appIndex);
+            newItem.rowAppIndex = orgItem.rowAppIndex;
+
+            mAdapterItems.set(i, newItem);
             mFilteredApps.set(i, info);
             mAdapter.notifyItemChanged(i);
         }
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 63aa7be..bf03a0e 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -15,16 +15,13 @@
  */
 package com.android.launcher3.allapps.search;
 
-import android.content.Context;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.view.KeyEvent;
-import android.view.View;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
@@ -50,7 +47,6 @@
     protected String mQuery;
 
     protected SearchAlgorithm mSearchAlgorithm;
-    protected InputMethodManager mInputMethodManager;
 
     public void setVisibility(int visibility) {
         mInput.setVisibility(visibility);
@@ -68,10 +64,6 @@
         mInput.addTextChangedListener(this);
         mInput.setOnEditorActionListener(this);
         mInput.setOnBackKeyListener(this);
-
-        mInputMethodManager = (InputMethodManager)
-                mInput.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-
         mSearchAlgorithm = searchAlgorithm;
     }
 
@@ -137,22 +129,9 @@
      * Resets the search bar state.
      */
     public void reset() {
-        unfocusSearchField();
         mCb.clearSearchResult();
-        mInput.setText("");
+        mInput.reset();
         mQuery = null;
-        hideKeyboard();
-    }
-
-    protected void hideKeyboard() {
-        mInputMethodManager.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
-    }
-
-    protected void unfocusSearchField() {
-        View nextFocus = mInput.focusSearch(View.FOCUS_DOWN);
-        if (nextFocus != null) {
-            nextFocus.requestFocus();
-        }
     }
 
     /**
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index 4e00eae..fd1f0cc 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -24,10 +24,13 @@
 import android.os.UserHandle;
 import android.support.annotation.Nullable;
 
+import com.android.launcher3.LauncherAppWidgetInfo;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.custom.CustomWidgetParser;
 
 import java.util.HashMap;
 import java.util.List;
@@ -40,7 +43,7 @@
     public static AppWidgetManagerCompat getInstance(Context context) {
         synchronized (sInstanceLock) {
             if (sInstance == null) {
-                if (Utilities.isAtLeastO()) {
+                if (Utilities.ATLEAST_OREO) {
                     sInstance = new AppWidgetManagerCompatVO(context.getApplicationContext());
                 } else {
                     sInstance = new AppWidgetManagerCompatVL(context.getApplicationContext());
@@ -58,12 +61,13 @@
         mAppWidgetManager = AppWidgetManager.getInstance(context);
     }
 
-    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
-        return mAppWidgetManager.getAppWidgetInfo(appWidgetId);
-    }
-
     public LauncherAppWidgetProviderInfo getLauncherAppWidgetInfo(int appWidgetId) {
-        AppWidgetProviderInfo info = getAppWidgetInfo(appWidgetId);
+        if (FeatureFlags.ENABLE_CUSTOM_WIDGETS
+                && appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
+            return CustomWidgetParser.getWidgetProvider(mContext, appWidgetId);
+        }
+
+        AppWidgetProviderInfo info = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
         return info == null ? null : LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
     }
 
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index cb3bd6c..8430285 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -20,14 +20,17 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Bundle;
+import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.support.annotation.Nullable;
 
+import com.android.launcher3.LauncherAppWidgetInfo;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.custom.CustomWidgetParser;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -54,6 +57,10 @@
             for (UserHandle user : mUserManager.getUserProfiles()) {
                 providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user));
             }
+
+            if (FeatureFlags.ENABLE_CUSTOM_WIDGETS) {
+                providers.addAll(CustomWidgetParser.getCustomWidgets(mContext));
+            }
             return providers;
         }
         // Only get providers for the given package/user.
@@ -65,6 +72,11 @@
                 iterator.remove();
             }
         }
+
+        if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && Process.myUserHandle().equals(packageUser.mUser)
+                && mContext.getPackageName().equals(packageUser.mPackageName)) {
+            providers.addAll(CustomWidgetParser.getCustomWidgets(mContext));
+        }
         return providers;
     }
 
@@ -74,6 +86,11 @@
         if (FeatureFlags.GO_DISABLE_WIDGETS) {
             return false;
         }
+
+        if (FeatureFlags.ENABLE_CUSTOM_WIDGETS
+                && appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
+            return true;
+        }
         return mAppWidgetManager.bindAppWidgetIdIfAllowed(
                 appWidgetId, info.getProfile(), info.provider, options);
     }
@@ -89,6 +106,15 @@
                 return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
             }
         }
+
+        if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && Process.myUserHandle().equals(user)) {
+            for (LauncherAppWidgetProviderInfo info :
+                    CustomWidgetParser.getCustomWidgets(mContext)) {
+                if (info.provider.equals(provider)) {
+                    return info;
+                }
+            }
+        }
         return null;
     }
 
@@ -104,6 +130,13 @@
                 result.put(new ComponentKey(info.provider, user), info);
             }
         }
+
+        if (FeatureFlags.ENABLE_CUSTOM_WIDGETS) {
+            for (LauncherAppWidgetProviderInfo info :
+                    CustomWidgetParser.getCustomWidgets(mContext)) {
+                result.put(new ComponentKey(info.provider, info.getProfile()), info);
+            }
+        }
         return result;
     }
 }
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index 75a2a5d..2cac536 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -53,7 +53,7 @@
     public static LauncherAppsCompat getInstance(Context context) {
         synchronized (sInstanceLock) {
             if (sInstance == null) {
-                if (Utilities.isAtLeastO()) {
+                if (Utilities.ATLEAST_OREO) {
                     sInstance = new LauncherAppsCompatVO(context.getApplicationContext());
                 } else {
                     sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompat.java b/src/com/android/launcher3/compat/WallpaperManagerCompat.java
index cbcabdf..00258c7 100644
--- a/src/com/android/launcher3/compat/WallpaperManagerCompat.java
+++ b/src/com/android/launcher3/compat/WallpaperManagerCompat.java
@@ -31,10 +31,10 @@
             if (sInstance == null) {
                 context = context.getApplicationContext();
 
-                if (Utilities.isAtLeastO()) {
+                if (Utilities.ATLEAST_OREO) {
                     try {
                         sInstance = new WallpaperManagerCompatVOMR1(context);
-                    } catch (Exception e) {
+                    } catch (Throwable e) {
                         // The wallpaper APIs do not yet exist
                     }
                 }
diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompatVL.java b/src/com/android/launcher3/compat/WallpaperManagerCompatVL.java
index 8e572ee..4cc70d3 100644
--- a/src/com/android/launcher3/compat/WallpaperManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/WallpaperManagerCompatVL.java
@@ -15,6 +15,10 @@
  */
 package com.android.launcher3.compat;
 
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+
+import static com.android.launcher3.Utilities.getDevicePrefs;
+
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
 import android.app.job.JobInfo;
@@ -38,7 +42,6 @@
 import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
 import android.support.annotation.Nullable;
-import android.support.v7.graphics.Palette;
 import android.util.Log;
 import android.util.Pair;
 
@@ -46,12 +49,6 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import static android.app.WallpaperManager.FLAG_SYSTEM;
-import static com.android.launcher3.Utilities.getDevicePrefs;
 
 public class WallpaperManagerCompatVL extends WallpaperManagerCompat {
 
@@ -260,27 +257,8 @@
             String value = VERSION_PREFIX + wallpaperId;
 
             if (bitmap != null) {
-                Palette palette = Palette.from(bitmap).generate();
-                bitmap.recycle();
-
-                StringBuilder builder = new StringBuilder(value);
-                List<Pair<Integer,Integer>> colorsToOccurrences = new ArrayList<>();
-                for (Palette.Swatch swatch : palette.getSwatches()) {
-                    colorsToOccurrences.add(new Pair(swatch.getRgb(), swatch.getPopulation()));
-                }
-
-                Collections.sort(colorsToOccurrences, new Comparator<Pair<Integer, Integer>>() {
-                    @Override
-                    public int compare(Pair<Integer, Integer> a, Pair<Integer, Integer> b) {
-                        return b.second - a.second;
-                    }
-                });
-
-                for (int i=0; i < Math.min(3, colorsToOccurrences.size()); i++) {
-                    builder.append(',').append(colorsToOccurrences.get(i).first);
-                }
-
-                value = builder.toString();
+                int color = Utilities.findDominantColorByHue(bitmap, MAX_WALLPAPER_EXTRACTION_AREA);
+                value += "," + color;
             }
 
             // Send the result
diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java b/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java
index 28b780a..524f266 100644
--- a/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java
+++ b/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java
@@ -35,8 +35,9 @@
     private final WallpaperManager mWm;
     private Method mWCColorHintsMethod;
 
-    WallpaperManagerCompatVOMR1(Context context) throws Exception {
+    WallpaperManagerCompatVOMR1(Context context) throws Throwable {
         mWm = context.getSystemService(WallpaperManager.class);
+        String className = WallpaperColors.class.getName();
         try {
             mWCColorHintsMethod = WallpaperColors.class.getDeclaredMethod("getColorHints");
         } catch (Exception exc) {
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 5adeec1..8a1bc63 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -39,8 +39,6 @@
     public static final boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = false;
     // 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.
@@ -50,16 +48,15 @@
     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 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 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;
+
+    // When true, custom widgets are loaded using CustomWidgetParser.
+    public static final boolean ENABLE_CUSTOM_WIDGETS = false;
 
     // Features to control Launcher3Go behavior
     public static final boolean GO_DISABLE_WIDGETS = false;
diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
index d0f2629..727fb51 100644
--- a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
@@ -159,21 +159,6 @@
     }
 
     @Override
-    public boolean supportsAppInfoDropTarget() {
-        return false;
-    }
-
-    @Override
-    public boolean supportsDeleteDropTarget() {
-        return false;
-    }
-
-    @Override
-    public float getIntrinsicIconScaleFactor() {
-        return 1f;
-    }
-
-    @Override
     public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete,
             boolean success) {
         if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index b852714..a7ed87f 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -27,7 +27,6 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.inputmethod.InputMethodManager;
 
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
@@ -39,6 +38,7 @@
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.TouchController;
+import com.android.launcher3.util.UiThreadHelper;
 
 import java.util.ArrayList;
 
@@ -138,8 +138,7 @@
         }
 
         // Hide soft keyboard, if visible
-        mLauncher.getSystemService(InputMethodManager.class)
-                .hideSoftInputFromWindow(mWindowToken, 0);
+        UiThreadHelper.hideKeyboardAsync(mLauncher, mWindowToken);
 
         mOptions = options;
         if (mOptions.systemDndStartPoint != null) {
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index fde7995..60ce3c3 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -24,13 +24,11 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -42,13 +40,10 @@
 import android.widget.TextView;
 
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.AppWidgetResizeFrame;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DropTargetBar;
-import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppWidgetHostView;
 import com.android.launcher3.PinchToOverviewListener;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
@@ -59,11 +54,9 @@
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
-import com.android.launcher3.logging.LoggerUtils;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.TouchController;
-import com.android.launcher3.widget.WidgetsBottomSheet;
 
 import java.util.ArrayList;
 
@@ -81,10 +74,6 @@
 
     private Launcher mLauncher;
 
-    // Variables relating to resizing widgets
-    private final boolean mIsRtl;
-    private AppWidgetResizeFrame mCurrentResizeFrame;
-
     // Variables relating to animation of views after drop
     private ValueAnimator mDropAnim = null;
     private final TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
@@ -105,7 +94,6 @@
     private float mBackgroundAlpha = 0;
 
     // Related to adjacent page hints
-    private final Rect mScrollChildPosition = new Rect();
     private final ViewGroupFocusHelper mFocusIndicatorHelper;
     private final WallpaperColorInfo mWallpaperColorInfo;
 
@@ -129,7 +117,6 @@
         setMotionEventSplittingEnabled(false);
         setChildrenDrawingOrderEnabled(true);
 
-        mIsRtl = Utilities.isRtl(getResources());
         mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
         mWallpaperColorInfo = WallpaperColorInfo.getInstance(getContext());
     }
@@ -159,10 +146,6 @@
                 ? null : new PinchToOverviewListener(mLauncher);
     }
 
-    public boolean isEventOverPageIndicator(MotionEvent ev) {
-        return isEventOverView(mLauncher.getWorkspace().getPageIndicator(), ev);
-    }
-
     public boolean isEventOverHotseat(MotionEvent ev) {
         return isEventOverView(mLauncher.getHotseat(), ev);
     }
@@ -180,36 +163,6 @@
         return mHitRect.contains((int) ev.getX(), (int) ev.getY());
     }
 
-    private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
-        AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
-        if (topView != null && intercept) {
-            ExtendedEditText textView = topView.getActiveTextView();
-            if (textView != null) {
-                if (!isEventOverView(textView, ev)) {
-                    textView.dispatchBackKey();
-                    return true;
-                }
-            } else if (!isEventOverView(topView, ev)) {
-                if (isInAccessibleDrag()) {
-                    // Do not close the container if in drag and drop.
-                    if (!isEventOverDropTargetBar(ev)) {
-                        return true;
-                    }
-                } else {
-                    mLauncher.getUserEventDispatcher().logActionTapOutside(
-                            LoggerUtils.newContainerTarget(topView.getLogContainerType()));
-                    topView.close(true);
-
-                    // We let touches on the original icon go through so that users can launch
-                    // the app with one tap if they don't find a shortcut they want.
-                    View extendedTouch = topView.getExtendedTouchView();
-                    return extendedTouch == null || !isEventOverView(extendedTouch, ev);
-                }
-            }
-        }
-        return false;
-    }
-
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         int action = ev.getAction();
@@ -219,9 +172,6 @@
             // dray layer even if mAllAppsController is NOT the active controller.
             // TODO: handle other input other than touch
             mAllAppsController.cancelDiscoveryAnimation();
-            if (handleTouchDown(ev, true)) {
-                return true;
-            }
         } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
             if (mTouchCompleteListener != null) {
                 mTouchCompleteListener.onTouchComplete();
@@ -230,12 +180,10 @@
         }
         mActiveController = null;
 
-        if (mCurrentResizeFrame != null
-                && mCurrentResizeFrame.onControllerInterceptTouchEvent(ev)) {
-            mActiveController = mCurrentResizeFrame;
+        AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
+        if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
+            mActiveController = topView;
             return true;
-        } else {
-            clearResizeFrame();
         }
 
         if (mDragController.onControllerInterceptTouchEvent(ev)) {
@@ -248,12 +196,6 @@
             return true;
         }
 
-        WidgetsBottomSheet widgetsBottomSheet = WidgetsBottomSheet.getOpen(mLauncher);
-        if (widgetsBottomSheet != null && widgetsBottomSheet.onControllerInterceptTouchEvent(ev)) {
-            mActiveController = widgetsBottomSheet;
-            return true;
-        }
-
         if (mPinchListener != null && mPinchListener.onControllerInterceptTouchEvent(ev)) {
             // Stop listening for scrolling etc. (onTouchEvent() handles the rest of the pinch.)
             mActiveController = mPinchListener;
@@ -357,12 +299,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         int action = ev.getAction();
-
-        if (action == MotionEvent.ACTION_DOWN) {
-            if (handleTouchDown(ev, false)) {
-                return true;
-            }
-        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
             if (mTouchCompleteListener != null) {
                 mTouchCompleteListener.onTouchComplete();
             }
@@ -542,25 +479,6 @@
         }
     }
 
-    public void clearResizeFrame() {
-        if (mCurrentResizeFrame != null) {
-            removeView(mCurrentResizeFrame);
-            mCurrentResizeFrame = null;
-        }
-    }
-
-    public void addResizeFrame(LauncherAppWidgetHostView widget, CellLayout cellLayout) {
-        clearResizeFrame();
-
-        mCurrentResizeFrame = (AppWidgetResizeFrame) LayoutInflater.from(mLauncher)
-                .inflate(R.layout.app_widget_resize_frame, this, false);
-        mCurrentResizeFrame.setupForWidget(widget, cellLayout, this);
-        ((LayoutParams) mCurrentResizeFrame.getLayoutParams()).customPosition = true;
-
-        addView(mCurrentResizeFrame);
-        mCurrentResizeFrame.snapToWidget(false);
-    }
-
     public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
             float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
             int duration) {
diff --git a/src/com/android/launcher3/dragndrop/DragOptions.java b/src/com/android/launcher3/dragndrop/DragOptions.java
index 9433aad..f108f8b 100644
--- a/src/com/android/launcher3/dragndrop/DragOptions.java
+++ b/src/com/android/launcher3/dragndrop/DragOptions.java
@@ -34,6 +34,9 @@
     /** Determines when a pre-drag should transition to a drag. By default, this is immediate. */
     public PreDragCondition preDragCondition = null;
 
+    /** Scale of the icons over the workspace icon size. */
+    public float intrinsicIconScaleFactor = 1f;
+
     /**
      * Specifies a condition that must be met before DragListener#onDragStart() is called.
      * By default, there is no condition and onDragStart() is called immediately following
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index e81e2a3..17fad84 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -169,7 +169,7 @@
             }
         });
 
-        mBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight());
+        mBitmap = bitmap;
         setDragRegion(new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()));
 
         // The point in our scaled bitmap that the touch events are located
@@ -193,7 +193,7 @@
      */
     @TargetApi(Build.VERSION_CODES.O)
     public void setItemInfo(final ItemInfo info) {
-        if (!(FeatureFlags.LAUNCHER3_SPRING_ICONS && Utilities.isAtLeastO())) {
+        if (!(FeatureFlags.LAUNCHER3_SPRING_ICONS && Utilities.ATLEAST_OREO)) {
             return;
         }
         if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
@@ -427,6 +427,10 @@
         return mDragRegion;
     }
 
+    public Bitmap getPreviewBitmap() {
+        return mBitmap;
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         mHasDrawn = true;
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index c8d3890..b9d97ac 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -128,7 +128,7 @@
     }
 
     public static boolean handleDragRequest(Launcher launcher, Intent intent) {
-        if (!Utilities.isAtLeastO()) {
+        if (!Utilities.ATLEAST_OREO) {
             return false;
         }
         if (intent == null || !Intent.ACTION_MAIN.equals(intent.getAction())) {
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionService.java b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
deleted file mode 100644
index b9dd3b5..0000000
--- a/src/com/android/launcher3/dynamicui/ColorExtractionService.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.dynamicui;
-
-import android.annotation.TargetApi;
-import android.app.WallpaperManager;
-import android.app.job.JobParameters;
-import android.app.job.JobService;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapRegionDecoder;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.ParcelFileDescriptor;
-import android.support.v7.graphics.Palette;
-import android.util.Log;
-
-import com.android.launcher3.LauncherProvider;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-
-import java.io.IOException;
-
-/**
- * Extracts colors from the wallpaper, and saves results to {@link LauncherProvider}.
- */
-public class ColorExtractionService extends JobService {
-
-    private static final String TAG = "ColorExtractionService";
-    private static final boolean DEBUG = false;
-
-    /** The fraction of the wallpaper to extract colors for use on the hotseat. */
-    private static final float HOTSEAT_FRACTION = 1f / 4;
-
-    private HandlerThread mWorkerThread;
-    private Handler mWorkerHandler;
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mWorkerThread = new HandlerThread("ColorExtractionService");
-        mWorkerThread.start();
-        mWorkerHandler = new Handler(mWorkerThread.getLooper());
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        mWorkerThread.quit();
-    }
-
-    @Override
-    public boolean onStartJob(final JobParameters jobParameters) {
-        if (DEBUG) Log.d(TAG, "onStartJob");
-        mWorkerHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                WallpaperManager wallpaperManager = WallpaperManager.getInstance(
-                        ColorExtractionService.this);
-                int wallpaperId = ExtractionUtils.getWallpaperId(wallpaperManager);
-
-                ExtractedColors extractedColors = new ExtractedColors();
-                if (wallpaperManager.getWallpaperInfo() != null) {
-                    // We can't extract colors from live wallpapers; always use the default color.
-                    extractedColors.updateHotseatPalette(null);
-
-                    if (FeatureFlags.QSB_IN_HOTSEAT || FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-                        extractedColors.updateWallpaperThemePalette(null);
-                    }
-                } else {
-                    // We extract colors for the hotseat and status bar separately,
-                    // since they only consider part of the wallpaper.
-                    extractedColors.updateHotseatPalette(getHotseatPalette());
-
-                    if (FeatureFlags.LIGHT_STATUS_BAR) {
-                        extractedColors.updateStatusBarPalette(getStatusBarPalette());
-                    }
-
-                    if (FeatureFlags.QSB_IN_HOTSEAT || FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-                        extractedColors.updateWallpaperThemePalette(getWallpaperPalette());
-                    }
-                }
-
-                // Save the extracted colors and wallpaper id to LauncherProvider.
-                String colorsString = extractedColors.encodeAsString();
-                Bundle extras = new Bundle();
-                extras.putInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID, wallpaperId);
-                extras.putString(LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS, colorsString);
-                getContentResolver().call(
-                        LauncherSettings.Settings.CONTENT_URI,
-                        LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID,
-                        null, extras);
-                jobFinished(jobParameters, false /* needsReschedule */);
-                if (DEBUG) Log.d(TAG, "job finished!");
-            }
-        });
-        return true;
-    }
-
-    @Override
-    public boolean onStopJob(JobParameters jobParameters) {
-        if (DEBUG) Log.d(TAG, "onStopJob");
-        mWorkerHandler.removeCallbacksAndMessages(null);
-        return true;
-    }
-
-    @TargetApi(Build.VERSION_CODES.N)
-    private Palette getHotseatPalette() {
-        WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
-        if (Utilities.ATLEAST_NOUGAT) {
-            try (ParcelFileDescriptor fd = wallpaperManager
-                    .getWallpaperFile(WallpaperManager.FLAG_SYSTEM)) {
-                BitmapRegionDecoder decoder = BitmapRegionDecoder
-                        .newInstance(fd.getFileDescriptor(), false);
-                int height = decoder.getHeight();
-                Rect decodeRegion = new Rect(0, (int) (height * (1f - HOTSEAT_FRACTION)),
-                        decoder.getWidth(), height);
-                Bitmap bitmap = decoder.decodeRegion(decodeRegion, null);
-                decoder.recycle();
-                if (bitmap != null) {
-                    return Palette.from(bitmap).clearFilters().generate();
-                }
-            } catch (IOException | NullPointerException e) {
-                Log.e(TAG, "Fetching partial bitmap failed, trying old method", e);
-            }
-        }
-
-        Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap();
-        return Palette.from(wallpaper)
-                .setRegion(0, (int) (wallpaper.getHeight() * (1f - HOTSEAT_FRACTION)),
-                        wallpaper.getWidth(), wallpaper.getHeight())
-                .clearFilters()
-                .generate();
-    }
-
-    @TargetApi(Build.VERSION_CODES.N)
-    private Palette getStatusBarPalette() {
-        WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
-        int statusBarHeight = getResources()
-                .getDimensionPixelSize(R.dimen.status_bar_height);
-
-        if (Utilities.ATLEAST_NOUGAT) {
-            try (ParcelFileDescriptor fd = wallpaperManager
-                    .getWallpaperFile(WallpaperManager.FLAG_SYSTEM)) {
-                BitmapRegionDecoder decoder = BitmapRegionDecoder
-                        .newInstance(fd.getFileDescriptor(), false);
-                Rect decodeRegion = new Rect(0, 0,
-                        decoder.getWidth(), statusBarHeight);
-                Bitmap bitmap = decoder.decodeRegion(decodeRegion, null);
-                decoder.recycle();
-                if (bitmap != null) {
-                    return Palette.from(bitmap).clearFilters().generate();
-                }
-            } catch (IOException | NullPointerException e) {
-                Log.e(TAG, "Fetching partial bitmap failed, trying old method", e);
-            }
-        }
-
-        Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap();
-        return Palette.from(wallpaper)
-                .setRegion(0, 0, wallpaper.getWidth(), statusBarHeight)
-                .clearFilters()
-                .generate();
-    }
-
-    @TargetApi(Build.VERSION_CODES.N)
-    private Palette getWallpaperPalette() {
-        WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
-        if (Utilities.ATLEAST_NOUGAT) {
-            try (ParcelFileDescriptor fd = wallpaperManager
-                    .getWallpaperFile(WallpaperManager.FLAG_SYSTEM)) {
-                Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor());
-                if (bitmap != null) {
-                    return Palette.from(bitmap).clearFilters().generate();
-                }
-            } catch (IOException | NullPointerException e) {
-                Log.e(TAG, "Fetching partial bitmap failed, trying old method", e);
-            }
-        }
-
-        Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap();
-        return Palette.from(wallpaper).clearFilters().generate();
-    }
-}
diff --git a/src/com/android/launcher3/dynamicui/ExtractedColors.java b/src/com/android/launcher3/dynamicui/ExtractedColors.java
deleted file mode 100644
index 2d8bb86..0000000
--- a/src/com/android/launcher3/dynamicui/ExtractedColors.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.dynamicui;
-
-import android.app.WallpaperManager;
-import android.content.Context;
-import android.graphics.Color;
-import android.support.annotation.Nullable;
-import android.support.v4.graphics.ColorUtils;
-import android.support.v7.graphics.Palette;
-import android.util.Log;
-
-import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * Saves and loads colors extracted from the wallpaper, as well as the associated wallpaper id.
- */
-public class ExtractedColors {
-    private static final String TAG = "ExtractedColors";
-
-    public static final int DEFAULT_LIGHT = Color.WHITE;
-    public static final int DEFAULT_DARK = Color.BLACK;
-
-    // These color profile indices should NOT be changed, since they are used when saving and
-    // loading extracted colors. New colors should always be added at the end.
-    public static final int VERSION_INDEX = 0;
-    public static final int HOTSEAT_INDEX = 1;
-    public static final int STATUS_BAR_INDEX = 2;
-    public static final int WALLPAPER_VIBRANT_INDEX = 3;
-    public static final int ALLAPPS_GRADIENT_MAIN_INDEX = 4;
-    public static final int ALLAPPS_GRADIENT_SECONDARY_INDEX = 5;
-
-    private static final int VERSION;
-    private static final int[] DEFAULT_VALUES;
-
-    static {
-        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-            VERSION = 3;
-            DEFAULT_VALUES = new int[] {
-                    VERSION,            // VERSION_INDEX
-                    0x40FFFFFF,         // HOTSEAT_INDEX: White with 25% alpha
-                    DEFAULT_DARK,       // STATUS_BAR_INDEX
-                    0xFFCCCCCC,         // WALLPAPER_VIBRANT_INDEX
-                    0xFF000000,         // ALLAPPS_GRADIENT_MAIN_INDEX
-                    0xFF000000          // ALLAPPS_GRADIENT_SECONDARY_INDEX
-            };
-        } else if (FeatureFlags.QSB_IN_HOTSEAT) {
-            VERSION = 2;
-            DEFAULT_VALUES = new int[] {
-                    VERSION,            // VERSION_INDEX
-                    0x40FFFFFF,         // HOTSEAT_INDEX: White with 25% alpha
-                    DEFAULT_DARK,       // STATUS_BAR_INDEX
-                    0xFFCCCCCC,         // WALLPAPER_VIBRANT_INDEX
-            };
-        } else {
-            VERSION = 1;
-            DEFAULT_VALUES = new int[] {
-                    VERSION,            // VERSION_INDEX
-                    0x40FFFFFF,         // HOTSEAT_INDEX: White with 25% alpha
-                    DEFAULT_DARK,       // STATUS_BAR_INDEX
-            };
-        }
-    }
-
-    private static final String COLOR_SEPARATOR = ",";
-
-    private final ArrayList<OnChangeListener> mListeners = new ArrayList<>();
-    private final int[] mColors;
-
-    public ExtractedColors() {
-        // The first entry is reserved for the version number.
-        mColors = Arrays.copyOf(DEFAULT_VALUES, DEFAULT_VALUES.length);
-    }
-
-    public void setColorAtIndex(int index, int color) {
-        if (index > VERSION_INDEX && index < mColors.length) {
-            mColors[index] = color;
-        } else {
-            Log.e(TAG, "Attempted to set a color at an invalid index " + index);
-        }
-    }
-
-    /**
-     * Encodes {@link #mColors} as a comma-separated String.
-     */
-    String encodeAsString() {
-        StringBuilder colorsStringBuilder = new StringBuilder();
-        for (int color : mColors) {
-            colorsStringBuilder.append(color).append(COLOR_SEPARATOR);
-        }
-        return colorsStringBuilder.toString();
-    }
-
-    /**
-     * Loads colors and wallpaper id from {@link Utilities#getPrefs(Context)}.
-     * These were saved there in {@link ColorExtractionService}.
-     */
-    public void load(Context context) {
-        String encodedString = Utilities.getPrefs(context).getString(
-                ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, VERSION + "");
-
-        String[] splitColorsString = encodedString.split(COLOR_SEPARATOR);
-        if (splitColorsString.length == DEFAULT_VALUES.length &&
-                Integer.parseInt(splitColorsString[VERSION_INDEX]) == VERSION) {
-            // Parse and apply the saved values.
-            for (int i = 0; i < mColors.length; i++) {
-                mColors[i] = Integer.parseInt(splitColorsString[i]);
-            }
-        } else {
-            // Leave the values as default values as the saved values may not be compatible.
-            ExtractionUtils.startColorExtractionService(context);
-        }
-    }
-
-    /** @param index must be one of the index values defined at the top of this class. */
-    public int getColor(int index) {
-        return mColors[index];
-    }
-
-    /**
-     * The hotseat's color is defined as follows:
-     * - 12% black for super light wallpaper
-     * - 18% white for super dark
-     * - 25% white otherwise
-     */
-    public void updateHotseatPalette(Palette hotseatPalette) {
-        int hotseatColor;
-        if (hotseatPalette != null && ExtractionUtils.isSuperLight(hotseatPalette)) {
-            hotseatColor = ColorUtils.setAlphaComponent(Color.BLACK, (int) (0.12f * 255));
-        } else if (hotseatPalette != null && ExtractionUtils.isSuperDark(hotseatPalette)) {
-            hotseatColor = ColorUtils.setAlphaComponent(Color.WHITE, (int) (0.18f * 255));
-        } else {
-            hotseatColor = DEFAULT_VALUES[HOTSEAT_INDEX];
-        }
-        setColorAtIndex(HOTSEAT_INDEX, hotseatColor);
-    }
-
-    public void updateStatusBarPalette(Palette statusBarPalette) {
-        setColorAtIndex(STATUS_BAR_INDEX, ExtractionUtils.isSuperLight(statusBarPalette) ?
-                DEFAULT_LIGHT : DEFAULT_DARK);
-    }
-
-    public void updateWallpaperThemePalette(@Nullable Palette wallpaperPalette) {
-        int defaultColor = DEFAULT_VALUES[WALLPAPER_VIBRANT_INDEX];
-        setColorAtIndex(WALLPAPER_VIBRANT_INDEX, wallpaperPalette == null
-                ? defaultColor : wallpaperPalette.getVibrantColor(defaultColor));
-    }
-
-    public void addOnChangeListener(OnChangeListener listener) {
-        mListeners.add(listener);
-    }
-
-    public void notifyChange() {
-        for (OnChangeListener listener : mListeners) {
-            listener.onExtractedColorsChanged();
-        }
-    }
-
-    /**
-     * Interface for listening for extracted color changes
-     */
-    public interface OnChangeListener {
-
-        void onExtractedColorsChanged();
-    }
-}
diff --git a/src/com/android/launcher3/dynamicui/ExtractionUtils.java b/src/com/android/launcher3/dynamicui/ExtractionUtils.java
deleted file mode 100644
index cc0e0be..0000000
--- a/src/com/android/launcher3/dynamicui/ExtractionUtils.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.dynamicui;
-
-import android.annotation.TargetApi;
-import android.app.WallpaperManager;
-import android.app.job.JobInfo;
-import android.app.job.JobScheduler;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.graphics.Color;
-import android.os.Build;
-import android.support.v4.graphics.ColorUtils;
-import android.support.v7.graphics.Palette;
-
-import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-
-import java.util.List;
-
-/**
- * Contains helper fields and methods related to extracting colors from the wallpaper.
- */
-public class ExtractionUtils {
-    public static final String EXTRACTED_COLORS_PREFERENCE_KEY = "pref_extractedColors";
-    public static final String WALLPAPER_ID_PREFERENCE_KEY = "pref_wallpaperId";
-
-    private static final float MIN_CONTRAST_RATIO = 2f;
-
-    /**
-     * Extract colors in the :wallpaper-chooser process, if the wallpaper id has changed.
-     * When the new colors are saved in the LauncherProvider,
-     * Launcher will be notified in Launcher#onSettingsChanged(String, String).
-     */
-    public static void startColorExtractionServiceIfNecessary(final Context context) {
-        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-            return;
-        }
-        // Run on a background thread, since the service is asynchronous anyway.
-        Utilities.THREAD_POOL_EXECUTOR.execute(new Runnable() {
-            @Override
-            public void run() {
-                if (hasWallpaperIdChanged(context)) {
-                    startColorExtractionService(context);
-                }
-            }
-        });
-    }
-
-    /** Starts the {@link ColorExtractionService} without checking the wallpaper id */
-    public static void startColorExtractionService(Context context) {
-        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-            return;
-        }
-        JobScheduler jobScheduler = (JobScheduler) context.getSystemService(
-                Context.JOB_SCHEDULER_SERVICE);
-        jobScheduler.schedule(new JobInfo.Builder(Utilities.COLOR_EXTRACTION_JOB_ID,
-                new ComponentName(context, ColorExtractionService.class))
-                .setMinimumLatency(0).build());
-    }
-
-    private static boolean hasWallpaperIdChanged(Context context) {
-        if (!Utilities.ATLEAST_NOUGAT) {
-            // TODO: update an id in sharedprefs in onWallpaperChanged broadcast, and read it here.
-            return false;
-        }
-        final SharedPreferences sharedPrefs = Utilities.getPrefs(context);
-        int wallpaperId = getWallpaperId(WallpaperManager.getInstance(context));
-        int savedWallpaperId = sharedPrefs.getInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, -1);
-        return wallpaperId != savedWallpaperId;
-    }
-
-    @TargetApi(Build.VERSION_CODES.N)
-    public static int getWallpaperId(WallpaperManager wallpaperManager) {
-        return Utilities.ATLEAST_NOUGAT ?
-                wallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM) : -1;
-    }
-
-    public static boolean isSuperLight(Palette p) {
-        return !isLegibleOnWallpaper(Color.WHITE, p.getSwatches());
-    }
-
-    public static boolean isSuperDark(Palette p) {
-        return !isLegibleOnWallpaper(Color.BLACK, p.getSwatches());
-    }
-
-    /**
-     * Given a color, returns true if that color is legible on
-     * the given wallpaper color swatches, else returns false.
-     */
-    private static boolean isLegibleOnWallpaper(int color, List<Palette.Swatch> wallpaperSwatches) {
-        int legiblePopulation = 0;
-        int illegiblePopulation = 0;
-        for (Palette.Swatch swatch : wallpaperSwatches) {
-            if (isLegible(color, swatch.getRgb())) {
-                legiblePopulation += swatch.getPopulation();
-            } else {
-                illegiblePopulation += swatch.getPopulation();
-            }
-        }
-        return legiblePopulation > illegiblePopulation;
-    }
-
-    /** @return Whether the foreground color is legible on the background color. */
-    private static boolean isLegible(int foreground, int background) {
-        background = ColorUtils.setAlphaComponent(background, 255);
-        return ColorUtils.calculateContrast(foreground, background) >= MIN_CONTRAST_RATIO;
-    }
-
-}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index b7f8f3e..0932b74 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -32,6 +32,7 @@
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
@@ -66,6 +67,7 @@
 import com.android.launcher3.dragndrop.DragController.DragListener;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.logging.LoggerUtils;
 import com.android.launcher3.pageindicators.PageIndicatorDots;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -368,11 +370,6 @@
         return false;
     }
 
-    @Override
-    public ExtendedEditText getActiveTextView() {
-        return isEditingName() ? mFolderName : null;
-    }
-
     public FolderIcon getFolderIcon() {
         return mFolderIcon;
     }
@@ -709,6 +706,7 @@
         mContent.setCurrentPage(0);
     }
 
+    @Override
     public boolean acceptDrop(DragObject d) {
         final ItemInfo item = d.dragInfo;
         final int itemType = item.itemType;
@@ -941,21 +939,6 @@
         }
     }
 
-    @Override
-    public float getIntrinsicIconScaleFactor() {
-        return 1f;
-    }
-
-    @Override
-    public boolean supportsAppInfoDropTarget() {
-        return true;
-    }
-
-    @Override
-    public boolean supportsDeleteDropTarget() {
-        return true;
-    }
-
     private void updateItemLocationsInDatabaseBatch() {
         ArrayList<View> list = getItemsInReadingOrder();
         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
@@ -1532,7 +1515,45 @@
     }
 
     @Override
-    public int getLogContainerType() {
-        return ContainerType.FOLDER;
+    public void logActionCommand(int command) {
+        mLauncher.getUserEventDispatcher().logActionCommand(
+                command, getFolderIcon(), ContainerType.FOLDER);
+    }
+
+    @Override
+    public void onBackPressed() {
+        if (isEditingName()) {
+            mFolderName.dispatchBackKey();
+        } else {
+            super.onBackPressed();
+        }
+    }
+
+    @Override
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            DragLayer dl = mLauncher.getDragLayer();
+
+            if (isEditingName()) {
+                if (!dl.isEventOverView(mFolderName, ev)) {
+                    mFolderName.dispatchBackKey();
+                    return true;
+                }
+                return false;
+            } else if (!dl.isEventOverView(this, ev)) {
+                if (mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) {
+                    // Do not close the container if in drag and drop.
+                    if (!dl.isEventOverView(mLauncher.getDropTargetBar(), ev)) {
+                        return true;
+                    }
+                } else {
+                    mLauncher.getUserEventDispatcher().logActionTapOutside(
+                            LoggerUtils.newContainerTarget(ContainerType.FOLDER));
+                    close(true);
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 }
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 10e91c0..355c231 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -18,10 +18,15 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
 import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
 import android.view.View;
 
 import com.android.launcher3.BubbleTextView;
@@ -30,6 +35,9 @@
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.util.UiThreadHelper;
+
+import java.nio.ByteBuffer;
 
 /**
  * A utility class to generate preview bitmap for dragging.
@@ -45,6 +53,7 @@
 
     protected final int blurSizeOutline;
 
+    private OutlineGeneratorCallback mOutlineGeneratorCallback;
     public Bitmap generatedDragOutline;
 
     public DragPreviewProvider(View view) {
@@ -106,7 +115,7 @@
      * Returns a new bitmap to show when the {@link #mView} is being dragged around.
      * Responsibility for the bitmap is transferred to the caller.
      */
-    public Bitmap createDragBitmap(Canvas canvas) {
+    public Bitmap createDragBitmap() {
         float scale = 1f;
         int width = mView.getWidth();
         int height = mView.getHeight();
@@ -124,7 +133,7 @@
 
         Bitmap b = Bitmap.createBitmap(width + blurSizeOutline, height + blurSizeOutline,
                 Bitmap.Config.ARGB_8888);
-        canvas.setBitmap(b);
+        Canvas canvas = new Canvas(b);
 
         canvas.save();
         canvas.scale(scale, scale);
@@ -136,43 +145,13 @@
         return b;
     }
 
-    public final void generateDragOutline(Canvas canvas) {
-        if (FeatureFlags.IS_DOGFOOD_BUILD && generatedDragOutline != null) {
+    public final void generateDragOutline(Bitmap preview) {
+        if (FeatureFlags.IS_DOGFOOD_BUILD && mOutlineGeneratorCallback != null) {
             throw new RuntimeException("Drag outline generated twice");
         }
 
-        generatedDragOutline = createDragOutline(canvas);
-    }
-
-    /**
-     * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
-     * Responsibility for the bitmap is transferred to the caller.
-     */
-    public Bitmap createDragOutline(Canvas canvas) {
-        float scale = 1f;
-        int width = mView.getWidth();
-        int height = mView.getHeight();
-
-        if (mView instanceof LauncherAppWidgetHostView) {
-            scale = ((LauncherAppWidgetHostView) mView).getScaleToFit();
-            width = (int) Math.floor(mView.getWidth() * scale);
-            height = (int) Math.floor(mView.getHeight() * scale);
-        }
-
-        Bitmap b = Bitmap.createBitmap(width + blurSizeOutline, height + blurSizeOutline,
-                Bitmap.Config.ALPHA_8);
-        canvas.setBitmap(b);
-
-        canvas.save();
-        canvas.scale(scale, scale);
-        drawDragView(canvas);
-        canvas.restore();
-
-        HolographicOutlineHelper.getInstance(mView.getContext())
-                .applyExpensiveOutlineWithBlur(b, canvas);
-
-        canvas.setBitmap(null);
-        return b;
+        mOutlineGeneratorCallback = new OutlineGeneratorCallback(preview);
+        new Handler(UiThreadHelper.getBackgroundLooper()).post(mOutlineGeneratorCallback);
     }
 
     protected static Rect getDrawableBounds(Drawable d) {
@@ -201,4 +180,89 @@
                 - previewPadding / 2);
         return scale;
     }
+
+    protected Bitmap convertPreviewToAlphaBitmap(Bitmap preview) {
+        return preview.copy(Bitmap.Config.ALPHA_8, true);
+    }
+
+    private class OutlineGeneratorCallback implements Runnable {
+
+        private final Bitmap mPreviewSnapshot;
+        private final Context mContext;
+
+        OutlineGeneratorCallback(Bitmap preview) {
+            mPreviewSnapshot = preview;
+            mContext = mView.getContext();
+        }
+
+        @Override
+        public void run() {
+            Bitmap preview = convertPreviewToAlphaBitmap(mPreviewSnapshot);
+
+            // We start by removing most of the alpha channel so as to ignore shadows, and
+            // other types of partial transparency when defining the shape of the object
+            byte[] pixels = new byte[preview.getWidth() * preview.getHeight()];
+            ByteBuffer buffer = ByteBuffer.wrap(pixels);
+            buffer.rewind();
+            preview.copyPixelsToBuffer(buffer);
+
+            for (int i = 0; i < pixels.length; i++) {
+                if ((pixels[i] & 0xFF) < 188) {
+                    pixels[i] = 0;
+                }
+            }
+
+            buffer.rewind();
+            preview.copyPixelsFromBuffer(buffer);
+
+            final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+            Canvas canvas = new Canvas();
+
+            // calculate the outer blur first
+            paint.setMaskFilter(new BlurMaskFilter(blurSizeOutline, BlurMaskFilter.Blur.OUTER));
+            int[] outerBlurOffset = new int[2];
+            Bitmap thickOuterBlur = preview.extractAlpha(paint, outerBlurOffset);
+
+            paint.setMaskFilter(new BlurMaskFilter(
+                    mContext.getResources().getDimension(R.dimen.blur_size_thin_outline),
+                    BlurMaskFilter.Blur.OUTER));
+            int[] brightOutlineOffset = new int[2];
+            Bitmap brightOutline = preview.extractAlpha(paint, brightOutlineOffset);
+
+            // calculate the inner blur
+            canvas.setBitmap(preview);
+            canvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
+            paint.setMaskFilter(new BlurMaskFilter(blurSizeOutline, BlurMaskFilter.Blur.NORMAL));
+            int[] thickInnerBlurOffset = new int[2];
+            Bitmap thickInnerBlur = preview.extractAlpha(paint, thickInnerBlurOffset);
+
+            // mask out the inner blur
+            paint.setMaskFilter(null);
+            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+            canvas.setBitmap(thickInnerBlur);
+            canvas.drawBitmap(preview, -thickInnerBlurOffset[0],
+                    -thickInnerBlurOffset[1], paint);
+            canvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(), paint);
+            canvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1], paint);
+
+            // draw the inner and outer blur
+            paint.setXfermode(null);
+            canvas.setBitmap(preview);
+            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+            canvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
+                    paint);
+            canvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1], paint);
+
+            // draw the bright outline
+            canvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1], paint);
+
+            // cleanup
+            canvas.setBitmap(null);
+            brightOutline.recycle();
+            thickOuterBlur.recycle();
+            thickInnerBlur.recycle();
+
+            generatedDragOutline = preview;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
index 45344c0..371479b 100644
--- a/src/com/android/launcher3/graphics/DrawableFactory.java
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -80,7 +80,7 @@
 
 
     protected Path getPreloadProgressPath(Context context) {
-        if (Utilities.isAtLeastO()) {
+        if (Utilities.ATLEAST_OREO) {
             try {
                 // Try to load the path from Mask Icon
                 Drawable icon = context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper);
diff --git a/src/com/android/launcher3/graphics/HolographicOutlineHelper.java b/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
index b221828..9e67f56 100644
--- a/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
+++ b/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
@@ -17,7 +17,6 @@
 package com.android.launcher3.graphics;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BlurMaskFilter;
 import android.graphics.Canvas;
@@ -31,9 +30,6 @@
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
-
-import java.nio.ByteBuffer;
 
 /**
  * Utility class to generate shadow and outline effect, which are used for click feedback
@@ -44,14 +40,9 @@
     private static HolographicOutlineHelper sInstance;
 
     private final Canvas mCanvas = new Canvas();
-    private final Paint mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
     private final Paint mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
     private final Paint mErasePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
 
-    private final BlurMaskFilter mMediumOuterBlurMaskFilter;
-    private final BlurMaskFilter mThinOuterBlurMaskFilter;
-    private final BlurMaskFilter mMediumInnerBlurMaskFilter;
-
     private final float mShadowBitmapShift;
     private final BlurMaskFilter mShadowBlurMaskFilter;
 
@@ -59,18 +50,8 @@
     private final SparseArray<Bitmap> mBitmapCache = new SparseArray<>(4);
 
     private HolographicOutlineHelper(Context context) {
-        Resources res = context.getResources();
-
-        float mediumBlur = res.getDimension(R.dimen.blur_size_medium_outline);
-        mMediumOuterBlurMaskFilter = new BlurMaskFilter(mediumBlur, BlurMaskFilter.Blur.OUTER);
-        mMediumInnerBlurMaskFilter = new BlurMaskFilter(mediumBlur, BlurMaskFilter.Blur.NORMAL);
-
-        mThinOuterBlurMaskFilter = new BlurMaskFilter(
-                res.getDimension(R.dimen.blur_size_thin_outline), BlurMaskFilter.Blur.OUTER);
-
-        mShadowBitmapShift = res.getDimension(R.dimen.blur_size_click_shadow);
+        mShadowBitmapShift = context.getResources().getDimension(R.dimen.blur_size_click_shadow);
         mShadowBlurMaskFilter = new BlurMaskFilter(mShadowBitmapShift, BlurMaskFilter.Blur.NORMAL);
-
         mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
     }
 
@@ -81,75 +62,6 @@
         return sInstance;
     }
 
-    /**
-     * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
-     * bitmap.
-     */
-    public void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas) {
-        if (FeatureFlags.IS_DOGFOOD_BUILD && srcDst.getConfig() != Bitmap.Config.ALPHA_8) {
-            throw new RuntimeException("Outline blue is only supported on alpha bitmaps");
-        }
-
-        // We start by removing most of the alpha channel so as to ignore shadows, and
-        // other types of partial transparency when defining the shape of the object
-        byte[] pixels = new byte[srcDst.getWidth() * srcDst.getHeight()];
-        ByteBuffer buffer = ByteBuffer.wrap(pixels);
-        buffer.rewind();
-        srcDst.copyPixelsToBuffer(buffer);
-
-        for (int i = 0; i < pixels.length; i++) {
-            if ((pixels[i] & 0xFF) < 188) {
-                pixels[i] = 0;
-            }
-        }
-
-        buffer.rewind();
-        srcDst.copyPixelsFromBuffer(buffer);
-
-        // calculate the outer blur first
-        mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter);
-        int[] outerBlurOffset = new int[2];
-        Bitmap thickOuterBlur = srcDst.extractAlpha(mBlurPaint, outerBlurOffset);
-
-        mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter);
-        int[] brightOutlineOffset = new int[2];
-        Bitmap brightOutline = srcDst.extractAlpha(mBlurPaint, brightOutlineOffset);
-
-        // calculate the inner blur
-        srcDstCanvas.setBitmap(srcDst);
-        srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
-        mBlurPaint.setMaskFilter(mMediumInnerBlurMaskFilter);
-        int[] thickInnerBlurOffset = new int[2];
-        Bitmap thickInnerBlur = srcDst.extractAlpha(mBlurPaint, thickInnerBlurOffset);
-
-        // mask out the inner blur
-        srcDstCanvas.setBitmap(thickInnerBlur);
-        srcDstCanvas.drawBitmap(srcDst, -thickInnerBlurOffset[0],
-                -thickInnerBlurOffset[1], mErasePaint);
-        srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(),
-                mErasePaint);
-        srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1],
-                mErasePaint);
-
-        // draw the inner and outer blur
-        srcDstCanvas.setBitmap(srcDst);
-        srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
-        srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
-                mDrawPaint);
-        srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
-                mDrawPaint);
-
-        // draw the bright outline
-        srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
-                mDrawPaint);
-
-        // cleanup
-        srcDstCanvas.setBitmap(null);
-        brightOutline.recycle();
-        thickOuterBlur.recycle();
-        thickInnerBlur.recycle();
-    }
-
     public Bitmap createMediumDropShadow(BubbleTextView view) {
         Drawable drawable = view.getIcon();
         if (drawable == null) {
diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java
index 8ed62bc..5ee6a30 100644
--- a/src/com/android/launcher3/graphics/IconNormalizer.java
+++ b/src/com/android/launcher3/graphics/IconNormalizer.java
@@ -28,12 +28,15 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.util.Log;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.nio.ByteBuffer;
@@ -231,12 +234,17 @@
      */
     public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds,
             @Nullable Path path, @Nullable boolean[] outMaskShape) {
-        if (Utilities.isAtLeastO() && d instanceof AdaptiveIconDrawable &&
-                mAdaptiveIconScale != SCALE_NOT_INITIALIZED) {
-            if (outBounds != null) {
-                outBounds.set(mAdaptiveIconBounds);
+        if (Utilities.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) {
+            if (mAdaptiveIconScale != SCALE_NOT_INITIALIZED) {
+                if (outBounds != null) {
+                    outBounds.set(mAdaptiveIconBounds);
+                }
+                return mAdaptiveIconScale;
             }
-            return mAdaptiveIconScale;
+            if (d instanceof FolderAdaptiveIcon) {
+                // Since we just want the scale, avoid heavy drawing operations
+                d = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null);
+            }
         }
         int width = d.getIntrinsicWidth();
         int height = d.getIntrinsicHeight();
@@ -347,7 +355,7 @@
         float areaScale = area / (width * height);
         // Use sqrt of the final ratio as the images is scaled across both width and height.
         float scale = areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
-        if (Utilities.isAtLeastO() && d instanceof AdaptiveIconDrawable &&
+        if (Utilities.ATLEAST_OREO && d instanceof AdaptiveIconDrawable &&
                 mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
             mAdaptiveIconScale = scale;
             mAdaptiveIconBounds.set(mBounds);
diff --git a/src/com/android/launcher3/graphics/IconShapeOverride.java b/src/com/android/launcher3/graphics/IconShapeOverride.java
index 654fa98..223243b 100644
--- a/src/com/android/launcher3/graphics/IconShapeOverride.java
+++ b/src/com/android/launcher3/graphics/IconShapeOverride.java
@@ -59,7 +59,7 @@
     private static final int RESTART_REQUEST_CODE = 42; // the answer to everything
 
     public static boolean isSupported(Context context) {
-        if (!Utilities.isAtLeastO()) {
+        if (!Utilities.ATLEAST_OREO) {
             return false;
         }
         // Only supported when developer settings is enabled
@@ -82,7 +82,7 @@
     }
 
     public static void apply(Context context) {
-        if (!Utilities.isAtLeastO()) {
+        if (!Utilities.ATLEAST_OREO) {
             return;
         }
         String path = getAppliedValue(context);
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 7c80c30..d471af6 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -16,10 +16,12 @@
 
 package com.android.launcher3.graphics;
 
+import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.Intent.ShortcutIconResource;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -70,11 +72,15 @@
         PackageManager packageManager = context.getPackageManager();
         // the resource
         try {
-            Resources resources = packageManager.getResourcesForApplication(iconRes.packageName);
+            Resources resources = packageManager.getResourcesForApplication(iconRes.resourceName);
             if (resources != null) {
                 final int id = resources.getIdentifier(iconRes.resourceName, null, null);
-                return createIconBitmap(resources.getDrawableForDensity(
-                        id, LauncherAppState.getIDP(context).fillResIconDpi), context);
+                // do not stamp old legacy shortcuts as the app may have already forgotten about it
+                return createBadgedIconBitmap(resources.getDrawableForDensity(
+                        id, LauncherAppState.getIDP(context).fillResIconDpi),
+                        Process.myUserHandle() /* only available on primary user */,
+                        context,
+                        0 /* do not apply legacy treatment */);
             }
         } catch (Exception e) {
             // Icon not found.
@@ -90,11 +96,12 @@
         if (iconBitmapSize == icon.getWidth() && iconBitmapSize == icon.getHeight()) {
             return icon;
         }
-        return createIconBitmap(new BitmapDrawable(context.getResources(), icon), context);
+        return createIconBitmap(new BitmapDrawable(context.getResources(), icon), context, 1f);
     }
 
     /**
-     * Returns a bitmap suitable for the all apps view. The icon is badged for {@param user}.
+     * Returns a bitmap suitable for displaying as an icon at various launcher UIs like all apps
+     * view or workspace. The icon is badged for {@param user}.
      * The bitmap is also visually normalized with other icons.
      */
     public static Bitmap createBadgedIconBitmap(
@@ -104,7 +111,7 @@
         float scale = 1f;
         if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) {
             normalizer = IconNormalizer.getInstance(context);
-            if (Utilities.isAtLeastO() && iconAppTargetSdk >= Build.VERSION_CODES.O) {
+            if (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) {
                 boolean[] outShape = new boolean[1];
                 AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
                         context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
@@ -123,28 +130,22 @@
             }
         }
         Bitmap bitmap = createIconBitmap(icon, context, scale);
-        if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.isAtLeastO() &&
+        if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.ATLEAST_OREO &&
                 icon instanceof AdaptiveIconDrawable) {
             bitmap = ShadowGenerator.getInstance(context).recreateIcon(bitmap);
         }
-        return badgeIconForUser(bitmap, user, context);
-    }
 
-    /**
-     * Badges the provided icon with the user badge if required.
-     */
-    public static Bitmap badgeIconForUser(Bitmap icon, UserHandle user, Context context) {
         if (user != null && !Process.myUserHandle().equals(user)) {
-            BitmapDrawable drawable = new FixedSizeBitmapDrawable(icon);
+            BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap);
             Drawable badged = context.getPackageManager().getUserBadgedIcon(
                     drawable, user);
             if (badged instanceof BitmapDrawable) {
                 return ((BitmapDrawable) badged).getBitmap();
             } else {
-                return createIconBitmap(badged, context);
+                return createIconBitmap(badged, context, 1f);
             }
         } else {
-            return icon;
+            return bitmap;
         }
     }
 
@@ -152,19 +153,20 @@
      * Creates a normalized bitmap suitable for the all apps view. The bitmap is also visually
      * normalized with other icons and has enough spacing to add shadow.
      */
-    public static Bitmap createScaledBitmapWithoutShadow(Drawable icon, Context context, int iconAppTargetSdk) {
+    public static Bitmap createScaledBitmapWithoutShadow(
+            Drawable icon, Context context, int iconAppTargetSdk) {
         RectF iconBounds = new RectF();
         IconNormalizer normalizer;
         float scale = 1f;
         if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) {
             normalizer = IconNormalizer.getInstance(context);
-            if (Utilities.isAtLeastO() && iconAppTargetSdk >= Build.VERSION_CODES.O) {
+            if (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) {
                 boolean[] outShape = new boolean[1];
                 AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
                         context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
                 dr.setBounds(0, 0, 1, 1);
                 scale = normalizer.getScale(icon, iconBounds, dr.getIconMask(), outShape);
-                if (Utilities.isAtLeastO() && FeatureFlags.LEGACY_ICON_TREATMENT &&
+                if (Utilities.ATLEAST_OREO && FeatureFlags.LEGACY_ICON_TREATMENT &&
                         !outShape[0]) {
                     Drawable wrappedIcon = wrapToAdaptiveIconDrawable(context, icon, scale);
                     if (wrappedIcon != icon) {
@@ -181,21 +183,6 @@
         return createIconBitmap(icon, context, scale);
     }
 
-    /**
-     * Adds a shadow to the provided icon. It assumes that the icon has already been scaled using
-     * {@link #createScaledBitmapWithoutShadow(Drawable, Context, int)}
-     */
-    public static Bitmap addShadowToIcon(Bitmap icon, Context context) {
-        return ShadowGenerator.getInstance(context).recreateIcon(icon);
-    }
-
-    /**
-     * Adds the {@param badge} on top of {@param srcTgt} using the badge dimensions.
-     */
-    public static Bitmap badgeWithBitmap(Bitmap srcTgt, Bitmap badge, Context context) {
-        return badgeWithDrawable(srcTgt, new FastBitmapDrawable(badge), context);
-    }
-
     public static Bitmap badgeWithDrawable(Bitmap srcTgt, Drawable badge, Context context) {
         int badgeSize = context.getResources().getDimensionPixelSize(R.dimen.profile_badge_size);
         synchronized (sCanvas) {
@@ -209,26 +196,9 @@
     }
 
     /**
-     * Returns a bitmap suitable for the all apps view.
-     */
-    public static Bitmap createIconBitmap(Drawable icon, Context context) {
-        float scale = 1f;
-        if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.isAtLeastO() &&
-                icon instanceof AdaptiveIconDrawable) {
-            scale = ShadowGenerator.getScaleForBounds(new RectF(0, 0, 0, 0));
-        }
-        Bitmap bitmap =  createIconBitmap(icon, context, scale);
-        if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.isAtLeastO() &&
-                icon instanceof AdaptiveIconDrawable) {
-            bitmap = ShadowGenerator.getInstance(context).recreateIcon(bitmap);
-        }
-        return bitmap;
-    }
-
-    /**
      * @param scale the scale to apply before drawing {@param icon} on the canvas
      */
-    public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
+    private static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
         synchronized (sCanvas) {
             final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize;
             int width = iconBitmapSize;
@@ -271,7 +241,7 @@
             final int top = (textureHeight-height) / 2;
 
             sOldBounds.set(icon.getBounds());
-            if (Utilities.isAtLeastO() && icon instanceof AdaptiveIconDrawable) {
+            if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
                 int offset = Math.max((int)(ShadowGenerator.BLUR_FACTOR * iconBitmapSize),
                         Math.min(left, top));
                 int size = Math.max(width, height);
@@ -295,8 +265,10 @@
      * shrink the legacy icon and set it as foreground. Use color drawable as background to
      * create AdaptiveIconDrawable.
      */
-    static Drawable wrapToAdaptiveIconDrawable(Context context, Drawable drawable, float scale) {
-        if (!(FeatureFlags.LEGACY_ICON_TREATMENT && Utilities.isAtLeastO())) {
+    @TargetApi(Build.VERSION_CODES.O)
+    private static Drawable wrapToAdaptiveIconDrawable(
+            Context context, Drawable drawable, float scale) {
+        if (!(FeatureFlags.LEGACY_ICON_TREATMENT && Utilities.ATLEAST_OREO)) {
             return drawable;
         }
 
@@ -307,7 +279,7 @@
                 FixedScaleDrawable fsd = ((FixedScaleDrawable) iconWrapper.getForeground());
                 fsd.setDrawable(drawable);
                 fsd.setScale(scale);
-                return (Drawable) iconWrapper;
+                return iconWrapper;
             }
         } catch (Exception e) {
             return drawable;
@@ -326,15 +298,9 @@
 
     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);
+        // 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 createShortcutIcon(shortcutInfo, context, true, Provider.of(fallbackIcon));
     }
 
     public static Bitmap createShortcutIcon(ShortcutInfoCompat shortcutInfo, Context context,
@@ -360,8 +326,9 @@
         if (!badged) {
             return unbadgedBitmap;
         }
-        unbadgedBitmap = LauncherIcons.addShadowToIcon(unbadgedBitmap, context);
-        return badgeWithBitmap(unbadgedBitmap, getShortcutInfoBadge(shortcutInfo, cache), context);
+        unbadgedBitmap = ShadowGenerator.getInstance(context).recreateIcon(unbadgedBitmap);
+        return badgeWithDrawable(unbadgedBitmap,
+                new FastBitmapDrawable(getShortcutInfoBadge(shortcutInfo, cache)), context);
     }
 
     public static Bitmap getShortcutInfoBadge(ShortcutInfoCompat shortcutInfo, IconCache cache) {
diff --git a/src/com/android/launcher3/graphics/ShadowDrawable.java b/src/com/android/launcher3/graphics/ShadowDrawable.java
index ffcedb2..b40bf78 100644
--- a/src/com/android/launcher3/graphics/ShadowDrawable.java
+++ b/src/com/android/launcher3/graphics/ShadowDrawable.java
@@ -146,7 +146,7 @@
             d.draw(canvas);
         }
 
-        if (Utilities.isAtLeastO()) {
+        if (Utilities.ATLEAST_OREO) {
             bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false);
         }
         mState.mLastDrawnBitmap = bitmap;
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index ebb69c4..81333b1 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -105,13 +105,13 @@
     private static String getItemStr(Target t) {
         String typeStr = getFieldName(t.itemType, ItemType.class);
         if (t.packageNameHash != 0) {
-            typeStr += ", packageHash=" + t.packageNameHash;
+            typeStr += ", packageHash=" + t.packageNameHash + ", predictiveRank=" + t.predictedRank;
         }
         if (t.componentHash != 0) {
-            typeStr += ", componentHash=" + t.componentHash;
+            typeStr += ", componentHash=" + t.componentHash + ", predictiveRank=" + t.predictedRank;
         }
         if (t.intentHash != 0) {
-            typeStr += ", intentHash=" + t.intentHash;
+            typeStr += ", intentHash=" + t.intentHash + ", predictiveRank=" + t.predictedRank;
         }
         return typeStr + ", grid(" + t.gridX + "," + t.gridY + "), span(" + t.spanX + "," + t.spanY
                 + "), pageIdx=" + t.pageIndex;
@@ -125,9 +125,11 @@
 
     public static Target newItemTarget(ItemInfo info) {
         Target t = newTarget(Target.Type.ITEM);
+
         switch (info.itemType) {
             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                 t.itemType = ItemType.APP_ICON;
+                t.predictedRank = -100; // Never assigned
                 break;
             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                 t.itemType = ItemType.SHORTCUT;
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index 8de0de0..d9b1a3f 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -726,7 +726,7 @@
                                 mContext).getLauncherAppWidgetInfo(widgetId);
                         Point spans = null;
                         if (pInfo != null) {
-                            spans = pInfo.getMinSpans(mIdp, mContext);
+                            spans = pInfo.getMinSpans();
                         }
                         if (spans != null) {
                             entry.minSpanX = spans.x > 0 ? spans.x : entry.spanX;
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index e1b208a..5386fb4 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -66,6 +66,7 @@
 import com.android.launcher3.util.MultiHashMap;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Provider;
+import com.android.launcher3.util.TraceHelper;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -85,7 +86,6 @@
  *   - deep shortcuts within apps
  */
 public class LoaderTask implements Runnable {
-    private static final boolean DEBUG_LOADERS = false;
     private static final String TAG = "LoaderTask";
 
     private final LauncherAppState mApp;
@@ -142,73 +142,64 @@
             }
         }
 
+        TraceHelper.beginSection(TAG);
         try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
-            long now = 0;
-            if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
+            TraceHelper.partitionSection(TAG, "step 1.1: loading workspace");
             loadWorkspace();
 
             verifyNotStopped();
-            if (DEBUG_LOADERS) Log.d(TAG, "step 1.2: bind workspace workspace");
+            TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace");
             mResults.bindWorkspace();
 
             // Take a break
-            if (DEBUG_LOADERS) {
-                Log.d(TAG, "step 1 completed, wait for idle");
-                now = SystemClock.uptimeMillis();
-            }
+            TraceHelper.partitionSection(TAG, "step 1 completed, wait for idle");
             waitForIdle();
-            if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms");
             verifyNotStopped();
 
             // second step
-            if (DEBUG_LOADERS) Log.d(TAG, "step 2.1: loading all apps");
+            TraceHelper.partitionSection(TAG, "step 2.1: loading all apps");
             loadAllApps();
 
-            if (DEBUG_LOADERS) Log.d(TAG, "step 2.2: Binding all apps");
+            TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps");
             verifyNotStopped();
             mResults.bindAllApps();
 
             verifyNotStopped();
-            if (DEBUG_LOADERS) Log.d(TAG, "step 2.3: Update icon cache");
+            TraceHelper.partitionSection(TAG, "step 2.3: Update icon cache");
             updateIconCache();
 
             // Take a break
-            if (DEBUG_LOADERS) {
-                Log.d(TAG, "step 2 completed, wait for idle");
-                now = SystemClock.uptimeMillis();
-            }
+            TraceHelper.partitionSection(TAG, "step 2 completed, wait for idle");
             waitForIdle();
-            if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms");
             verifyNotStopped();
 
             // third step
-            if (DEBUG_LOADERS) Log.d(TAG, "step 3.1: loading deep shortcuts");
+            TraceHelper.partitionSection(TAG, "step 3.1: loading deep shortcuts");
             loadDeepShortcuts();
 
             verifyNotStopped();
-            if (DEBUG_LOADERS) Log.d(TAG, "step 3.2: bind deep shortcuts");
+            TraceHelper.partitionSection(TAG, "step 3.2: bind deep shortcuts");
             mResults.bindDeepShortcuts();
 
             // Take a break
-            if (DEBUG_LOADERS) Log.d(TAG, "step 3 completed, wait for idle");
+            TraceHelper.partitionSection(TAG, "step 3 completed, wait for idle");
             waitForIdle();
             verifyNotStopped();
 
             // fourth step
-            if (DEBUG_LOADERS) Log.d(TAG, "step 4.1: loading widgets");
+            TraceHelper.partitionSection(TAG, "step 4.1: loading widgets");
             mBgDataModel.widgetsModel.update(mApp, null);
 
             verifyNotStopped();
-            if (DEBUG_LOADERS) Log.d(TAG, "step 4.2: Binding widgets");
+            TraceHelper.partitionSection(TAG, "step 4.2: Binding widgets");
             mResults.bindWidgets();
 
             transaction.commit();
         } catch (CancellationException e) {
             // Loader stopped, ignore
-            if (DEBUG_LOADERS) {
-                Log.d(TAG, "Loader cancelled", e);
-            }
+            TraceHelper.partitionSection(TAG, "Cancelled");
         }
+        TraceHelper.endSection(TAG);
     }
 
     public synchronized void stopLocked() {
@@ -217,10 +208,6 @@
     }
 
     private void loadWorkspace() {
-        if (LauncherAppState.PROFILE_STARTUP) {
-            Trace.beginSection("Loading Workspace");
-        }
-
         final Context context = mApp.getContext();
         final ContentResolver contentResolver = context.getContentResolver();
         final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
@@ -766,9 +753,6 @@
                 LauncherModel.updateWorkspaceScreenOrder(context, mBgDataModel.workspaceScreens);
             }
         }
-        if (LauncherAppState.PROFILE_STARTUP) {
-            Trace.endSection();
-        }
     }
 
     private void updateIconCache() {
@@ -793,21 +777,13 @@
     }
 
     private void loadAllApps() {
-        final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-
         final List<UserHandle> profiles = mUserManager.getUserProfiles();
 
         // Clear the list of apps
         mBgAllAppsList.clear();
         for (UserHandle user : profiles) {
             // Query for the set of apps
-            final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
             final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
-            if (DEBUG_LOADERS) {
-                Log.d(TAG, "getActivityList took "
-                        + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);
-                Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);
-            }
             // Fail if we don't have any apps
             // TODO: Fix this. Only fail for the current user.
             if (apps == null || apps.isEmpty()) {
@@ -834,10 +810,6 @@
         }
 
         mBgAllAppsList.added = new ArrayList<>();
-        if (DEBUG_LOADERS) {
-            Log.d(TAG, "All apps loaded in in "
-                    + (SystemClock.uptimeMillis() - loadTime) + "ms");
-        }
     }
 
     private void loadDeepShortcuts() {
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 13962a2..78ecbc6 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -101,7 +101,7 @@
                     appsList.addPackage(context, packages[i], mUser);
 
                     // Automatically add homescreen icon for work profile apps for below O device.
-                    if (!Utilities.isAtLeastO() && !Process.myUserHandle().equals(mUser)) {
+                    if (!Utilities.ATLEAST_OREO && !Process.myUserHandle().equals(mUser)) {
                         SessionCommitReceiver.queueAppIconAddition(context, packages[i], mUser);
                     }
                 }
@@ -178,6 +178,9 @@
         if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
             final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>();
             final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<>();
+
+            // For system apps, package manager send OP_UPDATE when an app is enabled.
+            final boolean isNewApkAvailable = mOp == OP_ADD || mOp == OP_UPDATE;
             synchronized (dataModel) {
                 for (ItemInfo info : dataModel.itemsIdMap) {
                     if (info instanceof ShortcutInfo && mUser.equals(info.user)) {
@@ -206,9 +209,7 @@
                                 }
                             }
 
-                            // For system apps, package manager send OP_UPDATE when an
-                            // app is enabled.
-                            if (si.isPromise() && (mOp == OP_ADD || mOp == OP_UPDATE)) {
+                            if (si.isPromise() && isNewApkAvailable) {
                                 if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINSTALL_ICON)) {
                                     // Auto install icon
                                     LauncherAppsCompat launcherApps
@@ -231,10 +232,13 @@
                                             continue;
                                         }
                                     }
+                                } else {
+                                    si.status = ShortcutInfo.DEFAULT;
+                                    infoUpdated = true;
                                 }
                             }
 
-                            if ((mOp == OP_ADD || mOp == OP_UPDATE) &&
+                            if (isNewApkAvailable &&
                                     si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
                                 iconCache.getTitleAndIcon(si, si.usingLowResIcon);
                                 infoUpdated = true;
@@ -253,7 +257,7 @@
                         if (infoUpdated) {
                             getModelWriter().updateItemInDatabase(si);
                         }
-                    } else if (info instanceof LauncherAppWidgetInfo && mOp == OP_ADD) {
+                    } else if (info instanceof LauncherAppWidgetInfo && isNewApkAvailable) {
                         LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
                         if (mUser.equals(widgetInfo.user)
                                 && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
@@ -342,8 +346,9 @@
                     callbacks.notifyWidgetProvidersChanged();
                 }
             });
-        } else if (Utilities.isAtLeastO() && mOp == OP_ADD) {
-            // Load widgets for the new package.
+        } else if (Utilities.ATLEAST_OREO && mOp == OP_ADD) {
+            // Load widgets for the new package. Changes due to app updates are handled through
+            // AppWidgetHost events, this is just to initialize the long-press options.
             for (int i = 0; i < N; i++) {
                 dataModel.widgetsModel.update(app, new PackageUserKey(packages[i], mUser));
             }
diff --git a/src/com/android/launcher3/notification/NotificationGroup.java b/src/com/android/launcher3/notification/NotificationGroup.java
new file mode 100644
index 0000000..bce2117
--- /dev/null
+++ b/src/com/android/launcher3/notification/NotificationGroup.java
@@ -0,0 +1,52 @@
+/*
+ * 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 java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Contains data related to a group of notifications, like the group summary key and the child keys.
+ */
+public class NotificationGroup {
+    private String mGroupSummaryKey;
+    private Set<String> mChildKeys;
+
+    public NotificationGroup() {
+        mChildKeys = new HashSet<>();
+    }
+
+    public void setGroupSummaryKey(String groupSummaryKey) {
+        mGroupSummaryKey = groupSummaryKey;
+    }
+
+    public String getGroupSummaryKey() {
+        return mGroupSummaryKey;
+    }
+
+    public void addChildKey(String childKey) {
+        mChildKeys.add(childKey);
+    }
+
+    public void removeChildKey(String childKey) {
+        mChildKeys.remove(childKey);
+    }
+
+    public boolean isEmpty() {
+        return mChildKeys.isEmpty();
+    }
+}
diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java
index 1b7c87b..6e36f4f 100644
--- a/src/com/android/launcher3/notification/NotificationInfo.java
+++ b/src/com/android/launcher3/notification/NotificationInfo.java
@@ -94,6 +94,9 @@
 
     @Override
     public void onClick(View view) {
+        if (intent == null) {
+            return;
+        }
         final Launcher launcher = Launcher.getLauncher(view.getContext());
         Bundle activityOptions = ActivityOptions.makeClipRevealAnimation(
                 view, 0, 0, view.getWidth(), view.getHeight()).toBundle();
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 9126626..7b70df7 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -38,7 +38,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
@@ -66,6 +68,8 @@
     private final Handler mWorkerHandler;
     private final Handler mUiHandler;
     private final Ranking mTempRanking = new Ranking();
+    /** Maps groupKey's to the corresponding group of notifications. */
+    private final Map<String, NotificationGroup> mNotificationGroupMap = new HashMap<>();
 
     private SettingsObserver mNotificationBadgingObserver;
 
@@ -227,6 +231,15 @@
                         NotificationKeyData.fromNotification(sbn));
         mWorkerHandler.obtainMessage(MSG_NOTIFICATION_REMOVED, packageUserKeyAndNotificationKey)
                 .sendToTarget();
+
+        NotificationGroup notificationGroup = mNotificationGroupMap.get(sbn.getGroupKey());
+        if (notificationGroup != null) {
+            notificationGroup.removeChildKey(sbn.getKey());
+            if (notificationGroup.isEmpty()) {
+                cancelNotification(notificationGroup.getGroupSummaryKey());
+                mNotificationGroupMap.remove(sbn.getGroupKey());
+            }
+        }
     }
 
     /** This makes a potentially expensive binder call and should be run on a background thread. */
@@ -264,18 +277,34 @@
     }
 
     private boolean shouldBeFilteredOut(StatusBarNotification sbn) {
+        Notification notification = sbn.getNotification();
+
+        boolean isGroupHeader = (notification.flags & Notification.FLAG_GROUP_SUMMARY) != 0;
+        if (sbn.isGroup()) {
+            // Maintain group info so we can cancel the summary when the last child is canceled.
+            NotificationGroup notificationGroup = mNotificationGroupMap.get(sbn.getGroupKey());
+            if (notificationGroup == null) {
+                notificationGroup = new NotificationGroup();
+                mNotificationGroupMap.put(sbn.getGroupKey(), notificationGroup);
+            }
+            if (isGroupHeader) {
+                notificationGroup.setGroupSummaryKey(sbn.getKey());
+            } else {
+                notificationGroup.addChildKey(sbn.getKey());
+            }
+        }
+
         getCurrentRanking().getRanking(sbn.getKey(), mTempRanking);
         if (!mTempRanking.canShowBadge()) {
             return true;
         }
-        Notification notification = sbn.getNotification();
         if (mTempRanking.getChannel().getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
             // Special filtering for the default, legacy "Miscellaneous" channel.
             if ((notification.flags & Notification.FLAG_ONGOING_EVENT) != 0) {
                 return true;
             }
         }
-        boolean isGroupHeader = (notification.flags & Notification.FLAG_GROUP_SUMMARY) != 0;
+
         CharSequence title = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
         CharSequence text = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
         boolean missingTitleAndText = TextUtils.isEmpty(title) && TextUtils.isEmpty(text);
diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 47c2ffb..d6ef5b4 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -20,8 +20,6 @@
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 
-import com.android.launcher3.dynamicui.ExtractedColors;
-
 /**
  * Base class for a page indicator.
  */
@@ -74,8 +72,6 @@
 
     public void setShouldAutoHide(boolean shouldAutoHide) {}
 
-    public void updateColor(ExtractedColors extractedColors) {}
-
     @Override
     protected boolean verifyDrawable(Drawable who) {
         return super.verifyDrawable(who) || who == getCaretDrawable();
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
index 682d5a9..911be93 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
@@ -48,7 +48,6 @@
         setCaretDrawable(caretDrawable);
 
         Launcher l = Launcher.getLauncher(context);
-        setOnTouchListener(l.getHapticFeedbackTouchListener());
         setOnClickListener(l);
         setOnFocusChangeListener(l.mFocusHandler);
     }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
index 29834d7..5eedd92 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
@@ -11,9 +11,7 @@
 import android.graphics.Paint;
 import android.os.Handler;
 import android.os.Looper;
-import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.Property;
 import android.view.ViewConfiguration;
 import android.widget.ImageView;
@@ -21,8 +19,6 @@
 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;
 
 /**
@@ -31,9 +27,6 @@
  * The fraction is 1 / number of pages and the position is based on the progress of the page scroll.
  */
 public class PageIndicatorLineCaret extends PageIndicator {
-    private static final String TAG = "PageIndicatorLine";
-
-    private static final int[] sTempCoords = new int[2];
 
     private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
     private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
@@ -141,7 +134,6 @@
         super.onFinishInflate();
         mAllAppsHandle = (ImageView) findViewById(R.id.all_apps_handle);
         mAllAppsHandle.setImageDrawable(getCaretDrawable());
-        mAllAppsHandle.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
         mAllAppsHandle.setOnClickListener(mLauncher);
         mAllAppsHandle.setOnFocusChangeListener(mLauncher.mFocusHandler);
         mLauncher.setAllAppsButton(mAllAppsHandle);
@@ -219,32 +211,6 @@
         }
     }
 
-    /**
-     * The line's color will be:
-     * - mostly opaque white if the hotseat is white (ignoring alpha)
-     * - 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) {
-            color = ColorUtils.setAlphaComponent(color, 255);
-            if (color == Color.BLACK) {
-                mActiveAlpha = BLACK_ALPHA;
-            } else if (color == Color.WHITE) {
-                mActiveAlpha = WHITE_ALPHA;
-            } else {
-                Log.e(TAG, "Setting workspace page indicators to an unsupported color: #"
-                        + Integer.toHexString(color));
-            }
-            mLinePaint.setColor(color);
-            mLinePaint.setAlpha(originalLineAlpha);
-        }
-    }
-
     private void animateLineToAlpha(int alpha) {
         if (alpha == mToAlpha) {
             // Ignore the new animation if it is going to the same alpha as the current animation.
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 8441598..5c49b4b 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -16,6 +16,11 @@
 
 package com.android.launcher3.popup;
 
+import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -66,6 +71,7 @@
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.graphics.IconPalette;
 import com.android.launcher3.graphics.TriangleShape;
+import com.android.launcher3.logging.LoggerUtils;
 import com.android.launcher3.notification.NotificationItemView;
 import com.android.launcher3.notification.NotificationKeyData;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
@@ -81,11 +87,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-
 /**
  * A container for shortcuts to deep links within apps.
  */
@@ -593,11 +594,6 @@
         return arrowView;
     }
 
-    @Override
-    public View getExtendedTouchView() {
-        return mOriginalIcon;
-    }
-
     /**
      * Determines when the deferred drag should be started.
      *
@@ -797,21 +793,6 @@
     }
 
     @Override
-    public boolean supportsAppInfoDropTarget() {
-        return true;
-    }
-
-    @Override
-    public boolean supportsDeleteDropTarget() {
-        return false;
-    }
-
-    @Override
-    public float getIntrinsicIconScaleFactor() {
-        return 1f;
-    }
-
-    @Override
     public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete,
             boolean success) {
         if (!success) {
@@ -950,7 +931,25 @@
     }
 
     @Override
-    public int getLogContainerType() {
-        return ContainerType.DEEPSHORTCUTS;
+    public void logActionCommand(int command) {
+        mLauncher.getUserEventDispatcher().logActionCommand(
+                command, mOriginalIcon, ContainerType.DEEPSHORTCUTS);
+    }
+
+    @Override
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            DragLayer dl = mLauncher.getDragLayer();
+            if (!dl.isEventOverView(this, ev)) {
+                mLauncher.getUserEventDispatcher().logActionTapOutside(
+                        LoggerUtils.newContainerTarget(ContainerType.DEEPSHORTCUTS));
+                close(true);
+
+                // We let touches on the original icon go through so that users can launch
+                // the app with one tap if they don't find a shortcut they want.
+                return mOriginalIcon == null || !dl.isEventOverView(mOriginalIcon, ev);
+            }
+        }
+        return false;
     }
 }
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index d26f9f6..65acaa9 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -36,6 +36,7 @@
 
 import com.android.launcher3.AppWidgetResizeFrame;
 import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -79,10 +80,15 @@
         private AppWidgetProviderInfo mWidgetInfo;
         private QsbWidgetHostView mQsb;
 
+        // We need to store the orientation here, due to a bug (b/64916689) that results in widgets
+        // being inflated in the wrong orientation.
+        private int mOrientation;
+
         @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             mQsbWidgetHost = new QsbWidgetHost(getActivity());
+            mOrientation = getContext().getResources().getConfiguration().orientation;
         }
 
         private FrameLayout mWrapper;
@@ -193,7 +199,7 @@
         @Override
         public void onResume() {
             super.onResume();
-            if (mQsb != null && mQsb.isReinflateRequired()) {
+            if (mQsb != null && mQsb.isReinflateRequired(mOrientation)) {
                 rebindFragment();
             }
         }
diff --git a/src/com/android/launcher3/qsb/QsbWidgetHostView.java b/src/com/android/launcher3/qsb/QsbWidgetHostView.java
index 8b6fa16..a8a41f6 100644
--- a/src/com/android/launcher3/qsb/QsbWidgetHostView.java
+++ b/src/com/android/launcher3/qsb/QsbWidgetHostView.java
@@ -47,9 +47,9 @@
     }
 
 
-    public boolean isReinflateRequired() {
+    public boolean isReinflateRequired(int orientation) {
         // Re-inflate is required if the orientation has changed since last inflation.
-        return mPreviousOrientation != getResources().getConfiguration().orientation;
+        return mPreviousOrientation != orientation;
     }
 
 
diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
index e9d2b50..cfb9258 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
@@ -26,7 +26,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.graphics.DragPreviewProvider;
-import com.android.launcher3.graphics.HolographicOutlineHelper;
 
 /**
  * Extension of {@link DragPreviewProvider} which generates bitmaps scaled to the default icon size.
@@ -40,35 +39,17 @@
         mPositionShift = shift;
     }
 
-    @Override
-    public Bitmap createDragOutline(Canvas canvas) {
-        Bitmap b = drawScaledPreview(canvas, Bitmap.Config.ALPHA_8);
-
-        HolographicOutlineHelper.getInstance(mView.getContext())
-                .applyExpensiveOutlineWithBlur(b, canvas);
-        canvas.setBitmap(null);
-        return b;
-    }
-
-    @Override
-    public Bitmap createDragBitmap(Canvas canvas) {
-        Bitmap b = drawScaledPreview(canvas, Bitmap.Config.ARGB_8888);
-        canvas.setBitmap(null);
-        return b;
-    }
-
-    private Bitmap drawScaledPreview(Canvas canvas, Bitmap.Config config) {
+    public Bitmap createDragBitmap() {
         Drawable d = mView.getBackground();
         Rect bounds = getDrawableBounds(d);
 
         int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx;
-
         final Bitmap b = Bitmap.createBitmap(
                 size + blurSizeOutline,
                 size + blurSizeOutline,
-                config);
+                Bitmap.Config.ARGB_8888);
 
-        canvas.setBitmap(b);
+        Canvas canvas = new Canvas(b);
         canvas.save(Canvas.MATRIX_SAVE_FLAG);
         canvas.translate(blurSizeOutline / 2, blurSizeOutline / 2);
         canvas.scale(((float) size) / bounds.width(), ((float) size) / bounds.height(), 0, 0);
diff --git a/src/com/android/launcher3/testing/DummyWidget.java b/src/com/android/launcher3/testing/DummyWidget.java
deleted file mode 100644
index df887ac..0000000
--- a/src/com/android/launcher3/testing/DummyWidget.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.android.launcher3.testing;
-
-import android.appwidget.AppWidgetProviderInfo;
-
-import com.android.launcher3.CustomAppWidget;
-import com.android.launcher3.R;
-
-public class DummyWidget implements CustomAppWidget {
-    @Override
-    public String getLabel() {
-        return "Dumb Launcher Widget";
-    }
-
-    @Override
-    public int getPreviewImage() {
-        return 0;
-    }
-
-    @Override
-    public int getIcon() {
-        return 0;
-    }
-
-    @Override
-    public int getWidgetLayout() {
-        return R.layout.zzz_dummy_widget;
-    }
-
-    @Override
-    public int getSpanX() {
-        return 2;
-    }
-
-    @Override
-    public int getSpanY() {
-        return 2;
-    }
-
-    @Override
-    public int getMinSpanX() {
-        return 1;
-    }
-
-    @Override
-    public int getMinSpanY() {
-        return 1;
-    }
-
-    @Override
-    public int getResizeMode() {
-        return AppWidgetProviderInfo.RESIZE_BOTH;
-    }
-}
diff --git a/src/com/android/launcher3/testing/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java
index 355963b..a1a4d75 100644
--- a/src/com/android/launcher3/testing/LauncherExtension.java
+++ b/src/com/android/launcher3/testing/LauncherExtension.java
@@ -7,13 +7,10 @@
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherCallbacks;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.ComponentKeyMapper;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * This class represents a very trivial LauncherExtension. It primarily serves as a simple
@@ -150,12 +147,6 @@
         }
 
         @Override
-        public List<ComponentKeyMapper<AppInfo>> getPredictedApps() {
-            // To debug app predictions, enable AlphabeticalAppsList#DEBUG_PREDICTIONS
-            return new ArrayList<>();
-        }
-
-        @Override
         public void onAttachedToWindow() {
         }
 
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index 091dd84..009aee7 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -67,7 +67,7 @@
             return;
         }
 
-        if (Utilities.isAtLeastO() && !SessionCommitReceiver.isEnabled(context)) {
+        if (Utilities.ATLEAST_OREO && !SessionCommitReceiver.isEnabled(context)) {
             // Just mark the folder id preference to avoid new folder creation later.
             ufi.prefs.edit().putLong(ufi.folderIdKey, ItemInfo.NO_ID).apply();
             return;
diff --git a/src/com/android/launcher3/util/SystemUiController.java b/src/com/android/launcher3/util/SystemUiController.java
index d7a2625..edbf05a 100644
--- a/src/com/android/launcher3/util/SystemUiController.java
+++ b/src/com/android/launcher3/util/SystemUiController.java
@@ -59,7 +59,7 @@
         // Apply the state flags in priority order
         int newFlags = oldFlags;
         for (int stateFlag : mStates) {
-            if (Utilities.isAtLeastO()) {
+            if (Utilities.ATLEAST_OREO) {
                 if ((stateFlag & FLAG_LIGHT_NAV) != 0) {
                     newFlags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
                 } else if ((stateFlag & FLAG_DARK_NAV) != 0) {
diff --git a/src/com/android/launcher3/util/TestingUtils.java b/src/com/android/launcher3/util/TestingUtils.java
index a7cc42b..d927dc3 100644
--- a/src/com/android/launcher3/util/TestingUtils.java
+++ b/src/com/android/launcher3/util/TestingUtils.java
@@ -3,18 +3,14 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.widget.FrameLayout;
 
-import com.android.launcher3.CustomAppWidget;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 
-import java.util.HashMap;
-
 public class TestingUtils {
 
     public static final String MEMORY_TRACKER = "com.android.launcher3.testing.MemoryTracker";
@@ -23,9 +19,6 @@
     public static final boolean MEMORY_DUMP_ENABLED = false;
     public static final String SHOW_WEIGHT_WATCHER = "debug.show_mem";
 
-    public static final boolean ENABLE_CUSTOM_WIDGET_TEST = false;
-    public static final String DUMMY_WIDGET = "com.android.launcher3.testing.DummyWidget";
-
     public static void startTrackingMemory(Context context) {
         if (MEMORY_DUMP_ENABLED) {
             context.startService(new Intent()
@@ -55,16 +48,4 @@
             launcher.mWeightWatcher = watcher;
         }
     }
-
-    public static void addDummyWidget(HashMap<String, CustomAppWidget> set) {
-        if (ENABLE_CUSTOM_WIDGET_TEST) {
-            try {
-                Class<?> clazz = Class.forName(DUMMY_WIDGET);
-                CustomAppWidget widget = (CustomAppWidget) clazz.newInstance();
-                set.put(widget.getClass().getName(), widget);
-            } catch (Exception e) {
-                Log.e("TestingUtils", "Error adding dummy widget", e);
-            }
-        }
-    }
 }
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
new file mode 100644
index 0000000..5b66fcd
--- /dev/null
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -0,0 +1,90 @@
+/*
+ * 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.util;
+
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.MutableLong;
+
+import com.android.launcher3.config.FeatureFlags;
+
+/**
+ * A wrapper around {@link Trace} to allow easier proguarding for production builds.
+ *
+ * To enable any tracing log, execute the following command:
+ * $ adb shell setprop log.tag.TAGNAME VERBOSE
+ */
+public class TraceHelper {
+
+    private static final boolean ENABLED = FeatureFlags.IS_DOGFOOD_BUILD;
+
+    private static final boolean SYSTEM_TRACE = true;
+    private static final ArrayMap<String, MutableLong> sUpTimes =
+            ENABLED ? new ArrayMap<String, MutableLong>() : null;
+
+    public static void beginSection(String sectionName) {
+        if (ENABLED) {
+            MutableLong time = sUpTimes.get(sectionName);
+            if (time == null) {
+                time = new MutableLong(Log.isLoggable(sectionName, Log.VERBOSE) ? 0 : -1);
+                sUpTimes.put(sectionName, time);
+            }
+            if (time.value >= 0) {
+                if (SYSTEM_TRACE) {
+                    Trace.beginSection(sectionName);
+                }
+                time.value = SystemClock.uptimeMillis();
+            }
+        }
+    }
+
+    public static void partitionSection(String sectionName, String partition) {
+        if (ENABLED) {
+            MutableLong time = sUpTimes.get(sectionName);
+            if (time.value >= 0) {
+
+                if (SYSTEM_TRACE) {
+                    Trace.endSection();
+                    Trace.beginSection(sectionName);
+                }
+
+                long now = SystemClock.uptimeMillis();
+                Log.d(sectionName, partition + " : " + (now - time.value));
+                time.value = now;
+            }
+        }
+    }
+
+    public static void endSection(String sectionName) {
+        if (ENABLED) {
+            endSection(sectionName, "End");
+        }
+    }
+
+    public static void endSection(String sectionName, String msg) {
+        if (ENABLED) {
+            MutableLong time = sUpTimes.get(sectionName);
+            if (time.value >= 0) {
+                if (SYSTEM_TRACE) {
+                    Trace.endSection();
+                }
+                Log.d(sectionName, msg + " : " + (SystemClock.uptimeMillis() - time.value));
+            }
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java
new file mode 100644
index 0000000..27140a1
--- /dev/null
+++ b/src/com/android/launcher3/util/UiThreadHelper.java
@@ -0,0 +1,76 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.view.inputmethod.InputMethodManager;
+
+/**
+ * Utility class for offloading some class from UI thread
+ */
+public class UiThreadHelper {
+
+    private static HandlerThread sHandlerThread;
+    private static Handler sHandler;
+
+    private static final int MSG_HIDE_KEYBOARD = 1;
+
+    public static Looper getBackgroundLooper() {
+        if (sHandlerThread == null) {
+            sHandlerThread =
+                    new HandlerThread("UiThreadHelper", Process.THREAD_PRIORITY_FOREGROUND);
+            sHandlerThread.start();
+        }
+        return sHandlerThread.getLooper();
+    }
+
+    private static Handler getHandler(Context context) {
+        if (sHandler == null) {
+            sHandler = new Handler(getBackgroundLooper(),
+                    new UiCallbacks(context.getApplicationContext()));
+        }
+        return sHandler;
+    }
+
+    public static void hideKeyboardAsync(Context context, IBinder token) {
+        Message.obtain(getHandler(context), MSG_HIDE_KEYBOARD, token).sendToTarget();
+    }
+
+    private static class UiCallbacks implements Handler.Callback {
+
+        private final InputMethodManager mIMM;
+
+        UiCallbacks(Context context) {
+            mIMM = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+        }
+
+        @Override
+        public boolean handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_HIDE_KEYBOARD:
+                    mIMM.hideSoftInputFromWindow((IBinder) message.obj, 0);
+                    return true;
+            }
+            return false;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
index f99efce..ec494f1 100644
--- a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
+++ b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
@@ -1,9 +1,15 @@
 package com.android.launcher3.util;
 
 import android.app.WallpaperManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Message;
+import android.os.SystemClock;
 import android.util.Log;
-import android.view.Choreographer;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
@@ -13,60 +19,30 @@
 /**
  * Utility class to handle wallpaper scrolling along with workspace.
  */
-public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback {
+public class WallpaperOffsetInterpolator extends BroadcastReceiver {
+
+    private static final int[] sTempInt = new int[2];
     private static final String TAG = "WPOffsetInterpolator";
     private static final int ANIMATION_DURATION = 250;
 
     // Don't use all the wallpaper for parallax until you have at least this many pages
     private static final int MIN_PARALLAX_PAGE_SPAN = 4;
 
-    private final Choreographer mChoreographer;
-    private final Interpolator mInterpolator;
-    private final WallpaperManager mWallpaperManager;
     private final Workspace mWorkspace;
     private final boolean mIsRtl;
+    private final Handler mHandler;
 
+    private boolean mRegistered = false;
     private IBinder mWindowToken;
     private boolean mWallpaperIsLiveWallpaper;
-    private float mLastSetWallpaperOffsetSteps = 0;
 
-    private float mFinalOffset = 0.0f;
-    private float mCurrentOffset = 0.5f; // to force an initial update
-    private boolean mWaitingForUpdate;
     private boolean mLockedToDefaultPage;
-
-    private boolean mAnimating;
-    private long mAnimationStartTime;
-    private float mAnimationStartOffset;
-    int mNumScreens;
-    int mNumPagesForWallpaperParallax;
+    private int mNumScreens;
 
     public WallpaperOffsetInterpolator(Workspace workspace) {
-        mChoreographer = Choreographer.getInstance();
-        mInterpolator = new DecelerateInterpolator(1.5f);
-
         mWorkspace = workspace;
-        mWallpaperManager = WallpaperManager.getInstance(workspace.getContext());
         mIsRtl = Utilities.isRtl(workspace.getResources());
-    }
-
-    @Override
-    public void doFrame(long frameTimeNanos) {
-        updateOffset(false);
-    }
-
-    private void updateOffset(boolean force) {
-        if (mWaitingForUpdate || force) {
-            mWaitingForUpdate = false;
-            if (computeScrollOffset() && mWindowToken != null) {
-                try {
-                    mWallpaperManager.setWallpaperOffsets(mWindowToken, getCurrX(), 0.5f);
-                    setWallpaperOffsetSteps();
-                } catch (IllegalArgumentException e) {
-                    Log.e(TAG, "Error updating wallpaper offset: " + e);
-                }
-            }
-        }
+        mHandler = new OffsetHandler(workspace.getContext());
     }
 
     /**
@@ -80,46 +56,25 @@
         return mLockedToDefaultPage;
     }
 
-    public boolean computeScrollOffset() {
-        final float oldOffset = mCurrentOffset;
-        if (mAnimating) {
-            long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime;
-            float t0 = durationSinceAnimation / (float) ANIMATION_DURATION;
-            float t1 = mInterpolator.getInterpolation(t0);
-            mCurrentOffset = mAnimationStartOffset +
-                    (mFinalOffset - mAnimationStartOffset) * t1;
-            mAnimating = durationSinceAnimation < ANIMATION_DURATION;
-        } else {
-            mCurrentOffset = mFinalOffset;
-        }
-
-        if (Math.abs(mCurrentOffset - mFinalOffset) > 0.0000001f) {
-            scheduleUpdate();
-        }
-        if (Math.abs(oldOffset - mCurrentOffset) > 0.0000001f) {
-            return true;
-        }
-        return false;
-    }
-
     /**
+     * Computes the wallpaper offset as an int ratio (out[0] / out[1])
+     *
      * TODO: do different behavior if it's  a live wallpaper?
      */
-    public float wallpaperOffsetForScroll(int scroll) {
+    private void wallpaperOffsetForScroll(int scroll, int numScrollingPages, final int[] out) {
+        out[1] = 1;
+
         // To match the default wallpaper behavior in the system, we default to either the left
         // or right edge on initialization
-        int numScrollingPages = getNumScreensExcludingEmpty();
         if (mLockedToDefaultPage || numScrollingPages <= 1) {
-            return mIsRtl ? 1f : 0f;
+            out[0] =  mIsRtl ? 1 : 0;
+            return;
         }
 
         // Distribute the wallpaper parallax over a minimum of MIN_PARALLAX_PAGE_SPAN workspace
         // screens, not including the custom screen, and empty screens (if > MIN_PARALLAX_PAGE_SPAN)
-        if (mWallpaperIsLiveWallpaper) {
-            mNumPagesForWallpaperParallax = numScrollingPages;
-        } else {
-            mNumPagesForWallpaperParallax = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages);
-        }
+        int numPagesForWallpaperParallax = mWallpaperIsLiveWallpaper ? numScrollingPages :
+                        Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages);
 
         // Offset by the custom screen
         int leftPageIndex;
@@ -136,106 +91,184 @@
         int leftPageScrollX = mWorkspace.getScrollForPage(leftPageIndex);
         int rightPageScrollX = mWorkspace.getScrollForPage(rightPageIndex);
         int scrollRange = rightPageScrollX - leftPageScrollX;
-        if (scrollRange == 0) {
-            return 0f;
+        if (scrollRange <= 0) {
+            out[0] = 0;
+            return;
         }
 
         // Sometimes the left parameter of the pages is animated during a layout transition;
         // this parameter offsets it to keep the wallpaper from animating as well
         int adjustedScroll = scroll - leftPageScrollX -
                 mWorkspace.getLayoutTransitionOffsetForPage(0);
-        float offset = Utilities.boundToRange((float) adjustedScroll / scrollRange, 0f, 1f);
+        adjustedScroll = Utilities.boundToRange(adjustedScroll, 0, scrollRange);
+        out[1] = (numPagesForWallpaperParallax - 1) * scrollRange;
 
         // The offset is now distributed 0..1 between the left and right pages that we care about,
         // so we just map that between the pages that we are using for parallax
-        float rtlOffset = 0;
+        int rtlOffset = 0;
         if (mIsRtl) {
             // In RTL, the pages are right aligned, so adjust the offset from the end
-            rtlOffset = (float) ((mNumPagesForWallpaperParallax - 1) - (numScrollingPages - 1)) /
-                    (mNumPagesForWallpaperParallax - 1);
+            rtlOffset = out[1] - (numScrollingPages - 1) * scrollRange;
         }
-        return rtlOffset + offset *
-                ((float) (numScrollingPages - 1) / (mNumPagesForWallpaperParallax - 1));
+        out[0] = rtlOffset + adjustedScroll * (numScrollingPages - 1);
     }
 
-    private float wallpaperOffsetForCurrentScroll() {
-        return wallpaperOffsetForScroll(mWorkspace.getScrollX());
-    }
-
-    private int numEmptyScreensToIgnore() {
-        int numScrollingPages = mWorkspace.getChildCount();
-        if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && mWorkspace.hasExtraEmptyScreen()) {
-            return 1;
-        } else {
-            return 0;
-        }
+    public float wallpaperOffsetForScroll(int scroll) {
+        wallpaperOffsetForScroll(scroll, getNumScreensExcludingEmpty(), sTempInt);
+        return ((float) sTempInt[0]) / sTempInt[1];
     }
 
     private int getNumScreensExcludingEmpty() {
-        return mWorkspace.getChildCount() - numEmptyScreensToIgnore();
+        int numScrollingPages = mWorkspace.getChildCount();
+        if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && mWorkspace.hasExtraEmptyScreen()) {
+            return numScrollingPages - 1;
+        } else {
+            return numScrollingPages;
+        }
     }
 
     public void syncWithScroll() {
-        float offset = wallpaperOffsetForCurrentScroll();
-        setFinalX(offset);
-        updateOffset(true);
-    }
-
-    public float getCurrX() {
-        return mCurrentOffset;
-    }
-
-    public float getFinalX() {
-        return mFinalOffset;
-    }
-
-    private void animateToFinal() {
-        mAnimating = true;
-        mAnimationStartOffset = mCurrentOffset;
-        mAnimationStartTime = System.currentTimeMillis();
-    }
-
-    private void setWallpaperOffsetSteps() {
-        // Set wallpaper offset steps (1 / (number of screens - 1))
-        float xOffset = 1.0f / (mNumPagesForWallpaperParallax - 1);
-        if (xOffset != mLastSetWallpaperOffsetSteps) {
-            mWallpaperManager.setWallpaperOffsetSteps(xOffset, 1.0f);
-            mLastSetWallpaperOffsetSteps = xOffset;
-        }
-    }
-
-    public void setFinalX(float x) {
-        scheduleUpdate();
-        mFinalOffset = Math.max(0f, Math.min(x, 1f));
-        if (getNumScreensExcludingEmpty() != mNumScreens) {
-            if (mNumScreens > 0 && Float.compare(mCurrentOffset, mFinalOffset) != 0) {
-                // Don't animate if we're going from 0 screens, or if the final offset is the same
-                // as the current offset
-                animateToFinal();
+        int numScreens = getNumScreensExcludingEmpty();
+        wallpaperOffsetForScroll(mWorkspace.getScrollX(), numScreens, sTempInt);
+        Message msg = Message.obtain(mHandler, MSG_UPDATE_OFFSET, sTempInt[0], sTempInt[1],
+                mWindowToken);
+        if (numScreens != mNumScreens) {
+            if (mNumScreens > 0) {
+                // Don't animate if we're going from 0 screens
+                msg.what = MSG_START_ANIMATION;
             }
-            mNumScreens = getNumScreensExcludingEmpty();
+            mNumScreens = numScreens;
+            updateOffset();
         }
+        msg.sendToTarget();
     }
 
-    private void scheduleUpdate() {
-        if (!mWaitingForUpdate) {
-            mChoreographer.postFrameCallback(this);
-            mWaitingForUpdate = true;
+    private void updateOffset() {
+        int numPagesForWallpaperParallax;
+        if (mWallpaperIsLiveWallpaper) {
+            numPagesForWallpaperParallax = mNumScreens;
+        } else {
+            numPagesForWallpaperParallax = Math.max(MIN_PARALLAX_PAGE_SPAN, mNumScreens);
         }
+        Message.obtain(mHandler, MSG_SET_NUM_PARALLAX, numPagesForWallpaperParallax, 0,
+                mWindowToken).sendToTarget();
     }
 
     public void jumpToFinal() {
-        mCurrentOffset = mFinalOffset;
-    }
-
-    public void onResume() {
-        mWallpaperIsLiveWallpaper = mWallpaperManager.getWallpaperInfo() != null;
-        // Force the wallpaper offset steps to be set again, because another app might have changed
-        // them
-        mLastSetWallpaperOffsetSteps = 0f;
+        Message.obtain(mHandler, MSG_JUMP_TO_FINAL, mWindowToken).sendToTarget();
     }
 
     public void setWindowToken(IBinder token) {
         mWindowToken = token;
+        if (mWindowToken == null && mRegistered) {
+            mWorkspace.getContext().unregisterReceiver(this);
+            mRegistered = false;
+        } else if (mWindowToken != null && !mRegistered) {
+            mWorkspace.getContext()
+                    .registerReceiver(this, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED));
+            onReceive(mWorkspace.getContext(), null);
+            mRegistered = true;
+        }
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        mWallpaperIsLiveWallpaper =
+                WallpaperManager.getInstance(mWorkspace.getContext()).getWallpaperInfo() != null;
+        updateOffset();
+    }
+
+    private static final int MSG_START_ANIMATION = 1;
+    private static final int MSG_UPDATE_OFFSET = 2;
+    private static final int MSG_APPLY_OFFSET = 3;
+    private static final int MSG_SET_NUM_PARALLAX = 4;
+    private static final int MSG_JUMP_TO_FINAL = 5;
+
+    private static class OffsetHandler extends Handler {
+
+        private final Interpolator mInterpolator;
+        private final WallpaperManager mWM;
+
+        private float mCurrentOffset = 0.5f; // to force an initial update
+        private boolean mAnimating;
+        private long mAnimationStartTime;
+        private float mAnimationStartOffset;
+
+        private float mFinalOffset;
+        private float mOffsetX;
+
+        public OffsetHandler(Context context) {
+            super(UiThreadHelper.getBackgroundLooper());
+            mInterpolator = new DecelerateInterpolator(1.5f);
+            mWM = WallpaperManager.getInstance(context);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            final IBinder token = (IBinder) msg.obj;
+            if (token == null) {
+                return;
+            }
+
+            switch (msg.what) {
+                case MSG_START_ANIMATION: {
+                    mAnimating = true;
+                    mAnimationStartOffset = mCurrentOffset;
+                    mAnimationStartTime = msg.getWhen();
+                    // Follow through
+                }
+                case MSG_UPDATE_OFFSET:
+                    mFinalOffset = ((float) msg.arg1) / msg.arg2;
+                    // Follow through
+                case MSG_APPLY_OFFSET: {
+                    float oldOffset = mCurrentOffset;
+                    if (mAnimating) {
+                        long durationSinceAnimation = SystemClock.uptimeMillis()
+                                - mAnimationStartTime;
+                        float t0 = durationSinceAnimation / (float) ANIMATION_DURATION;
+                        float t1 = mInterpolator.getInterpolation(t0);
+                        mCurrentOffset = mAnimationStartOffset +
+                                (mFinalOffset - mAnimationStartOffset) * t1;
+                        mAnimating = durationSinceAnimation < ANIMATION_DURATION;
+                    } else {
+                        mCurrentOffset = mFinalOffset;
+                    }
+
+                    if (Float.compare(mCurrentOffset, oldOffset) != 0) {
+                        setOffsetSafely(token);
+                        // Force the wallpaper offset steps to be set again, because another app
+                        // might have changed them
+                        mWM.setWallpaperOffsetSteps(mOffsetX, 1.0f);
+                    }
+                    if (mAnimating) {
+                        // If we are animating, keep updating the offset
+                        Message.obtain(this, MSG_APPLY_OFFSET, token).sendToTarget();
+                    }
+                    return;
+                }
+                case MSG_SET_NUM_PARALLAX: {
+                    // Set wallpaper offset steps (1 / (number of screens - 1))
+                    mOffsetX = 1.0f / (msg.arg1 - 1);
+                    mWM.setWallpaperOffsetSteps(mOffsetX, 1.0f);
+                    return;
+                }
+                case MSG_JUMP_TO_FINAL: {
+                    if (Float.compare(mCurrentOffset, mFinalOffset) != 0) {
+                        mCurrentOffset = mFinalOffset;
+                        setOffsetSafely(token);
+                    }
+                    mAnimating = false;
+                    return;
+                }
+            }
+        }
+
+        private void setOffsetSafely(IBinder token) {
+            try {
+                mWM.setWallpaperOffsets(token, mCurrentOffset, 0.5f);
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Error updating wallpaper offset: " + e);
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index ad05ce9..bc40484 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -35,13 +35,13 @@
     public Bundle bindOptions = null;
 
     public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i) {
-        if (i.isCustomWidget) {
+        if (i.isCustomWidget()) {
             itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
         } else {
             itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
         }
         this.info = i;
-        user = i.getUser();
+        user = i.getProfile();
         componentName = i.provider;
         previewImage = i.previewImage;
         icon = i.icon;
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 19be28d..c5cf5e2 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -22,7 +22,6 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.view.View;
 import android.widget.RemoteViews;
 
@@ -32,11 +31,9 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.R;
-import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.LivePreviewWidgetCell;
 import com.android.launcher3.graphics.DragPreviewProvider;
-import com.android.launcher3.graphics.HolographicOutlineHelper;
 import com.android.launcher3.graphics.LauncherIcons;
 
 /**
@@ -48,8 +45,8 @@
     private static final float MAX_WIDGET_SCALE = 1.25f;
 
     private final PendingAddItemInfo mAddInfo;
+    private int[] mEstimatedCellSize;
 
-    private Bitmap mPreviewBitmap;
     private RemoteViews mPreview;
 
     public PendingItemDragHelper(View view) {
@@ -80,12 +77,12 @@
         final Point dragOffset;
         final Rect dragRegion;
 
+        mEstimatedCellSize = launcher.getWorkspace().estimateItemSize(mAddInfo);
 
         if (mAddInfo instanceof PendingAddWidgetInfo) {
             PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) mAddInfo;
-            int[] size = launcher.getWorkspace().estimateItemSize(createWidgetInfo, true, false);
 
-            int maxWidth = Math.min((int) (previewBitmapWidth * MAX_WIDGET_SCALE), size[0]);
+            int maxWidth = Math.min((int) (previewBitmapWidth * MAX_WIDGET_SCALE), mEstimatedCellSize[0]);
 
             int[] previewSizeBeforeScale = new int[1];
 
@@ -117,14 +114,12 @@
             PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo;
             Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache());
             preview = LauncherIcons.createScaledBitmapWithoutShadow(icon, launcher, 0);
-            mAddInfo.spanX = mAddInfo.spanY = 1;
             scale = ((float) launcher.getDeviceProfile().iconSizePx) / preview.getWidth();
 
             dragOffset = new Point(previewPadding / 2, previewPadding / 2);
 
             // Create a preview same as the workspace cell size and draw the icon at the
             // appropriate position.
-            int[] size = launcher.getWorkspace().estimateItemSize(mAddInfo, false, true);
             DeviceProfile dp = launcher.getDeviceProfile();
             int iconSize = dp.iconSizePx;
 
@@ -134,9 +129,10 @@
             previewBounds.top += padding;
 
             dragRegion = new Rect();
-            dragRegion.left = (size[0] - iconSize) / 2;
+            dragRegion.left = (mEstimatedCellSize[0] - iconSize) / 2;
             dragRegion.right = dragRegion.left + iconSize;
-            dragRegion.top = (size[1] - iconSize - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2;
+            dragRegion.top = (mEstimatedCellSize[1]
+                    - iconSize - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2;
             dragRegion.bottom = dragRegion.top + iconSize;
         }
 
@@ -149,60 +145,31 @@
         int dragLayerY = screenPos.y + previewBounds.top
                 + (int) ((scale * preview.getHeight() - preview.getHeight()) / 2);
 
-        mPreviewBitmap = preview;
         // Start the drag
         launcher.getDragController().startDrag(preview, dragLayerX, dragLayerY, source, mAddInfo,
                 dragOffset, dragRegion, scale, options);
     }
 
-
     @Override
-    public Bitmap createDragOutline(Canvas canvas) {
-        if (mAddInfo instanceof PendingAddShortcutInfo) {
-            int width = mPreviewBitmap.getWidth();
-            int height = mPreviewBitmap.getHeight();
-            Bitmap b = Bitmap.createBitmap(width + blurSizeOutline, height + blurSizeOutline,
-                    Bitmap.Config.ALPHA_8);
-            canvas.setBitmap(b);
-
-            Launcher launcher = Launcher.getLauncher(mView.getContext());
-            int size = launcher.getDeviceProfile().iconSizePx;
-
-            Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight());
-            Rect dst = new Rect(0, 0, size, size);
-            dst.offset(blurSizeOutline / 2, blurSizeOutline / 2);
-            canvas.drawBitmap(mPreviewBitmap, src, dst, new Paint(Paint.FILTER_BITMAP_FLAG));
-
-            HolographicOutlineHelper.getInstance(mView.getContext())
-                    .applyExpensiveOutlineWithBlur(b, canvas);
-
-            canvas.setBitmap(null);
-            return b;
+    protected Bitmap convertPreviewToAlphaBitmap(Bitmap preview) {
+        if (mAddInfo instanceof PendingAddShortcutInfo || mEstimatedCellSize == null) {
+            return super.convertPreviewToAlphaBitmap(preview);
         }
 
-        Workspace workspace = Launcher.getLauncher(mView.getContext()).getWorkspace();
-        int[] size = workspace.estimateItemSize(mAddInfo, false, false);
-
-        int w = size[0];
-        int h = size[1];
+        int w = mEstimatedCellSize[0];
+        int h = mEstimatedCellSize[1];
         final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8);
-        canvas.setBitmap(b);
+        Rect src = new Rect(0, 0, preview.getWidth(), preview.getHeight());
 
-        Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight());
-        float scaleFactor = Math.min((w - blurSizeOutline) / (float) mPreviewBitmap.getWidth(),
-                (h - blurSizeOutline) / (float) mPreviewBitmap.getHeight());
-        int scaledWidth = (int) (scaleFactor * mPreviewBitmap.getWidth());
-        int scaledHeight = (int) (scaleFactor * mPreviewBitmap.getHeight());
+        float scaleFactor = Math.min((w - blurSizeOutline) / (float) preview.getWidth(),
+                (h - blurSizeOutline) / (float) preview.getHeight());
+        int scaledWidth = (int) (scaleFactor * preview.getWidth());
+        int scaledHeight = (int) (scaleFactor * preview.getHeight());
         Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
 
         // center the image
         dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
-
-        canvas.drawBitmap(mPreviewBitmap, src, dst, null);
-        HolographicOutlineHelper.getInstance(mView.getContext())
-                .applyExpensiveOutlineWithBlur(b, canvas);
-        canvas.setBitmap(null);
-
+        new Canvas(b).drawBitmap(preview, src, dst, new Paint(Paint.FILTER_BITMAP_FLAG));
         return b;
     }
 }
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index 5eeea44..8dcdd44 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -85,7 +85,7 @@
     private boolean preloadWidget() {
         final LauncherAppWidgetProviderInfo pInfo = mInfo.info;
 
-        if (pInfo.isCustomWidget) {
+        if (pInfo.isCustomWidget()) {
             return false;
         }
         final Bundle options = getDefaultOptionsForWidget(mLauncher, mInfo);
@@ -129,7 +129,7 @@
                 mWidgetLoadingId = -1;
 
                 hostView.setVisibility(View.INVISIBLE);
-                int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo, false, true);
+                int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo);
                 // We want the first widget layout to be the correct size. This will be important
                 // for width size reporting to the AppWidgetManager.
                 DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 01101ac..7aa50a4 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -40,24 +40,23 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-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.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 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;
 
 /**
  * Bottom sheet for the "Widgets" system shortcut in the long-press popup.
  */
-public class WidgetsBottomSheet extends AbstractFloatingView implements Insettable, TouchController,
+public class WidgetsBottomSheet extends AbstractFloatingView implements Insettable,
         SwipeDetector.Listener, View.OnClickListener, View.OnLongClickListener,
         DragController.DragListener {
 
@@ -108,7 +107,6 @@
         onWidgetsBound();
 
         mLauncher.getDragLayer().addView(mGradientBackground);
-        mGradientBackground.setVisibility(VISIBLE);
         mLauncher.getDragLayer().addView(this);
         measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
         setTranslationY(mTranslationYClosed);
@@ -242,18 +240,6 @@
     }
 
     @Override
-    public int getLogContainerType() {
-        return LauncherLogProto.ContainerType.WIDGETS; // TODO: be more specific
-    }
-
-    /**
-     * Returns a {@link WidgetsBottomSheet} which is already open or null
-     */
-    public static WidgetsBottomSheet getOpen(Launcher launcher) {
-        return getOpenView(launcher, TYPE_WIDGETS_BOTTOM_SHEET);
-    }
-
-    @Override
     public void setInsets(Rect insets) {
         // Extend behind left, right, and bottom insets.
         int leftInset = insets.left - mInsets.left;
@@ -302,12 +288,27 @@
     }
 
     @Override
+    public void logActionCommand(int command) {
+        // TODO: be more specific
+        mLauncher.getUserEventDispatcher().logActionCommand(command, ContainerType.WIDGETS);
+    }
+
+    @Override
     public boolean onControllerTouchEvent(MotionEvent ev) {
         return mSwipeDetector.onTouchEvent(ev);
     }
 
     @Override
     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_UP) {
+            // If we got ACTION_UP without ever returning true on intercept,
+            // the user never started dragging the bottom sheet.
+            if (!mLauncher.getDragLayer().isEventOverView(this, ev)) {
+                close(true);
+                return false;
+            }
+        }
+
         int directionsToDetectScroll = mSwipeDetector.isIdleState() ?
                 SwipeDetector.DIRECTION_NEGATIVE : 0;
         mSwipeDetector.setDetectableScrollConditions(
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index acec3dd..39dd0d4 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -197,25 +197,6 @@
     //
 
     @Override
-    public boolean supportsAppInfoDropTarget() {
-        return true;
-    }
-
-    /*
-     * Both this method and {@link #supportsFlingToDelete} has to return {@code false} for the
-     * {@link DeleteDropTarget} to be invisible.)
-     */
-    @Override
-    public boolean supportsDeleteDropTarget() {
-        return false;
-    }
-
-    @Override
-    public float getIntrinsicIconScaleFactor() {
-        return 0;
-    }
-
-    @Override
     public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
             boolean success) {
         if (LOGD) {
diff --git a/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java
new file mode 100644
index 0000000..1086987
--- /dev/null
+++ b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java
@@ -0,0 +1,103 @@
+/*
+ * 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.widget.custom;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.Utilities;
+
+/**
+ * Custom app widget provider info that can be used as a widget, but provide extra functionality
+ * by allowing custom code and views.
+ */
+public class CustomAppWidgetProviderInfo extends LauncherAppWidgetProviderInfo
+        implements Parcelable {
+
+    public final int providerId;
+
+    protected CustomAppWidgetProviderInfo(Parcel parcel, boolean readSelf, int providerId) {
+        super(parcel);
+        if (readSelf) {
+            this.providerId = parcel.readInt();
+
+            provider = new ComponentName(parcel.readString(), CLS_CUSTOM_WIDGET_PREFIX + providerId);
+
+            label = parcel.readString();
+            initialLayout = parcel.readInt();
+            icon = parcel.readInt();
+            previewImage = parcel.readInt();
+
+            resizeMode = parcel.readInt();
+            spanX = parcel.readInt();
+            spanY = parcel.readInt();
+            minSpanX = parcel.readInt();
+            minSpanY = parcel.readInt();
+        } else {
+            this.providerId = providerId;
+        }
+    }
+
+    @Override
+    public void initSpans(Context context) { }
+
+    @Override
+    public String getLabel(PackageManager packageManager) {
+        return Utilities.trim(label);
+    }
+
+    @Override
+    public String toString() {
+        return "WidgetProviderInfo(" + provider + ")";
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        super.writeToParcel(out, flags);
+        out.writeInt(providerId);
+        out.writeString(provider.getPackageName());
+
+        out.writeString(label);
+        out.writeInt(initialLayout);
+        out.writeInt(icon);
+        out.writeInt(previewImage);
+
+        out.writeInt(resizeMode);
+        out.writeInt(spanX);
+        out.writeInt(spanY);
+        out.writeInt(minSpanX);
+        out.writeInt(minSpanY);
+    }
+
+    public static final Parcelable.Creator<CustomAppWidgetProviderInfo> CREATOR
+            = new Parcelable.Creator<CustomAppWidgetProviderInfo>() {
+
+        @Override
+        public CustomAppWidgetProviderInfo createFromParcel(Parcel parcel) {
+            return new CustomAppWidgetProviderInfo(parcel, true, 0);
+        }
+
+        @Override
+        public CustomAppWidgetProviderInfo[] newArray(int size) {
+            return new CustomAppWidgetProviderInfo[size];
+        }
+    };
+}
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetParser.java b/src/com/android/launcher3/widget/custom/CustomWidgetParser.java
new file mode 100644
index 0000000..00720c4
--- /dev/null
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetParser.java
@@ -0,0 +1,142 @@
+/*
+ * 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.widget.custom;
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Parcel;
+import android.os.Process;
+import android.util.SparseArray;
+import android.util.Xml;
+
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
+
+/**
+ * Utility class to parse {@ink CustomAppWidgetProviderInfo} definitions from xml
+ */
+public class CustomWidgetParser {
+
+    private static List<LauncherAppWidgetProviderInfo> sCustomWidgets;
+    private static SparseArray<ComponentName> sWidgetsIdMap;
+
+    public static List<LauncherAppWidgetProviderInfo> getCustomWidgets(Context context) {
+        if (sCustomWidgets == null) {
+            // Synchronization not needed as it it safe to load multiple times
+            parseCustomWidgets(context);
+        }
+
+        return sCustomWidgets;
+    }
+
+    public static int getWidgetIdForCustomProvider(Context context, ComponentName provider) {
+        if (sWidgetsIdMap == null) {
+            parseCustomWidgets(context);
+        }
+        int index = sWidgetsIdMap.indexOfValue(provider);
+        if (index >= 0) {
+            return LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - sWidgetsIdMap.keyAt(index);
+        } else {
+            return AppWidgetManager.INVALID_APPWIDGET_ID;
+        }
+    }
+
+    public static LauncherAppWidgetProviderInfo getWidgetProvider(Context context, int widgetId) {
+        if (sWidgetsIdMap == null || sCustomWidgets == null) {
+            parseCustomWidgets(context);
+        }
+        ComponentName cn = sWidgetsIdMap.get(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - widgetId);
+        for (LauncherAppWidgetProviderInfo info : sCustomWidgets) {
+            if (info.provider.equals(cn)) {
+                return info;
+            }
+        }
+        return null;
+    }
+
+    private static void parseCustomWidgets(Context context) {
+        ArrayList<LauncherAppWidgetProviderInfo> widgets = new ArrayList<>();
+        SparseArray<ComponentName> idMap = new SparseArray<>();
+
+        List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(context)
+                .getInstalledProvidersForProfile(Process.myUserHandle());
+        if (providers.isEmpty()) {
+            sCustomWidgets = widgets;
+            sWidgetsIdMap = idMap;
+            return;
+        }
+
+        Parcel parcel = Parcel.obtain();
+        providers.get(0).writeToParcel(parcel, 0);
+
+        try (XmlResourceParser parser = context.getResources().getXml(R.xml.custom_widgets)) {
+            final int depth = parser.getDepth();
+            int type;
+
+            while (((type = parser.next()) != XmlPullParser.END_TAG ||
+                    parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+                if ((type == XmlPullParser.START_TAG) && "widget".equals(parser.getName())) {
+                    TypedArray a = context.obtainStyledAttributes(
+                            Xml.asAttributeSet(parser), R.styleable.CustomAppWidgetProviderInfo);
+
+                    parcel.setDataPosition(0);
+                    CustomAppWidgetProviderInfo info = newInfo(a, parcel, context);
+                    widgets.add(info);
+                    a.recycle();
+
+                    idMap.put(info.providerId, info.provider);
+                }
+            }
+        } catch (IOException | XmlPullParserException e) {
+            throw new RuntimeException(e);
+        }
+        parcel.recycle();
+        sCustomWidgets = widgets;
+        sWidgetsIdMap = idMap;
+    }
+
+    private static CustomAppWidgetProviderInfo newInfo(TypedArray a, Parcel parcel, Context context) {
+        int providerId = a.getInt(R.styleable.CustomAppWidgetProviderInfo_providerId, 0);
+        CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false, providerId);
+        info.provider = new ComponentName(context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId);
+
+        info.label = a.getString(R.styleable.CustomAppWidgetProviderInfo_android_label);
+        info.initialLayout = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_initialLayout, 0);
+        info.icon = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_icon, 0);
+        info.previewImage = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_previewImage, 0);
+        info.resizeMode = a.getInt(R.styleable.CustomAppWidgetProviderInfo_android_resizeMode, 0);
+
+        info.spanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numColumns, 1);
+        info.spanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numRows, 1);
+        info.minSpanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinColumns, 1);
+        info.minSpanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinRows, 1);
+        return info;
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index d4d517a..87103d7 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.ui.widget;
 
 import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -171,8 +172,9 @@
         // Widget has a valid Id now.
         assertEquals(0, mCursor.getInt(mCursor.getColumnIndex(LauncherSettings.Favorites.RESTORED))
                 & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
-        assertNotNull(mWidgetManager.getAppWidgetInfo(mCursor.getInt(mCursor.getColumnIndex(
-                LauncherSettings.Favorites.APPWIDGET_ID))));
+        assertNotNull(AppWidgetManager.getInstance(mTargetContext)
+                .getAppWidgetInfo(mCursor.getInt(mCursor.getColumnIndex(
+                        LauncherSettings.Favorites.APPWIDGET_ID))));
     }
 
     @Test
@@ -297,7 +299,7 @@
         item.spanY = info.minSpanY;
         item.minSpanX = info.minSpanX;
         item.minSpanY = info.minSpanY;
-        item.user = info.getUser();
+        item.user = info.getProfile();
         item.cellX = 0;
         item.cellY = 1;
         item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index 4b9d83f..bd21315 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -141,7 +141,7 @@
 
     private void runTest(String activityMethod, boolean isWidget, ItemOperator itemMatcher,
             Intent... commandIntents) throws Throwable {
-        if (!Utilities.isAtLeastO()) {
+        if (!Utilities.ATLEAST_OREO) {
             return;
         }
         lockRotation(true);