Merge "Fixing two critical bugs in all apps transition controller" into ub-launcher3-calgary
am: b7d16b7e5c

Change-Id: I95a6bfc2247eb98d5c3758589989bcaf2657e072
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 3da3535..bbe1f4a 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -50,7 +50,7 @@
         android:fullBackupContent="@xml/backupscheme"
         android:hardwareAccelerated="true"
         android:icon="@mipmap/ic_launcher_home"
-        android:label="@string/app_name"
+        android:label="@string/derived_app_name"
         android:largeHeap="@bool/config_largeHeap"
         android:restoreAnyVersion="true"
         android:supportsRtl="true" >
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3a3a28d..6c5990d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -55,7 +55,7 @@
         android:fullBackupContent="@xml/backupscheme"
         android:hardwareAccelerated="true"
         android:icon="@mipmap/ic_launcher_home"
-        android:label="@string/app_name"
+        android:label="@string/derived_app_name"
         android:largeHeap="@bool/config_largeHeap"
         android:restoreAnyVersion="true"
         android:supportsRtl="true" >
diff --git a/build.gradle b/build.gradle
index ffe4455..e103d79 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,8 +3,8 @@
         mavenCentral()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.1.0'
-        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.7.0'
+        classpath 'com.android.tools.build:gradle:2.1.3'
+        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
     }
 }
 
@@ -16,13 +16,11 @@
     buildToolsVersion '24.0.0'
 
     defaultConfig {
-        applicationId "com.android.launcher3"
         minSdkVersion 21
-        targetSdkVersion 'N'
+        targetSdkVersion 25
         versionCode 1
         versionName "1.0"
 
-        testApplicationId "com.android.launcher3.tests"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
     buildTypes {
@@ -30,11 +28,18 @@
             minifyEnabled false
         }
     }
+
+    productFlavors {
+        aosp {
+            applicationId 'com.android.launcher3'
+            testApplicationId 'com.android.launcher3.tests'
+        }
+    }
     sourceSets {
         main {
             res.srcDirs = ['res']
             java.srcDirs = ['src', 'src_config']
-            manifest.srcFile 'AndroidManifest.xml'
+            manifest.srcFile 'AndroidManifest-common.xml'
             proto.srcDirs 'protos/'
         }
 
@@ -42,6 +47,10 @@
             java.srcDirs = ['tests/src']
             manifest.srcFile "tests/AndroidManifest.xml"
         }
+
+        aosp {
+            manifest.srcFile "AndroidManifest.xml"
+        }
     }
 }
 
@@ -65,5 +74,16 @@
     // Configure the protoc executable
     protoc {
         artifact = 'com.google.protobuf:protoc:3.0.0-alpha-3'
+
+        generateProtoTasks {
+            all().each { task ->
+                task.builtins {
+                    remove java
+                    javanano {
+                        option 'ignore_services=false'
+                    }
+                }
+            }
+        }
     }
 }
diff --git a/res/drawable-hdpi/ic_all_apps_bg_hand.png b/res/drawable-hdpi/ic_all_apps_bg_hand.png
index 43b1bed..dff2f54 100644
--- a/res/drawable-hdpi/ic_all_apps_bg_hand.png
+++ b/res/drawable-hdpi/ic_all_apps_bg_hand.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_all_apps_bg_icon_1.png b/res/drawable-hdpi/ic_all_apps_bg_icon_1.png
deleted file mode 100644
index d2c4cc1..0000000
--- a/res/drawable-hdpi/ic_all_apps_bg_icon_1.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_all_apps_bg_icon_2.png b/res/drawable-hdpi/ic_all_apps_bg_icon_2.png
deleted file mode 100644
index 57b7456..0000000
--- a/res/drawable-hdpi/ic_all_apps_bg_icon_2.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_all_apps_bg_icon_3.png b/res/drawable-hdpi/ic_all_apps_bg_icon_3.png
deleted file mode 100644
index 54fe70b..0000000
--- a/res/drawable-hdpi/ic_all_apps_bg_icon_3.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_all_apps_bg_icon_4.png b/res/drawable-hdpi/ic_all_apps_bg_icon_4.png
deleted file mode 100644
index 9c0f777..0000000
--- a/res/drawable-hdpi/ic_all_apps_bg_icon_4.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/workspace_bg.9.png b/res/drawable-hdpi/workspace_bg.9.png
old mode 100644
new mode 100755
index ff75186..1d82fd4
--- a/res/drawable-hdpi/workspace_bg.9.png
+++ b/res/drawable-hdpi/workspace_bg.9.png
Binary files differ
diff --git a/res/drawable-land-hdpi/workspace_bg.9.png b/res/drawable-land-hdpi/workspace_bg.9.png
deleted file mode 100644
index eecd6de..0000000
--- a/res/drawable-land-hdpi/workspace_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-land-mdpi/workspace_bg.9.png b/res/drawable-land-mdpi/workspace_bg.9.png
deleted file mode 100644
index 626f4a4..0000000
--- a/res/drawable-land-mdpi/workspace_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-land-xhdpi/workspace_bg.9.png b/res/drawable-land-xhdpi/workspace_bg.9.png
deleted file mode 100644
index 60f7d73..0000000
--- a/res/drawable-land-xhdpi/workspace_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-land-xxhdpi/workspace_bg.9.png b/res/drawable-land-xxhdpi/workspace_bg.9.png
deleted file mode 100644
index fc71a0f..0000000
--- a/res/drawable-land-xxhdpi/workspace_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_all_apps_bg_hand.png b/res/drawable-mdpi/ic_all_apps_bg_hand.png
index 8868d6b..0d1d7bb 100644
--- a/res/drawable-mdpi/ic_all_apps_bg_hand.png
+++ b/res/drawable-mdpi/ic_all_apps_bg_hand.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_all_apps_bg_icon_1.png b/res/drawable-mdpi/ic_all_apps_bg_icon_1.png
deleted file mode 100644
index 4c78288..0000000
--- a/res/drawable-mdpi/ic_all_apps_bg_icon_1.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_all_apps_bg_icon_2.png b/res/drawable-mdpi/ic_all_apps_bg_icon_2.png
deleted file mode 100644
index 0ed311b..0000000
--- a/res/drawable-mdpi/ic_all_apps_bg_icon_2.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_all_apps_bg_icon_3.png b/res/drawable-mdpi/ic_all_apps_bg_icon_3.png
deleted file mode 100644
index 2aa3d4e..0000000
--- a/res/drawable-mdpi/ic_all_apps_bg_icon_3.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_all_apps_bg_icon_4.png b/res/drawable-mdpi/ic_all_apps_bg_icon_4.png
deleted file mode 100644
index 2cdea9c..0000000
--- a/res/drawable-mdpi/ic_all_apps_bg_icon_4.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/workspace_bg.9.png b/res/drawable-mdpi/workspace_bg.9.png
old mode 100644
new mode 100755
index c67c432..116ce44
--- a/res/drawable-mdpi/workspace_bg.9.png
+++ b/res/drawable-mdpi/workspace_bg.9.png
Binary files differ
diff --git a/res/drawable-sw720dp-hdpi/workspace_bg.9.png b/res/drawable-sw720dp-hdpi/workspace_bg.9.png
deleted file mode 100644
index ff75186..0000000
--- a/res/drawable-sw720dp-hdpi/workspace_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-sw720dp-mdpi/workspace_bg.9.png b/res/drawable-sw720dp-mdpi/workspace_bg.9.png
deleted file mode 100644
index c67c432..0000000
--- a/res/drawable-sw720dp-mdpi/workspace_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-sw720dp-xhdpi/workspace_bg.9.png b/res/drawable-sw720dp-xhdpi/workspace_bg.9.png
deleted file mode 100644
index 0b80cbf..0000000
--- a/res/drawable-sw720dp-xhdpi/workspace_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-sw720dp-xxhdpi/workspace_bg.9.png b/res/drawable-sw720dp-xxhdpi/workspace_bg.9.png
deleted file mode 100644
index 0d180c2..0000000
--- a/res/drawable-sw720dp-xxhdpi/workspace_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_all_apps_bg_hand.png b/res/drawable-xhdpi/ic_all_apps_bg_hand.png
index 8a67245..e727d37 100644
--- a/res/drawable-xhdpi/ic_all_apps_bg_hand.png
+++ b/res/drawable-xhdpi/ic_all_apps_bg_hand.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_all_apps_bg_icon_1.png b/res/drawable-xhdpi/ic_all_apps_bg_icon_1.png
deleted file mode 100644
index c0ebaed..0000000
--- a/res/drawable-xhdpi/ic_all_apps_bg_icon_1.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_all_apps_bg_icon_2.png b/res/drawable-xhdpi/ic_all_apps_bg_icon_2.png
deleted file mode 100644
index 71cf250..0000000
--- a/res/drawable-xhdpi/ic_all_apps_bg_icon_2.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_all_apps_bg_icon_3.png b/res/drawable-xhdpi/ic_all_apps_bg_icon_3.png
deleted file mode 100644
index 3c69fc5..0000000
--- a/res/drawable-xhdpi/ic_all_apps_bg_icon_3.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_all_apps_bg_icon_4.png b/res/drawable-xhdpi/ic_all_apps_bg_icon_4.png
deleted file mode 100644
index 5f6ca38..0000000
--- a/res/drawable-xhdpi/ic_all_apps_bg_icon_4.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/workspace_bg.9.png b/res/drawable-xhdpi/workspace_bg.9.png
old mode 100644
new mode 100755
index 0b80cbf..b1b3b85
--- a/res/drawable-xhdpi/workspace_bg.9.png
+++ b/res/drawable-xhdpi/workspace_bg.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_all_apps_bg_hand.png b/res/drawable-xxhdpi/ic_all_apps_bg_hand.png
index ed694f8..fffcc6b 100644
--- a/res/drawable-xxhdpi/ic_all_apps_bg_hand.png
+++ b/res/drawable-xxhdpi/ic_all_apps_bg_hand.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_all_apps_bg_icon_1.png b/res/drawable-xxhdpi/ic_all_apps_bg_icon_1.png
deleted file mode 100644
index 5cb0427..0000000
--- a/res/drawable-xxhdpi/ic_all_apps_bg_icon_1.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_all_apps_bg_icon_2.png b/res/drawable-xxhdpi/ic_all_apps_bg_icon_2.png
deleted file mode 100644
index cd0322b..0000000
--- a/res/drawable-xxhdpi/ic_all_apps_bg_icon_2.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_all_apps_bg_icon_3.png b/res/drawable-xxhdpi/ic_all_apps_bg_icon_3.png
deleted file mode 100644
index 19ffc2d..0000000
--- a/res/drawable-xxhdpi/ic_all_apps_bg_icon_3.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_all_apps_bg_icon_4.png b/res/drawable-xxhdpi/ic_all_apps_bg_icon_4.png
deleted file mode 100644
index 311c3df..0000000
--- a/res/drawable-xxhdpi/ic_all_apps_bg_icon_4.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/workspace_bg.9.png b/res/drawable-xxhdpi/workspace_bg.9.png
old mode 100644
new mode 100755
index 0d180c2..d47f6b2
--- a/res/drawable-xxhdpi/workspace_bg.9.png
+++ b/res/drawable-xxhdpi/workspace_bg.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_all_apps_bg_hand.png b/res/drawable-xxxhdpi/ic_all_apps_bg_hand.png
index 615374a..4d065d8 100644
--- a/res/drawable-xxxhdpi/ic_all_apps_bg_hand.png
+++ b/res/drawable-xxxhdpi/ic_all_apps_bg_hand.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_all_apps_bg_icon_1.png b/res/drawable-xxxhdpi/ic_all_apps_bg_icon_1.png
deleted file mode 100644
index 10f8c41..0000000
--- a/res/drawable-xxxhdpi/ic_all_apps_bg_icon_1.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_all_apps_bg_icon_2.png b/res/drawable-xxxhdpi/ic_all_apps_bg_icon_2.png
deleted file mode 100644
index 102d925..0000000
--- a/res/drawable-xxxhdpi/ic_all_apps_bg_icon_2.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_all_apps_bg_icon_3.png b/res/drawable-xxxhdpi/ic_all_apps_bg_icon_3.png
deleted file mode 100644
index 9be5b7a..0000000
--- a/res/drawable-xxxhdpi/ic_all_apps_bg_icon_3.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_all_apps_bg_icon_4.png b/res/drawable-xxxhdpi/ic_all_apps_bg_icon_4.png
deleted file mode 100644
index d7fb29b..0000000
--- a/res/drawable-xxxhdpi/ic_all_apps_bg_icon_4.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/workspace_bg.9.png b/res/drawable-xxxhdpi/workspace_bg.9.png
new file mode 100755
index 0000000..3281548
--- /dev/null
+++ b/res/drawable-xxxhdpi/workspace_bg.9.png
Binary files differ
diff --git a/res/drawable/bg_pill_focused.xml b/res/drawable/bg_pill_focused.xml
new file mode 100644
index 0000000..37afad0
--- /dev/null
+++ b/res/drawable/bg_pill_focused.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true">
+        <shape xmlns:android="http://schemas.android.com/apk/res/android"
+               android:shape="rectangle">
+            <stroke android:color="#616161" android:width="2dp"/>
+            <corners android:radius="@dimen/bg_pill_radius" />
+        </shape>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/res/drawable/ic_all_apps_bg_icon_1.xml b/res/drawable/ic_all_apps_bg_icon_1.xml
new file mode 100644
index 0000000..c9c0a75
--- /dev/null
+++ b/res/drawable/ic_all_apps_bg_icon_1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+
+    <path
+        android:fillColor="#1A000000"
+        android:pathData="M44.28,30.96c4.84-10.68,0.09-23.27-10.59-28.11S10.42,2.74,5.58,13.42
+        C1,23.54,6.5,35.92,16.62,40.51l0,0l-3.23,7.12C27.84,47,39.79,40.86,44.28,30.96z" />
+    <path
+        android:fillColor="#E0E0E0"
+        android:pathData="M41.75,30.05c4.84-10.68,0.09-23.27-10.59-28.11S7.9,1.83,3.06,12.51
+        c-4.59,10.12,0.92,22.5,11.03,27.09l0,0l-3.23,7.12C25.31,46.09,37.26,39.94,41.75,30.05z" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_all_apps_bg_icon_2.xml b/res/drawable/ic_all_apps_bg_icon_2.xml
new file mode 100644
index 0000000..b6269e3
--- /dev/null
+++ b/res/drawable/ic_all_apps_bg_icon_2.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+
+    <path
+        android:fillColor="#1A000000"
+        android:pathData="M20.54,44.59c0.57-0.04,1.15-0.38,1.67-1.04l24.23-30.62c0.62-0.78,0.77-1.54,0.52-2.12
+        c-0.25-0.58-0.9-0.99-1.89-1.1L6.2,5.99C5.39,5.91,4.74,6.08,4.32,6.44l0,0C3.7,6.97,3.55,7.88,4.01,8.96l14.54,34.09
+        C19,44.13,19.75,44.65,20.54,44.59L20.54,44.59z" />
+    <path
+        android:fillColor="#E0E0E0"
+        android:pathData="M18.49,43.22c0.57-0.04,1.15-0.38,1.67-1.04l24.23-30.62c0.62-0.78,0.77-1.54,0.52-2.12
+        c-0.25-0.58-0.9-0.99-1.89-1.1L4.15,4.62C3.34,4.54,2.69,4.71,2.27,5.08l0,0C1.65,5.6,1.5,6.52,1.96,7.6L16.5,41.69
+        C16.96,42.76,17.7,43.28,18.49,43.22L18.49,43.22z" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_all_apps_bg_icon_3.xml b/res/drawable/ic_all_apps_bg_icon_3.xml
new file mode 100644
index 0000000..4c255a9
--- /dev/null
+++ b/res/drawable/ic_all_apps_bg_icon_3.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+
+    <path
+        android:fillColor="#1A000000"
+        android:pathData="M25.18,1.27c-12.32,0-23.41,9.99-23.41,22.31s11.09,22.31,23.41,22.31
+        s22.31-9.99,22.31-22.31S37.5,1.27,25.18,1.27z M25.18,33.55c-5.5,0-14.35-5.1-14.35-10.6s8.32-12.19,13.82-12.19
+        c5.5,0,10.49,7.33,10.49,12.83S30.68,33.55,25.18,33.55z" />
+    <path
+        android:fillColor="#E0E0E0"
+        android:pathData="M22.93,0.22c-12.32,0-22.31,9.99-22.31,22.31s9.99,22.31,22.31,22.31
+        s22.31-9.99,22.31-22.31S35.25,0.22,22.93,0.22z M22.93,32.5c-5.5,0-9.97-4.46-9.97-9.97s4.46-9.97,9.97-9.97
+        c5.5,0,9.97,4.46,9.97,9.97S28.43,32.5,22.93,32.5z" />
+    <path
+        android:fillColor="#E0E0E0"
+        android:pathData="M14.81,22.53a8.12,8.12 0 1,0 16.24,0a8.12,8.12 0 1,0 -16.24,0z" />
+</vector>
diff --git a/res/drawable/ic_all_apps_bg_icon_4.xml b/res/drawable/ic_all_apps_bg_icon_4.xml
new file mode 100644
index 0000000..12e05bc
--- /dev/null
+++ b/res/drawable/ic_all_apps_bg_icon_4.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+
+    <path
+        android:fillColor="#1A000000"
+        android:pathData="M11.53,8.02l23.39-5.73c1.61-0.39,3.25,0.6,3.64,2.21l7.64,31.19
+        c0.39,1.61-0.6,3.25-2.21,3.64L12.8,46.97c-1.61,0.39-3.25-0.6-3.64-2.21L3.43,21.37L11.53,8.02z" />
+    <path
+        android:fillColor="#E0E0E0"
+        android:pathData="M9.2,6.53L32.59,0.8C34.2,0.4,35.84,1.4,36.23,3l7.64,31.19c0.39,1.61-0.6,3.25-2.21,3.64
+        l-31.19,7.64c-1.61,0.39-3.25-0.6-3.64-2.21L1.11,19.87L9.2,6.53z" />
+    <path
+        android:fillColor="#1A000000"
+        android:pathData="M9.27,6.47l1.91,7.8c0.4,1.62-0.59,3.24-2.21,3.64l-7.8,1.91L9.27,6.47z" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_setting.xml b/res/drawable/ic_setting.xml
index 256d24c..8a50c0c 100644
--- a/res/drawable/ic_setting.xml
+++ b/res/drawable/ic_setting.xml
@@ -20,5 +20,5 @@
         android:viewportHeight="48.0">
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M38.86 25.95c.08-.64.14-1.29.14-1.95s-.06-1.31-.14-1.95l4.23-3.31c.38-.3.49-.84.24-1.28l-4-6.93c-.25-.43-.77-.61-1.22-.43l-4.98 2.01c-1.03-.79-2.16-1.46-3.38-1.97L29 4.84c-.09-.47-.5-.84-1-.84h-8c-.5 0-.91.37-.99.84l-.75 5.3c-1.22.51-2.35 1.17-3.38 1.97L9.9 10.1c-.45-.17-.97 0-1.22.43l-4 6.93c-.25.43-.14.97.24 1.28l4.22 3.31C9.06 22.69 9 23.34 9 24s.06 1.31.14 1.95l-4.22 3.31c-.38.3-.49.84-.24 1.28l4 6.93c.25.43.77.61 1.22.43l4.98-2.01c1.03.79 2.16 1.46 3.38 1.97l.75 5.3c.08.47.49.84.99.84h8c.5 0 .91-.37.99-.84l.75-5.3c1.22-.51 2.35-1.17 3.38-1.97l4.98 2.01c.45.17.97 0 1.22-.43l4-6.93c.25-.43.14-.97-.24-1.28l-4.22-3.31zM24 31c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/>
+        android:pathData="M38.86 25.95c.08-.64 .14-1.29 .14-1.95s-.06-1.31-.14-1.95l4.23-3.31c.38-.3 .49-.84 .24-1.28l-4-6.93c-.25-.43-.77-.61-1.22-.43l-4.98 2.01c-1.03-.79-2.16-1.46-3.38-1.97L29 4.84c-.09-.47-.5-.84-1-.84h-8c-.5 0-.91 .37-.99 .84l-.75 5.3c-1.22 .51-2.35 1.17-3.38 1.97L9.9 10.1c-.45-.17-.97 0-1.22 .43l-4 6.93c-.25 .43-.14 .97 .24 1.28l4.22 3.31C9.06 22.69 9 23.34 9 24s.06 1.31 .14 1.95l-4.22 3.31c-.38 .3-.49 .84-.24 1.28l4 6.93c.25 .43 .77 .61 1.22 .43l4.98-2.01c1.03 .79 2.16 1.46 3.38 1.97l.75 5.3c.08 .47 .49 .84 .99 .84h8c.5 0 .91-.37 .99-.84l.75-5.3c1.22-.51 2.35-1.17 3.38-1.97l4.98 2.01c.45 .17 .97 0 1.22-.43l4-6.93c.25-.43 .14-.97-.24-1.28l-4.22-3.31zM24 31c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/>
 </vector>
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 2e64f6c..ef0dfdc 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -27,6 +27,7 @@
         android:id="@+id/drag_layer"
         android:clipChildren="false"
         android:clipToPadding="false"
+        android:background="@drawable/workspace_bg"
         android:importantForAccessibility="no"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index e304987..a2e2f9b 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -29,6 +29,7 @@
         android:clipChildren="false"
         android:importantForAccessibility="no"
         android:clipToPadding="false"
+        android:background="@drawable/workspace_bg"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 50921eb..12c01b7 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -28,6 +28,7 @@
         android:clipChildren="false"
         android:clipToPadding="false"
         android:importantForAccessibility="no"
+        android:background="@drawable/workspace_bg"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
@@ -75,7 +76,8 @@
             android:id="@+id/apps_view"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:visibility="invisible" />
+            android:visibility="invisible"
+           launcher:layout_ignoreInsets="true" />
     </com.android.launcher3.dragndrop.DragLayer>
 
 </com.android.launcher3.LauncherRootView>
diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml
index 2d66d72..7b42ec7 100644
--- a/res/layout/deep_shortcut.xml
+++ b/res/layout/deep_shortcut.xml
@@ -26,7 +26,8 @@
         style="@style/Icon.DeepShortcut"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:focusable="true" />
+        android:focusable="true"
+        android:background="@drawable/bg_pill_focused" />
 
     <View
         android:id="@+id/deep_shortcut_icon"
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index d950750..50bd896 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -28,7 +28,7 @@
         android:layout_height="match_parent"
         android:paddingLeft="4dp"
         android:paddingRight="4dp"
-        android:paddingTop="8dp"
+        android:paddingTop="4dp"
         launcher:pageIndicator="@+id/folder_page_indicator" />
 
     <LinearLayout
@@ -37,8 +37,8 @@
         android:layout_height="wrap_content"
         android:clipChildren="false"
         android:orientation="horizontal"
-        android:paddingLeft="8dp"
-        android:paddingRight="8dp" >
+        android:paddingLeft="12dp"
+        android:paddingRight="12dp" >
 
         <com.android.launcher3.ExtendedEditText
             android:id="@+id/folder_name"
@@ -51,13 +51,14 @@
             android:gravity="center_horizontal"
             android:hint="@string/folder_hint_text"
             android:imeOptions="flagNoExtractUi"
-            android:paddingBottom="8dp"
-            android:paddingTop="4dp"
+            android:paddingBottom="@dimen/folder_label_padding"
+            android:paddingTop="@dimen/folder_label_padding"
             android:singleLine="true"
             android:textColor="#ff777777"
+            android:includeFontPadding="false"
             android:textColorHighlight="#ffCCCCCC"
             android:textColorHint="#ff808080"
-            android:textSize="14sp" />
+            android:textSize="@dimen/folder_label_text_size" />
 
         <com.android.launcher3.pageindicators.PageIndicatorDots
             android:id="@+id/folder_page_indicator"
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index bb6bd76..16e618a 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -26,9 +26,9 @@
         android:id="@+id/folder_content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingLeft="8dp"
-        android:paddingRight="8dp"
-        android:paddingTop="8dp"
+        android:paddingLeft="4dp"
+        android:paddingRight="4dp"
+        android:paddingTop="4dp"
         launcher:pageIndicator="@+id/folder_page_indicator" />
 
     <LinearLayout
@@ -37,8 +37,8 @@
         android:layout_height="wrap_content"
         android:clipChildren="false"
         android:orientation="horizontal"
-        android:paddingLeft="8dp"
-        android:paddingRight="8dp" >
+        android:paddingLeft="12dp"
+        android:paddingRight="12dp" >
 
         <com.android.launcher3.ExtendedEditText
             android:id="@+id/folder_name"
@@ -52,13 +52,13 @@
             android:gravity="center_horizontal"
             android:hint="@string/folder_hint_text"
             android:imeOptions="flagNoExtractUi"
-            android:paddingBottom="12dp"
-            android:paddingTop="4dp"
+            android:paddingBottom="@dimen/folder_label_padding"
+            android:paddingTop="@dimen/folder_label_padding"
             android:singleLine="true"
             android:textColor="#EE777777"
             android:textColorHighlight="#ffCCCCCC"
             android:textColorHint="#ff808080"
-            android:textSize="14sp" />
+            android:textSize="@dimen/folder_label_text_size" />
 
         <com.android.launcher3.pageindicators.PageIndicatorDots
             android:id="@+id/folder_page_indicator"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index cde143e..644dcb5 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Raak en hou om \'n legstuk op te tel."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dubbeltik en hou om \'n legstuk op te tel of gebruik gepasmaakte handelinge."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Deursoek programme"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Laai tans programme …"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Geen programme gevind wat met \"<xliff:g id="QUERY">%1$s</xliff:g>\" ooreenstem nie"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 53513a6..7661f99 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ፍርግም ለማንሳት ይንኩ እና ይያዙት"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"አንድ ንዑስ ፕሮግራም ለመምረጥ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ አድርገው ይያዙ።"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"መተግበሪያዎችን ይፈልጉ"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"መተግበሪያዎችን በመጫን ላይ..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"ከ«<xliff:g id="QUERY">%1$s</xliff:g>» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index d7e57c3..c58d20b 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"المس مع الاستمرار لاختيار إحدى الأدوات."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"انقر نقرًا مزدوجًا مع الاستمرار لاختيار أداة أو استخدم الإجراءات المخصصة."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"البحث في التطبيقات"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"جارٍ تحميل التطبيقات…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"لم يتم العثور على أية تطبيقات تتطابق مع \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
index 625fa0c..d3928b2 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az-rAZ/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Vidceti götürmək üçün toxunub saxlayın."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Vidceti götürmək üçün &amp; iki dəfə toxunub saxlayın və ya fərdi fəaliyyətləri istifadə edin."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Tətbiq Axtarın"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Tətbiqlər endirilir..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" sorğusuna uyğun Tətbiqlər tapılmadı"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 9b0ca96..1e0ed45 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Dodirnite i zadržite da biste izabrali vidžet."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dvaput dodirnite i zadržite da biste izabrali vidžet ili koristite prilagođene radnje."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pretražite aplikacije"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Aplikacije se učitavaju..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nije pronađena nijedna aplikacija za „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
diff --git a/res/values-be-rBY/strings.xml b/res/values-be-rBY/strings.xml
index f450091..c3debe9 100644
--- a/res/values-be-rBY/strings.xml
+++ b/res/values-be-rBY/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Дакраніцеся і ўтрымлiвайце віджэт, каб выбр. яго."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Дакраніцеся двойчы і ўтрымлівайце, каб выбраць віджэт або выкарыстоўваць карыстальніцкія дзеянні."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Пошук у Праграмах"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Ідзе загрузка праграм…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Праграм, якія адпавядаюць запыту \"<xliff:g id="QUERY">%1$s</xliff:g>\", не знойдзена"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 04786ab..5158b6a 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Докоснете и задръжте за избор на приспособление."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Докоснете двукратно и задръжте за избор на приспособление или използвайте персонализирани действия."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Търсене в приложенията"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Приложенията се зареждат…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Няма намерени приложения, съответстващи на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index ca74b76..cb7900b 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"একটি উইজেট তুলতে তা স্পর্শ করে ধরে রাখুন৷"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"কোনো উইজেট বেছে নিতে দুবার-আলতো চেপে ধরে থাকুন অথবা কাস্টম ক্রিয়াগুলি ব্যবহার করুন৷"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"অ্যাপ্লিকেশানগুলি অনুসন্ধান করুন"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"অ্যাপ্লিকেশানগুলি লোড হচ্ছে..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" এর সাথে মেলে এমন কোনো অ্যাপ্লিকেশান পাওয়া যায়নি"</string>
diff --git a/res/values-bs-rBA/strings.xml b/res/values-bs-rBA/strings.xml
index 560dde0..4f10fd2 100644
--- a/res/values-bs-rBA/strings.xml
+++ b/res/values-bs-rBA/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Dodirnite &amp; i držite da biste uzeli dodatak."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dvaput dodirnite &amp; i držite da biste uzeli vidžet ili koristite prilagođene radnje."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pretraži aplikacije"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Aplikacije se učitavaju…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nije pronađena nijedna aplikacija koja odgovara upitu \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 4f174ae..c3a32cd 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Mantén premut un widget per triar-lo."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Fes doble toc i mantén premut per seleccionar un widget o per utilitzar les accions personalitzades."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Cerca a les aplicacions"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"S\'estan carregant les aplicacions..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No s\'ha trobat cap aplicació que coincideixi amb <xliff:g id="QUERY">%1$s</xliff:g>"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index a6a9dd6..b02e250 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Widget vyberete dotykem a podržením."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dvojitým klepnutím a podržením vyberte widget, případně použijte vlastní akce."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Hledat aplikace"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Načítání aplikací…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Dotazu „<xliff:g id="QUERY">%1$s</xliff:g>“ neodpovídají žádné aplikace"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 99bc220..e97605d 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Tryk på en widget, og hold den nede for at vælge."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Tryk to gange, og hold fingeren nede for at vælge en widget eller bruge tilpassede handlinger."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Søg i Apps"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Indlæser apps…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Der blev ikke fundet nogen apps, som matcher \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 36ac06f..9d2670c 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Zum Hinzufügen Widget berühren und halten"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Zum Hinzufügen auf Widget doppeltippen und gedrückt halten oder benutzerdefinierte Aktionen verwenden."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"In Apps suchen"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Apps werden geladen..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Keine Apps für \"<xliff:g id="QUERY">%1$s</xliff:g>\" gefunden"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 4d3f708..d517af6 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Αγγίξτε παρατεταμένα για να πάρετε ένα γραφ.στοιχ."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Πατήστε δύο φορές παρατεταμένα για επιλογή γραφικού στοιχείου ή χρήση προσαρμοσμένων ενεργειών."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Αναζήτηση εφαρμογών"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Φόρτωση εφαρμογών…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Δεν βρέθηκαν εφαρμογές για το ερώτημα \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 8c95ae1..9b5231d 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Touch &amp; hold to pick up a widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Double-tap &amp; hold to pick up a widget or use customised actions."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 8c95ae1..9b5231d 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Touch &amp; hold to pick up a widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Double-tap &amp; hold to pick up a widget or use customised actions."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 8c95ae1..9b5231d 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Touch &amp; hold to pick up a widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Double-tap &amp; hold to pick up a widget or use customised actions."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 4002b97..0e1abf1 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Mantén presionado el widget que desees elegir."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Presiona dos veces y mantén presionado para elegir un widget o usa una acción personalizada."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Buscar aplicaciones"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicaciones…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No hay aplicaciones que coincidan con <xliff:g id="QUERY">%1$s</xliff:g>."</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index a6340e0..1d7f824 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Mantén pulsado el widget que quieras seleccionar."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Toca dos veces y mantén pulsado el widget que quieras seleccionar o utiliza acciones personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Busca aplicaciones"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicaciones…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"No se han encontrado aplicaciones que contengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
index 9deeef9..31cc0ae 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et-rEE/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Vidina valimiseks vajutage ja hoidke seda all."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Topeltpuudutage ja hoidke vidina valimiseks või kohandatud toimingute kasutamiseks."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Otsige rakendustest"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Rakenduste laadimine ..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Päringule „<xliff:g id="QUERY">%1$s</xliff:g>” ei vastanud ükski rakendus"</string>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index 9bb9e36..f9265d0 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Eduki sakatuta widgeta aukeratzeko."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Sakatu birritan eta eduki sakatuta widgeta aukeratzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Bilatu aplikazioetan"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Aplikazioak kargatzen…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ez da aurkitu \"<xliff:g id="QUERY">%1$s</xliff:g>\" bilaketarekin bat datorren aplikaziorik"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 92f80f4..01390c3 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"برای انتخاب ابزارک لمس کنید و نگه دارید."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"برای انتخاب یک ابزارک، دو ضربه سریع بزنید و نگه‌دارید یا از اقدامات سفارشی استفاده کنید."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"جستجوی برنامه‌ها"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"در حال بارگیری برنامه‌ها..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"هیچ برنامه‌ای مطابق با «<xliff:g id="QUERY">%1$s</xliff:g>» پیدا نشد"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index dd90ddc..eb55bad 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Valitse widget painamalla sitä pitkään."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Valitse widget tai käytä muokattuja toimintoja kaksoisnapauttamalla ja painamalla kohdetta pitkään."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sovellushaku"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Ladataan sovelluksia…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"”<xliff:g id="QUERY">%1$s</xliff:g>” ei palauttanut sovelluksia."</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 1fb2e82..c9ea37c 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Maintenez un doigt sur le widget pour l\'ajouter."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Touchez 2x un widget et maintenez doigt dessus pour l’ajouter ou utiliser des actions personnalisées"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Rechercher des applications"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Chargement des applications en cours..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Aucune application trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 8154c66..0a60378 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"App. de manière prolongée pour sélectionner widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Appuyez 2 fois et maintenez la pression pour sélectionner widget ou utilisez actions personnalisées."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Rechercher dans les applications"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Chargement des applications en cours…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Aucune application ne correspond à la requête \"<xliff:g id="QUERY">%1$s</xliff:g>\"."</string>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index 06d95da..e678b19 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Mantén premido un widget para seleccionalo."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Toca dúas veces e mantén premido para seleccionar un widget ou utiliza accións personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Aplicacións de busca"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicacións..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Non se atoparon aplicacións que coincidan con \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index c5cdad3..8ad0396 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"વિજેટ ચૂંટવા માટે ટચ કરો અને પકડી રાખો."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"વિજેટ ચૂંટવા અથવા કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટેપ કરો અને પકડી રાખો."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"શોધ ઍપ્લિકેશનો"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ઍપ્લિકેશનો લોડ કરી રહ્યું છે…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index ee179c1..a9de815 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"विजेट को चुनने के लिए स्‍पर्श करके रखें."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"कोई विजेट चुनने के लिए डबल टैप करके रखें या कस्‍टम कार्रवाइयां चुनें."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ऐप्‍स खोजें"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ऐप्स लोड हो रहे हैं..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" से मिलान करने वाला कोई ऐप नहीं मिला"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 00bb190..10407d1 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Dodirnite i držite kako biste podigli widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dodirnite dvaput i držite kako biste podigli widget ili pokušajte prilagođenim radnjama."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pretraži aplikacije"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Učitavanje aplikacija…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nema aplikacija podudarnih s upitom \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 775365b..2bf1d27 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Modul felvételéhez érintse meg, és tartsa lenyomva"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Modul mozgatásához koppintson rá duplán és tartsa lenyomva, vagy használjon egyéni műveleteket."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Alkalmazások keresése"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Alkalmazások betöltése…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Egy alkalmazás sem található a(z) „<xliff:g id="QUERY">%1$s</xliff:g>” lekérdezésre."</string>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index 1579614..b9052e5 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Հպեք և պահեք՝ վիջեթն ընտրելու համար:"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Կրկնակի հպեք և պահեք՝ վիջեթ ավելացնելու համար կամ օգտվեք հարմարեցրած գործողություններից:"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Հավելվածների որոնում"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Հավելվածների բեռնում…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"«<xliff:g id="QUERY">%1$s</xliff:g>» հարցմանը համապատասխանող հավելվածներ չեն գտնվել"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 84f91a5..bf55bc3 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Sentuh lama untuk memilih widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Ketuk dua kalip &amp; tahan untuk mengambil widget atau menggunakan tindakan khusus."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Telusuri Apps"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Memuat Aplikasi..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Tidak ditemukan Aplikasi yang cocok dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
index 5937d96..5d5e894 100644
--- a/res/values-is-rIS/strings.xml
+++ b/res/values-is-rIS/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Haltu fingri á græju til að grípa hana."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Ýttu tvisvar og haltu fingri á græju til að grípa hana eða notaðu sérsniðnar aðgerðir."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Leita í forritum"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Hleður forrit…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ekki fundust forrit sem samsvara „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 5db8c1a..a699b9c 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Tocca e tieni premuto per scegliere un widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Tocca due volte e tieni premuto per scegliere un widget o per utilizzare azioni personalizzate."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Cerca app"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Caricamento di app…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nessuna app trovata corrispondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index c9721d8..2c28733 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"גע נגיעה רציפה בווידג\'ט כדי לבחור בו."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"הקש פעמיים וגע נגיעה רציפה בווידג\'ט כדי לבחור בו, או השתמש בפעולות מותאמות אישית."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"חפש אפליקציות"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"טוען אפליקציות…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"לא נמצאו אפליקציות התואמות ל-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 4961433..166ef2d 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ウィジェットを追加するには押し続けます。"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ダブルタップ後に押し続けてウィジェットを選択するか、カスタム操作を使用してください。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$dx%2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"アプリを検索"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"アプリを読み込んでいます…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"「<xliff:g id="QUERY">%1$s</xliff:g>」に一致するアプリは見つかりませんでした"</string>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index cac3b4d..74ab85b 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"შეეხეთ და დააყოვნეთ ვიჯეტის ასარჩევად."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ორმაგად შეეხეთ და გეჭიროთ ვიჯეტის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"აპების ძიება"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"აპები იტვირთება..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"„<xliff:g id="QUERY">%1$s</xliff:g>“-ის თანხვედრი აპები არ მოიძებნა"</string>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
index 68cd6c6..9da9ade 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk-rKZ/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетті таңдау үшін түртіп, мықтап ұстаңыз."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Виджетті таңдау немесе арнаулы әрекеттерді таңдау үшін екі рет түртіп, ұстап тұрыңыз."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Қолданбаларды іздеу"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Қолданбалар жүктелуде…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"«<xliff:g id="QUERY">%1$s</xliff:g>» сұрауына сәйкес келетін қолданбалар жоқ"</string>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
index 87d31d5..8fa9179 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km-rKH/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ប៉ះ &amp; សង្កត់ ដើម្បី​ជ្រើស​ធាតុ​ក្រាហ្វិក។"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ប៉ះពីរដង ហើយចុចឲ្យជាប់ដើម្បីជ្រើសយកធាតុក្រាហ្វិក ឬប្រើសកម្មភាពផ្ទាល់ខ្លួន។"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ស្វែងរកកម្មវិធី"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"កំពុងដំណើរការកម្មវិធី..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"គ្មានកម្មវិធីដែលត្រូវជាមួយ \"<xliff:g id="QUERY">%1$s</xliff:g>\" ទេ"</string>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index eb5e8bd..2401e41 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ವಿಜೆಟ್ ಅನ್ನು ಆರಿಸಿಕೊಳ್ಳಲು ಸ್ಪರ್ಶಿಸಿ &amp; ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ವಿಜೆಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ಅಪ್ಲಿಕೇಷನ್‌ಗಳನ್ನು ಹುಡುಕಿ"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
@@ -70,7 +72,7 @@
     <string name="allow_rotation_title" msgid="7728578836261442095">"ಮುಖಪುಟ ತಿರುಗುವಿಕೆಯನ್ನು ಅನುಮತಿಸಿ"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ಫೋನ್‌ ತಿರುಗಿಸಿದಾಗ"</string>
     <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"ಪ್ರಸ್ತುತ ಪ್ರದರ್ಶನ ಸೆಟ್ಟಿಂಗ್ ತಿರುಗುವಿಕೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
-    <string name="package_state_unknown" msgid="7592128424511031410">"ಅಜ್ಞಾತ"</string>
+    <string name="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>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index bf8e780..06b7014 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"위젯을 선택하려면 길게 터치하세요."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"위젯을 선택하려면 두 번 탭한 다음 길게 터치하거나 맞춤 액션을 사용합니다."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"앱 검색"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"앱 로드 중..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\'<xliff:g id="QUERY">%1$s</xliff:g>\'와(과) 일치하는 앱이 없습니다."</string>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
index 817f8cc..734c7b4 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky-rKG/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетти тандаш үчүн, басып туруңуз"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Виджет тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Колдонмолорду издөө"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Колдонмолор жүктөлүүдө…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" дал келген колдонмолор табылган жок"</string>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
index 8329577..8a26fd6 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo-rLA/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ສຳພັດຄ້າງໄວ້ ເພື່ອຈັບວິດເຈັດ."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ແຕະ​ຄ້າງ​ໄວ້ ເພື່ອ​ເລືອກວິດ​ເຈັດ ຫຼື ໃຊ້​ການ​ດຳ​ເນີນ​ການ​ກຳ​ນົດ​ເອງ."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ຊອກຫາແອັບ"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"​ກຳ​ລັງ​ໂຫລດ​ແອັບ..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"ບໍ່​ພົບ​ແອັບ​ໃດ​ທີ່​ກົງ​ກັນ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 272c559..210062f 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Palieskite ir laikykite, kad pasirinkt. valdiklį."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dukart palieskite ir laikykite, kad pasirinktumėte valdiklį ar naudotumėte tinkintus veiksmus."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Ieškoti programų"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Įkeliamos programos..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nerasta jokių užklausą „<xliff:g id="QUERY">%1$s</xliff:g>“ atitinkančių programų"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index d60682e..40746d6 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Lai izvēlētos logrīku, pieskarieties un turiet to."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Lai atlasītu logrīku, veiciet dubultskārienu uz tā un turiet to vai arī veiciet pielāgotas darbības."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Meklēt lietotnes"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Notiek lietotņu ielāde…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Vaicājumam “<xliff:g id="QUERY">%1$s</xliff:g>” neatbilda neviena lietotne."</string>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
index 7e9abaf..431db0b 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Допри и задржи за да се избере виџетот."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Допрете двапати и задржете за да изберете додаток или да користите приспособени дејства."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Пребарување апликации"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Се вчитуваат апликации…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Не се најдени апликации што одговараат на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index 607db55..43a0fe2 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ഒരു വിജറ്റ് ചേർക്കുന്നതിന് അത് സ്‌പർശിച്ച് പിടിക്കുക."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"വിജറ്റ് തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ രണ്ടുതവണ ടാപ്പുചെയ്ത് പിടിക്കുക."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ആപ്പ്‌സ് തിരയുക"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ആപ്പ്‌സ് ലോഡുചെയ്യുന്നു..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പ്‌സൊന്നും കണ്ടെത്തിയില്ല"</string>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
index 600b5fc..df1d7b8 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn-rMN/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетийг авах бол хүрээд барина уу."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Жижиг хэрэгсэл авах болон тохируулсан үйлдлийг ашиглахын тулд 2 удаа товшоод барина уу."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Апп хайх"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Аппликейшныг ачаалж байна..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"-д нийцэх апп олдсонгүй"</string>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index b680fea..69e20be 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"विजेट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"एक विजेट निवडण्यासाठी दोनदा टॅप करा आणि धरून ठेवा किंवा सानुकूल क्रिया वापरा."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"अॅप्स शोधा"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"अॅप्स लोड करीत आहे..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"</string>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index 6a2b104..eb80ff9 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Sentuh &amp; tahan untuk mengambil widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Ketik dua kali &amp; tahan untuk mengambil widget atau menggunakan tindakan tersuai"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Cari Apl"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Memuatkan Apl…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Tiada Apl yang ditemui sepadan dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index 6d3003a..7c978ab 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ဝဒ်ဂျက်တစ်ခုကို ကောက်ယူရန် ဖိနှိပ်ထားပါ"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ဝစ်ဂျက်တစ်ခုကိုရယူရန် သို့မဟုတ် စိတ်ကြိုက်လုပ်ဆောင်မှုများကို အသုံးပြုရန် နှစ်ချက်တို့ပြီး ကိုင်ထားပါ။"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ရှာဖွေမှု အက်ပ်များ"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"အက်ပ်များ ရယူနေစဉ်..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" နှင့်ကိုက်ညီသည့် အပ်ဖ်များမတွေ့ပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 16f22ea..ceb2091 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Trykk og hold inne for å plukke opp en modul."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dobbelttrykk og hold inne for å velge en modul eller bruke tilpassede handlinger."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Søk i apper"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Laster inn apper …"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Fant ingen apper som samsvarer med «<xliff:g id="QUERY">%1$s</xliff:g>»"</string>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index 61d054f..4343223 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"एउटा विजेटलाई टिप्नको लागि टच गरेर होल्ड गर्नुहोस्।"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"विजेटलाई छान्न वा अनुकूलन कार्यहरू प्रयोग गर्न डबल ट्याप गरी होल्ड गर्नुहोस्।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"अनुप्रयोगहरू खोज्नुहोस्"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"अनुप्रयोगहरू लोड गरिँदै..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" सँग मिल्दो कुनै अनुप्रयोगहरू फेला परेनन्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 24ee20d..64c02b2 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Blijf aanraken om een widget toe te voegen."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dubbeltik en blijf aanraken om een widget toe te voegen of aangepaste acties te gebruiken."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Apps zoeken"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Apps laden…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Er zijn geen apps gevonden die overeenkomen met \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
index e41e46c..b5c69e1 100644
--- a/res/values-pa-rIN/strings.xml
+++ b/res/values-pa-rIN/strings.xml
@@ -30,6 +30,8 @@
     <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="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ਐਪਸ ਖੋਜੋ"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ਐਪਾਂ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ਨਾਲ ਮਿਲਦੀਆਂ ਕੋਈ ਵੀ ਐਪਾਂ ਨਹੀਂ ਮਿਲੀਆਂ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index a230856..5b39faf 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Aby dodać widżet, kliknij go i przytrzymaj."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Kliknij dwukrotnie i przytrzymaj, by wybrać widżet lub użyć działań niestandardowych."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Szukaj w aplikacjach"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Wczytuję aplikacje…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nie znaleziono aplikacji pasujących do zapytania „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index d1e37c1..cda63ee 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Prima sem soltar para escolher um widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Toque duas vezes sem soltar para escolher um widget ou utilize ações personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pesquisar aplicações"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"A carregar aplicações..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Não foram encontradas aplic. que correspondam a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index ac0c828..6f3e0a0 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Toque e pressione para selecionar um widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Toque duas vezes e segure para selecionar um widget ou usar ações personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pesquisar apps"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Carregando apps…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nenhum app encontrado que corresponda a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 22a2e4e..f2c55eb 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Atingeți lung un widget pentru a-l alege."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Atingeți de două ori și mențineți apăsat ca să alegeți un widget sau folosiți acțiuni personalizate."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Căutați aplicații"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Se încarcă aplicațiile..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nu s-a găsit nicio aplicație pentru „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 73bbbf8..d1dfea1 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Чтобы выбрать виджет, нажмите на значок и удерживайте его."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Чтобы выбрать виджет, нажмите на него дважды и не отпускайте или выполните предложенные действия."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Поиск приложений"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Загрузка…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"По запросу \"<xliff:g id="QUERY">%1$s</xliff:g>\" ничего не найдено"</string>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index 82bb226..a91e267 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"විජට් එක ස්පර්ශ කර අහුලා ගැනීමට අල්ලාගෙන සිටින්න."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"විජට් එකක් අහුලා ගැනීමට හෝ අභිරුචි ක්‍රියා කිරීමට ඩබල් ටැප් කර අල්ලා ගෙන සිටින්න."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"යෙදුම් සෙවීම"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"යෙදුම් පූරණය වෙමින්…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" සමග ගැළපෙන යෙදුම් හමු නොවිණි"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 4e541ce..7d6b5c2 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Miniaplikáciu pridáte stlačením a podržaním."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Miniaplikáciu pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Hľadať aplikácie"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Načítavajú sa aplikácie..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nenašli sa žiadne aplikácie zodpovedajúce dopytu <xliff:g id="QUERY">%1$s</xliff:g>"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index c8693b8..c3e1cbd 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Za izbiro pripomočka se ga dotaknite in pridržite."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Če želite izbrati pripomoček ali uporabiti dejanja po meri, se ga dvakrat dotaknite in ga pridržite."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Iskanje po aplikacijah"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Nalaganje aplikacij …"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ni aplikacij, ki bi ustrezale poizvedbi »<xliff:g id="QUERY">%1$s</xliff:g>«"</string>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
index caa65b2..fbf08c5 100644
--- a/res/values-sq-rAL/strings.xml
+++ b/res/values-sq-rAL/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Prek dhe mbaj shtypur për të zgjedhur një miniaplikacion."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Prek dy herë dhe mbaj shtypur për të zgjedhur një miniaplikacion ose për të përdorur veprimet e personalizuara."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Kërko për aplikacione"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Po ngarkon aplikacionet..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nuk u gjet asnjë aplikacion që përputhet me \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 856f647..e1dba80 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Додирните и задржите да бисте изабрали виџет."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Двапут додирните и задржите да бисте изабрали виџет или користите прилагођене радње."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Претражите апликације"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Апликације се учитавају..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Није пронађена ниједна апликација за „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 1d405ba..6b7d9dc 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Tryck länge om du vill flytta en widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Tryck två gånger och håll kvar om du vill ta upp en widget eller använda anpassade åtgärder."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sök efter appar"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Läser in appar …"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Det gick inte att hitta några appar som matchar <xliff:g id="QUERY">%1$s</xliff:g>"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 0e7b768..b5fa1cf 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Gusa na ushikilie ili kuteua wijeti."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Gonga mara mbili na ushikilie ile uchague wijeti au utumie vitendo maalum."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Tafuta Programu"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Inapakia Programu..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Haikupata programu zinazolingana na \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index 87081aa..4b43e21 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"விட்ஜெட்டைத் தேர்வுசெய்ய தொட்டுப் பிடிக்கவும்."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"விட்ஜெட்டைத் தேர்ந்தெடுக்க இருமுறை தட்டிப் பிடிக்கவும் அல்லது தனிப்பயன் செயல்களைப் பயன்படுத்தவும்."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"பயன்பாடுகளில் தேடுக"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"பயன்பாடுகளை ஏற்றுகிறது..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை"</string>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index 2fda6a5..09d2525 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"విడ్జెట్‌ను ఎంచుకోవడానికి తాకి &amp; నొక్కి పెట్టండి."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"విడ్జెట్‌ను ఎంచుకోవడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కి, ఉంచండి."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"అనువర్తనాలను శోధించండి"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"అనువర్తనాలను లోడ్ చేస్తోంది…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"కి సరిపోలే అనువర్తనాలేవీ కనుగొనబడలేదు"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 8ad5a7c..b847f75 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"แตะค้างเพื่อรับวิดเจ็ต"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"แตะ 2 ครั้งค้างไว้เพื่อเลือกวิดเจ็ตหรือใช้การกระทำที่กำหนดเอง"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ค้นหาแอป"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"กำลังโหลดแอป…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"ไม่พบแอปที่ตรงกับ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 922cb53..8f251af 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Pindutin nang matagal upang kumuha ng widget."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"I-double tap nang matagal upang pumili ng widget o gumamit ng mga custom na pagkilos."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Mga App sa Paghahanap"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Nilo-load ang Mga App…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Walang nakitang Mga App na tumutugma sa \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 08d5d52..c91b3dc 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Widget seçmek için dokunun ve basılı tutun."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Bir widget\'ı seçmek veya özel işlemleri kullanmak için iki kez hafifçe dokunun ve basılı tutun."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Uygulamalarda Ara"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Uygulamalar Yükleniyor…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ile eşleşen uygulama bulunamadı"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index c24e02a..700775f 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Натисніть і утримуйте, щоб вибрати віджет."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Двічі натисніть і утримуйте, щоб вибрати віджет, або виконайте іншу дію."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Пошук додатків"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Завантаження додатків…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Немає додатків для запиту \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
index 5ed9ddb..c325783 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur-rPK/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"کوئی ویجیٹ منتخب کرنے کیلئے ٹچ کریں اور پکڑے رہیں۔"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"کوئی ویجٹ منتخب کرنے یا حسب ضرورت کاروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور پکڑے رکھیں۔"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ایپس تلاش کریں"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"ایپس لوڈ ہو رہی ہیں…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" سے مماثل کوئی ایپس نہیں ملیں"</string>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index a58b57c..4ffd90c 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Vidjetni tanlash uchun bosib turing."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Ikki marta bosib va bosib turgan holatda vidjetni tanlang yoki maxsus amaldan foydalaning."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Ilovalar ichidan qidirish"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Ilovalar yuklanmoqda…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"“<xliff:g id="QUERY">%1$s</xliff:g>” so‘rovi bo‘yicha hech narsa topilmadi"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 8440060..e744793 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Chạm và giữ để chọn tiện ích con."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Nhấn đúp và giữ để chọn tiện ích hoặc sử dụng tác vụ tùy chỉnh."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Tìm kiếm ứng dụng"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Đang tải ứng dụng..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Không tìm thấy ứng dụng nào phù hợp với \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index e487225..ddd93cf 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"触摸并按住小部件即可选择。"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"点按两次并按住小部件即可选择小部件,您也可以使用自定义操作。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"搜索应用"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"正在加载应用…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"未找到与“<xliff:g id="QUERY">%1$s</xliff:g>”相符的应用"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 7b96d658..2733d7f 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"輕觸並按住小工具即可選取。"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"連扲兩下,然後扲住,就可以新增小工具,或者執行自訂操作。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"搜尋應用程式"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"正在載入應用程式…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"無法找到與「<xliff:g id="QUERY">%1$s</xliff:g>」相符的應用程式"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index cf7a86a..5bb9ab9 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"輕觸並按住小工具即可選取。"</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"輕觸兩下並按住小工具即可選取,您也可以使用自訂動作。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"搜尋應用程式"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"正在載入應用程式…"</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"找不到符合「<xliff:g id="QUERY">%1$s</xliff:g>」的應用程式"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 06cfa20..3d62400 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -30,6 +30,8 @@
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Thinta uphinde ubambe ukuze uphakamise iwijethi."</string>
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Thepha kabili bese uyabamba ukuze uthathe iwijethi noma sebenzisa izenzo ezingokwezifiso."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <!-- no translation found for widget_accessible_dims_format (3640149169885301790) -->
+    <skip />
     <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sesha Izinhlelo Zokusebenza"</string>
     <string name="all_apps_loading_message" msgid="7557140873644765180">"Ilayisha izinhlelo zokusebenza..."</string>
     <string name="all_apps_no_search_results" msgid="6332185285860416787">"Azikho izinhlelo zokusebenza ezitholakele ezifana ne-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 3cfaf02..3423835 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -25,7 +25,8 @@
         <attr name="iconDisplay" format="integer">
             <enum name="workspace" value="0" />
             <enum name="all_apps" value="1" />
-            <enum name="widget_section" value="2" />
+            <enum name="folder" value="2" />
+            <enum name="widget_section" value="3" />
         </attr>
         <attr name="deferShadowGeneration" format="boolean" />
         <attr name="customShadows" format="boolean" />
diff --git a/res/values/config.xml b/res/values/config.xml
index 94f02f9..2347f66 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -9,6 +9,10 @@
     <bool name="is_large_tablet">false</bool>
     <bool name="allow_rotation">false</bool>
 
+    <!-- A string pointer to the original app name string. This allows derived projects to
+     easily override the app name without providing all translations -->
+    <string name="derived_app_name" translatable="false">@string/app_name</string>
+
 <!-- DragController -->
     <item type="id" name="drag_event_parity" />
 
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 1ae4685..33466a8 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -137,6 +137,12 @@
     <dimen name="folder_preview_padding">6dp</dimen>
     <dimen name="page_indicator_dot_size">8dp</dimen>
 
+    <dimen name="folder_cell_x_padding">9dp</dimen>
+    <dimen name="folder_cell_y_padding">8dp</dimen>
+    <dimen name="folder_child_text_size">13sp</dimen>
+    <dimen name="folder_label_padding">12dp</dimen>
+    <dimen name="folder_label_text_size">14sp</dimen>
+
 <!-- Sizes for managed profile badges -->
     <dimen name="profile_badge_size">24dp</dimen>
     <dimen name="profile_badge_margin">5dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d11d5a5..60a37e5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -46,6 +46,8 @@
     <!-- The format string for the dimensions of a widget in the drawer -->
     <!-- There is a special version of this format string for Farsi -->
     <string name="widget_dims_format">%1$d \u00d7 %2$d</string>
+    <!-- Accessibility spoken message format for the dimensions of a widget in the drawer -->
+    <string name="widget_accessible_dims_format">%1$d wide by %2$d high</string>
 
     <!-- All Apps -->
     <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index f029765..ecc11b0 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -74,7 +74,11 @@
         <item name="android:background">@null</item>
         <item name="android:textColor">@color/quantum_panel_text_color</item>
         <item name="android:shadowRadius">0</item>
+        <item name="android:textSize">@dimen/folder_child_text_size</item>
+        <item name="android:gravity">center</item>
+        <item name="android:includeFontPadding">false</item>
         <item name="customShadows">false</item>
+        <item name="iconDisplay">folder</item>
     </style>
 
     <style name="Icon.DeepShortcut">
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index e0694f3..4c4d67c 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -62,7 +62,7 @@
      */
     int isDisabled = ShortcutInfo.DEFAULT;
 
-    AppInfo() {
+    public AppInfo() {
         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
     }
 
@@ -125,11 +125,8 @@
     }
 
     @Override
-    public String toString() {
-        return "ApplicationInfo(title=" + title + " id=" + this.id
-                + " type=" + this.itemType + " container=" + this.container
-                + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY
-                + " spanX=" + spanX + " spanY=" + spanY + " user=" + user + ")";
+    protected String dumpProperties() {
+        return super.dumpProperties() + " componentName=" + componentName;
     }
 
     /**
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 0d5043b..d5309b4 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -316,7 +316,7 @@
         parsers.put(TAG_APP_ICON, new AppShortcutParser());
         parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
         parsers.put(TAG_FOLDER, new FolderParser());
-        parsers.put(TAG_APPWIDGET, new AppWidgetParser());
+        parsers.put(TAG_APPWIDGET, new PendingWidgetParser());
         parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
         return parsers;
     }
@@ -459,8 +459,12 @@
     /**
      * AppWidget parser: Required attributes packageName, className, spanX and spanY.
      * Options child nodes: <extra key=... value=... />
+     * It adds a pending widget which allows the widget to come later. If there are extras, those
+     * are passed to widget options during bind.
+     * The config activity for the widget (if present) is not shown, so any optional configurations
+     * should be passed as extras and the widget should support reading these widget options.
      */
-    protected class AppWidgetParser implements TagParser {
+    protected class PendingWidgetParser implements TagParser {
 
         @Override
         public long parseAndAdd(XmlResourceParser parser)
@@ -468,27 +472,13 @@
             final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
             final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
             if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) {
-                if (LOGD) Log.d(TAG, "Skipping invalid <favorite> with no component");
+                if (LOGD) Log.d(TAG, "Skipping invalid <appwidget> with no component");
                 return -1;
             }
 
-            ComponentName cn = new ComponentName(packageName, className);
-            try {
-                mPackageManager.getReceiverInfo(cn, 0);
-            } catch (Exception e) {
-                String[] packages = mPackageManager.currentToCanonicalPackageNames(
-                        new String[] { packageName });
-                cn = new ComponentName(packages[0], className);
-                try {
-                    mPackageManager.getReceiverInfo(cn, 0);
-                } catch (Exception e1) {
-                    if (LOGD) Log.d(TAG, "Can't find widget provider: " + className);
-                    return -1;
-                }
-            }
-
             mValues.put(Favorites.SPANX, getAttributeValue(parser, ATTR_SPAN_X));
             mValues.put(Favorites.SPANY, getAttributeValue(parser, ATTR_SPAN_Y));
+            mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
 
             // Read the extras
             Bundle extras = new Bundle();
@@ -513,38 +503,26 @@
                 }
             }
 
-            final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
-            long insertedId = -1;
-            try {
-                int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+            return verifyAndInsert(new ComponentName(packageName, className), extras);
+        }
 
-                if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn)) {
-                    if (LOGD) Log.e(TAG, "Unable to bind app widget id " + cn);
-                    return -1;
-                }
-
-                mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
-                mValues.put(Favorites.APPWIDGET_ID, appWidgetId);
-                mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString());
-                mValues.put(Favorites._ID, mCallback.generateNewItemId());
-                insertedId = mCallback.insertAndCheck(mDb, mValues);
-                if (insertedId < 0) {
-                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
-                    return insertedId;
-                }
-
-                // Send a broadcast to configure the widget
-                if (!extras.isEmpty()) {
-                    Intent intent = new Intent(ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE);
-                    intent.setComponent(cn);
-                    intent.putExtras(extras);
-                    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
-                    mContext.sendBroadcast(intent);
-                }
-            } catch (RuntimeException ex) {
-                if (LOGD) Log.e(TAG, "Problem allocating appWidgetId", ex);
+        protected long verifyAndInsert(ComponentName cn, Bundle extras) {
+            mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString());
+            mValues.put(Favorites.RESTORED,
+                    LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
+                            LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY |
+                            LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG);
+            mValues.put(Favorites._ID, mCallback.generateNewItemId());
+            if (!extras.isEmpty()) {
+                mValues.put(Favorites.INTENT, new Intent().putExtras(extras).toUri(0));
             }
-            return insertedId;
+
+            long insertedId = mCallback.insertAndCheck(mDb, mValues);
+            if (insertedId < 0) {
+                return -1;
+            } else {
+                return insertedId;
+            }
         }
     }
 
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 33b3ad3..a294fa5 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -65,6 +65,7 @@
 
     private static final int DISPLAY_WORKSPACE = 0;
     private static final int DISPLAY_ALL_APPS = 1;
+    private static final int DISPLAY_FOLDER = 2;
 
     private final Launcher mLauncher;
     private Drawable mIcon;
@@ -125,12 +126,13 @@
             setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
             setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
             defaultIconSize = grid.allAppsIconSizePx;
+        } else if (display == DISPLAY_FOLDER) {
+            setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
         }
         mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
 
         mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
                 defaultIconSize);
-
         a.recycle();
 
         if (mCustomShadowsEnabled) {
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 0f6073e..cf8abae 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -43,6 +43,7 @@
 
 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.util.Thunk;
 
@@ -199,8 +200,8 @@
     }
 
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
-        mActive = supportsDrop(source, info);
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+        mActive = supportsDrop(dragObject.dragSource, dragObject.dragInfo);
         mDrawable.setColorFilter(null);
         if (mCurrentColorAnim != null) {
             mCurrentColorAnim.cancel();
@@ -209,6 +210,9 @@
         setTextColor(mOriginalTextColor);
         (mHideParentOnDisable ? ((ViewGroup) getParent()) : this)
                 .setVisibility(mActive ? View.VISIBLE : View.GONE);
+
+        mAccessibleDrag = options.isAccessibleDrag;
+        setOnClickListener(mAccessibleDrag ? this : null);
     }
 
     @Override
@@ -227,6 +231,7 @@
     @Override
     public void onDragEnd() {
         mActive = false;
+        setOnClickListener(null);
     }
 
     /**
@@ -254,7 +259,8 @@
             }
         };
         dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
-                DRAG_VIEW_DROP_DURATION, new DecelerateInterpolator(2),
+                mLauncher.getDragController().isExternalDrag() ? 1 : DRAG_VIEW_DROP_DURATION,
+                new DecelerateInterpolator(2),
                 new LinearInterpolator(), onAnimationEndRunnable,
                 DragLayer.ANIMATION_END_DISAPPEAR, null);
     }
@@ -308,11 +314,6 @@
         return to;
     }
 
-    public void enableAccessibleDrag(boolean enable) {
-        mAccessibleDrag = enable;
-        setOnClickListener(enable ? this : null);
-    }
-
     @Override
     public void onClick(View v) {
         mLauncher.getAccessibilityDelegate().handleAccessibleDrop(this, null, null);
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 77f6612..6714d9f 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -54,6 +54,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.util.CellAndSpan;
 import com.android.launcher3.util.GridOccupancy;
 import com.android.launcher3.util.ParcelableSparseArray;
@@ -235,6 +236,7 @@
         for (int i = 0; i < mDragOutlines.length; i++) {
             mDragOutlines[i] = new Rect(-1, -1, -1, -1);
         }
+        mDragOutlinePaint.setColor(getResources().getColor(R.color.outline_color));
 
         // When dragging things around the home screens, we show a green outline of
         // where the item will land. The outlines gradually fade out, leaving a trail
@@ -1047,15 +1049,16 @@
         return false;
     }
 
-    void visualizeDropLocation(View v, Bitmap dragOutline, int cellX, int cellY, int spanX,
-            int spanY, boolean resize, DropTarget.DragObject dragObject) {
+    void visualizeDropLocation(View v, DragPreviewProvider outlineProvider, int cellX, int cellY,
+            int spanX, int spanY, boolean resize, DropTarget.DragObject dragObject) {
         final int oldDragCellX = mDragCell[0];
         final int oldDragCellY = mDragCell[1];
 
-        if (dragOutline == null && v == null) {
+        if (outlineProvider == null || outlineProvider.gerenatedDragOutline == null) {
             return;
         }
 
+        Bitmap dragOutline = outlineProvider.gerenatedDragOutline;
         if (cellX != oldDragCellX || cellY != oldDragCellY) {
             Point dragOffset = dragObject.dragView.getDragVisualizeOffset();
             Rect dragRegion = dragObject.dragView.getDragRegion();
@@ -1354,12 +1357,9 @@
                 // and that passed in.
                 int curDirectionScore = direction[0] * curDirection[0] +
                         direction[1] * curDirection[1];
-                boolean exactDirectionOnly = false;
-                boolean directionMatches = direction[0] == curDirection[0] &&
-                        direction[0] == curDirection[0];
-                if ((directionMatches || !exactDirectionOnly) &&
-                        Float.compare(distance,  bestDistance) < 0 || (Float.compare(distance,
-                        bestDistance) == 0 && curDirectionScore > bestDirectionScore)) {
+                if (Float.compare(distance,  bestDistance) < 0 ||
+                        (Float.compare(distance, bestDistance) == 0
+                                && curDirectionScore > bestDirectionScore)) {
                     bestDistance = distance;
                     bestDirectionScore = curDirectionScore;
                     bestXY[0] = x;
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index e6f34d9..ef28d1e 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -1,6 +1,8 @@
 package com.android.launcher3;
 
 import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -9,6 +11,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -42,6 +45,10 @@
     private static final String ATTR_SCREEN = "screen";
     private static final String ATTR_FOLDER_ITEMS = "folderItems";
 
+    // TODO: Remove support for this broadcast, instead use widget options to send bind time options
+    private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
+            "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
+
     public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
             LayoutParserCallback callback, Resources sourceRes, int layoutId) {
         super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES);
@@ -270,4 +277,61 @@
             return super.parseAndAdd(parser);
         }
     }
+
+
+    /**
+     * AppWidget parser which enforces that the app is already installed when the layout is parsed.
+     */
+    protected class AppWidgetParser extends PendingWidgetParser {
+
+        @Override
+        protected long verifyAndInsert(ComponentName cn, Bundle extras) {
+            try {
+                mPackageManager.getReceiverInfo(cn, 0);
+            } catch (Exception e) {
+                String[] packages = mPackageManager.currentToCanonicalPackageNames(
+                        new String[] { cn.getPackageName() });
+                cn = new ComponentName(packages[0], cn.getClassName());
+                try {
+                    mPackageManager.getReceiverInfo(cn, 0);
+                } catch (Exception e1) {
+                    Log.d(TAG, "Can't find widget provider: " + cn.getClassName());
+                    return -1;
+                }
+            }
+
+            final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
+            long insertedId = -1;
+            try {
+                int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+
+                if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn)) {
+                    Log.e(TAG, "Unable to bind app widget id " + cn);
+                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                    return -1;
+                }
+
+                mValues.put(Favorites.APPWIDGET_ID, appWidgetId);
+                mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString());
+                mValues.put(Favorites._ID, mCallback.generateNewItemId());
+                insertedId = mCallback.insertAndCheck(mDb, mValues);
+                if (insertedId < 0) {
+                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                    return insertedId;
+                }
+
+                // Send a broadcast to configure the widget
+                if (!extras.isEmpty()) {
+                    Intent intent = new Intent(ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE);
+                    intent.setComponent(cn);
+                    intent.putExtras(extras);
+                    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+                    mContext.sendBroadcast(intent);
+                }
+            } catch (RuntimeException ex) {
+                Log.e(TAG, "Problem allocating appWidgetId", ex);
+            }
+            return insertedId;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index f24e00b..705f841 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -25,6 +25,7 @@
 import android.view.animation.AnimationUtils;
 
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.util.FlingAnimation;
 import com.android.launcher3.util.Thunk;
@@ -49,9 +50,9 @@
     }
 
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
-        super.onDragStart(source, info, dragAction);
-        setTextBasedOnDragSource(source);
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+        super.onDragStart(dragObject, options);
+        setTextBasedOnDragSource(dragObject.dragSource);
     }
 
     /** @return true for items that should have a "Remove" action in accessibility. */
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c9fd85a..c4e6ed1 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -20,8 +20,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.Paint;
-import android.graphics.Paint.FontMetrics;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
@@ -100,6 +98,7 @@
     public int folderIconPreviewPadding;
     public int folderCellWidthPx;
     public int folderCellHeightPx;
+    public int folderChildDrawablePaddingPx;
 
     // Hotseat
     public int hotseatCellWidthPx;
@@ -255,12 +254,9 @@
         allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
         allAppsIconTextSizePx = iconTextSizePx;
 
-        // Calculate the actual text height
-        Paint textPaint = new Paint();
-        textPaint.setTextSize(iconTextSizePx);
-        FontMetrics fm = textPaint.getFontMetrics();
         cellWidthPx = iconSizePx;
-        cellHeightPx = iconSizePx + iconDrawablePaddingPx + (int) Math.ceil(fm.bottom - fm.top);
+        cellHeightPx = iconSizePx + iconDrawablePaddingPx
+                + Utilities.calculateTextHeight(iconTextSizePx);
         final float scaleDps = !FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND ? 0f
                 : res.getDimensionPixelSize(R.dimen.dragViewScale);
         dragViewScale = (iconSizePx + scaleDps) / iconSizePx;
@@ -281,12 +277,25 @@
                     res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
         }
 
-        // Folder
-        int folderCellPadding = isTablet || isLandscape ? 6 * edgeMarginPx : 3 * edgeMarginPx;
+        // Folder cell
+        int cellPaddingX = res.getDimensionPixelSize(R.dimen.folder_cell_x_padding);
+        int cellPaddingY = res.getDimensionPixelSize(R.dimen.folder_cell_y_padding);
+        final int folderChildTextSize =
+                Utilities.calculateTextHeight(res.getDimension(R.dimen.folder_child_text_size));
+
+        final int folderBottomPanelSize =
+                2 * res.getDimensionPixelSize(R.dimen.folder_label_padding)
+                + Utilities.calculateTextHeight(res.getDimension(R.dimen.folder_label_text_size));
+
         // Don't let the folder get too close to the edges of the screen.
-        folderCellWidthPx = Math.min(cellWidthPx + folderCellPadding,
+        folderCellWidthPx = Math.min(iconSizePx + 2 * cellPaddingX,
                 (availableWidthPx - 4 * edgeMarginPx) / inv.numFolderColumns);
-        folderCellHeightPx = cellHeightPx + edgeMarginPx;
+        folderCellHeightPx = Math.min(iconSizePx + 3 * cellPaddingY + folderChildTextSize,
+                (availableHeightPx - 4 * edgeMarginPx - folderBottomPanelSize) / inv.numFolderRows);
+        folderChildDrawablePaddingPx = Math.max(0,
+                (folderCellHeightPx - iconSizePx - folderChildTextSize) / 3);
+
+        // Folder icon
         folderBackgroundOffset = -edgeMarginPx;
         folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset;
         folderIconPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
@@ -296,9 +305,6 @@
         mInsets.set(insets);
     }
 
-    /**
-     * @param recyclerViewWidth the available width of the AllAppsRecyclerView
-     */
     public void updateAppsViewNumCols() {
         allAppsNumCols = allAppsNumPredictiveCols = inv.numColumns;
     }
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index 5966af5..42bab47 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -27,6 +27,7 @@
 import android.widget.LinearLayout;
 
 import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.dragndrop.DragOptions;
 
 /*
  * The top bar containing various drop targets: Delete/App Info/Uninstall.
@@ -120,17 +121,11 @@
         }
     }
 
-    public void enableAccessibleDrag(boolean enable) {
-        mDeleteDropTarget.enableAccessibleDrag(enable);
-        mAppInfoDropTarget.enableAccessibleDrag(enable);
-        mUninstallDropTarget.enableAccessibleDrag(enable);
-    }
-
     /*
      * DragController.DragListener implementation
      */
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
         animateToVisibility(true);
     }
 
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index bf4551b..c06f727 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -19,6 +19,7 @@
 import android.util.AttributeSet;
 import android.view.DragEvent;
 import android.view.KeyEvent;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 
 
@@ -27,6 +28,8 @@
  */
 public class ExtendedEditText extends EditText {
 
+    private boolean mShowImeAfterFirstLayout;
+
     /**
      * Implemented by listeners of the back key.
      */
@@ -37,10 +40,12 @@
     private OnBackKeyListener mBackKeyListener;
 
     public ExtendedEditText(Context context) {
+        // ctor chaining breaks the touch handling
         super(context);
     }
 
     public ExtendedEditText(Context context, AttributeSet attrs) {
+        // ctor chaining breaks the touch handling
         super(context, attrs);
     }
 
@@ -69,4 +74,29 @@
         // We don't want this view to interfere with Launcher own drag and drop.
         return false;
     }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (mShowImeAfterFirstLayout) {
+            // soft input only shows one frame after the layout of the EditText happens,
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    showSoftInput();
+                    mShowImeAfterFirstLayout = false;
+                }
+            });
+        }
+    }
+
+    public void showKeyboard() {
+        mShowImeAfterFirstLayout = !showSoftInput();
+    }
+
+    private boolean showSoftInput() {
+        return requestFocus() &&
+                ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE))
+                    .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
+    }
 }
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 9a99852..c0a8caa 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -126,14 +126,6 @@
         public void onItemsChanged(boolean animate);
     }
 
-    @Override
-    public String toString() {
-        return "FolderInfo(id=" + this.id + " type=" + this.itemType
-                + " container=" + this.container + " screen=" + screenId
-                + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
-                + " spanY=" + spanY + ")";
-    }
-
     public boolean hasOption(int optionFlag) {
         return (options & optionFlag) != 0;
     }
diff --git a/src/com/android/launcher3/HolographicOutlineHelper.java b/src/com/android/launcher3/HolographicOutlineHelper.java
index 427acea..9dec7d9 100644
--- a/src/com/android/launcher3/HolographicOutlineHelper.java
+++ b/src/com/android/launcher3/HolographicOutlineHelper.java
@@ -29,6 +29,10 @@
 import android.graphics.drawable.Drawable;
 import android.util.SparseArray;
 
+import com.android.launcher3.config.ProviderConfig;
+
+import java.nio.ByteBuffer;
+
 /**
  * Utility class to generate shadow and outline effect, which are used for click feedback
  * and drag-n-drop respectively.
@@ -79,50 +83,53 @@
      * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
      * bitmap.
      */
-    public void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
-            int outlineColor) {
-        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true);
+    public void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas) {
+        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, true);
     }
 
-    void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
-            int outlineColor, boolean clipAlpha) {
+    public void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas,
+            boolean clipAlpha) {
+        if (ProviderConfig.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
         if (clipAlpha) {
-            int[] srcBuffer = new int[srcDst.getWidth() * srcDst.getHeight()];
-            srcDst.getPixels(srcBuffer,
-                    0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
-            for (int i = 0; i < srcBuffer.length; i++) {
-                final int alpha = srcBuffer[i] >>> 24;
-                if (alpha < 188) {
-                    srcBuffer[i] = 0;
+            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;
                 }
             }
-            srcDst.setPixels(srcBuffer,
-                    0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
+
+            buffer.rewind();
+            srcDst.copyPixelsFromBuffer(buffer);
         }
-        Bitmap glowShape = srcDst.extractAlpha();
 
         // calculate the outer blur first
         mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter);
         int[] outerBlurOffset = new int[2];
-        Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset);
+        Bitmap thickOuterBlur = srcDst.extractAlpha(mBlurPaint, outerBlurOffset);
 
         mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter);
         int[] brightOutlineOffset = new int[2];
-        Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset);
+        Bitmap brightOutline = srcDst.extractAlpha(mBlurPaint, brightOutlineOffset);
 
         // calculate the inner blur
-        srcDstCanvas.setBitmap(glowShape);
+        srcDstCanvas.setBitmap(srcDst);
         srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
         mBlurPaint.setMaskFilter(mMediumInnerBlurMaskFilter);
         int[] thickInnerBlurOffset = new int[2];
-        Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset);
+        Bitmap thickInnerBlur = srcDst.extractAlpha(mBlurPaint, thickInnerBlurOffset);
 
         // mask out the inner blur
         srcDstCanvas.setBitmap(thickInnerBlur);
-        srcDstCanvas.drawBitmap(glowShape, -thickInnerBlurOffset[0],
+        srcDstCanvas.drawBitmap(srcDst, -thickInnerBlurOffset[0],
                 -thickInnerBlurOffset[1], mErasePaint);
         srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(),
                 mErasePaint);
@@ -132,14 +139,12 @@
         // draw the inner and outer blur
         srcDstCanvas.setBitmap(srcDst);
         srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
-        mDrawPaint.setColor(color);
         srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
                 mDrawPaint);
         srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
                 mDrawPaint);
 
         // draw the bright outline
-        mDrawPaint.setColor(outlineColor);
         srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
                 mDrawPaint);
 
@@ -148,7 +153,6 @@
         brightOutline.recycle();
         thickOuterBlur.recycle();
         thickInnerBlur.recycle();
-        glowShape.recycle();
     }
 
     Bitmap createMediumDropShadow(BubbleTextView view) {
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index c738480..f9424d4 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -25,6 +25,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.support.v4.content.ContextCompat;
 import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -69,7 +70,7 @@
         mLauncher = (Launcher) context;
         mHasVerticalHotseat = mLauncher.getDeviceProfile().isVerticalBarLayout();
         mBackgroundColor = ColorUtils.setAlphaComponent(
-                context.getColor(R.color.all_apps_container_color), 0);
+                ContextCompat.getColor(context, R.color.all_apps_container_color), 0);
         mBackground = new ColorDrawable(mBackgroundColor);
         setBackground(mBackground);
     }
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index a49162c..d3fb38e 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -853,8 +853,7 @@
         values.put(IconDB.COLUMN_ICON_LOW_RES, Utilities.flattenBitmap(lowResIcon));
 
         values.put(IconDB.COLUMN_LABEL, label);
-        values.put(IconDB.COLUMN_SYSTEM_STATE,
-                mIconProvider.getIconSystemState(mIconProvider.getIconSystemState(packageName)));
+        values.put(IconDB.COLUMN_SYSTEM_STATE, mIconProvider.getIconSystemState(packageName));
 
         return values;
     }
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index e136bcd..398c9d2 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -100,6 +100,7 @@
                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1;
         return developmentSettingsEnabled
                 && (info instanceof AppInfo || info instanceof ShortcutInfo
-                || info instanceof PendingAddItemInfo || info instanceof LauncherAppWidgetInfo);
+                || info instanceof PendingAddItemInfo || info instanceof LauncherAppWidgetInfo)
+                && info.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
     }
 }
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index df87cc2..d8e58d8 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Thunk;
 
 import org.json.JSONException;
@@ -146,6 +147,15 @@
         }
         PendingInstallShortcutInfo info = createPendingInfo(context, data);
         if (info != null) {
+            if (!info.isLauncherActivity()) {
+                // Since its a custom shortcut, verify that it is safe to launch.
+                if (!PackageManagerHelper.hasPermissionForActivity(
+                        context, info.launchIntent, null)) {
+                    // Target cannot be launched, or requires some special permission to launch
+                    Log.e(TAG, "Ignoring malicious intent " + info.launchIntent.toUri(0));
+                    return;
+                }
+            }
             queuePendingShortcutInfo(info, context);
         }
     }
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 2a94e55..c0c22a3 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -189,10 +189,24 @@
     }
 
     @Override
-    public String toString() {
-        return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container
-            + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
-            + " spanY=" + spanY + " user=" + user + ")";
+    public final String toString() {
+        return getClass().getSimpleName() + "(" + dumpProperties() + ")";
+    }
+
+    protected String dumpProperties() {
+        return "id=" + id
+                + " type=" + itemType
+                + " container=" + container
+                + " screen=" + screenId
+                + " cellX=" + cellX
+                + " cellY=" + cellY
+                + " spanX=" + spanX
+                + " spanY=" + spanY
+                + " minSpanX=" + minSpanX
+                + " minSpanY=" + minSpanY
+                + " rank=" + rank
+                + " user=" + user
+                + " title=" + title;
     }
 
     /**
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 1caec33..b6474e6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -25,7 +25,6 @@
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.app.Activity;
-import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AlertDialog;
 import android.app.SearchManager;
@@ -36,7 +35,6 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.DialogInterface;
@@ -51,10 +49,8 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Build;
@@ -81,7 +77,6 @@
 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;
 import android.view.animation.OvershootInterpolator;
@@ -106,6 +101,7 @@
 import com.android.launcher3.config.ProviderConfig;
 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.dynamicui.ExtractedColors;
 import com.android.launcher3.folder.Folder;
@@ -119,10 +115,12 @@
 import com.android.launcher3.shortcuts.DeepShortcutsContainer;
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.util.ActivityResultInfo;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.MultiHashMap;
 import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.PendingRequestArgs;
 import com.android.launcher3.util.TestingUtils;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -164,10 +162,6 @@
 
     private static final int REQUEST_PERMISSION_CALL_PHONE = 13;
 
-    private static final int WORKSPACE_BACKGROUND_GRADIENT = 0;
-    private static final int WORKSPACE_BACKGROUND_TRANSPARENT = 1;
-    private static final int WORKSPACE_BACKGROUND_BLACK = 2;
-
     private static final float BOUNCE_ANIMATION_TENSION = 1.3f;
 
     /**
@@ -191,15 +185,11 @@
     private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
     // Type: int
     private static final String RUNTIME_STATE = "launcher.state";
-    // Type: Content Values / parcelable
-    private static final String RUNTIME_STATE_PENDING_ADD_ITEM = "launcher.add_item";
-    // Type: parcelable
-    private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_INFO = "launcher.add_widget_info";
-    // Type: parcelable
-    private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_ID = "launcher.add_widget_id";
+    // Type: PendingRequestArgs
+    private static final String RUNTIME_STATE_PENDING_REQUEST_ARGS = "launcher.request_args";
+    // Type: ActivityResultInfo
+    private static final String RUNTIME_STATE_PENDING_ACTIVITY_RESULT = "launcher.activity_result";
 
-    static final String INTRO_SCREEN_DISMISSED = "launcher.intro_screen_dismissed";
-    static final String FIRST_RUN_ACTIVITY_DISPLAYED = "launcher.first_run_activity_displayed";
     static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
 
     /** The different states that Launcher can be in. */
@@ -246,10 +236,6 @@
     private AppWidgetManagerCompat mAppWidgetManager;
     private LauncherAppWidgetHost mAppWidgetHost;
 
-    @Thunk final ItemInfo mPendingAddInfo = new ItemInfo();
-    private LauncherAppWidgetProviderInfo mPendingAddWidgetInfo;
-    private int mPendingAddWidgetId = -1;
-
     private int[] mTmpAddItemCellCoordinates = new int[2];
 
     @Thunk Hotseat mHotseat;
@@ -279,8 +265,6 @@
     @Thunk boolean mWorkspaceLoading = true;
 
     private boolean mPaused = true;
-    private boolean mRestoring;
-    private boolean mWaitingForResult;
     private boolean mOnResumeNeedsLoad;
 
     private ArrayList<Runnable> mBindOnResumeCallbacks = new ArrayList<Runnable>();
@@ -316,10 +300,7 @@
     // match the sensor state.
     private static final int RESTORE_SCREEN_ORIENTATION_DELAY = 500;
 
-    @Thunk Drawable mWorkspaceBackgroundDrawable;
-
     private final ArrayList<Integer> mSynchronouslyBoundPages = new ArrayList<Integer>();
-    private static final boolean DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE = false;
 
     // We only want to get the SharedPreferences once since it does an FS stat each time we get
     // it from the context.
@@ -363,17 +344,13 @@
         }
     };
 
-    private static PendingAddArguments sPendingAddItem;
-
-    @Thunk static class PendingAddArguments {
-        int requestCode;
-        Intent intent;
-        long container;
-        long screenId;
-        int cellX;
-        int cellY;
-        int appWidgetId;
-    }
+    // Activity result which needs to be processed after workspace has loaded.
+    private ActivityResultInfo mPendingActivityResult;
+    /**
+     * Holds extra information required to handle a result from an external call, like
+     * {@link #startActivityForResult(Intent, int)} or {@link #requestPermissions(String[], int)}
+     */
+    private PendingRequestArgs mPendingRequestArgs;
 
     private UserEventDispatcher mUserEventDispatcher;
 
@@ -464,20 +441,14 @@
             Trace.endSection();
         }
 
-        if (!mRestoring) {
-            if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
-                // If the user leaves launcher, then we should just load items asynchronously when
-                // they return.
-                mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);
-            } else {
-                // We only load the page synchronously if the user rotates (or triggers a
-                // configuration change) while launcher is in the foreground
-                if (!mModel.startLoader(mWorkspace.getRestorePage())) {
-                    // If we are not binding synchronously, show a fade in animation when
-                    // the first page bind completes.
-                    mDragLayer.setAlpha(0);
-                }
-            }
+        // We only load the page synchronously if the user rotates (or triggers a
+        // configuration change) while launcher is in the foreground
+        if (!mModel.startLoader(mWorkspace.getRestorePage())) {
+            // If we are not binding synchronously, show a fade in animation when
+            // the first page bind completes.
+            mDragLayer.setAlpha(0);
+        } else {
+            setWorkspaceLoading(true);
         }
 
         // For handling default keys
@@ -504,12 +475,6 @@
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onCreate(savedInstanceState);
         }
-
-        if (shouldShowIntroScreen()) {
-            showIntroScreen();
-        } else {
-            showFirstRunActivity();
-        }
     }
 
     @Override
@@ -676,53 +641,61 @@
      * Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
      * a configuration step, this allows the proper animations to run after other transitions.
      */
-    private long completeAdd(PendingAddArguments args) {
-        long screenId = args.screenId;
-        if (args.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+    private long completeAdd(
+            int requestCode, Intent intent, int appWidgetId, PendingRequestArgs info) {
+        long screenId = info.screenId;
+        if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
             // When the screen id represents an actual screen (as opposed to a rank) we make sure
             // that the drop page actually exists.
-            screenId = ensurePendingDropLayoutExists(args.screenId);
+            screenId = ensurePendingDropLayoutExists(info.screenId);
         }
 
-        switch (args.requestCode) {
+        switch (requestCode) {
             case REQUEST_CREATE_SHORTCUT:
-                completeAddShortcut(args.intent, args.container, screenId, args.cellX,
-                        args.cellY);
+                completeAddShortcut(intent, info.container, screenId, info.cellX, info.cellY, info);
                 break;
             case REQUEST_CREATE_APPWIDGET:
-                completeAddAppWidget(args.appWidgetId, args.container, screenId, null, null);
+                completeAddAppWidget(appWidgetId, info, null, null);
                 break;
             case REQUEST_RECONFIGURE_APPWIDGET:
-                completeRestoreAppWidget(args.appWidgetId, LauncherAppWidgetInfo.RESTORE_COMPLETED);
+                completeRestoreAppWidget(appWidgetId, LauncherAppWidgetInfo.RESTORE_COMPLETED);
                 break;
             case REQUEST_BIND_PENDING_APPWIDGET: {
-                int widgetId = args.appWidgetId;
-                LauncherAppWidgetInfo info =
+                int widgetId = appWidgetId;
+                LauncherAppWidgetInfo widgetInfo =
                         completeRestoreAppWidget(widgetId, LauncherAppWidgetInfo.FLAG_UI_NOT_READY);
-                if (info != null) {
+                if (widgetInfo != null) {
                     // Since the view was just bound, also launch the configure activity if needed
                     LauncherAppWidgetProviderInfo provider = mAppWidgetManager
                             .getLauncherAppWidgetInfo(widgetId);
                     if (provider != null && provider.configure != null) {
-                        startRestoredWidgetReconfigActivity(provider, info);
+                        startRestoredWidgetReconfigActivity(provider, widgetInfo);
                     }
                 }
                 break;
             }
         }
-        // Before adding this resetAddInfo(), after a shortcut was added to a workspace screen,
-        // if you turned the screen off and then back while in All Apps, Launcher would not
-        // return to the workspace. Clearing mAddInfo.container here fixes this issue
-        resetAddInfo();
+
         return screenId;
     }
 
     private void handleActivityResult(
             final int requestCode, final int resultCode, final Intent data) {
+        if (isWorkspaceLoading()) {
+            // process the result once the workspace has loaded.
+            mPendingActivityResult = new ActivityResultInfo(requestCode, resultCode, data);
+            return;
+        }
+        mPendingActivityResult = null;
+
         // Reset the startActivity waiting flag
-        setWaitingForResult(false);
-        final int pendingAddWidgetId = mPendingAddWidgetId;
-        mPendingAddWidgetId = -1;
+        final PendingRequestArgs requestArgs = mPendingRequestArgs;
+        setWaitingForResult(null);
+        if (requestArgs == null) {
+            return;
+        }
+
+        final int pendingAddWidgetId = requestArgs.getWidgetId();
 
         Runnable exitSpringLoaded = new Runnable() {
             @Override
@@ -737,12 +710,14 @@
             final int appWidgetId = data != null ?
                     data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
             if (resultCode == RESULT_CANCELED) {
-                completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId);
+                completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId, requestArgs);
                 mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
                         ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
             } else if (resultCode == RESULT_OK) {
-                addAppWidgetImpl(appWidgetId, mPendingAddInfo, null,
-                        mPendingAddWidgetInfo, ON_ACTIVITY_RESULT_ANIMATION_DELAY);
+                addAppWidgetImpl(
+                        appWidgetId, requestArgs, null,
+                        requestArgs.getWidgetProvider(),
+                        ON_ACTIVITY_RESULT_ANIMATION_DELAY);
             }
             return;
         } else if (requestCode == REQUEST_PICK_WALLPAPER) {
@@ -758,7 +733,6 @@
         boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET ||
                 requestCode == REQUEST_CREATE_APPWIDGET);
 
-        final boolean workspaceLocked = isWorkspaceLocked();
         // We have special handling for widgets
         if (isWidgetDrop) {
             final int appWidgetId;
@@ -775,46 +749,36 @@
                 Log.e(TAG, "Error: appWidgetId (EXTRA_APPWIDGET_ID) was not " +
                         "returned from the widget configuration activity.");
                 result = RESULT_CANCELED;
-                completeTwoStageWidgetDrop(result, appWidgetId);
+                completeTwoStageWidgetDrop(result, appWidgetId, requestArgs);
                 final Runnable onComplete = new Runnable() {
                     @Override
                     public void run() {
                         exitSpringLoadedDragModeDelayed(false, 0, null);
                     }
                 };
-                if (workspaceLocked) {
-                    // No need to remove the empty screen if we're mid-binding, as the
-                    // the bind will not add the empty screen.
-                    mWorkspace.postDelayed(onComplete, ON_ACTIVITY_RESULT_ANIMATION_DELAY);
-                } else {
-                    mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete,
-                            ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
-                }
-            } else {
-                if (!workspaceLocked) {
-                    if (mPendingAddInfo.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
-                        // When the screen id represents an actual screen (as opposed to a rank)
-                        // we make sure that the drop page actually exists.
-                        mPendingAddInfo.screenId =
-                                ensurePendingDropLayoutExists(mPendingAddInfo.screenId);
-                    }
-                    final CellLayout dropLayout = mWorkspace.getScreenWithId(mPendingAddInfo.screenId);
 
-                    dropLayout.setDropPending(true);
-                    final Runnable onComplete = new Runnable() {
-                        @Override
-                        public void run() {
-                            completeTwoStageWidgetDrop(resultCode, appWidgetId);
-                            dropLayout.setDropPending(false);
-                        }
-                    };
-                    mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete,
-                            ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
-                } else {
-                    PendingAddArguments args = preparePendingAddArgs(requestCode, data, appWidgetId,
-                            mPendingAddInfo);
-                    sPendingAddItem = args;
+                mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete,
+                        ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
+            } else {
+                if (requestArgs.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+                    // When the screen id represents an actual screen (as opposed to a rank)
+                    // we make sure that the drop page actually exists.
+                    requestArgs.screenId =
+                            ensurePendingDropLayoutExists(requestArgs.screenId);
                 }
+                final CellLayout dropLayout =
+                        mWorkspace.getScreenWithId(requestArgs.screenId);
+
+                dropLayout.setDropPending(true);
+                final Runnable onComplete = new Runnable() {
+                    @Override
+                    public void run() {
+                        completeTwoStageWidgetDrop(resultCode, appWidgetId, requestArgs);
+                        dropLayout.setDropPending(false);
+                    }
+                };
+                mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete,
+                        ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
             }
             return;
         }
@@ -823,13 +787,7 @@
                 || requestCode == REQUEST_BIND_PENDING_APPWIDGET) {
             if (resultCode == RESULT_OK) {
                 // Update the widget view.
-                PendingAddArguments args = preparePendingAddArgs(requestCode, data,
-                        pendingAddWidgetId, mPendingAddInfo);
-                if (workspaceLocked) {
-                    sPendingAddItem = args;
-                } else {
-                    completeAdd(args);
-                }
+                completeAdd(requestCode, data, pendingAddWidgetId, requestArgs);
             }
             // Leave the widget in the pending state if the user canceled the configure.
             return;
@@ -837,23 +795,17 @@
 
         if (requestCode == REQUEST_CREATE_SHORTCUT) {
             // Handle custom shortcuts created using ACTION_CREATE_SHORTCUT.
-            if (resultCode == RESULT_OK && mPendingAddInfo.container != ItemInfo.NO_ID) {
-                final PendingAddArguments args = preparePendingAddArgs(requestCode, data, -1,
-                        mPendingAddInfo);
-                if (isWorkspaceLocked()) {
-                    sPendingAddItem = args;
-                } else {
-                    completeAdd(args);
-                    mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
-                            ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
-                }
+            if (resultCode == RESULT_OK && requestArgs.container != ItemInfo.NO_ID) {
+                completeAdd(requestCode, data, -1, requestArgs);
+                mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
+                        ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
+
             } else if (resultCode == RESULT_CANCELED) {
                 mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
                         ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
             }
         }
         mDragLayer.clearAnimatedView();
-
     }
 
     @Override
@@ -868,22 +820,25 @@
     /** @Override for MNC */
     public void onRequestPermissionsResult(int requestCode, String[] permissions,
             int[] grantResults) {
-        if (requestCode == REQUEST_PERMISSION_CALL_PHONE && sPendingAddItem != null
-                && sPendingAddItem.requestCode == REQUEST_PERMISSION_CALL_PHONE) {
+        PendingRequestArgs pendingArgs = mPendingRequestArgs;
+        if (requestCode == REQUEST_PERMISSION_CALL_PHONE && pendingArgs != null
+                && pendingArgs.getRequestCode() == REQUEST_PERMISSION_CALL_PHONE) {
+            setWaitingForResult(null);
+
             View v = null;
-            CellLayout layout = getCellLayout(sPendingAddItem.container, sPendingAddItem.screenId);
+            CellLayout layout = getCellLayout(pendingArgs.container, pendingArgs.screenId);
             if (layout != null) {
-                v = layout.getChildAt(sPendingAddItem.cellX, sPendingAddItem.cellY);
+                v = layout.getChildAt(pendingArgs.cellX, pendingArgs.cellY);
             }
-            Intent intent = sPendingAddItem.intent;
-            sPendingAddItem = null;
+            Intent intent = pendingArgs.getPendingIntent();
+
             if (grantResults.length > 0
                     && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                 startActivitySafely(v, intent, null);
             } else {
                 // TODO: Show a snack bar with link to settings
                 Toast.makeText(this, getString(R.string.msg_no_phone_permission,
-                        getString(R.string.app_name)), Toast.LENGTH_SHORT).show();
+                        getString(R.string.derived_app_name)), Toast.LENGTH_SHORT).show();
             }
         }
         if (mLauncherCallbacks != null) {
@@ -892,19 +847,6 @@
         }
     }
 
-    private PendingAddArguments preparePendingAddArgs(int requestCode, Intent data, int
-            appWidgetId, ItemInfo info) {
-        PendingAddArguments args = new PendingAddArguments();
-        args.requestCode = requestCode;
-        args.intent = data;
-        args.container = info.container;
-        args.screenId = info.screenId;
-        args.cellX = info.cellX;
-        args.cellY = info.cellY;
-        args.appWidgetId = appWidgetId;
-        return args;
-    }
-
     /**
      * Check to see if a given screen id exists. If not, create it at the end, return the new id.
      *
@@ -923,8 +865,9 @@
         }
     }
 
-    @Thunk void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) {
-        CellLayout cellLayout = mWorkspace.getScreenWithId(mPendingAddInfo.screenId);
+    @Thunk void completeTwoStageWidgetDrop(
+            final int resultCode, final int appWidgetId, final PendingRequestArgs requestArgs) {
+        CellLayout cellLayout = mWorkspace.getScreenWithId(requestArgs.screenId);
         Runnable onCompleteRunnable = null;
         int animationType = 0;
 
@@ -932,13 +875,12 @@
         if (resultCode == RESULT_OK) {
             animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
             final AppWidgetHostView layout = mAppWidgetHost.createView(this, appWidgetId,
-                    mPendingAddWidgetInfo);
+                    requestArgs.getWidgetProvider());
             boundWidget = layout;
             onCompleteRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    completeAddAppWidget(appWidgetId, mPendingAddInfo.container,
-                            mPendingAddInfo.screenId, layout, null);
+                    completeAddAppWidget(appWidgetId, requestArgs, layout, null);
                     exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED),
                             EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
                 }
@@ -948,7 +890,7 @@
             animationType = Workspace.CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION;
         }
         if (mDragLayer.getAnimatedView() != null) {
-            mWorkspace.animateWidgetDrop(mPendingAddInfo, cellLayout,
+            mWorkspace.animateWidgetDrop(requestArgs, cellLayout,
                     (DragView) mDragLayer.getAnimatedView(), onCompleteRunnable,
                     animationType, boundWidget, true);
         } else if (onCompleteRunnable != null) {
@@ -1009,21 +951,16 @@
             // 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 */,
-                    false /* focusSearchBar */);
+                    mAppsView.shouldRestoreImeState() /* focusSearchBar */);
         } else if (mOnResumeState == State.WIDGETS) {
             showWidgetsView(false, false);
         }
         mOnResumeState = State.NONE;
 
-        // Background was set to gradient in onPause(), restore to transparent if in all apps.
-        setWorkspaceBackground(mState == State.WORKSPACE ? WORKSPACE_BACKGROUND_GRADIENT
-                : WORKSPACE_BACKGROUND_TRANSPARENT);
-
         mPaused = false;
-        if (mRestoring || mOnResumeNeedsLoad) {
+        if (mOnResumeNeedsLoad) {
             setWorkspaceLoading(true);
             mModel.startLoader(getCurrentWorkspaceScreen());
-            mRestoring = false;
             mOnResumeNeedsLoad = false;
         }
         if (mBindOnResumeCallbacks.size() > 0) {
@@ -1295,7 +1232,8 @@
         return mDefaultKeySsb.toString();
     }
 
-    private void clearTypedText() {
+    @Override
+    public void clearTypedText() {
         mDefaultKeySsb.clear();
         mDefaultKeySsb.clearSpans();
         Selection.setSelection(mDefaultKeySsb, 0);
@@ -1338,18 +1276,12 @@
             mWorkspace.setRestorePage(currentScreen);
         }
 
-        ContentValues itemValues = savedState.getParcelable(RUNTIME_STATE_PENDING_ADD_ITEM);
-        if (itemValues != null) {
-            mPendingAddInfo.readFromValues(itemValues);
-            AppWidgetProviderInfo info = savedState.getParcelable(
-                    RUNTIME_STATE_PENDING_ADD_WIDGET_INFO);
-            mPendingAddWidgetInfo = info == null ?
-                    null : LauncherAppWidgetProviderInfo.fromProviderInfo(this, info);
-
-            mPendingAddWidgetId = savedState.getInt(RUNTIME_STATE_PENDING_ADD_WIDGET_ID);
-            setWaitingForResult(true);
-            mRestoring = true;
+        PendingRequestArgs requestArgs = savedState.getParcelable(RUNTIME_STATE_PENDING_REQUEST_ARGS);
+        if (requestArgs != null) {
+            setWaitingForResult(requestArgs);
         }
+
+        mPendingActivityResult = savedState.getParcelable(RUNTIME_STATE_PENDING_ACTIVITY_RESULT);
     }
 
     /**
@@ -1367,10 +1299,8 @@
         mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
-        mWorkspaceBackgroundDrawable = getResources().getDrawable(R.drawable.workspace_bg);
 
         // Setup the drag layer
-
         mDragLayer.setup(this, mDragController, mAllAppsController);
 
         // Setup the hotseat
@@ -1527,12 +1457,19 @@
      * @param data The intent describing the shortcut.
      */
     private void completeAddShortcut(Intent data, long container, long screenId, int cellX,
-            int cellY) {
+            int cellY, PendingRequestArgs args) {
         int[] cellXY = mTmpAddItemCellCoordinates;
         CellLayout layout = getCellLayout(container, screenId);
 
         ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(this, data);
-        if (info == null) {
+        if (info == null || args.getRequestCode() != REQUEST_CREATE_SHORTCUT ||
+                args.getPendingIntent().getComponent() == null) {
+            return;
+        }
+        if (!PackageManagerHelper.hasPermissionForActivity(
+                this, info.intent, args.getPendingIntent().getComponent().getPackageName())) {
+            // The app is trying to add a shortcut without sufficient permissions
+            Log.e(TAG, "Ignoring malicious intent " + info.intent.toUri(0));
             return;
         }
         final View view = createShortcut(info);
@@ -1566,10 +1503,8 @@
 
         LauncherModel.addItemToDatabase(this, info, container, screenId, cellXY[0], cellXY[1]);
 
-        if (!mRestoring) {
-            mWorkspace.addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1,
-                    isWorkspaceLocked());
-        }
+        mWorkspace.addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1,
+                isWorkspaceLocked());
     }
 
     /**
@@ -1577,10 +1512,9 @@
      *
      * @param appWidgetId The app widget id
      */
-    @Thunk void completeAddAppWidget(int appWidgetId, long container, long screenId,
+    @Thunk void completeAddAppWidget(int appWidgetId, ItemInfo itemInfo,
             AppWidgetHostView hostView, LauncherAppWidgetProviderInfo appWidgetInfo) {
 
-        ItemInfo info = mPendingAddInfo;
         if (appWidgetInfo == null) {
             appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(appWidgetId);
         }
@@ -1591,24 +1525,21 @@
 
         LauncherAppWidgetInfo launcherInfo;
         launcherInfo = new LauncherAppWidgetInfo(appWidgetId, appWidgetInfo.provider);
-        launcherInfo.spanX = info.spanX;
-        launcherInfo.spanY = info.spanY;
-        launcherInfo.minSpanX = info.minSpanX;
-        launcherInfo.minSpanY = info.minSpanY;
+        launcherInfo.spanX = itemInfo.spanX;
+        launcherInfo.spanY = itemInfo.spanY;
+        launcherInfo.minSpanX = itemInfo.minSpanX;
+        launcherInfo.minSpanY = itemInfo.minSpanY;
         launcherInfo.user = mAppWidgetManager.getUser(appWidgetInfo);
 
         LauncherModel.addItemToDatabase(this, launcherInfo,
-                container, screenId, info.cellX, info.cellY);
+                itemInfo.container, itemInfo.screenId, itemInfo.cellX, itemInfo.cellY);
 
-        if (!mRestoring) {
-            if (hostView == null) {
-                // Perform actual inflation because we're live
-                hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
-            }
-            hostView.setVisibility(View.VISIBLE);
-            addAppWidgetToWorkspace(hostView, launcherInfo, appWidgetInfo, isWorkspaceLocked());
+        if (hostView == null) {
+            // Perform actual inflation because we're live
+            hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
         }
-        resetAddInfo();
+        hostView.setVisibility(View.VISIBLE);
+        addAppWidgetToWorkspace(hostView, launcherInfo, appWidgetInfo, isWorkspaceLocked());
     }
 
     private void addAppWidgetToWorkspace(
@@ -1639,8 +1570,7 @@
 
                 // 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 &&
-                        mPendingAddInfo.container == ItemInfo.NO_ID) {
+                if (mAppsView != null && mWidgetsView != null && mPendingRequestArgs == null) {
                     if (!showWorkspace(false)) {
                         // If we are already on the workspace, then manually reset all apps
                         mAppsView.reset();
@@ -1852,7 +1782,7 @@
         getWindow().closeAllPanels();
 
         // Whatever we were doing is hereby canceled.
-        setWaitingForResult(false);
+        setWaitingForResult(null);
     }
 
     @Override
@@ -1970,13 +1900,11 @@
         closeFolder(false);
         closeShortcutsContainer(false);
 
-        if (mPendingAddInfo.container != ItemInfo.NO_ID && mPendingAddInfo.screenId > -1 &&
-                mWaitingForResult) {
-            ContentValues itemValues = new ContentValues();
-            mPendingAddInfo.writeToValues(itemValues);
-            outState.putParcelable(RUNTIME_STATE_PENDING_ADD_ITEM, itemValues);
-            outState.putParcelable(RUNTIME_STATE_PENDING_ADD_WIDGET_INFO, mPendingAddWidgetInfo);
-            outState.putInt(RUNTIME_STATE_PENDING_ADD_WIDGET_ID, mPendingAddWidgetId);
+        if (mPendingRequestArgs != null) {
+            outState.putParcelable(RUNTIME_STATE_PENDING_REQUEST_ARGS, mPendingRequestArgs);
+        }
+        if (mPendingActivityResult != null) {
+            outState.putParcelable(RUNTIME_STATE_PENDING_ACTIVITY_RESULT, mPendingActivityResult);
         }
 
         if (mLauncherCallbacks != null) {
@@ -2039,14 +1967,12 @@
 
     @Override
     public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
-        onStartForResult(requestCode);
         super.startActivityForResult(intent, requestCode, options);
     }
 
     @Override
     public void startIntentSenderForResult (IntentSender intent, int requestCode,
             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) {
-        onStartForResult(requestCode);
         try {
             super.startIntentSenderForResult(intent, requestCode,
                 fillInIntent, flagsMask, flagsValues, extraFlags, options);
@@ -2055,12 +1981,6 @@
         }
     }
 
-    private void onStartForResult(int requestCode) {
-        if (requestCode >= 0) {
-            setWaitingForResult(true);
-        }
-    }
-
     /**
      * Indicates that we want global search for this activity by setting the globalSearch
      * argument for {@link #startSearch} to true.
@@ -2078,13 +1998,10 @@
             appSearchData.putString("source", "launcher-search");
         }
 
-        // TODO send proper bounds.
-        Rect sourceBounds = null;
-
-        boolean clearTextImmediately = startSearch(initialQuery, selectInitialQuery,
-                appSearchData, sourceBounds);
-        if (clearTextImmediately) {
-            clearTypedText();
+        if (mLauncherCallbacks == null ||
+                !mLauncherCallbacks.startSearch(initialQuery, selectInitialQuery, appSearchData)) {
+            // Starting search from the callbacks failed. Start the default global search.
+            startGlobalSearch(initialQuery, selectInitialQuery, appSearchData, null);
         }
 
         // We need to show the workspace after starting the search
@@ -2092,28 +2009,9 @@
     }
 
     /**
-     * Start a text search.
-     *
-     * @return {@code true} if the search will start immediately, so any further keypresses
-     * will be handled directly by the search UI. {@code false} if {@link Launcher} should continue
-     * to buffer keypresses.
-     */
-    public boolean startSearch(String initialQuery,
-            boolean selectInitialQuery, Bundle appSearchData, Rect sourceBounds) {
-        if (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch()) {
-            return mLauncherCallbacks.startSearch(initialQuery, selectInitialQuery, appSearchData,
-                    sourceBounds);
-        }
-
-        startGlobalSearch(initialQuery, selectInitialQuery,
-                appSearchData, sourceBounds);
-        return false;
-    }
-
-    /**
      * Starts the global search activity. This code is a copied from SearchManager
      */
-    private void startGlobalSearch(String initialQuery,
+    public void startGlobalSearch(String initialQuery,
             boolean selectInitialQuery, Bundle appSearchData, Rect sourceBounds) {
         final SearchManager searchManager =
             (SearchManager) getSystemService(Context.SEARCH_SERVICE);
@@ -2171,7 +2069,7 @@
     }
 
     public boolean isWorkspaceLocked() {
-        return mWorkspaceLoading || mWaitingForResult;
+        return mWorkspaceLoading || mPendingRequestArgs != null;
     }
 
     public boolean isWorkspaceLoading() {
@@ -2186,9 +2084,9 @@
         }
     }
 
-    private void setWaitingForResult(boolean value) {
+    private void setWaitingForResult(PendingRequestArgs args) {
         boolean isLocked = isWorkspaceLocked();
-        mWaitingForResult = value;
+        mPendingRequestArgs = args;
         if (isLocked != isWorkspaceLocked()) {
             onWorkspaceLockedChanged();
         }
@@ -2200,33 +2098,23 @@
         }
     }
 
-    private void resetAddInfo() {
-        mPendingAddInfo.container = ItemInfo.NO_ID;
-        mPendingAddInfo.screenId = -1;
-        mPendingAddInfo.cellX = mPendingAddInfo.cellY = -1;
-        mPendingAddInfo.spanX = mPendingAddInfo.spanY = -1;
-        mPendingAddInfo.minSpanX = mPendingAddInfo.minSpanY = 1;
-    }
-
-    void addAppWidgetFromDropImpl(final int appWidgetId, final ItemInfo info, final
-            AppWidgetHostView boundWidget, final LauncherAppWidgetProviderInfo appWidgetInfo) {
+    void addAppWidgetFromDropImpl(int appWidgetId, ItemInfo info, AppWidgetHostView boundWidget,
+            LauncherAppWidgetProviderInfo appWidgetInfo) {
         if (LOGD) {
             Log.d(TAG, "Adding widget from drop");
         }
         addAppWidgetImpl(appWidgetId, info, boundWidget, appWidgetInfo, 0);
     }
 
-    void addAppWidgetImpl(final int appWidgetId, final ItemInfo info,
-            final AppWidgetHostView boundWidget, final LauncherAppWidgetProviderInfo appWidgetInfo,
+    void addAppWidgetImpl(int appWidgetId, ItemInfo info,
+            AppWidgetHostView boundWidget, LauncherAppWidgetProviderInfo appWidgetInfo,
             int delay) {
         if (appWidgetInfo.configure != null) {
-            mPendingAddWidgetInfo = appWidgetInfo;
-            mPendingAddWidgetId = appWidgetId;
+            setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, appWidgetInfo, info));
 
             // Launch over to configure widget, if needed
             mAppWidgetManager.startConfigActivity(appWidgetInfo, appWidgetId, this,
                     mAppWidgetHost, REQUEST_CREATE_APPWIDGET);
-
         } else {
             // Otherwise just add it
             Runnable onComplete = new Runnable() {
@@ -2237,8 +2125,7 @@
                             null);
                 }
             };
-            completeAddAppWidget(appWidgetId, info.container, info.screenId, boundWidget,
-                    appWidgetInfo);
+            completeAddAppWidget(appWidgetId, info, boundWidget, appWidgetInfo);
             mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete, delay, false);
         }
     }
@@ -2251,17 +2138,22 @@
 
     public void addPendingItem(PendingAddItemInfo info, long container, long screenId,
             int[] cell, int spanX, int spanY) {
+        info.container = container;
+        info.screenId = screenId;
+        if (cell != null) {
+            info.cellX = cell[0];
+            info.cellY = cell[1];
+        }
+        info.spanX = spanX;
+        info.spanY = spanY;
+
         switch (info.itemType) {
             case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                int span[] = new int[2];
-                span[0] = spanX;
-                span[1] = spanY;
-                addAppWidgetFromDrop((PendingAddWidgetInfo) info,
-                        container, screenId, cell, span);
+                addAppWidgetFromDrop((PendingAddWidgetInfo) info);
                 break;
             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                processShortcutFromDrop(info.componentName, container, screenId, cell);
+                processShortcutFromDrop(info);
                 break;
             default:
                 throw new IllegalStateException("Unknown item type: " + info.itemType);
@@ -2270,51 +2162,17 @@
 
     /**
      * Process a shortcut drop.
-     *
-     * @param componentName The name of the component
-     * @param screenId The ID of the screen where it should be added
-     * @param cell The cell it should be added to, optional
      */
-    private void processShortcutFromDrop(ComponentName componentName, long container, long screenId,
-            int[] cell) {
-        resetAddInfo();
-        mPendingAddInfo.container = container;
-        mPendingAddInfo.screenId = screenId;
-
-        if (cell != null) {
-            mPendingAddInfo.cellX = cell[0];
-            mPendingAddInfo.cellY = cell[1];
-        }
-
-        Intent createShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
-        createShortcutIntent.setComponent(componentName);
-        Utilities.startActivityForResultSafely(this, createShortcutIntent, REQUEST_CREATE_SHORTCUT);
+    private void processShortcutFromDrop(PendingAddItemInfo info) {
+        Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(info.componentName);
+        setWaitingForResult(PendingRequestArgs.forIntent(REQUEST_CREATE_SHORTCUT, intent, info));
+        Utilities.startActivityForResultSafely(this, intent, REQUEST_CREATE_SHORTCUT);
     }
 
     /**
      * Process a widget drop.
-     *
-     * @param info The PendingAppWidgetInfo of the widget being added.
-     * @param screenId The ID of the screen where it should be added
-     * @param cell The cell it should be added to, optional
      */
-    private void addAppWidgetFromDrop(PendingAddWidgetInfo info, long container, long screenId,
-            int[] cell, int[] span) {
-        resetAddInfo();
-        mPendingAddInfo.container = info.container = container;
-        mPendingAddInfo.screenId = info.screenId = screenId;
-        mPendingAddInfo.minSpanX = info.minSpanX;
-        mPendingAddInfo.minSpanY = info.minSpanY;
-
-        if (cell != null) {
-            mPendingAddInfo.cellX = cell[0];
-            mPendingAddInfo.cellY = cell[1];
-        }
-        if (span != null) {
-            mPendingAddInfo.spanX = span[0];
-            mPendingAddInfo.spanY = span[1];
-        }
-
+    private void addAppWidgetFromDrop(PendingAddWidgetInfo info) {
         AppWidgetHostView hostView = info.boundWidget;
         int appWidgetId;
         if (hostView != null) {
@@ -2340,11 +2198,11 @@
             if (success) {
                 addAppWidgetFromDropImpl(appWidgetId, info, null, info.info);
             } else {
-                mPendingAddWidgetInfo = info.info;
+                setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, info.info, info));
                 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
                 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
                 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName);
-                mAppWidgetManager.getUser(mPendingAddWidgetInfo)
+                mAppWidgetManager.getUser(info.info)
                     .addToIntent(intent, AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE);
                 // TODO: we need to make sure that this accounts for the options bundle.
                 // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
@@ -2563,14 +2421,13 @@
                 LauncherAppWidgetProviderInfo appWidgetInfo =
                         mAppWidgetManager.findProvider(info.providerName, info.user);
                 if (appWidgetInfo != null) {
-                    mPendingAddWidgetId = info.appWidgetId;
-                    mPendingAddInfo.copyFrom(info);
-                    mPendingAddWidgetInfo = appWidgetInfo;
+                    setWaitingForResult(PendingRequestArgs
+                            .forWidgetInfo(info.appWidgetId, appWidgetInfo, info));
 
                     Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
-                    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mPendingAddWidgetId);
+                    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, info.appWidgetId);
                     intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, appWidgetInfo.provider);
-                    mAppWidgetManager.getUser(mPendingAddWidgetInfo)
+                    mAppWidgetManager.getUser(appWidgetInfo)
                             .addToIntent(intent, AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE);
                     startActivityForResult(intent, REQUEST_BIND_PENDING_APPWIDGET);
                 }
@@ -2599,9 +2456,7 @@
 
     private void startRestoredWidgetReconfigActivity(
             LauncherAppWidgetProviderInfo provider, LauncherAppWidgetInfo info) {
-        mPendingAddWidgetInfo = provider;
-        mPendingAddInfo.copyFrom(info);
-        mPendingAddWidgetId = info.appWidgetId;
+        setWaitingForResult(PendingRequestArgs.forWidgetInfo(info.appWidgetId, provider, info));
         mAppWidgetManager.startConfigActivity(provider,
                 info.appWidgetId, this, mAppWidgetHost, REQUEST_RECONFIGURE_APPWIDGET);
     }
@@ -2771,6 +2626,7 @@
         int pageScroll = mWorkspace.getScrollForPage(mWorkspace.getPageNearestToCenterOfScreen());
         float offset = mWorkspace.mWallpaperOffset.wallpaperOffsetForScroll(pageScroll);
 
+        setWaitingForResult(new PendingRequestArgs(new ItemInfo()));
         Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
                 .setPackage(pickerPackage)
                 .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset);
@@ -2784,8 +2640,10 @@
      */
     public void onClickSettingsButton(View v) {
         if (LOGD) Log.d(TAG, "onClickSettingsButton");
-        startActivity(new Intent(Utilities.ACTION_APPLICATION_PREFERENCES)
-                .setPackage(getPackageName()));
+        Intent intent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
+                .setPackage(getPackageName());
+        intent.setSourceBounds(getViewBounds(v));
+        startActivity(intent, getActivityLaunchOptions(v));
     }
 
     public View.OnTouchListener getHapticFeedbackTouchListener() {
@@ -2809,7 +2667,7 @@
         mDragLayer.onAccessibilityStateChanged(enabled);
     }
 
-    public void onDragStarted(View view) {
+    public void onDragStarted() {
         if (isOnCustomContent()) {
             // Custom content screen doesn't participate in drag and drop. If on custom
             // content screen, move to default.
@@ -2885,9 +2743,9 @@
                     && Intent.ACTION_CALL.equals(intent.getAction())
                     && checkSelfPermission(Manifest.permission.CALL_PHONE) !=
                     PackageManager.PERMISSION_GRANTED) {
-                // TODO: Rename sPendingAddItem to a generic name.
-                sPendingAddItem = preparePendingAddArgs(REQUEST_PERMISSION_CALL_PHONE, intent,
-                        0, info);
+
+                setWaitingForResult(PendingRequestArgs
+                        .forIntent(REQUEST_PERMISSION_CALL_PHONE, intent, info));
                 requestPermissions(new String[]{Manifest.permission.CALL_PHONE},
                         REQUEST_PERMISSION_CALL_PHONE);
             } else {
@@ -3172,6 +3030,14 @@
         }
     }
 
+    public View getTopFloatingView() {
+        View topView = getOpenShortcutsContainer();
+        if (topView == null) {
+            topView = getWorkspace().getOpenFolder();
+        }
+        return topView;
+    }
+
     /**
      * @return The open shortcuts container, or null if there is none
      */
@@ -3221,7 +3087,7 @@
             ItemInfo info = (ItemInfo) v.getTag();
             longClickCellInfo = new CellLayout.CellInfo(v, info);
             itemUnderLongClick = longClickCellInfo.cell;
-            resetAddInfo();
+            mPendingRequestArgs = null;
         }
 
         // The hotseat touch handling does not go through Workspace, and we always allow long press
@@ -3243,7 +3109,7 @@
                                         longClickCellInfo.cellX, longClickCellInfo.cellY));
                 if (!(itemUnderLongClick instanceof Folder || isAllAppsButton)) {
                     // User long pressed on an item
-                    mWorkspace.startDrag(longClickCellInfo);
+                    mWorkspace.startDrag(longClickCellInfo, new DragOptions());
                 }
             }
         }
@@ -3285,29 +3151,6 @@
         return (mState == State.WIDGETS) || (mOnResumeState == State.WIDGETS);
     }
 
-    private void setWorkspaceBackground(int background) {
-        switch (background) {
-            case WORKSPACE_BACKGROUND_TRANSPARENT:
-                getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
-                break;
-            case WORKSPACE_BACKGROUND_BLACK:
-                getWindow().setBackgroundDrawable(null);
-                break;
-            default:
-                getWindow().setBackgroundDrawable(mWorkspaceBackgroundDrawable);
-        }
-    }
-
-    protected void changeWallpaperVisiblity(boolean visible) {
-        int wpflags = visible ? WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER : 0;
-        int curflags = getWindow().getAttributes().flags
-                & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-        if (wpflags != curflags) {
-            getWindow().setFlags(wpflags, WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
-        }
-        setWorkspaceBackground(visible ? WORKSPACE_BACKGROUND_GRADIENT : WORKSPACE_BACKGROUND_BLACK);
-    }
-
     @Override
     public void onTrimMemory(int level) {
         super.onTrimMemory(level);
@@ -3564,10 +3407,6 @@
         // TODO
     }
 
-    public boolean launcherCallbacksProvidesSearch() {
-        return (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch());
-    }
-
     @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
         final boolean result = super.dispatchPopulateAccessibilityEvent(event);
@@ -3955,14 +3794,30 @@
                     pendingInfo.minSpanX = item.minSpanX;
                     pendingInfo.minSpanY = item.minSpanY;
                     Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo);
+
+                    boolean isDirectConfig =
+                            item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG);
+                    if (isDirectConfig && item.bindOptions != null) {
+                        Bundle newOptions = item.bindOptions.getExtras();
+                        if (options != null) {
+                            newOptions.putAll(options);
+                        }
+                        options = newOptions;
+                    }
                     boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
                             item.appWidgetId, appWidgetInfo, options);
 
+                    // We tried to bind once. If we were not able to bind, we would need to
+                    // go through the permission dialog, which means we cannot skip the config
+                    // activity.
+                    item.bindOptions = null;
+                    item.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG;
+
                     // Bind succeeded
                     if (success) {
                         // If the widget has a configure activity, it is still needs to set it up,
                         // otherwise the widget is ready to go.
-                        item.restoreStatus = (appWidgetInfo.configure == null)
+                        item.restoreStatus = (appWidgetInfo.configure == null) || isDirectConfig
                                 ? LauncherAppWidgetInfo.RESTORE_COMPLETED
                                 : LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
                     }
@@ -4105,21 +3960,10 @@
 
         setWorkspaceLoading(false);
 
-        // If we received the result of any pending adds while the loader was running (e.g. the
-        // widget configuration forced an orientation change), process them now.
-        if (sPendingAddItem != null) {
-            final long screenId = completeAdd(sPendingAddItem);
-
-            // TODO: this moves the user to the page where the pending item was added. Ideally,
-            // the screen would be guaranteed to exist after bind, and the page would be set through
-            // the workspace restore process.
-            mWorkspace.post(new Runnable() {
-                @Override
-                public void run() {
-                    mWorkspace.snapToScreenId(screenId);
-                }
-            });
-            sPendingAddItem = null;
+        if (mPendingActivityResult != null) {
+            handleActivityResult(mPendingActivityResult.requestCode,
+                    mPendingActivityResult.resultCode, mPendingActivityResult.data);
+            mPendingActivityResult = null;
         }
 
         InstallShortcutReceiver.disableAndFlushInstallQueue(this);
@@ -4202,6 +4046,10 @@
             return Collections.EMPTY_LIST;
         }
         ComponentName component = info.getTargetComponent();
+        if (component == null) {
+            return Collections.EMPTY_LIST;
+        }
+
         List<String> ids = mDeepShortcutMap.get(new ComponentKey(component, info.user));
         return ids == null ? Collections.EMPTY_LIST : ids;
     }
@@ -4442,51 +4290,6 @@
         }
     }
 
-    /**
-     * To be overridden by subclasses to indicate that there is an activity to launch
-     * before showing the standard launcher experience.
-     */
-    protected boolean hasFirstRunActivity() {
-        if (mLauncherCallbacks != null) {
-            return mLauncherCallbacks.hasFirstRunActivity();
-        }
-        return false;
-    }
-
-    /**
-     * To be overridden by subclasses to launch any first run activity
-     */
-    protected Intent getFirstRunActivity() {
-        if (mLauncherCallbacks != null) {
-            return mLauncherCallbacks.getFirstRunActivity();
-        }
-        return null;
-    }
-
-    private boolean shouldRunFirstRunActivity() {
-        return !ActivityManager.isRunningInTestHarness() &&
-                !mSharedPrefs.getBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, false);
-    }
-
-    public boolean showFirstRunActivity() {
-        if (shouldRunFirstRunActivity() &&
-                hasFirstRunActivity()) {
-            Intent firstRunIntent = getFirstRunActivity();
-            if (firstRunIntent != null) {
-                startActivity(firstRunIntent);
-                markFirstRunActivityShown();
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private void markFirstRunActivityShown() {
-        SharedPreferences.Editor editor = mSharedPrefs.edit();
-        editor.putBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, true);
-        editor.apply();
-    }
-
     private void markAppsViewShown() {
         if (mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false)) {
             return;
@@ -4510,44 +4313,6 @@
         return true;
     }
 
-    /**
-     * To be overridden by subclasses to indicate that there is an in-activity full-screen intro
-     * screen that must be displayed and dismissed.
-     */
-    protected boolean hasDismissableIntroScreen() {
-        if (mLauncherCallbacks != null) {
-            return mLauncherCallbacks.hasDismissableIntroScreen();
-        }
-        return false;
-    }
-
-    /**
-     * Full screen intro screen to be shown and dismissed before the launcher can be used.
-     */
-    protected View getIntroScreen() {
-        if (mLauncherCallbacks != null) {
-            return mLauncherCallbacks.getIntroScreen();
-        }
-        return null;
-    }
-
-    /**
-     * To be overriden by subclasses to indicate whether the in-activity intro screen has been
-     * dismissed. This method is ignored if #hasDismissableIntroScreen returns false.
-     */
-    private boolean shouldShowIntroScreen() {
-        return hasDismissableIntroScreen() &&
-                !mSharedPrefs.getBoolean(INTRO_SCREEN_DISMISSED, false);
-    }
-
-    protected void showIntroScreen() {
-        View introScreen = getIntroScreen();
-        changeWallpaperVisiblity(false);
-        if (introScreen != null) {
-            mDragLayer.showOverlayView(introScreen);
-        }
-    }
-
     // TODO: These method should be a part of LauncherSearchCallback
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public ItemInfo createAppDragInfo(Intent appLaunchIntent) {
@@ -4614,8 +4379,8 @@
         Log.d(TAG, "BEGIN launcher3 dump state for launcher " + this);
         Log.d(TAG, "mSavedState=" + mSavedState);
         Log.d(TAG, "mWorkspaceLoading=" + mWorkspaceLoading);
-        Log.d(TAG, "mRestoring=" + mRestoring);
-        Log.d(TAG, "mWaitingForResult=" + mWaitingForResult);
+        Log.d(TAG, "mPendingRequestArgs=" + mPendingRequestArgs);
+        Log.d(TAG, "mPendingActivityResult=" + mPendingActivityResult);
         mModel.dumpState();
         // TODO(hyunyoungs): add mWidgetsView.dumpState(); or mWidgetsModel.dumpState();
 
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index 99210fd..66d8957 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 
 import com.android.launcher3.compat.UserHandleCompat;
 
@@ -57,6 +58,12 @@
     public static final int FLAG_ID_ALLOCATED = 16;
 
     /**
+     * Indicates that the widget does not need to show config activity, even if it has a
+     * configuration screen. It can also optionally have some extras which are sent during bind.
+     */
+    public static final int FLAG_DIRECT_CONFIG = 32;
+
+    /**
      * Indicates that the widget hasn't been instantiated yet.
      */
     static final int NO_ID = -1;
@@ -84,6 +91,11 @@
      */
     int installProgress = -1;
 
+    /**
+     * Optional extras sent during widget bind. See {@link #FLAG_DIRECT_CONFIG}.
+     */
+    public Intent bindOptions;
+
     private boolean mHasNotifiedInitialWidgetSizeChanged;
 
     LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) {
@@ -115,6 +127,8 @@
         values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
         values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString());
         values.put(LauncherSettings.Favorites.RESTORED, restoreStatus);
+        values.put(LauncherSettings.Favorites.INTENT,
+                bindOptions == null ? null : bindOptions.toUri(0));
     }
 
     /**
@@ -129,8 +143,8 @@
     }
 
     @Override
-    public String toString() {
-        return "AppWidget(id=" + Integer.toString(appWidgetId) + ")";
+    protected String dumpProperties() {
+        return super.dumpProperties() + " appWidgetId=" + appWidgetId;
     }
 
     public final boolean isWidgetIdAllocated() {
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 2bbe0fb..6394b90 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -79,9 +79,11 @@
     @Deprecated
     public void onWorkspaceLockedChanged();
 
-    public boolean providesSearch();
-    public boolean startSearch(String initialQuery, boolean selectInitialQuery,
-            Bundle appSearchData, Rect sourceBounds);
+    /**
+     * Starts a search with {@param initialQuery}. Return false if search was not started.
+     */
+    public boolean startSearch(
+            String initialQuery, boolean selectInitialQuery, Bundle appSearchData);
     public boolean hasCustomContentToLeft();
     public void populateCustomContentContainer();
     public View getQsbBar();
@@ -91,10 +93,6 @@
      * Extensions points for adding / replacing some other aspects of the Launcher experience.
      */
     public UserEventDispatcher getUserEventDispatcher();
-    public Intent getFirstRunActivity();
-    public boolean hasFirstRunActivity();
-    public boolean hasDismissableIntroScreen();
-    public View getIntroScreen();
     public boolean shouldMoveToDefaultScreenOnHomeIntent();
     public boolean hasSettings();
     public AllAppsSearchBarController getAllAppsSearchBarController();
diff --git a/src/com/android/launcher3/LauncherExterns.java b/src/com/android/launcher3/LauncherExterns.java
index c7a8668..887859c 100644
--- a/src/com/android/launcher3/LauncherExterns.java
+++ b/src/com/android/launcher3/LauncherExterns.java
@@ -29,4 +29,6 @@
     public SharedPreferences getSharedPrefs();
 
     public void setLauncherOverlay(Launcher.LauncherOverlay overlay);
+
+    void clearTypedText();
 }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index c5c52b4..68450e7 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -103,7 +103,6 @@
         implements LauncherAppsCompat.OnAppsChangedCallbackCompat {
     static final boolean DEBUG_LOADERS = false;
     private static final boolean DEBUG_RECEIVER = false;
-    private static final boolean REMOVE_UNRESTORED_ICONS = true;
 
     static final String TAG = "Launcher.Model";
 
@@ -1883,12 +1882,12 @@
                                                     restored = false;
                                                     itemReplaced = true;
 
-                                                } else if (REMOVE_UNRESTORED_ICONS) {
+                                                } else {
                                                     FileLog.d(TAG, "Unrestored package removed: " + cn);
                                                     itemsToRemove.add(id);
                                                     continue;
                                                 }
-                                            } else if (REMOVE_UNRESTORED_ICONS) {
+                                            } else {
                                                 FileLog.d(TAG, "Unrestored package removed: " + cn);
                                                 itemsToRemove.add(id);
                                                 continue;
@@ -2148,7 +2147,7 @@
 
                                             // Id would be valid only if the widget restore broadcast was received.
                                             if (isIdValid) {
-                                                status = LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
+                                                status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
                                             } else {
                                                 status &= ~LauncherAppWidgetInfo
                                                         .FLAG_PROVIDER_NOT_READY;
@@ -2170,7 +2169,7 @@
                                             // App restore has started. Update the flag
                                             appWidgetInfo.restoreStatus |=
                                                     LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
-                                        } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {
+                                        } else if (!isSafeMode) {
                                             FileLog.d(TAG, "Unrestored widget removed: " + component);
                                             itemsToRemove.add(id);
                                             continue;
@@ -2179,6 +2178,14 @@
                                         appWidgetInfo.installProgress =
                                                 installProgress == null ? 0 : installProgress;
                                     }
+                                    if (appWidgetInfo.hasRestoreFlag(
+                                            LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
+                                        intentDescription = c.getString(intentIndex);
+                                        if (!TextUtils.isEmpty(intentDescription)) {
+                                            appWidgetInfo.bindOptions =
+                                                    Intent.parseUri(intentDescription, 0);
+                                        }
+                                    }
 
                                     appWidgetInfo.id = id;
                                     appWidgetInfo.screenId = c.getInt(screenIndex);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index eee5627..f3d9493 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -67,6 +67,7 @@
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Locale;
 
 public class LauncherProvider extends ContentProvider {
     private static final String TAG = "LauncherProvider";
@@ -313,10 +314,32 @@
         SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
 
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-        int count = db.delete(args.table, args.where, args.args);
-        if (count > 0) notifyListeners();
 
-        reloadLauncherIfExternal();
+        if (Binder.getCallingPid() != Process.myPid()
+                && Favorites.TABLE_NAME.equalsIgnoreCase(args.table)) {
+            String widgetSelection = TextUtils.isEmpty(args.where) ? "1=1" : args.where;
+            widgetSelection = String.format(Locale.ENGLISH, "%1$s = %2$d AND ( %3$s )",
+                    Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET, widgetSelection);
+            try (Cursor c = db.query(Favorites.TABLE_NAME, new String[] { Favorites.APPWIDGET_ID },
+                    widgetSelection, args.args, null, null, null)) {
+                AppWidgetHost host = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID);
+                while (c.moveToNext()) {
+                    int widgetId = c.getInt(0);
+                    if (widgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
+                        try {
+                            host.deleteAppWidgetId(widgetId);
+                        } catch (RuntimeException e) {
+                            Log.e(TAG, "Error deleting widget id " + widgetId, e);
+                        }
+                    }
+                }
+            }
+        }
+        int count = db.delete(args.table, args.where, args.args);
+        if (count > 0) {
+            notifyListeners();
+            reloadLauncherIfExternal();
+        }
         return count;
     }
 
diff --git a/src/com/android/launcher3/PendingAddItemInfo.java b/src/com/android/launcher3/PendingAddItemInfo.java
index 1aaf85b..31820d7 100644
--- a/src/com/android/launcher3/PendingAddItemInfo.java
+++ b/src/com/android/launcher3/PendingAddItemInfo.java
@@ -29,4 +29,9 @@
      * The component that will be created.
      */
     public ComponentName componentName;
+
+    @Override
+    protected String dumpProperties() {
+        return super.dumpProperties() + " componentName=" + componentName;
+    }
 }
diff --git a/src/com/android/launcher3/PinchToOverviewListener.java b/src/com/android/launcher3/PinchToOverviewListener.java
index 6ee96fc..48a75d1 100644
--- a/src/com/android/launcher3/PinchToOverviewListener.java
+++ b/src/com/android/launcher3/PinchToOverviewListener.java
@@ -102,8 +102,8 @@
             // once the state switching animation is complete.
             return false;
         }
-        if (mWorkspace.getOpenFolder() != null) {
-            // Don't listen for the pinch gesture if a folder is open.
+        if (mLauncher.getTopFloatingView() != null) {
+            // Don't listen for the pinch gesture if a floating view is open.
             return false;
         }
 
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 21fa8a0..fb93743 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -158,7 +158,7 @@
      */
     Intent promisedIntent;
 
-    ShortcutInfo() {
+    public ShortcutInfo() {
         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
     }
 
@@ -270,14 +270,6 @@
         }
     }
 
-    @Override
-    public String toString() {
-        return "ShortcutInfo(title=" + title + "intent=" + intent + "id=" + this.id
-                + " type=" + this.itemType + " container=" + this.container + " screen=" + screenId
-                + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY
-                + " user=" + user + ")";
-    }
-
     public ComponentName getTargetComponent() {
         return promisedIntent != null ? promisedIntent.getComponent() : intent.getComponent();
     }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 045b1d3..b0e096a 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -58,6 +58,8 @@
 import android.util.TypedValue;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
 
 import com.android.launcher3.compat.UserHandleCompat;
@@ -168,10 +170,6 @@
         return false;
     }
 
-    // TODO: Use Intent.ACTION_APPLICATION_PREFERENCES when N SDK is available.
-    public static final String ACTION_APPLICATION_PREFERENCES
-            = "android.intent.action.APPLICATION_PREFERENCES";
-
     public static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
         byte[] data = c.getBlob(iconIndex);
         try {
@@ -688,11 +686,11 @@
     /**
      * Calculates the height of a given string at a specific text size.
      */
-    public static float calculateTextHeight(float textSizePx) {
+    public static int calculateTextHeight(float textSizePx) {
         Paint p = new Paint();
         p.setTextSize(textSizePx);
         Paint.FontMetrics fm = p.getFontMetrics();
-        return -fm.top + fm.bottom;
+        return (int) Math.ceil(fm.bottom - fm.top);
     }
 
     /**
@@ -765,16 +763,21 @@
     }
 
     public static boolean isBootCompleted() {
+        return "1".equals(getSystemProperty("sys.boot_completed", "1"));
+    }
+
+    public static String getSystemProperty(String property, String defaultValue) {
         try {
             Class clazz = Class.forName("android.os.SystemProperties");
             Method getter = clazz.getDeclaredMethod("get", String.class);
-            String value = (String) getter.invoke(null, "sys.boot_completed");
-            return "1".equals(value);
+            String value = (String) getter.invoke(null, property);
+            if (!TextUtils.isEmpty(value)) {
+                return value;
+            }
         } catch (Exception e) {
             Log.d(TAG, "Unable to read system properties");
-            // Assume that boot has completed
-            return true;
         }
+        return defaultValue;
     }
 
     /**
@@ -905,4 +908,15 @@
         ta.recycle();
         return colorAccent;
     }
+
+    public static void sendCustomAccessibilityEvent(View target, int type, String text) {
+        AccessibilityManager accessibilityManager = (AccessibilityManager)
+                target.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+        if (accessibilityManager.isEnabled()) {
+            AccessibilityEvent event = AccessibilityEvent.obtain(type);
+            target.onInitializeAccessibilityEvent(event);
+            event.getText().add(text);
+            accessibilityManager.sendAccessibilityEvent(event);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 75692a6..c499bee 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -59,7 +59,7 @@
 import com.android.launcher3.Launcher.CustomContentCallbacks;
 import com.android.launcher3.Launcher.LauncherOverlay;
 import com.android.launcher3.UninstallDropTarget.DropTargetSource;
-import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
+import com.android.launcher3.accessibility.AccessibileDragListenerAdapter;
 import com.android.launcher3.accessibility.OverviewAccessibilityDelegate;
 import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate;
 import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
@@ -69,13 +69,13 @@
 import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.graphics.DragPreviewProvider;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragScroller;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.SpringLoadedDragController;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.shortcuts.ShortcutsContainerListener;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -84,6 +84,7 @@
 import com.android.launcher3.util.LongArrayMap;
 import com.android.launcher3.util.MultiStateAlphaController;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.VerticalFlingDetector;
 import com.android.launcher3.util.WallpaperOffsetInterpolator;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -100,7 +101,7 @@
 public class Workspace extends PagedView
         implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
         DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,
-        Insettable, DropTargetSource, AccessibilityDragSource {
+        Insettable, DropTargetSource {
     private static final String TAG = "Launcher.Workspace";
 
     private static boolean ENFORCE_DRAG_EVENT_ORDER = false;
@@ -134,7 +135,6 @@
 
     @Thunk Runnable mRemoveEmptyScreenRunnable;
     @Thunk boolean mDeferRemoveExtraEmptyScreen = false;
-    @Thunk boolean mAddNewPageOnDrag = true;
 
     /**
      * CellInfo for the cell that is currently being dragged
@@ -247,8 +247,7 @@
     /** Is the user is dragging an item near the edge of a page? */
     private boolean mInScrollArea = false;
 
-    private HolographicOutlineHelper mOutlineHelper;
-    @Thunk Bitmap mDragOutline = null;
+    private DragPreviewProvider mOutlineProvider = null;
     public static final int DRAG_BITMAP_PADDING = DragPreviewProvider.DRAG_BITMAP_PADDING;
     private boolean mWorkspaceFadeInAdjacentScreens;
 
@@ -343,8 +342,6 @@
     public Workspace(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        mOutlineHelper = HolographicOutlineHelper.obtain(context);
-
         mLauncher = (Launcher) context;
         mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this);
         final Resources res = getResources();
@@ -412,25 +409,56 @@
     }
 
     @Override
-    public void onDragStart(final DragSource source, ItemInfo info, int dragAction) {
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
         if (ENFORCE_DRAG_EVENT_ORDER) {
             enfoceDragParity("onDragStart", 0, 0);
         }
 
+        if (mOutlineProvider != null) {
+            // The outline is used to visualize where the item will land if dropped
+            mOutlineProvider.generateDragOutline(mCanvas);
+        }
+
         updateChildrenLayersEnabled(false);
+        mLauncher.onDragStarted();
         mLauncher.lockScreenOrientation();
         mLauncher.onInteractionBegin();
         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
         InstallShortcutReceiver.enableInstallQueue();
 
-        if (mAddNewPageOnDrag) {
+        // Do not add a new page if it is a accessible drag which was not started by the workspace.
+        // We do not support accessibility drag from other sources and instead provide a direct
+        // action for move/add to homescreen.
+        // When a accessible drag is started by the folder, we only allow rearranging withing the
+        // folder.
+        boolean addNewPage = !(options.isAccessibleDrag && dragObject.dragSource != this);
+
+        if (addNewPage) {
             mDeferRemoveExtraEmptyScreen = false;
             addExtraEmptyScreenOnDrag();
-        }
-    }
 
-    public void setAddNewPageOnDrag(boolean addPage) {
-        mAddNewPageOnDrag = addPage;
+            if (dragObject.dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+                    && dragObject.dragSource != this) {
+                // When dragging a widget from different source, move to a page which has
+                // enough space to place this widget (after rearranging/resizing). We special case
+                // widgets as they cannot be placed inside a folder.
+                // Start at the current page and search right (on LTR) until finding a page with
+                // enough space. Since an empty screen is the furthest right, a page must be found.
+                int currentPage = getPageNearestToCenterOfScreen();
+                for (int pageIndex = currentPage; pageIndex < getPageCount(); pageIndex++) {
+                    CellLayout page = (CellLayout) getPageAt(pageIndex);
+                    if (page.hasReorderSolution(dragObject.dragInfo)) {
+                        setCurrentPage(pageIndex);
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (!FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND) {
+            // Always enter the spring loaded mode
+            mLauncher.enterSpringLoadedDragMode();
+        }
     }
 
     public void deferRemoveExtraEmptyScreen() {
@@ -566,7 +594,31 @@
         }
         // Add the first page
         CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, 0);
-
+        if (FeatureFlags.PULLDOWN_SEARCH) {
+            firstPage.setOnTouchListener(new VerticalFlingDetector(mLauncher) {
+                // detect fling when touch started from empty space
+                @Override
+                public boolean onTouch(View v, MotionEvent ev) {
+                    if (workspaceInModalState()) return false;
+                    if (shouldConsumeTouch(v)) return true;
+                    if (super.onTouch(v, ev)) {
+                        mLauncher.startSearch("", false, null, false);
+                    }
+                    return false;
+                }
+            });
+            firstPage.setOnInterceptTouchListener(new VerticalFlingDetector(mLauncher) {
+                // detect fling when touch started from on top of the icons
+                @Override
+                public boolean onTouch(View v, MotionEvent ev) {
+                    if (shouldConsumeTouch(v)) return true;
+                    if (super.onTouch(v, ev)) {
+                        mLauncher.startSearch("", false, null, false);
+                    }
+                    return false;
+                }
+            });
+        }
         // Always add a QSB on the first screen.
         if (qsb == null) {
             // In transposed layout, we add the QSB in the Grid. As workspace does not touch the
@@ -600,8 +652,8 @@
             ViewGroup.LayoutParams lp = qsbContainer.getLayoutParams();
             if (cellHeight > 0 && lp.height != cellHeight) {
                 lp.height = cellHeight;
+                qsbContainer.setLayoutParams(lp);
             }
-            qsbContainer.setLayoutParams(lp);
         }
     }
 
@@ -658,7 +710,6 @@
         // created CellLayout.
         CellLayout newScreen = (CellLayout) mLauncher.getLayoutInflater().inflate(
                         R.layout.workspace_screen, this, false /* attachToRoot */);
-
         newScreen.setOnLongClickListener(mLongClickListener);
         newScreen.setOnClickListener(mLauncher);
         newScreen.setSoundEffectsEnabled(false);
@@ -1144,6 +1195,10 @@
     @SuppressLint("ClickableViewAccessibility")
     @Override
     public boolean onTouch(View v, MotionEvent event) {
+        return shouldConsumeTouch(v);
+    }
+
+    private boolean shouldConsumeTouch(View v) {
         return (workspaceInModalState() || !isFinishedSwitchingState())
                 || (!workspaceInModalState() && indexOfChild(v) != mCurrentPage);
     }
@@ -1698,26 +1753,6 @@
         }
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    @Override
-    public void enableAccessibleDrag(boolean enable) {
-        for (int i = 0; i < getChildCount(); i++) {
-            CellLayout child = (CellLayout) getChildAt(i);
-            child.enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
-        }
-
-        if (enable) {
-            // We need to allow our individual children to become click handlers in this case
-            setOnClickListener(null);
-        } else {
-            // Reset our click listener
-            setOnClickListener(mLauncher);
-        }
-        mLauncher.getDropTargetBar().enableAccessibleDrag(enable);
-        mLauncher.getHotseat().getLayout()
-            .enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
-    }
-
     public boolean hasCustomContent() {
         return (mScreenOrder.size() > 0 && mScreenOrder.get(0) == CUSTOM_CONTENT_SCREEN_ID);
     }
@@ -1850,19 +1885,6 @@
     }
 
     @Override
-    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-        if (!mLauncher.isAppsViewVisible()) {
-            final Folder openFolder = getOpenFolder();
-            if (openFolder != null) {
-                return openFolder.requestFocus(direction, previouslyFocusedRect);
-            } else {
-                return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
-            }
-        }
-        return false;
-    }
-
-    @Override
     public int getDescendantFocusability() {
         if (workspaceInModalState()) {
             return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
@@ -1870,18 +1892,6 @@
         return super.getDescendantFocusability();
     }
 
-    @Override
-    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
-        if (!mLauncher.isAppsViewVisible()) {
-            final Folder openFolder = getOpenFolder();
-            if (openFolder != null) {
-                openFolder.addFocusables(views, direction);
-            } else {
-                super.addFocusables(views, direction, focusableMode);
-            }
-        }
-    }
-
     public boolean workspaceInModalState() {
         return mState != State.NORMAL;
     }
@@ -1999,23 +2009,8 @@
                 position[0], position[1], 0, null);
     }
 
-    public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {
-        // Find a page that has enough space to place this widget (after rearranging/resizing).
-        // Start at the current page and search right (on LTR) until finding a page with enough
-        // space. Since an empty screen is the furthest right, a page must be found.
-        int currentPageInOverview = getPageNearestToCenterOfScreen();
-        for (int pageIndex = currentPageInOverview; pageIndex < getPageCount(); pageIndex++) {
-            CellLayout page = (CellLayout) getPageAt(pageIndex);
-            if (page.hasReorderSolution(info)) {
-                setCurrentPage(pageIndex);
-                break;
-            }
-        }
-
-        int[] size = estimateItemSize(info, false);
-
-        // The outline is used to visualize where the item will land if dropped
-        mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha);
+    public void prepareDragWithProvider(DragPreviewProvider outlineProvider) {
+        mOutlineProvider = outlineProvider;
     }
 
     public void exitWidgetResizeMode() {
@@ -2271,40 +2266,7 @@
         return null;
     }
 
-    /**
-     * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
-     * Responsibility for the bitmap is transferred to the caller.
-     */
-    private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h,
-            boolean clipAlpha) {
-        final int outlineColor = getResources().getColor(R.color.outline_color);
-        final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
-        mCanvas.setBitmap(b);
-
-        Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
-        float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
-                (h - padding) / (float) orig.getHeight());
-        int scaledWidth = (int) (scaleFactor * orig.getWidth());
-        int scaledHeight = (int) (scaleFactor * orig.getHeight());
-        Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
-
-        // center the image
-        dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
-
-        mCanvas.drawBitmap(orig, src, dst, null);
-        mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor,
-                clipAlpha);
-        mCanvas.setBitmap(null);
-
-        return b;
-    }
-
-    public void startDrag(CellLayout.CellInfo cellInfo) {
-        startDrag(cellInfo, false);
-    }
-
-    @Override
-    public void startDrag(CellLayout.CellInfo cellInfo, boolean accessible) {
+    public void startDrag(CellLayout.CellInfo cellInfo, DragOptions options) {
         View child = cellInfo.cell;
 
         // Make sure the drag was started by a long press as opposed to a long click.
@@ -2317,10 +2279,25 @@
         CellLayout layout = (CellLayout) child.getParent().getParent();
         layout.prepareChildForDrag(child);
 
-        beginDragShared(child, this, accessible);
+        if (options.isAccessibleDrag) {
+            mDragController.addDragListener(new AccessibileDragListenerAdapter(
+                    this, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG) {
+                @Override
+                protected void enableAccessibleDrag(boolean enable) {
+                    super.enableAccessibleDrag(enable);
+                    setEnableForLayout(mLauncher.getHotseat().getLayout(),enable);
+
+                    // We need to allow our individual children to become click handlers in this
+                    // case, so temporarily unset the click handlers.
+                    setOnClickListener(enable ? null : mLauncher);
+                }
+            });
+        }
+
+        beginDragShared(child, this, options);
     }
 
-    public void beginDragShared(View child, DragSource source, boolean accessible) {
+    public void beginDragShared(View child, DragSource source, DragOptions options) {
         Object dragObject = child.getTag();
         if (!(dragObject instanceof ItemInfo)) {
             String msg = "Drag started with a view that has no tag set. This "
@@ -2328,20 +2305,17 @@
                     + "View: " + child + "  tag: " + child.getTag();
             throw new IllegalStateException(msg);
         }
-        beginDragShared(child, source, accessible, (ItemInfo) dragObject,
-                new DragPreviewProvider(child));
+        beginDragShared(child, source, (ItemInfo) dragObject,
+                new DragPreviewProvider(child), options);
     }
 
 
-    public DragView beginDragShared(View child, DragSource source, boolean accessible,
-            ItemInfo dragObject, DragPreviewProvider previewProvider) {
+    public DragView beginDragShared(View child, DragSource source, ItemInfo dragObject,
+            DragPreviewProvider previewProvider, DragOptions dragOptions) {
         child.clearFocus();
         child.setPressed(false);
+        mOutlineProvider = previewProvider;
 
-        // The outline is used to visualize where the item will land if dropped
-        mDragOutline = previewProvider.createDragOutline(mCanvas);
-
-        mLauncher.onDragStarted(child);
         // The drag bitmap follows the touch point around on the screen
         final Bitmap b = previewProvider.createDragBitmap(mCanvas);
         int halfPadding = previewProvider.previewPadding / 2;
@@ -2381,15 +2355,9 @@
         }
 
         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source,
-                dragObject, DragController.DRAG_ACTION_MOVE, dragVisualizeOffset,
-                dragRect, scale, accessible);
+                dragObject, dragVisualizeOffset, dragRect, scale, dragOptions);
         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
-
         b.recycle();
-
-        if (!FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND) {
-            mLauncher.enterSpringLoadedDragMode();
-        }
         return dv;
     }
 
@@ -2966,7 +2934,7 @@
 
     private void cleanupAddToFolder() {
         if (mDragOverFolderIcon != null) {
-            mDragOverFolderIcon.onDragExit(null);
+            mDragOverFolderIcon.onDragExit();
             mDragOverFolderIcon = null;
         }
     }
@@ -3180,7 +3148,7 @@
                     item.spanY, child, mTargetCell);
 
             if (!nearestDropOccupied) {
-                mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
+                mDragTargetLayout.visualizeDropLocation(child, mOutlineProvider,
                         mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false, d);
             } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
                     && !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX ||
@@ -3325,7 +3293,7 @@
             }
 
             boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;
-            mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
+            mDragTargetLayout.visualizeDropLocation(child, mOutlineProvider,
                 mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize, dragObject);
         }
     }
@@ -3717,7 +3685,7 @@
                 && mDragInfo.cell != null) {
             mDragInfo.cell.setVisibility(VISIBLE);
         }
-        mDragOutline = null;
+        mOutlineProvider = null;
         mDragInfo = null;
 
         if (!isFlingToDelete) {
diff --git a/src/com/android/launcher3/accessibility/AccessibileDragListenerAdapter.java b/src/com/android/launcher3/accessibility/AccessibileDragListenerAdapter.java
new file mode 100644
index 0000000..62a9a6d
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/AccessibileDragListenerAdapter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.accessibility;
+
+import android.view.ViewGroup;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.dragndrop.DragController.DragListener;
+import com.android.launcher3.dragndrop.DragOptions;
+
+/**
+ * Utility listener to enable/disable accessibility drag flags for a ViewGroup
+ * containing CellLayouts
+ */
+public class AccessibileDragListenerAdapter implements DragListener {
+
+    private final ViewGroup mViewGroup;
+    private final int mDragType;
+
+    /**
+     * @param parent
+     * @param dragType either {@link CellLayout#WORKSPACE_ACCESSIBILITY_DRAG} or
+     *                 {@link CellLayout#FOLDER_ACCESSIBILITY_DRAG}
+     */
+    public AccessibileDragListenerAdapter(ViewGroup parent, int dragType) {
+        mViewGroup = parent;
+        mDragType = dragType;
+    }
+
+    @Override
+    public void onDragStart(DragObject dragObject, DragOptions options) {
+        enableAccessibleDrag(true);
+    }
+
+    @Override
+    public void onDragEnd() {
+        enableAccessibleDrag(false);
+        Launcher.getLauncher(mViewGroup.getContext()).getDragController().removeDragListener(this);
+    }
+
+    protected void enableAccessibleDrag(boolean enable) {
+        for (int i = 0; i < mViewGroup.getChildCount(); i++) {
+            setEnableForLayout((CellLayout) mViewGroup.getChildAt(i), enable);
+        }
+    }
+
+    protected final void setEnableForLayout(CellLayout layout, boolean enable) {
+        layout.enableAccessibleDrag(enable, mDragType);
+    }
+}
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 0562cf5..173aad0 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -22,6 +22,8 @@
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeleteDropTarget;
 import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.FolderInfo;
 import com.android.launcher3.InfoDropTarget;
@@ -73,7 +75,6 @@
     @Thunk final Launcher mLauncher;
 
     private DragInfo mDragInfo = null;
-    private AccessibilityDragSource mDragSource = null;
 
     public LauncherAccessibilityDelegate(Launcher launcher) {
         mLauncher = launcher;
@@ -372,26 +373,25 @@
 
         Folder folder = workspace.getOpenFolder();
         if (folder != null) {
-            if (folder.getItemsInReadingOrder().contains(item)) {
-                mDragSource = folder;
-            } else {
+            if (!folder.getItemsInReadingOrder().contains(item)) {
                 mLauncher.closeFolder();
+                folder = null;
             }
         }
-        if (mDragSource == null) {
-            mDragSource = workspace;
-        }
-        mDragSource.enableAccessibleDrag(true);
-        mDragSource.startDrag(cellInfo, true);
 
-        if (mLauncher.getDragController().isDragging()) {
-            mLauncher.getDragController().addDragListener(this);
+        mLauncher.getDragController().addDragListener(this);
+
+        DragOptions options = new DragOptions();
+        options.isAccessibleDrag = true;
+        if (folder != null) {
+            folder.startDrag(cellInfo.cell, options);
+        } else {
+            workspace.startDrag(cellInfo, options);
         }
     }
 
-
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
+    public void onDragStart(DragObject dragObject, DragOptions options) {
         // No-op
     }
 
@@ -399,16 +399,6 @@
     public void onDragEnd() {
         mLauncher.getDragController().removeDragListener(this);
         mDragInfo = null;
-        if (mDragSource != null) {
-            mDragSource.enableAccessibleDrag(false);
-            mDragSource = null;
-        }
-    }
-
-    public static interface AccessibilityDragSource {
-        void startDrag(CellLayout.CellInfo cellInfo, boolean accessible);
-
-        void enableAccessibleDrag(boolean enable);
     }
 
     /**
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index ff70279..0baa8f3 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.shortcuts.DeepShortcutView;
 
 import java.util.ArrayList;
 
@@ -46,7 +47,10 @@
     @Override
     public boolean performAction(View host, ItemInfo item, int action) {
         if (action == ADD_TO_WORKSPACE) {
-            final ShortcutInfo info = (ShortcutInfo) item;
+            if (!(host.getParent() instanceof DeepShortcutView)) {
+                return false;
+            }
+            final ShortcutInfo info = ((DeepShortcutView) host.getParent()).getFinalInfo();
             final int[] coordinates = new int[2];
             final long screenId = findSpaceOnWorkspace(item, coordinates);
             Runnable onComplete = new Runnable() {
diff --git a/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java b/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java
index dafa73f..cfd07e6 100644
--- a/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java
+++ b/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java
@@ -96,14 +96,14 @@
     public AllAppsBackgroundDrawable(Context context) {
         Resources res = context.getResources();
         mHand = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_hand,
-                0.575f, 0.1f, Gravity.CENTER_HORIZONTAL);
+                0.575f, 0.f, Gravity.CENTER_HORIZONTAL);
         mIcons = new TransformedImageDrawable[4];
         mIcons[0] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_1,
                 0.375f, 0, Gravity.CENTER_HORIZONTAL);
         mIcons[1] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_2,
-                0.3125f, 0.25f, Gravity.CENTER_HORIZONTAL);
+                0.3125f, 0.2f, Gravity.CENTER_HORIZONTAL);
         mIcons[2] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_3,
-                0.475f, 0.4f, Gravity.CENTER_HORIZONTAL);
+                0.475f, 0.26f, Gravity.CENTER_HORIZONTAL);
         mIcons[3] = new TransformedImageDrawable(res, R.drawable.ic_all_apps_bg_icon_4,
                 0.7f, 0.125f, Gravity.CENTER_HORIZONTAL);
         mWidth = res.getDimensionPixelSize(R.dimen.all_apps_background_canvas_width);
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index a8e2140..290accb 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -25,6 +25,7 @@
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
 import android.text.method.TextKeyListener;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
@@ -48,10 +49,10 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.graphics.TintedDrawableSpan;
 import com.android.launcher3.keyboard.FocusedItemDecorator;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.ComponentKey;
 
@@ -277,6 +278,12 @@
         if (mAppsRecyclerView.getScrollBar().isNearThumb(point[0], point[1])) {
             return false;
         }
+
+        // IF a shortcuts container is open, container should not be pulled down.
+        if (mLauncher.getOpenShortcutsContainer() != null) {
+            return false;
+        }
+
         // IF scroller is at the very top OR there is no scroll bar because there is probably not
         // enough items to scroll, THEN it's okay for the container to be pulled down.
         if (mAppsRecyclerView.getScrollBar().getThumbOffset().y <= 0) {
@@ -539,7 +546,7 @@
         if (!mLauncher.isDraggingEnabled()) return false;
 
         // Start the drag
-        mLauncher.getWorkspace().beginDragShared(v, this, false);
+        mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions());
         // Enter spring loaded mode
         mLauncher.enterSpringLoadedDragMode();
 
@@ -707,4 +714,8 @@
     public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
         targetParent.containerType = mAppsRecyclerView.getContainerType(v);
     }
+
+    public boolean shouldRestoreImeState() {
+        return !TextUtils.isEmpty(mSearchInput.getText());
+    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
index 9a48367..365ab31 100644
--- a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
@@ -127,10 +127,9 @@
 
     @Override
     public boolean onBackKey() {
-        // Only hide the search field if there is no query, or if there
-        // are no filtered results
+        // Only hide the search field if there is no query
         String query = Utilities.trim(mInput.getEditableText().toString());
-        if (query.isEmpty() || mApps.hasNoFilteredResults()) {
+        if (query.isEmpty()) {
             reset();
             return true;
         }
@@ -163,8 +162,7 @@
      * Focuses the search field to handle key events.
      */
     public void focusSearchField() {
-        mInput.requestFocus();
-        mInputMethodManager.showSoftInput(mInput, InputMethodManager.SHOW_IMPLICIT);
+        mInput.showKeyboard();
     }
 
     /**
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 41d6393..1719b05 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -6,6 +6,7 @@
 import android.animation.AnimatorSet;
 import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
+import android.support.v4.content.ContextCompat;
 import android.support.v4.view.animation.FastOutSlowInInterpolator;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -101,7 +102,7 @@
                 R.dimen.all_apps_bezel_swipe_height);
 
         mEvaluator = new ArgbEvaluator();
-        mAllAppsBackgroundColor = l.getColor(R.color.all_apps_container_color);
+        mAllAppsBackgroundColor = ContextCompat.getColor(l, R.color.all_apps_container_color);
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithm.java
index 10740ec..ac22dd2 100644
--- a/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithm.java
@@ -22,15 +22,12 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.regex.Pattern;
 
 /**
  * The default search implementation.
  */
 public class DefaultAppSearchAlgorithm {
 
-    private static final Pattern SPLIT_PATTERN = Pattern.compile("[\\s|\\p{javaSpaceChar}]+");
-
     private final List<AppInfo> mApps;
     protected final Handler mResultHandler;
 
@@ -61,34 +58,79 @@
         // Do an intersection of the words in the query and each title, and filter out all the
         // apps that don't match all of the words in the query.
         final String queryTextLower = query.toLowerCase();
-        final String[] queryWords = SPLIT_PATTERN.split(queryTextLower);
-
         final ArrayList<ComponentKey> result = new ArrayList<>();
         for (AppInfo info : mApps) {
-            if (matches(info, queryWords)) {
+            if (matches(info, queryTextLower)) {
                 result.add(info.toComponentKey());
             }
         }
         return result;
     }
 
-    protected boolean matches(AppInfo info, String[] queryWords) {
+    protected boolean matches(AppInfo info, String query) {
+        int queryLength = query.length();
+
         String title = info.title.toString();
-        String[] words = SPLIT_PATTERN.split(title.toLowerCase());
-        for (int qi = 0; qi < queryWords.length; qi++) {
-            boolean foundMatch = false;
-            for (int i = 0; i < words.length; i++) {
-                if (words[i].startsWith(queryWords[qi])) {
-                    foundMatch = true;
-                    break;
-                }
-            }
-            if (!foundMatch) {
-                // If there is a word in the query that does not match any words in this
-                // title, so skip it.
-                return false;
+        int titleLength = title.length();
+
+        if (titleLength < queryLength || queryLength <= 0) {
+            return false;
+        }
+
+        int lastType;
+        int thisType = Character.UNASSIGNED;
+        int nextType = Character.getType(title.codePointAt(0));
+
+        int end = titleLength - queryLength;
+        for (int i = 0; i <= end; i++) {
+            lastType = thisType;
+            thisType = nextType;
+            nextType = i < (titleLength - 1) ?
+                    Character.getType(title.codePointAt(i + 1)) : Character.UNASSIGNED;
+            if (isBreak(thisType, lastType, nextType) &&
+                    title.substring(i, i + queryLength).equalsIgnoreCase(query)) {
+                return true;
             }
         }
-        return true;
+        return false;
+    }
+
+    /**
+     * Returns true if the current point should be a break point. Following cases
+     * are considered as break points:
+     *      1) Any non space character after a space character
+     *      2) Any digit after a non-digit character
+     *      3) Any capital character after a digit or small character
+     *      4) Any capital character before a small character
+     */
+    protected boolean isBreak(int thisType, int prevType, int nextType) {
+        switch (thisType) {
+            case Character.UPPERCASE_LETTER:
+                if (nextType == Character.UPPERCASE_LETTER) {
+                    return true;
+                }
+                // Follow through
+            case Character.TITLECASE_LETTER:
+                // Break point if previous was not a upper case
+                return prevType != Character.UPPERCASE_LETTER;
+            case Character.LOWERCASE_LETTER:
+                // Break point if previous was not a letter.
+                return prevType > Character.OTHER_LETTER;
+            case Character.DECIMAL_DIGIT_NUMBER:
+            case Character.LETTER_NUMBER:
+            case Character.OTHER_NUMBER:
+                // Break point if previous was not a number
+                return !(prevType == Character.DECIMAL_DIGIT_NUMBER
+                        || prevType == Character.LETTER_NUMBER
+                        || prevType == Character.OTHER_NUMBER);
+            case Character.MATH_SYMBOL:
+            case Character.CURRENCY_SYMBOL:
+            case Character.OTHER_PUNCTUATION:
+            case Character.DASH_PUNCTUATION:
+                // Always a break point for a symbol
+                return true;
+            default:
+                return false;
+        }
     }
 }
diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java
index 29ed5d9..a5f8dd2 100644
--- a/src/com/android/launcher3/compat/UserManagerCompat.java
+++ b/src/com/android/launcher3/compat/UserManagerCompat.java
@@ -32,8 +32,12 @@
     public static UserManagerCompat getInstance(Context context) {
         synchronized (sInstanceLock) {
             if (sInstance == null) {
-                if (Utilities.isNycOrAbove()) {
+                if (Utilities.isNycMR1OrAbove()) {
+                    sInstance = new UserManagerCompatVNMr1(context.getApplicationContext());
+                } else if (Utilities.isNycOrAbove()) {
                     sInstance = new UserManagerCompatVN(context.getApplicationContext());
+                } else if (Utilities.ATLEAST_MARSHMALLOW) {
+                    sInstance = new UserManagerCompatVM(context.getApplicationContext());
                 } else if (Utilities.ATLEAST_LOLLIPOP) {
                     sInstance = new UserManagerCompatVL(context.getApplicationContext());
                 } else if (Utilities.ATLEAST_JB_MR1) {
@@ -58,4 +62,6 @@
     public abstract long getUserCreationTime(UserHandleCompat user);
     public abstract boolean isQuietModeEnabled(UserHandleCompat user);
     public abstract boolean isUserUnlocked(UserHandleCompat user);
+
+    public abstract boolean isDemoUser();
 }
diff --git a/src/com/android/launcher3/compat/UserManagerCompatV16.java b/src/com/android/launcher3/compat/UserManagerCompatV16.java
index e678ffa..9bd4567 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatV16.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatV16.java
@@ -60,4 +60,9 @@
     public boolean isUserUnlocked(UserHandleCompat user) {
         return true;
     }
+
+    @Override
+    public boolean isDemoUser() {
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java
index c53d702..2552b0c 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (C) 2014 The Android Open Source Project
  *
@@ -94,9 +93,6 @@
 
     @Override
     public long getUserCreationTime(UserHandleCompat user) {
-        if (Utilities.ATLEAST_MARSHMALLOW) {
-            return mUserManager.getUserCreationTime(user.getUser());
-        }
         SharedPreferences prefs = Utilities.getPrefs(mContext);
         String key = USER_CREATION_TIME_KEY + getSerialNumberForUser(user);
         if (!prefs.contains(key)) {
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVM.java b/src/com/android/launcher3/compat/UserManagerCompatVM.java
new file mode 100644
index 0000000..81d67ea
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserManagerCompatVM.java
@@ -0,0 +1,34 @@
+/*
+ * 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.compat;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+
+@TargetApi(Build.VERSION_CODES.M)
+public class UserManagerCompatVM extends UserManagerCompatVL {
+
+    UserManagerCompatVM(Context context) {
+        super(context);
+    }
+
+    @Override
+    public long getUserCreationTime(UserHandleCompat user) {
+        return mUserManager.getUserCreationTime(user.getUser());
+    }
+}
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVN.java b/src/com/android/launcher3/compat/UserManagerCompatVN.java
index 771d141..4edac05 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVN.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVN.java
@@ -20,10 +20,10 @@
 import android.content.Context;
 import android.os.Build;
 
-@TargetApi(Build.VERSION_CODES.N)
-public class UserManagerCompatVN extends UserManagerCompatVL {
+import com.android.launcher3.Utilities;
 
-    private static final String TAG = "UserManagerCompatVN";
+@TargetApi(Build.VERSION_CODES.N)
+public class UserManagerCompatVN extends UserManagerCompatVM {
 
     UserManagerCompatVN(Context context) {
         super(context);
@@ -36,12 +36,7 @@
 
     @Override
     public boolean isUserUnlocked(UserHandleCompat user) {
-        // TODO: Remove the try-catch block when the API permission has been relaxed (b/30475753)
-        try {
-            return mUserManager.isUserUnlocked(user.getUser());
-        } catch (RuntimeException e) {
-            return !isQuietModeEnabled(user);
-        }
+        return mUserManager.isUserUnlocked(user.getUser());
     }
 }
 
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVNMr1.java b/src/com/android/launcher3/compat/UserManagerCompatVNMr1.java
new file mode 100644
index 0000000..3f64bc8
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserManagerCompatVNMr1.java
@@ -0,0 +1,34 @@
+/*
+ * 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.compat;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+
+@TargetApi(Build.VERSION_CODES.N_MR1)
+public class UserManagerCompatVNMr1 extends UserManagerCompatVN {
+
+    UserManagerCompatVNMr1(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean isDemoUser() {
+        return mUserManager.isDemoUser();
+    }
+}
diff --git a/src/com/android/launcher3/dragndrop/AnotherWindowDragSource.java b/src/com/android/launcher3/dragndrop/AnotherWindowDragSource.java
new file mode 100644
index 0000000..156941a
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/AnotherWindowDragSource.java
@@ -0,0 +1,76 @@
+/*
+ * 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.dragndrop;
+
+import android.content.Context;
+import android.view.View;
+
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+
+/**
+ * DragSource used when the drag started at another window.
+ */
+public class AnotherWindowDragSource implements DragSource {
+
+    private final Context mContext;
+
+    AnotherWindowDragSource(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public boolean supportsFlingToDelete() {
+        return false;
+    }
+
+    @Override
+    public boolean supportsAppInfoDropTarget() {
+        return false;
+    }
+
+    @Override
+    public boolean supportsDeleteDropTarget() {
+        return false;
+    }
+
+    @Override
+    public float getIntrinsicIconScaleFactor() {
+        return 1;
+    }
+
+    @Override
+    public void onFlingToDeleteCompleted() {
+    }
+
+    @Override
+    public void onDropCompleted(View target, DragObject d,
+            boolean isFlingToDelete, boolean success) {
+        if (!success) {
+            Launcher.getLauncher(mContext).exitSpringLoadedDragModeDelayed(false, 0, null);
+        }
+
+    }
+
+    @Override
+    public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
+        // TODO: Probably log something
+    }
+}
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index b57f5bf..a93ee90 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -25,7 +25,6 @@
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.IBinder;
-import android.util.Log;
 import android.view.DragEvent;
 import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
@@ -57,12 +56,6 @@
 public class DragController implements DragDriver.EventListener, TouchController {
     private static final String TAG = "Launcher.DragController";
 
-    /** Indicates the drag is a move.  */
-    public static int DRAG_ACTION_MOVE = 0;
-
-    /** Indicates the drag is a copy.  */
-    public static int DRAG_ACTION_COPY = 1;
-
     public static final int SCROLL_DELAY = 500;
     public static final int RESCROLL_DELAY = PagedView.PAGE_SNAP_ANIMATION_DURATION + 150;
 
@@ -91,8 +84,8 @@
      */
     private DragDriver mDragDriver = null;
 
-    /** Whether or not an accessible drag operation is in progress. */
-    private boolean mIsAccessibleDrag;
+    /** Options controlling the drag behavior. */
+    private DragOptions mOptions;
 
     /** X coordinate of the down event. */
     private int mMotionDownX;
@@ -145,12 +138,10 @@
         /**
          * A drag has begun
          *
-         * @param source An object representing where the drag originated
-         * @param info The data associated with the object that is being dragged
-         * @param dragAction The drag action: either {@link DragController#DRAG_ACTION_MOVE}
-         *        or {@link DragController#DRAG_ACTION_COPY}
+         * @param dragObject The object being dragged
+         * @param options Options used to start the drag
          */
-        void onDragStart(DragSource source, ItemInfo info, int dragAction);
+        void onDragStart(DropTarget.DragObject dragObject, DragOptions options);
 
         /**
          * The drag has ended
@@ -160,8 +151,6 @@
 
     /**
      * Used to create a new DragLayer from XML.
-     *
-     * @param context The application's context.
      */
     public DragController(Launcher launcher) {
         Resources r = launcher.getResources();
@@ -183,11 +172,9 @@
      * @param source An object representing where the drag originated
      * @param dragInfo The data associated with the object that is being dragged
      * @param viewImageBounds the position of the image inside the view
-     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
-     *        {@link #DRAG_ACTION_COPY}
      */
     public void startDrag(View v, Bitmap bmp, DragSource source, ItemInfo dragInfo,
-            Rect viewImageBounds, int dragAction, float initialDragViewScale) {
+            Rect viewImageBounds, float initialDragViewScale, DragOptions options) {
         int[] loc = mCoordinatesTemp;
         mLauncher.getDragLayer().getLocationInDragLayer(v, loc);
         int dragLayerX = loc[0] + viewImageBounds.left
@@ -195,12 +182,8 @@
         int dragLayerY = loc[1] + viewImageBounds.top
                 + (int) ((initialDragViewScale * bmp.getHeight() - bmp.getHeight()) / 2);
 
-        startDrag(bmp, dragLayerX, dragLayerY, source, dragInfo, dragAction, null,
-                null, initialDragViewScale, false);
-
-        if (dragAction == DRAG_ACTION_MOVE) {
-            v.setVisibility(View.GONE);
-        }
+        startDrag(bmp, dragLayerX, dragLayerY, source, dragInfo, null,
+                null, initialDragViewScale, options);
     }
 
     /**
@@ -212,15 +195,12 @@
      * @param dragLayerY The y position in the DragLayer of the left-top of the bitmap.
      * @param source An object representing where the drag originated
      * @param dragInfo The data associated with the object that is being dragged
-     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
-     *        {@link #DRAG_ACTION_COPY}
      * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
      *          Makes dragging feel more precise, e.g. you can clip out a transparent border
-     * @param accessible whether this drag should occur in accessibility mode
      */
     public DragView startDrag(Bitmap b, int dragLayerX, int dragLayerY,
-            DragSource source, ItemInfo dragInfo, int dragAction, Point dragOffset, Rect dragRegion,
-            float initialDragViewScale, boolean accessible) {
+            DragSource source, ItemInfo dragInfo, Point dragOffset, Rect dragRegion,
+            float initialDragViewScale, DragOptions options) {
         if (PROFILE_DRAWING_DURING_DRAG) {
             android.os.Debug.startMethodTracing("Launcher");
         }
@@ -232,8 +212,10 @@
         }
         mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0);
 
-        for (DragListener listener : mListeners) {
-            listener.onDragStart(source, dragInfo, dragAction);
+        mOptions = options;
+        if (mOptions.systemDndStartPoint != null) {
+            mMotionDownX = mOptions.systemDndStartPoint.x;
+            mMotionDownY = mOptions.systemDndStartPoint.y;
         }
 
         final int registrationX = mMotionDownX - dragLayerX;
@@ -242,7 +224,6 @@
         final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
         final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
 
-        mIsAccessibleDrag = accessible;
         mLastDropTarget = null;
 
         mDragObject = new DropTarget.DragObject();
@@ -254,7 +235,7 @@
                 registrationY, initialDragViewScale, scaleDps);
 
         mDragObject.dragComplete = false;
-        if (mIsAccessibleDrag) {
+        if (mOptions.isAccessibleDrag) {
             // For an accessible drag, we assume the view is being dragged from the center.
             mDragObject.xOffset = b.getWidth() / 2;
             mDragObject.yOffset = b.getHeight() / 2;
@@ -264,7 +245,7 @@
             mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
             mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView);
 
-            mDragDriver = DragDriver.create(this, dragInfo, dragView);
+            mDragDriver = DragDriver.create(mLauncher, this, mDragObject, mOptions);
         }
 
         mDragObject.dragSource = source;
@@ -282,6 +263,11 @@
         mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
         dragView.show(mMotionDownX, mMotionDownY);
         mDistanceSinceScroll = 0;
+
+        for (DragListener listener : new ArrayList<>(mListeners)) {
+            listener.onDragStart(mDragObject, mOptions);
+        }
+
         mLastTouch[0] = mMotionDownX;
         mLastTouch[1] = mMotionDownY;
         handleMoveEvent(mMotionDownX, mMotionDownY);
@@ -308,7 +294,11 @@
     }
 
     public boolean isDragging() {
-        return mDragDriver != null || mIsAccessibleDrag;
+        return mDragDriver != null || (mOptions != null && mOptions.isAccessibleDrag);
+    }
+
+    public boolean isExternalDrag() {
+        return (mOptions != null && mOptions.systemDndStartPoint != null);
     }
 
     /**
@@ -343,7 +333,7 @@
     private void endDrag() {
         if (isDragging()) {
             mDragDriver = null;
-            mIsAccessibleDrag = false;
+            mOptions = null;
             clearScrollRunnable();
             boolean isDeferred = false;
             if (mDragObject.dragView != null) {
@@ -422,10 +412,6 @@
 
     @Override
     public void onDriverDragEnd(float x, float y, DropTarget dropTargetOverride) {
-        final int[] dragLayerPos = getClampedDragLayerPos(x, y);
-        final int dragLayerX = dragLayerPos[0];
-        final int dragLayerY = dragLayerPos[1];
-
         DropTarget dropTarget;
         PointF vec = null;
 
@@ -454,14 +440,7 @@
      * Call this from a drag source view.
      */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        @SuppressWarnings("all") // suppress dead code warning
-        final boolean debug = false;
-        if (debug) {
-            Log.d(Launcher.TAG, "DragController.onInterceptTouchEvent " + ev + " Dragging="
-                    + (mDragDriver != null));
-        }
-
-        if (mIsAccessibleDrag) {
+        if (mOptions != null && mOptions.isAccessibleDrag) {
             return false;
         }
 
@@ -604,7 +583,7 @@
      * Call this from a drag source view.
      */
     public boolean onTouchEvent(MotionEvent ev) {
-        if (mDragDriver == null || mIsAccessibleDrag) {
+        if (mDragDriver == null || mOptions == null || mOptions.isAccessibleDrag) {
             return false;
         }
 
diff --git a/src/com/android/launcher3/dragndrop/DragDriver.java b/src/com/android/launcher3/dragndrop/DragDriver.java
index 2164708..4db8c07 100644
--- a/src/com/android/launcher3/dragndrop/DragDriver.java
+++ b/src/com/android/launcher3/dragndrop/DragDriver.java
@@ -17,18 +17,19 @@
 package com.android.launcher3.dragndrop;
 
 import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
 import android.content.Intent;
-import android.graphics.Canvas;
-import android.graphics.Point;
 import android.view.DragEvent;
 import android.view.MotionEvent;
-import android.view.View;
 
-import com.android.launcher3.AnotherWindowDropTarget;
 import com.android.launcher3.DropTarget;
-import com.android.launcher3.ItemInfo;
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.InstallShortcutReceiver;
+import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
+
+import java.util.ArrayList;
 
 /**
  * Base class for driving a drag/drop operation.
@@ -50,7 +51,7 @@
     /**
      * Handles ending of the DragView animation.
      */
-    public abstract void onDragViewAnimationEnd();
+    public void onDragViewAnimationEnd() { }
 
     public boolean onTouchEvent(MotionEvent ev) {
         final int action = ev.getAction();
@@ -89,100 +90,46 @@
         return true;
     }
 
-    public static DragDriver create(
-            DragController dragController, ItemInfo dragInfo, DragView dragView) {
-        if (FeatureFlags.LAUNCHER3_USE_SYSTEM_DRAG_DRIVER && Utilities.isNycOrAbove()) {
-            return new SystemDragDriver(dragController, dragInfo.getIntent(), dragView);
+    public static DragDriver create(Context context, DragController dragController,
+            DragObject dragObject, DragOptions options) {
+        if (Utilities.isNycOrAbove() && options.systemDndStartPoint != null) {
+            return new SystemDragDriver(dragController, context, dragObject);
         } else {
             return new InternalDragDriver(dragController);
         }
     }
-
-};
+}
 
 /**
  * Class for driving a system (i.e. framework) drag/drop operation.
  */
 class SystemDragDriver extends DragDriver {
-    /** Intent associated with the drag operation, or null is there no associated intent.  */
-    private final Intent mDragIntent;
 
-    private final DragView mDragView;
-    boolean mIsFrameworkDragActive = false;
+    private final DragObject mDragObject;
+    private final Context mContext;
+
     boolean mReceivedDropEvent = false;
     float mLastX = 0;
     float mLastY = 0;
 
-    public SystemDragDriver(DragController dragController, Intent dragIntent, DragView dragView) {
+    public SystemDragDriver(DragController dragController, Context context, DragObject dragObject) {
         super(dragController);
-        mDragIntent = dragIntent;
-        mDragView = dragView;
-    }
-
-    private static class ShadowBuilder extends View.DragShadowBuilder {
-        final DragView mDragView;
-
-        public ShadowBuilder(DragView dragView) {
-            mDragView = dragView;
-        }
-
-        @Override
-        public void onProvideShadowMetrics (Point size, Point touch) {
-            mDragView.provideDragShadowMetrics(size, touch);
-        }
-
-        @Override
-        public void onDrawShadow(Canvas canvas) {
-            mDragView.drawDragShadow(canvas);
-        }
-    };
-
-    @Override
-    public void onDragViewAnimationEnd() {
-        // Clip data for the drag operation. If there is an intent, create an intent-based ClipData,
-        // which will be passed to a global DND.
-        // If there is no intent, craft a fake ClipData and start a local DND operation; this
-        // ClipData will be ignored.
-        final ClipData dragData = mDragIntent != null ?
-                ClipData.newIntent("", mDragIntent) :
-                ClipData.newPlainText("", "");
-
-        View.DragShadowBuilder shadowBuilder = new ShadowBuilder(mDragView);
-        // TODO: DND flags are in flux, once settled, use the appropriate constant.
-        final int flagGlobal = 1 << 0;
-        final int flagOpaque = 1 << 9;
-        final int flags = (mDragIntent != null ? flagGlobal : 0) | flagOpaque;
-
-        mIsFrameworkDragActive = true;
-
-        if (!mDragView.startDrag(dragData, shadowBuilder, null, flags)) {
-            mIsFrameworkDragActive = false;
-            mEventListener.onDriverDragCancel();
-            return;
-        }
-
-        // Starting from this point, the driver takes over showing the drag shadow, so hiding the
-        // drag view.
-        mDragView.setVisibility(View.INVISIBLE);
+        mDragObject = dragObject;
+        mContext = context;
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        return !mIsFrameworkDragActive && super.onTouchEvent(ev);
+        return false;
     }
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        return !mIsFrameworkDragActive && super.onInterceptTouchEvent(ev);
+        return false;
     }
 
     @Override
     public boolean onDragEvent (DragEvent event) {
-        if (!mIsFrameworkDragActive) {
-            // We are interested only in drag events started by this driver.
-            return false;
-        }
-
         final int action = event.getAction();
 
         switch (action) {
@@ -192,8 +139,6 @@
                 return true;
 
             case DragEvent.ACTION_DRAG_ENTERED:
-                mLastX = event.getX();
-                mLastY = event.getY();
                 return true;
 
             case DragEvent.ACTION_DRAG_LOCATION:
@@ -205,35 +150,66 @@
             case DragEvent.ACTION_DROP:
                 mLastX = event.getX();
                 mLastY = event.getY();
-                mReceivedDropEvent = true;
-                return true;
+                mReceivedDropEvent =
+                        updateInfoFromClipData(event.getClipData(), event.getClipDescription());
+                return mReceivedDropEvent;
 
             case DragEvent.ACTION_DRAG_EXITED:
-                mLastX = event.getX();
-                mLastY = event.getY();
                 mEventListener.onDriverDragExitWindow();
                 return true;
 
             case DragEvent.ACTION_DRAG_ENDED:
-                final boolean dragAccepted = event.getResult();
-                final boolean acceptedByAnotherWindow = dragAccepted && !mReceivedDropEvent;
-
-                // When the system drag ends, its drag shadow disappears. Resume showing the drag
-                // view for the possible final animation.
-                mDragView.setVisibility(View.VISIBLE);
-
-                final DropTarget dropTargetOverride = acceptedByAnotherWindow ?
-                        new AnotherWindowDropTarget(mDragView.getContext()) : null;
-
-                mEventListener.onDriverDragEnd(mLastX, mLastY, dropTargetOverride);
-                mIsFrameworkDragActive = false;
+                if (mReceivedDropEvent) {
+                    mEventListener.onDriverDragEnd(mLastX, mLastY, null);
+                } else {
+                    mEventListener.onDriverDragCancel();
+                }
                 return true;
 
             default:
                 return false;
         }
     }
-};
+
+    private boolean updateInfoFromClipData(ClipData data, ClipDescription desc) {
+        if (data == null) {
+            return false;
+        }
+        ArrayList<Intent> intents = new ArrayList<>();
+        int itemCount = data.getItemCount();
+        for (int i = 0; i < itemCount; i++) {
+            Intent intent = data.getItemAt(i).getIntent();
+            if (intent == null) {
+                continue;
+            }
+
+            // Give preference to shortcut intents.
+            if (!Intent.ACTION_CREATE_SHORTCUT.equals(intent.getAction())) {
+                intents.add(intent);
+                continue;
+            }
+            ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, intent);
+            if (info != null) {
+                mDragObject.dragInfo = info;
+                return true;
+            }
+            return true;
+        }
+
+        // Try creating shortcuts just using the intent and label
+        Intent fullIntent = new Intent().putExtra(Intent.EXTRA_SHORTCUT_NAME, desc.getLabel());
+        for (Intent intent : intents) {
+            fullIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent);
+            ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, fullIntent);
+            if (info != null) {
+                mDragObject.dragInfo = info;
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
 
 /**
  * Class for driving an internal (i.e. not using framework) drag/drop operation.
@@ -244,8 +220,5 @@
     }
 
     @Override
-    public void onDragViewAnimationEnd() {}
-
-    @Override
     public boolean onDragEvent (DragEvent event) { return false; }
 };
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index e88e77e..016347b 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -21,14 +21,22 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
+import android.content.ClipDescription;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.DragEvent;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -45,12 +53,14 @@
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DropTargetBar;
 import com.android.launcher3.InsettableFrameLayout;
+import com.android.launcher3.InstallShortcutReceiver;
 import com.android.launcher3.ItemInfo;
 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;
+import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.allapps.AllAppsTransitionController;
@@ -62,6 +72,7 @@
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.TouchController;
 
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 
 /**
@@ -100,7 +111,6 @@
 
     private TouchCompleteListener mTouchCompleteListener;
 
-    private View mOverlayView;
     private int mTopViewIndex;
     private int mChildCountOnLastUpdate = -1;
 
@@ -172,20 +182,6 @@
                 ? null : new PinchToOverviewListener(mLauncher);
     }
 
-    public void showOverlayView(View overlayView) {
-        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-        mOverlayView = overlayView;
-        addView(overlayView, lp);
-
-        // ensure that the overlay view stays on top. we can't use drawing order for this
-        // because in API level 16 touch dispatch doesn't respect drawing order.
-        mOverlayView.bringToFront();
-    }
-
-    public void dismissOverlayView() {
-        removeView(mOverlayView);
-    }
-
     public boolean isEventOverPageIndicator(MotionEvent ev) {
         getDescendantRectRelativeToSelf(mLauncher.getWorkspace().getPageIndicator(), mHitRect);
         return mHitRect.contains((int) ev.getX(), (int) ev.getY());
@@ -358,16 +354,9 @@
     }
 
     private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
-        AccessibilityManager accessibilityManager = (AccessibilityManager)
-                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-        if (accessibilityManager.isEnabled()) {
-            int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
-            AccessibilityEvent event = AccessibilityEvent.obtain(
-                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
-            onInitializeAccessibilityEvent(event);
-            event.getText().add(getContext().getString(stringId));
-            accessibilityManager.sendAccessibilityEvent(event);
-        }
+        int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
+        Utilities.sendCustomAccessibilityEvent(
+                this, AccessibilityEvent.TYPE_VIEW_FOCUSED, getContext().getString(stringId));
     }
 
     private boolean isInAccessibleDrag() {
@@ -377,37 +366,27 @@
     @Override
     public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
         // Shortcuts can appear above folder
-        View topView = mLauncher.getOpenShortcutsContainer();
+        View topView = mLauncher.getTopFloatingView();
         if (topView != null) {
-            return handleTopViewSendAccessibilityEvent(topView, child, event);
-        }
-
-        topView = mLauncher.getWorkspace().getOpenFolder();
-        if (topView != null) {
-            return handleTopViewSendAccessibilityEvent(topView, child, event);
+            if (child == topView) {
+                return super.onRequestSendAccessibilityEvent(child, event);
+            }
+            if (isInAccessibleDrag() && child instanceof DropTargetBar) {
+                return super.onRequestSendAccessibilityEvent(child, event);
+            }
+            // Skip propagating onRequestSendAccessibilityEvent for all other children
+            // which are not topView
+            return false;
         }
         return super.onRequestSendAccessibilityEvent(child, event);
     }
 
-    private boolean handleTopViewSendAccessibilityEvent(
-            View topView, View child, AccessibilityEvent event) {
-        if (child == topView) {
-            return super.onRequestSendAccessibilityEvent(child, event);
-        }
-        if (isInAccessibleDrag() && child instanceof DropTargetBar) {
-            return super.onRequestSendAccessibilityEvent(child, event);
-        }
-        // Skip propagating onRequestSendAccessibilityEvent for all other children
-        // which are not topView
-        return false;
-    }
-
     @Override
     public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
-        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
-        if (currentFolder != null) {
-            // Only add the folder as a child for accessibility when it is open
-            childrenForAccessibility.add(currentFolder);
+        View topView = mLauncher.getTopFloatingView();
+        if (topView != null) {
+            // Only add the top view as a child for accessibility when it is open
+            childrenForAccessibility.add(topView);
 
             if (isInAccessibleDrag()) {
                 childrenForAccessibility.add(mLauncher.getDropTargetBar());
@@ -463,8 +442,46 @@
         return false;
     }
 
+    @TargetApi(Build.VERSION_CODES.N)
+    private void handleSystemDragStart(DragEvent event) {
+        if (!FeatureFlags.LAUNCHER3_USE_SYSTEM_DRAG_DRIVER || !Utilities.isNycOrAbove()) {
+            return;
+        }
+        if (mLauncher.isWorkspaceLocked()) {
+            return;
+        }
+
+        ClipDescription description = event.getClipDescription();
+        if (!description.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
+            return;
+        }
+        ShortcutInfo info = new ShortcutInfo();
+        // Set a dummy intent until we get the final value
+        info.intent = new Intent();
+
+        // Since we are not going through the workspace for starting the drag, set drag related
+        // information on the workspace before starting the drag.
+        ExternalDragPreviewProvider previewProvider =
+                new ExternalDragPreviewProvider(mLauncher, info);
+        mLauncher.getWorkspace().prepareDragWithProvider(previewProvider);
+
+        DragOptions options = new DragOptions();
+        options.systemDndStartPoint = new Point((int) event.getX(), (int) event.getY());
+
+        int halfPadding = previewProvider.previewPadding / 2;
+        mDragController.startDrag(
+                Bitmap.createBitmap(1, 1, Config.ARGB_8888),
+                0, 0,
+                new AnotherWindowDragSource(mLauncher), info,
+                new Point(- halfPadding, halfPadding),
+                previewProvider.getPreviewBounds(), 1f, options);
+    }
+
     @Override
     public boolean onDragEvent (DragEvent event) {
+        if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) {
+            handleSystemDragStart(event);
+        }
         return mDragController.onDragEvent(event);
     }
 
@@ -538,7 +555,9 @@
 
     @Override
     public boolean dispatchUnhandledMove(View focused, int direction) {
-        return mDragController.dispatchUnhandledMove(focused, direction);
+        // Consume the unhandled move if a container is open, to avoid switching pages underneath.
+        boolean isContainerOpen = mLauncher.getTopFloatingView() != null;
+        return isContainerOpen || mDragController.dispatchUnhandledMove(focused, direction);
     }
 
     @Override
@@ -788,11 +807,15 @@
 
         // If duration < 0, this is a cue to compute the duration based on the distance
         if (duration < 0) {
-            duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
-            if (dist < maxDist) {
-                duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
+            if (mDragController != null && mDragController.isExternalDrag()) {
+                duration = 1;
+            } else {
+                duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
+                if (dist < maxDist) {
+                    duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
+                }
+                duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
             }
-            duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
         }
 
         // Fall back to cubic ease out interpolator for the animation if none is specified
@@ -903,11 +926,6 @@
     @Override
     public void onChildViewAdded(View parent, View child) {
         super.onChildViewAdded(parent, child);
-        if (mOverlayView != null) {
-            // ensure that the overlay view stays on top. we can't use drawing order for this
-            // because in API level 16 touch dispatch doesn't respect drawing order.
-            mOverlayView.bringToFront();
-        }
         updateChildIndices();
     }
 
@@ -919,11 +937,6 @@
     @Override
     public void bringChildToFront(View child) {
         super.bringChildToFront(child);
-        if (child != mOverlayView && mOverlayView != null) {
-            // ensure that the overlay view stays on top. we can't use drawing order for this
-            // because in API level 16 touch dispatch doesn't respect drawing order.
-            mOverlayView.bringToFront();
-        }
         updateChildIndices();
     }
 
@@ -1062,6 +1075,26 @@
         return mBackgroundAlpha;
     }
 
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+        View topView = mLauncher.getTopFloatingView();
+        if (topView != null) {
+            return topView.requestFocus(direction, previouslyFocusedRect);
+        } else {
+            return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
+        }
+    }
+
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        View topView = mLauncher.getTopFloatingView();
+        if (topView != null) {
+            topView.addFocusables(views, direction);
+        } else {
+            super.addFocusables(views, direction, focusableMode);
+        }
+    }
+
     public void setTouchCompleteListener(TouchCompleteListener listener) {
         mTouchCompleteListener = listener;
     }
diff --git a/src/com/android/launcher3/dragndrop/DragOptions.java b/src/com/android/launcher3/dragndrop/DragOptions.java
new file mode 100644
index 0000000..3d52a48
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/DragOptions.java
@@ -0,0 +1,31 @@
+/*
+ * 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.dragndrop;
+
+import android.graphics.Point;
+
+/**
+ * Set of options to control the drag and drop behavior.
+ */
+public class DragOptions {
+
+    /** Whether or not an accessible drag operation is in progress. */
+    public boolean isAccessibleDrag = false;
+
+    /** Specifies the start location for the system DnD, null when using internal DnD */
+    public Point systemDndStartPoint = null;
+}
diff --git a/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java b/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java
new file mode 100644
index 0000000..6b14be7
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java
@@ -0,0 +1,79 @@
+/*
+ * 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.dragndrop;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.HolographicOutlineHelper;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.graphics.DragPreviewProvider;
+
+/**
+ * Extension of {@link DragPreviewProvider} which provides a dummy outline when drag starts from
+ * a different window.
+ * It just draws an empty circle to a placeholder outline.
+ */
+public class ExternalDragPreviewProvider extends DragPreviewProvider {
+
+    private final Launcher mLauncher;
+    private final ItemInfo mAddInfo;
+
+    private final int[] mOutlineSize;
+
+    public ExternalDragPreviewProvider(Launcher launcher, ItemInfo addInfo) {
+        super(null);
+        mLauncher = launcher;
+        mAddInfo = addInfo;
+
+        mOutlineSize = mLauncher.getWorkspace().estimateItemSize(mAddInfo, false);
+    }
+
+    public Rect getPreviewBounds() {
+        Rect rect = new Rect();
+        DeviceProfile dp = mLauncher.getDeviceProfile();
+        rect.left = DRAG_BITMAP_PADDING / 2;
+        rect.top = (mOutlineSize[1] - dp.cellHeightPx) / 2;
+        rect.right = rect.left + dp.iconSizePx;
+        rect.bottom = rect.top + dp.iconSizePx;
+        return rect;
+    }
+
+    @Override
+    public Bitmap createDragOutline(Canvas canvas) {
+        final Bitmap b = Bitmap.createBitmap(mOutlineSize[0], mOutlineSize[1], Bitmap.Config.ALPHA_8);
+        canvas.setBitmap(b);
+
+        Paint paint = new Paint();
+        paint.setColor(Color.WHITE);
+        paint.setStyle(Paint.Style.FILL);
+
+        // Use 0.9f times the radius for the actual circle to account for icon normalization.
+        float radius = getPreviewBounds().width() * 0.5f;
+        canvas.drawCircle(DRAG_BITMAP_PADDING / 2 + radius,
+                DRAG_BITMAP_PADDING / 2 + radius, radius * 0.9f, paint);
+
+        HolographicOutlineHelper.obtain(mLauncher).applyExpensiveOutlineWithBlur(b, canvas);
+        canvas.setBitmap(null);
+        return b;
+    }
+}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 5450423..b64d12c 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -42,7 +42,6 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.EditorInfo;
@@ -51,8 +50,8 @@
 import android.widget.TextView;
 
 import com.android.launcher3.Alarm;
+import com.android.launcher3.AppInfo;
 import com.android.launcher3.CellLayout;
-import com.android.launcher3.CellLayout.CellInfo;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
@@ -71,12 +70,12 @@
 import com.android.launcher3.UninstallDropTarget.DropTargetSource;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace.ItemOperator;
-import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
+import com.android.launcher3.accessibility.AccessibileDragListenerAdapter;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragController.DragListener;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.logging.UserEventDispatcher.LaunchSourceProvider;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.pageindicators.PageIndicatorDots;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -92,7 +91,7 @@
  */
 public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
         View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
-        View.OnFocusChangeListener, DragListener, DropTargetSource, AccessibilityDragSource {
+        View.OnFocusChangeListener, DragListener, DropTargetSource {
     private static final String TAG = "Launcher.Folder";
 
     /**
@@ -165,10 +164,8 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mRearrangeOnClose = false;
     boolean mItemsInvalidated = false;
-    private ShortcutInfo mCurrentDragInfo;
     private View mCurrentDragView;
     private boolean mIsExternalDrag;
-    boolean mSuppressOnAdd = false;
     private boolean mDragInProgress = false;
     private boolean mDeleteFolderOnDropCompleted = false;
     private boolean mSuppressFolderDeletion = false;
@@ -282,10 +279,10 @@
     public boolean onLongClick(View v) {
         // Return if global dragging is not enabled
         if (!mLauncher.isDraggingEnabled()) return true;
-        return beginDrag(v, false);
+        return startDrag(v, new DragOptions());
     }
 
-    private boolean beginDrag(View v, boolean accessible) {
+    public boolean startDrag(View v, DragOptions options) {
         Object tag = v.getTag();
         if (tag instanceof ShortcutInfo) {
             ShortcutInfo item = (ShortcutInfo) tag;
@@ -293,35 +290,55 @@
                 return false;
             }
 
-            mLauncher.getWorkspace().beginDragShared(v, this, accessible);
-
-            mCurrentDragInfo = item;
             mEmptyCellRank = item.rank;
             mCurrentDragView = v;
 
-            mContent.removeItem(mCurrentDragView);
-            mInfo.remove(mCurrentDragInfo, true);
-            mDragInProgress = true;
-            mItemAddedBackToSelfViaIcon = false;
+            mDragController.addDragListener(this);
+            if (options.isAccessibleDrag) {
+                mDragController.addDragListener(new AccessibileDragListenerAdapter(
+                        mContent, CellLayout.FOLDER_ACCESSIBILITY_DRAG) {
+
+                    @Override
+                    protected void enableAccessibleDrag(boolean enable) {
+                        super.enableAccessibleDrag(enable);
+                        mFooter.setImportantForAccessibility(enable
+                                ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+                                : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+                    }
+                });
+            }
+
+            mLauncher.getWorkspace().beginDragShared(v, this, options);
         }
         return true;
     }
 
     @Override
-    public void startDrag(CellInfo cellInfo, boolean accessible) {
-        beginDrag(cellInfo.cell, accessible);
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+        if (dragObject.dragSource != this) {
+            return;
+        }
+
+        mContent.removeItem(mCurrentDragView);
+        if (dragObject.dragInfo instanceof ShortcutInfo) {
+            mItemsInvalidated = true;
+
+            // We do not want to get events for the item being removed, as they will get handled
+            // when the drop completes
+            try (SuppressInfoChanges s = new SuppressInfoChanges()) {
+                mInfo.remove((ShortcutInfo) dragObject.dragInfo, true);
+            }
+        }
+        mDragInProgress = true;
+        mItemAddedBackToSelfViaIcon = false;
     }
 
     @Override
-    public void enableAccessibleDrag(boolean enable) {
-        mLauncher.getDropTargetBar().enableAccessibleDrag(enable);
-        for (int i = 0; i < mContent.getChildCount(); i++) {
-            mContent.getPageAt(i).enableAccessibleDrag(enable, CellLayout.FOLDER_ACCESSIBILITY_DRAG);
+    public void onDragEnd() {
+        if (mIsExternalDrag && mDragInProgress) {
+            completeDragExit();
         }
-
-        mFooter.setImportantForAccessibility(enable ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS :
-                IMPORTANT_FOR_ACCESSIBILITY_AUTO);
-        mLauncher.getWorkspace().setAddNewPageOnDrag(!enable);
+        mDragController.removeDragListener(this);
     }
 
     public boolean isEditingName() {
@@ -352,7 +369,8 @@
         LauncherModel.updateItemInDatabase(mLauncher, mInfo);
 
         if (commit) {
-            sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+            Utilities.sendCustomAccessibilityEvent(
+                    this, AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
                     getContext().getString(R.string.folder_renamed, newTitle));
         }
 
@@ -591,7 +609,9 @@
         openFolderAnim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
-                sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                Utilities.sendCustomAccessibilityEvent(
+                        Folder.this,
+                        AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
                         mContent.getAccessibilityDescription());
                 mState = STATE_ANIMATING;
             }
@@ -650,9 +670,8 @@
         mContent.verifyVisibleHighResIcons(mContent.getNextPage());
     }
 
-    public void beginExternalDrag(ShortcutInfo item) {
-        mCurrentDragInfo = item;
-        mEmptyCellRank = mContent.allocateRankForNewItem(item);
+    public void beginExternalDrag() {
+        mEmptyCellRank = mContent.allocateRankForNewItem();
         mIsExternalDrag = true;
         mDragInProgress = true;
 
@@ -661,28 +680,6 @@
         mDragController.addDragListener(this);
     }
 
-    @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) { }
-
-    @Override
-    public void onDragEnd() {
-        if (mIsExternalDrag && mDragInProgress) {
-            completeDragExit();
-        }
-        mDragController.removeDragListener(this);
-    }
-
-    @Thunk void sendCustomAccessibilityEvent(int type, String text) {
-        AccessibilityManager accessibilityManager = (AccessibilityManager)
-                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-        if (accessibilityManager.isEnabled()) {
-            AccessibilityEvent event = AccessibilityEvent.obtain(type);
-            onInitializeAccessibilityEvent(event);
-            event.getText().add(text);
-            accessibilityManager.sendAccessibilityEvent(event);
-        }
-    }
-
     public void animateClosed() {
         if (!(getParent() instanceof DragLayer)) return;
         final ObjectAnimator oa = LauncherAnimUtils.ofViewAlphaAndScale(this, 0, 0.9f, 0.9f);
@@ -694,7 +691,9 @@
             }
             @Override
             public void onAnimationStart(Animator animation) {
-                sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                Utilities.sendCustomAccessibilityEvent(
+                        Folder.this,
+                        AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
                         getContext().getString(R.string.folder_closed));
                 mState = STATE_ANIMATING;
             }
@@ -851,9 +850,7 @@
     }
 
     private void clearDragInfo() {
-        mCurrentDragInfo = null;
         mCurrentDragView = null;
-        mSuppressOnAdd = false;
         mIsExternalDrag = false;
     }
 
@@ -917,9 +914,9 @@
             mContent.arrangeChildren(views, views.size());
             mItemsInvalidated = true;
 
-            mSuppressOnAdd = true;
-            mFolderIcon.onDrop(d);
-            mSuppressOnAdd = false;
+            try (SuppressInfoChanges s = new SuppressInfoChanges()) {
+                mFolderIcon.onDrop(d);
+            }
         }
 
         if (target != this) {
@@ -936,9 +933,7 @@
         mDeleteFolderOnDropCompleted = false;
         mDragInProgress = false;
         mItemAddedBackToSelfViaIcon = false;
-        mCurrentDragInfo = null;
         mCurrentDragView = null;
-        mSuppressOnAdd = false;
 
         // Reordering may have occured, and we need to save the new item locations. We do this once
         // at the end to prevent unnecessary database operations.
@@ -1280,7 +1275,14 @@
         mContent.completePendingPageChanges();
 
         View currentDragView;
-        ShortcutInfo si = mCurrentDragInfo;
+        final ShortcutInfo si;
+        if (d.dragInfo instanceof AppInfo) {
+            // Came from all apps -- make a copy.
+            si = ((AppInfo) d.dragInfo).makeShortcut();
+        } else {
+            // ShortcutInfo
+            si = (ShortcutInfo) d.dragInfo;
+        }
         if (mIsExternalDrag) {
             currentDragView = mContent.createAndAddViewForRank(si, mEmptyCellRank);
             // Actually move the item in the database if it was an external drag. Call this
@@ -1317,11 +1319,11 @@
         rearrangeChildren();
 
         // Temporarily suppress the listener, as we did all the work already here.
-        mSuppressOnAdd = true;
-        mInfo.add(si, false);
-        mSuppressOnAdd = false;
+        try (SuppressInfoChanges s = new SuppressInfoChanges()) {
+            mInfo.add(si, false);
+        }
+
         // Clear the drag info, as it is no longer being dragged.
-        mCurrentDragInfo = null;
         mDragInProgress = false;
 
         if (mContent.getPageCount() > 1) {
@@ -1344,10 +1346,7 @@
 
     @Override
     public void onAdd(ShortcutInfo item) {
-        // If the item was dropped onto this open folder, we have done the work associated
-        // with adding the item to the folder, as indicated by mSuppressOnAdd being set
-        if (mSuppressOnAdd) return;
-        mContent.createAndAddViewForRank(item, mContent.allocateRankForNewItem(item));
+        mContent.createAndAddViewForRank(item, mContent.allocateRankForNewItem());
         mItemsInvalidated = true;
         LauncherModel.addOrMoveItemInDatabase(
                 mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
@@ -1355,9 +1354,6 @@
 
     public void onRemove(ShortcutInfo item) {
         mItemsInvalidated = true;
-        // If this item is being dragged from this open folder, we have already handled
-        // the work associated with removing the item, so we don't have to do anything here.
-        if (item == mCurrentDragInfo) return;
         View v = getViewForInfo(item);
         mContent.removeItem(v);
         if (mState == STATE_ANIMATING) {
@@ -1496,4 +1492,20 @@
             }
         }
     };
+
+    /**
+     * Temporary resource held while we don't want to handle info changes
+     */
+    private class SuppressInfoChanges implements AutoCloseable {
+
+        SuppressInfoChanges() {
+            mInfo.removeListener(Folder.this);
+        }
+
+        @Override
+        public void close() {
+            mInfo.addListener(Folder.this);
+            updateTextViewFocus();
+        }
+    }
 }
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index eebbfe8..69c2b0f 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -125,8 +125,6 @@
     Paint mBgPaint = new Paint();
 
     private Alarm mOpenAlarm = new Alarm();
-    @Thunk
-    ItemInfo mDragInfo;
 
     public FolderIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -195,8 +193,6 @@
         return super.onSaveInstanceState();
     }
 
-
-
     public Folder getFolder() {
         return mFolder;
     }
@@ -242,22 +238,11 @@
             // Workspace#onDropExternal.
             mOpenAlarm.setAlarm(ON_OPEN_DELAY);
         }
-        mDragInfo = dragInfo;
     }
 
     OnAlarmListener mOnOpenListener = new OnAlarmListener() {
         public void onAlarm(Alarm alarm) {
-            ShortcutInfo item;
-            if (mDragInfo instanceof AppInfo) {
-                // Came from all apps -- make a copy.
-                item = ((AppInfo) mDragInfo).makeShortcut();
-                item.spanX = 1;
-                item.spanY = 1;
-            } else {
-                // ShortcutInfo
-                item = (ShortcutInfo) mDragInfo;
-            }
-            mFolder.beginExternalDrag(item);
+            mFolder.beginExternalDrag();
             mLauncher.openFolder(FolderIcon.this);
         }
     };
@@ -284,7 +269,7 @@
         animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION, false, null);
 
         // This will animate the dragView (srcView) into the new folder
-        onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable, null);
+        onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable);
     }
 
     public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) {
@@ -298,18 +283,13 @@
                 onCompleteRunnable);
     }
 
-    public void onDragExit(Object dragInfo) {
-        onDragExit();
-    }
-
     public void onDragExit() {
         mBackground.animateToRest();
         mOpenAlarm.cancelAlarm();
     }
 
     private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect,
-            float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable,
-            DragObject d) {
+            float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable) {
         item.cellX = -1;
         item.cellY = -1;
 
@@ -379,7 +359,7 @@
             item = (ShortcutInfo) d.dragInfo;
         }
         mFolder.notifyDrop();
-        onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable, d);
+        onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable);
     }
 
     private void computePreviewDrawingParams(int drawableSize, int totalSize) {
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 3df1d24..1171d48 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -195,7 +195,7 @@
      * Create space for a new item at the end, and returns the rank for that item.
      * Also sets the current page to the last page.
      */
-    public int allocateRankForNewItem(ShortcutInfo info) {
+    public int allocateRankForNewItem() {
         int rank = getItemCount();
         ArrayList<View> views = new ArrayList<>(mFolder.getItemsInReadingOrder());
         views.add(rank, null);
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index b90c2fd..bc91c15 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -27,8 +27,8 @@
 import com.android.launcher3.HolographicOutlineHelper;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.PreloadIconDrawable;
-import com.android.launcher3.R;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.folder.FolderIcon;
 
 /**
@@ -45,6 +45,8 @@
     // The padding added to the drag view during the preview generation.
     public final int previewPadding;
 
+    public Bitmap gerenatedDragOutline;
+
     public DragPreviewProvider(View view) {
         mView = view;
 
@@ -118,19 +120,25 @@
         return b;
     }
 
+    public final void generateDragOutline(Canvas canvas) {
+        if (ProviderConfig.IS_DOGFOOD_BUILD && gerenatedDragOutline != null) {
+            throw new RuntimeException("Drag outline generated twice");
+        }
+
+        gerenatedDragOutline = 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) {
-        final int outlineColor = mView.getResources().getColor(R.color.outline_color);
         final Bitmap b = Bitmap.createBitmap(mView.getWidth() + DRAG_BITMAP_PADDING,
-                mView.getHeight() + DRAG_BITMAP_PADDING, Bitmap.Config.ARGB_8888);
-
+                mView.getHeight() + DRAG_BITMAP_PADDING, Bitmap.Config.ALPHA_8);
         canvas.setBitmap(b);
         drawDragView(canvas);
         HolographicOutlineHelper.obtain(mView.getContext())
-                .applyExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
+                .applyExpensiveOutlineWithBlur(b, canvas);
         canvas.setBitmap(null);
         return b;
     }
diff --git a/src/com/android/launcher3/model/PackageItemInfo.java b/src/com/android/launcher3/model/PackageItemInfo.java
index ddc9cbf..c86ba86 100644
--- a/src/com/android/launcher3/model/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/PackageItemInfo.java
@@ -46,17 +46,12 @@
      */
     public String titleSectionName;
 
-    int flags = 0;
-
     PackageItemInfo(String packageName) {
         this.packageName = packageName;
     }
 
     @Override
-    public String toString() {
-        return "PackageItemInfo(title=" + title + " id=" + this.id
-                + " type=" + this.itemType + " container=" + this.container
-                + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY
-                + " spanX=" + spanX + " spanY=" + spanY + " user=" + user + ")";
+    protected String dumpProperties() {
+        return super.dumpProperties() + " packageName=" + packageName;
     }
 }
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index b3f0c82..0d7ba1e 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -68,6 +68,17 @@
             return thisWorkProfile ? 1 : -1;
         }
 
-        return sCollator.compare(label, another.label);
+        int labelCompare = sCollator.compare(label, another.label);
+        if (labelCompare != 0) {
+            return labelCompare;
+        }
+
+        // If the label is same, put the smaller widget before the larger widget. If the area is
+        // also same, put the widget with smaller height before.
+        int thisArea = spanX * spanY;
+        int otherArea = another.spanX * another.spanY;
+        return thisArea == otherArea
+                ? Integer.compare(spanY, another.spanY)
+                : Integer.compare(thisArea, otherArea);
     }
 }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 747c21b..fb9d2f7 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -226,11 +226,6 @@
     public void setActiveMarker(int activePage) {
         if (mActivePage != activePage) {
             mActivePage = activePage;
-
-            // Simulate a scroll change
-            int totalScroll = mNumPages - 1;
-            int currentScroll = mIsRtl ? (totalScroll - mActivePage) : mActivePage;
-            setScroll(currentScroll, totalScroll);
         }
     }
 
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
index ca3a2dd..350bc8a 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
@@ -159,6 +159,11 @@
     }
 
     @Override
+    public void setContentDescription(CharSequence contentDescription) {
+        mAllAppsHandle.setContentDescription(contentDescription);
+    }
+
+    @Override
     public void setScroll(int currentScroll, int totalScroll) {
         if (getAlpha() == 0) {
             return;
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 9d8b6b3..47bee06 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -24,6 +24,7 @@
 import com.android.launcher3.LauncherAppWidgetInfo;
 import com.android.launcher3.LauncherProvider.DatabaseHelper;
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.FileLog;
 
@@ -43,6 +44,13 @@
     private static final String INFO_COLUMN_NAME = "name";
     private static final String INFO_COLUMN_DEFAULT_VALUE = "dflt_value";
 
+    /**
+     * When enabled all icons are kept on the home screen, even if they don't have an active
+     * session. To enable use:
+     *      adb shell setprop log.tag.launcher_keep_all_icons VERBOSE
+     */
+    private static final String KEEP_ALL_ICONS = "launcher_keep_all_icons";
+
     public static boolean performRestore(DatabaseHelper helper) {
         SQLiteDatabase db = helper.getWritableDatabase();
         db.beginTransaction();
@@ -77,15 +85,17 @@
         }
 
         // Mark all items as restored.
+        boolean keepAllIcons = Utilities.isPropertyEnabled(KEEP_ALL_ICONS);
         ContentValues values = new ContentValues();
-        values.put(Favorites.RESTORED, 1);
+        values.put(Favorites.RESTORED, ShortcutInfo.FLAG_RESTORED_ICON
+                | (keepAllIcons ? ShortcutInfo.FLAG_RESTORE_STARTED : 0));
         db.update(Favorites.TABLE_NAME, values, null, null);
 
         // Mark widgets with appropriate restore flag
-        values.put(Favorites.RESTORED,
-                LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
-                        LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY |
-                        LauncherAppWidgetInfo.FLAG_UI_NOT_READY);
+        values.put(Favorites.RESTORED,  LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
+                LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY |
+                LauncherAppWidgetInfo.FLAG_UI_NOT_READY |
+                (keepAllIcons ? LauncherAppWidgetInfo.FLAG_RESTORE_STARTED : 0));
         db.update(Favorites.TABLE_NAME, values, "itemType = ?",
                 new String[]{Integer.toString(Favorites.ITEM_TYPE_APPWIDGET)});
 
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 37b6d04..e7fc415 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -21,16 +21,19 @@
 import android.content.Context;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.FrameLayout;
 
 import com.android.launcher3.IconCache;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LogAccelerateInterpolator;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.shortcuts.DeepShortcutsContainer.UnbadgedShortcutInfo;
 import com.android.launcher3.util.PillRevealOutlineProvider;
 import com.android.launcher3.util.PillWidthRevealOutlineProvider;
 
@@ -48,6 +51,8 @@
     private View mIconView;
     private float mOpenAnimationProgress;
 
+    private UnbadgedShortcutInfo mInfo;
+
     public DeepShortcutView(Context context) {
         this(context, null, 0);
     }
@@ -87,10 +92,36 @@
         mPillRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
     }
 
-    public void applyShortcutInfo(ShortcutInfo info) {
+    /** package private **/
+    void applyShortcutInfo(UnbadgedShortcutInfo info, DeepShortcutsContainer container) {
+        mInfo = info;
         IconCache cache = LauncherAppState.getInstance().getIconCache();
         mBubbleText.applyFromShortcutInfo(info, cache);
         mIconView.setBackground(mBubbleText.getIcon());
+
+        // Use the long label as long as it exists and fits.
+        CharSequence longLabel = info.mDetail.getLongLabel();
+        int availableWidth = mBubbleText.getWidth() - mBubbleText.getTotalPaddingLeft()
+                - mBubbleText.getTotalPaddingRight();
+        boolean usingLongLabel = !TextUtils.isEmpty(longLabel)
+                && mBubbleText.getPaint().measureText(longLabel.toString()) <= availableWidth;
+        mBubbleText.setText(usingLongLabel ? longLabel : info.mDetail.getShortLabel());
+
+        // TODO: Add the click handler to this view directly and not the child view.
+        mBubbleText.setOnClickListener(Launcher.getLauncher(getContext()));
+        mBubbleText.setOnLongClickListener(container);
+        mBubbleText.setOnTouchListener(container);
+    }
+
+    /**
+     * Returns the shortcut info that is suitable to be added on the homescreen
+     */
+    public ShortcutInfo getFinalInfo() {
+        ShortcutInfo badged = new ShortcutInfo(mInfo);
+        // Queue an update task on the worker thread. This ensures that the badged
+        // shortcut eventually gets its icon updated.
+        Launcher.getLauncher(getContext()).getModel().updateShortcutInfo(mInfo.mDetail, badged);
+        return badged;
     }
 
     public View getIconView() {
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
index 6bd21cd..7657ed6 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
@@ -31,7 +31,6 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -53,6 +52,7 @@
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
+import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherViewPropertyAnimator;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
@@ -62,9 +62,9 @@
 import com.android.launcher3.compat.UserHandleCompat;
 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.graphics.TriangleShape;
-import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 
@@ -182,12 +182,8 @@
                 }
                 for (int i = 0; i < shortcuts.size(); i++) {
                     final ShortcutInfoCompat shortcut = shortcuts.get(i);
-                    final ShortcutInfo launcherShortcutInfo =
-                            new UnbadgedShortcutInfo(shortcut, mLauncher);
-                    CharSequence shortLabel = shortcut.getShortLabel();
-                    CharSequence longLabel = shortcut.getLongLabel();
-                    uiHandler.post(new UpdateShortcutChild(i, launcherShortcutInfo,
-                            shortLabel, longLabel));
+                    uiHandler.post(new UpdateShortcutChild(
+                            i, new UnbadgedShortcutInfo(shortcut, mLauncher)));
                 }
             }
         });
@@ -196,32 +192,17 @@
     /** Updates the child of this container at the given index based on the given shortcut info. */
     private class UpdateShortcutChild implements Runnable {
         private int mShortcutChildIndex;
-        private ShortcutInfo mShortcutChildInfo;
-        private CharSequence mShortLabel;
-        private CharSequence mLongLabel;
+        private UnbadgedShortcutInfo mShortcutChildInfo;
 
-        public UpdateShortcutChild(int shortcutChildIndex, ShortcutInfo shortcutChildInfo,
-                CharSequence shortLabel, CharSequence longLabel) {
+        public UpdateShortcutChild(int shortcutChildIndex, UnbadgedShortcutInfo shortcutChildInfo) {
             mShortcutChildIndex = shortcutChildIndex;
             mShortcutChildInfo = shortcutChildInfo;
-            mShortLabel = shortLabel;
-            mLongLabel = longLabel;
         }
 
         @Override
         public void run() {
-            DeepShortcutView shortcutViewContainer = getShortcutAt(mShortcutChildIndex);
-            shortcutViewContainer.applyShortcutInfo(mShortcutChildInfo);
-            BubbleTextView shortcutView = getShortcutAt(mShortcutChildIndex).getBubbleText();
-            // Use the long label as long as it exists and fits.
-            int availableWidth = shortcutView.getWidth() - shortcutView.getTotalPaddingLeft()
-                    - shortcutView.getTotalPaddingRight();
-            boolean usingLongLabel = !TextUtils.isEmpty(mLongLabel)
-                    && shortcutView.getPaint().measureText(mLongLabel.toString()) <= availableWidth;
-            shortcutView.setText(usingLongLabel ? mLongLabel : mShortLabel);
-            shortcutView.setOnClickListener(mLauncher);
-            shortcutView.setOnLongClickListener(DeepShortcutsContainer.this);
-            shortcutView.setOnTouchListener(DeepShortcutsContainer.this);
+            getShortcutAt(mShortcutChildIndex)
+                    .applyShortcutInfo(mShortcutChildInfo, DeepShortcutsContainer.this);
         }
     }
 
@@ -273,8 +254,10 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 mOpenCloseAnimator = null;
-
-                sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                Utilities.sendCustomAccessibilityEvent(
+                        DeepShortcutsContainer.this,
+                        AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                        getContext().getString(R.string.action_deep_shortcut));
             }
         });
 
@@ -524,14 +507,7 @@
         // Return if global dragging is not enabled
         if (!mLauncher.isDraggingEnabled()) return false;
 
-        UnbadgedShortcutInfo unbadgedInfo = (UnbadgedShortcutInfo) v.getTag();
-        ShortcutInfo badged = new ShortcutInfo(unbadgedInfo);
-        // Queue an update task on the worker thread. This ensures that the badged
-        // shortcut eventually gets its icon updated.
-        mLauncher.getModel().updateShortcutInfo(unbadgedInfo.mDetail, badged);
-
         // Long clicked on a shortcut.
-
         mDeferContainerRemoval = true;
         DeepShortcutView sv = (DeepShortcutView) v.getParent();
         sv.setWillDrawIcon(false);
@@ -541,8 +517,8 @@
         mIconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx;
 
         DragView dv = mLauncher.getWorkspace().beginDragShared(
-                sv.getBubbleText(), this, false, badged,
-                new ShortcutDragPreviewProvider(sv.getIconView(), mIconShift));
+                sv.getBubbleText(), this, sv.getFinalInfo(),
+                new ShortcutDragPreviewProvider(sv.getIconView(), mIconShift), new DragOptions());
         dv.animateShift(-mIconShift.x, -mIconShift.y);
 
         // TODO: support dragging from within folder without having to close it
@@ -586,7 +562,7 @@
     }
 
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
         // Either the original icon or one of the shortcuts was dragged.
         // Hide the container, but don't remove it yet because that interferes with touch events.
         animateClose();
@@ -603,8 +579,7 @@
             } else {
                 // Close animation is not running.
                 if (mDeferContainerRemoval) {
-                    mDeferContainerRemoval = false;
-                    mLauncher.getDragLayer().removeView(this);
+                    close();
                 }
             }
         }
@@ -625,7 +600,6 @@
             mOpenCloseAnimator.cancel();
         }
         mIsOpen = false;
-        mLauncher.getDragController().removeDragListener(this);
 
         final AnimatorSet shortcutAnims = LauncherAnimUtils.createAnimatorSet();
         final int shortcutCount = getShortcutCount();
@@ -714,7 +688,9 @@
         mDeferContainerRemoval = false;
         // Make the original icon visible in All Apps, but not in Workspace or Folders.
         cleanupDeferredDrag(mDeferredDragIcon.getTag() instanceof AppInfo);
-        mDeferredDragIcon.setTextVisibility(true);
+        boolean isInHotseat = ((ItemInfo) mDeferredDragIcon.getTag()).container
+                == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+        mDeferredDragIcon.setTextVisibility(!isInHotseat);
         mLauncher.getDragController().removeDragListener(this);
         mLauncher.getDragLayer().removeView(this);
     }
@@ -753,8 +729,8 @@
     /**
      * Extension of {@link ShortcutInfo} which does not badge the icons.
      */
-    private static class UnbadgedShortcutInfo extends ShortcutInfo {
-        private final ShortcutInfoCompat mDetail;
+    static class UnbadgedShortcutInfo extends ShortcutInfo {
+        public final ShortcutInfoCompat mDetail;
 
         public UnbadgedShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
             super(shortcutInfo, context);
diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
index a25e475..2adb82e 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
@@ -22,12 +22,9 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.view.View;
-import android.widget.ImageView;
 
-import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.HolographicOutlineHelper;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.graphics.DragPreviewProvider;
 
@@ -45,23 +42,22 @@
 
     @Override
     public Bitmap createDragOutline(Canvas canvas) {
-        Bitmap b = drawScaledPreview(canvas);
+        Bitmap b = drawScaledPreview(canvas, Bitmap.Config.ALPHA_8);
 
-        final int outlineColor = mView.getResources().getColor(R.color.outline_color);
         HolographicOutlineHelper.obtain(mView.getContext())
-                .applyExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
+                .applyExpensiveOutlineWithBlur(b, canvas);
         canvas.setBitmap(null);
         return b;
     }
 
     @Override
     public Bitmap createDragBitmap(Canvas canvas) {
-        Bitmap b = drawScaledPreview(canvas);
+        Bitmap b = drawScaledPreview(canvas, Bitmap.Config.ARGB_8888);
         canvas.setBitmap(null);
         return b;
     }
 
-    private Bitmap drawScaledPreview(Canvas canvas) {
+    private Bitmap drawScaledPreview(Canvas canvas, Bitmap.Config config) {
         Drawable d = mView.getBackground();
         Rect bounds = getDrawableBounds(d);
 
@@ -70,7 +66,7 @@
         final Bitmap b = Bitmap.createBitmap(
                 size + DRAG_BITMAP_PADDING,
                 size + DRAG_BITMAP_PADDING,
-                Bitmap.Config.ARGB_8888);
+                config);
 
         canvas.setBitmap(b);
         canvas.save(Canvas.MATRIX_SAVE_FLAG);
diff --git a/src/com/android/launcher3/testing/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java
index ae552d2..6797c7b 100644
--- a/src/com/android/launcher3/testing/LauncherExtension.java
+++ b/src/com/android/launcher3/testing/LauncherExtension.java
@@ -139,13 +139,8 @@
         }
 
         @Override
-        public boolean providesSearch() {
-            return false;
-        }
-
-        @Override
         public boolean startSearch(String initialQuery, boolean selectInitialQuery,
-                Bundle appSearchData, Rect sourceBounds) {
+                Bundle appSearchData) {
             return false;
         }
 
@@ -198,26 +193,6 @@
         }
 
         @Override
-        public Intent getFirstRunActivity() {
-            return null;
-        }
-
-        @Override
-        public boolean hasFirstRunActivity() {
-            return false;
-        }
-
-        @Override
-        public boolean hasDismissableIntroScreen() {
-            return false;
-        }
-
-        @Override
-        public View getIntroScreen() {
-            return null;
-        }
-
-        @Override
         public boolean shouldMoveToDefaultScreenOnHomeIntent() {
             return true;
         }
diff --git a/src/com/android/launcher3/util/ActivityResultInfo.java b/src/com/android/launcher3/util/ActivityResultInfo.java
new file mode 100644
index 0000000..2261bee
--- /dev/null
+++ b/src/com/android/launcher3/util/ActivityResultInfo.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util;
+
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Utility class which stores information from onActivityResult
+ */
+public class ActivityResultInfo implements Parcelable {
+
+    public final int requestCode;
+    public final int resultCode;
+    public final Intent data;
+
+    public ActivityResultInfo(int requestCode, int resultCode, Intent data) {
+        this.requestCode = requestCode;
+        this.resultCode = resultCode;
+        this.data = data;
+    }
+
+    private ActivityResultInfo(Parcel parcel) {
+        requestCode = parcel.readInt();
+        resultCode = parcel.readInt();
+        data = parcel.readInt() != 0 ? Intent.CREATOR.createFromParcel(parcel) : null;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(requestCode);
+        dest.writeInt(resultCode);
+        if (data != null) {
+            dest.writeInt(1);
+            data.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
+    }
+
+    public static final Parcelable.Creator<ActivityResultInfo> CREATOR =
+            new Parcelable.Creator<ActivityResultInfo>() {
+                public ActivityResultInfo createFromParcel(Parcel source) {
+                    return new ActivityResultInfo(source);
+                }
+
+                public ActivityResultInfo[] newArray(int size) {
+                    return new ActivityResultInfo[size];
+                }
+            };
+}
diff --git a/src/com/android/launcher3/util/ComponentKey.java b/src/com/android/launcher3/util/ComponentKey.java
index 144b411..5882f21 100644
--- a/src/com/android/launcher3/util/ComponentKey.java
+++ b/src/com/android/launcher3/util/ComponentKey.java
@@ -32,8 +32,8 @@
     private final int mHashCode;
 
     public ComponentKey(ComponentName componentName, UserHandleCompat user) {
-        assert (componentName != null);
-        assert (user != null);
+        Preconditions.assertNotNull(componentName);
+        Preconditions.assertNotNull(user);
         this.componentName = componentName;
         this.user = user;
         mHashCode = Arrays.hashCode(new Object[] {componentName, user});
@@ -58,6 +58,8 @@
             componentName = ComponentName.unflattenFromString(componentKeyStr);
             user = UserHandleCompat.myUserHandle();
         }
+        Preconditions.assertNotNull(componentName);
+        Preconditions.assertNotNull(user);
         mHashCode = Arrays.hashCode(new Object[] {componentName, user});
     }
 
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 3c4c79a..3e15d05 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -16,10 +16,15 @@
 
 package com.android.launcher3.util;
 
+import android.app.AppOpsManager;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.os.Build;
+import android.text.TextUtils;
 
 import com.android.launcher3.Utilities;
 
@@ -96,4 +101,53 @@
         }
         return excludePackages.get(0);
     }
+
+    /**
+     * Returns true if {@param srcPackage} has the permission required to start the activity from
+     * {@param intent}. If {@param srcPackage} is null, then the activity should not need
+     * any permissions
+     */
+    public static boolean hasPermissionForActivity(Context context, Intent intent,
+            String srcPackage) {
+        PackageManager pm = context.getPackageManager();
+        ResolveInfo target = pm.resolveActivity(intent, 0);
+        if (target == null) {
+            // Not a valid target
+            return false;
+        }
+        if (TextUtils.isEmpty(target.activityInfo.permission)) {
+            // No permission is needed
+            return true;
+        }
+        if (TextUtils.isEmpty(srcPackage)) {
+            // The activity requires some permission but there is no source.
+            return false;
+        }
+
+        // Source does not have sufficient permissions.
+        if(pm.checkPermission(target.activityInfo.permission, srcPackage) !=
+                PackageManager.PERMISSION_GRANTED) {
+            return false;
+        }
+
+        if (!Utilities.ATLEAST_MARSHMALLOW) {
+            // These checks are sufficient for below M devices.
+            return true;
+        }
+
+        // On M and above also check AppOpsManager for compatibility mode permissions.
+        if (TextUtils.isEmpty(AppOpsManager.permissionToOp(target.activityInfo.permission))) {
+            // There is no app-op for this permission, which could have been disabled.
+            return true;
+        }
+
+        // There is no direct way to check if the app-op is allowed for a particular app. Since
+        // app-op is only enabled for apps running in compatibility mode, simply block such apps.
+
+        try {
+            return pm.getApplicationInfo(srcPackage, 0).targetSdkVersion >= Build.VERSION_CODES.M;
+        } catch (NameNotFoundException e) { }
+
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/util/PendingRequestArgs.java b/src/com/android/launcher3/util/PendingRequestArgs.java
new file mode 100644
index 0000000..4e402f3
--- /dev/null
+++ b/src/com/android/launcher3/util/PendingRequestArgs.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util;
+
+import android.content.ContentValues;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+
+/**
+ * Utility class to store information regarding a pending request made by launcher. This information
+ * can be saved across launcher instances.
+ */
+public class PendingRequestArgs extends ItemInfo implements Parcelable {
+
+    private static final int TYPE_NONE = 0;
+    private static final int TYPE_INTENT = 1;
+    private static final int TYPE_APP_WIDGET = 2;
+
+    private final int mArg1;
+    private final int mObjectType;
+    private final Parcelable mObject;
+
+    public PendingRequestArgs(ItemInfo info) {
+        mArg1 = 0;
+        mObjectType = TYPE_NONE;
+        mObject = null;
+
+        copyFrom(info);
+    }
+
+    private PendingRequestArgs(int arg1, int objectType, Parcelable object) {
+        mArg1 = arg1;
+        mObjectType = objectType;
+        mObject = object;
+    }
+
+    public PendingRequestArgs(Parcel parcel) {
+        readFromValues(ContentValues.CREATOR.createFromParcel(parcel));
+
+        mArg1 = parcel.readInt();
+        mObjectType = parcel.readInt();
+        if (parcel.readInt() != 0) {
+            mObject = mObjectType == TYPE_INTENT
+                    ? Intent.CREATOR.createFromParcel(parcel)
+                    : new LauncherAppWidgetProviderInfo(parcel);
+        } else {
+            mObject = null;
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        ContentValues itemValues = new ContentValues();
+        writeToValues(itemValues);
+
+        dest.writeInt(mArg1);
+        dest.writeInt(mObjectType);
+        if (mObject != null) {
+            dest.writeInt(1);
+            mObject.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
+    }
+
+    public LauncherAppWidgetProviderInfo getWidgetProvider() {
+        return mObjectType == TYPE_APP_WIDGET ? (LauncherAppWidgetProviderInfo) mObject : null;
+    }
+
+    public int getWidgetId() {
+        return mObjectType == TYPE_APP_WIDGET ? mArg1 : 0;
+    }
+
+    public Intent getPendingIntent() {
+        return mObjectType == TYPE_INTENT ? (Intent) mObject : null;
+    }
+
+    public int getRequestCode() {
+        return mObjectType == TYPE_INTENT ? mArg1 : 0;
+    }
+
+    public static PendingRequestArgs forWidgetInfo(
+            int appWidgetId, LauncherAppWidgetProviderInfo widgetInfo, ItemInfo info) {
+        PendingRequestArgs args = new PendingRequestArgs(appWidgetId, TYPE_APP_WIDGET, widgetInfo);
+        args.copyFrom(info);
+        return args;
+    }
+
+    public static PendingRequestArgs forIntent(int requestCode, Intent intent, ItemInfo info) {
+        PendingRequestArgs args = new PendingRequestArgs(requestCode, TYPE_INTENT, intent);
+        args.copyFrom(info);
+        return args;
+    }
+
+    public static final Parcelable.Creator<PendingRequestArgs> CREATOR =
+            new Parcelable.Creator<PendingRequestArgs>() {
+                public PendingRequestArgs createFromParcel(Parcel source) {
+                    return new PendingRequestArgs(source);
+                }
+
+                public PendingRequestArgs[] newArray(int size) {
+                    return new PendingRequestArgs[size];
+                }
+            };
+}
diff --git a/src/com/android/launcher3/util/Preconditions.java b/src/com/android/launcher3/util/Preconditions.java
index 3760c63..89353e1 100644
--- a/src/com/android/launcher3/util/Preconditions.java
+++ b/src/com/android/launcher3/util/Preconditions.java
@@ -26,6 +26,12 @@
  */
 public class Preconditions {
 
+    public static void assertNotNull(Object o) {
+        if (ProviderConfig.IS_DOGFOOD_BUILD && o == null) {
+            throw new IllegalStateException();
+        }
+    }
+
     public static void assertWorkerThread() {
         if (ProviderConfig.IS_DOGFOOD_BUILD && !isSameLooper(LauncherModel.getWorkerLooper())) {
             throw new IllegalStateException();
diff --git a/src/com/android/launcher3/util/VerticalFlingDetector.java b/src/com/android/launcher3/util/VerticalFlingDetector.java
new file mode 100644
index 0000000..7236c2d
--- /dev/null
+++ b/src/com/android/launcher3/util/VerticalFlingDetector.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+public class VerticalFlingDetector implements View.OnTouchListener {
+
+    private static final float CUSTOM_SLOP_MULTIPLIER = 2.2f;
+    private static final int SEC_IN_MILLIS = 1000;
+
+    private VelocityTracker mVelocityTracker;
+    private float mMinimumFlingVelocity;
+    private float mMaximumFlingVelocity;
+    private float mDownX, mDownY;
+    private boolean mShouldCheckFling;
+    private double mCustomTouchSlop;
+
+    public VerticalFlingDetector(Context context) {
+        ViewConfiguration vc = ViewConfiguration.get(context);
+        mMinimumFlingVelocity = vc.getScaledMinimumFlingVelocity();
+        mMaximumFlingVelocity = vc.getScaledMaximumFlingVelocity();
+        mCustomTouchSlop = CUSTOM_SLOP_MULTIPLIER * vc.getScaledTouchSlop();
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent ev) {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mDownX = ev.getX();
+                mDownY = ev.getY();
+                mShouldCheckFling = false;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mShouldCheckFling) {
+                    break;
+                }
+                if (Math.abs(ev.getY() - mDownY) > mCustomTouchSlop &&
+                        Math.abs(ev.getY() - mDownY) > Math.abs(ev.getX() - mDownX)) {
+                    mShouldCheckFling = true;
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (mShouldCheckFling) {
+                    mVelocityTracker.computeCurrentVelocity(SEC_IN_MILLIS, mMaximumFlingVelocity);
+                    // only when fling is detected in down direction
+                    if (mVelocityTracker.getYVelocity() > mMinimumFlingVelocity) {
+                        cleanUp();
+                        return true;
+                    }
+                }
+                // fall through.
+            case MotionEvent.ACTION_CANCEL:
+                cleanUp();
+        }
+        return false;
+    }
+
+    private void cleanUp() {
+        if (mVelocityTracker == null) {
+            return;
+        }
+        mVelocityTracker.recycle();
+        mVelocityTracker = null;
+    }
+}
diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
index a569850..486b18e 100644
--- a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
@@ -35,10 +35,4 @@
         componentName = new ComponentName(activityInfo.packageName, activityInfo.name);
         itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
     }
-
-    @Override
-    public String toString() {
-        return String.format("PendingAddShortcutInfo package=%s, name=%s",
-                activityInfo.packageName, activityInfo.name);
-    }
 }
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index de06ab6..f800ac4 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -59,10 +59,4 @@
     public boolean isCustomWidget() {
         return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
     }
-
-    @Override
-    public String toString() {
-        return String.format("PendingAddWidgetInfo package=%s, name=%s",
-                componentName.getPackageName(), componentName.getShortClassName());
-    }
 }
diff --git a/src/com/android/launcher3/widget/PendingItemPreviewProvider.java b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java
new file mode 100644
index 0000000..eaa0bb3
--- /dev/null
+++ b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java
@@ -0,0 +1,76 @@
+/*
+ * 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.widget;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.view.View;
+
+import com.android.launcher3.HolographicOutlineHelper;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.graphics.DragPreviewProvider;
+
+/**
+ * Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts
+ * dragged from the widget tray.
+ */
+public class PendingItemPreviewProvider extends DragPreviewProvider {
+
+    private final PendingAddItemInfo mAddInfo;
+    private final Bitmap mPreviewBitmap;
+
+    public PendingItemPreviewProvider(View view, PendingAddItemInfo addInfo, Bitmap preview) {
+        super(view);
+        mAddInfo = addInfo;
+        mPreviewBitmap = preview;
+    }
+
+    @Override
+    public Bitmap createDragOutline(Canvas canvas) {
+        Workspace workspace = Launcher.getLauncher(mView.getContext()).getWorkspace();
+        int[] size = workspace.estimateItemSize(mAddInfo, false);
+
+        int w = size[0];
+        int h = size[1];
+        final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8);
+        canvas.setBitmap(b);
+
+        Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight());
+        float scaleFactor = Math.min((w - DRAG_BITMAP_PADDING) / (float) mPreviewBitmap.getWidth(),
+                (h - DRAG_BITMAP_PADDING) / (float) mPreviewBitmap.getHeight());
+        int scaledWidth = (int) (scaleFactor * mPreviewBitmap.getWidth());
+        int scaledHeight = (int) (scaleFactor * mPreviewBitmap.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);
+
+        // Don't clip alpha values for the drag outline if we're using the default widget preview
+        boolean clipAlpha = !(mAddInfo instanceof PendingAddWidgetInfo &&
+                (((PendingAddWidgetInfo) mAddInfo).previewImage == 0));
+        HolographicOutlineHelper.obtain(mView.getContext())
+                .applyExpensiveOutlineWithBlur(b, canvas, clipAlpha);
+        canvas.setBitmap(null);
+
+        return b;
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 97877fd..293585d 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -135,6 +135,8 @@
         mWidgetName.setText(mItem.label);
         mWidgetDims.setText(getContext().getString(R.string.widget_dims_format,
                 mItem.spanX, mItem.spanY));
+        mWidgetDims.setContentDescription(getContext().getString(
+                R.string.widget_accessible_dims_format, mItem.spanX, mItem.spanY));
         mWidgetPreviewLoader = loader;
 
         if (item.activityInfo != null) {
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index 297505b..049871f 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -11,6 +11,7 @@
 
 import com.android.launcher3.AppWidgetResizeFrame;
 import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -18,6 +19,7 @@
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.util.Thunk;
 
 public class WidgetHostViewLoader implements DragController.DragListener {
@@ -47,7 +49,7 @@
     }
 
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) { }
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { }
 
     @Override
     public void onDragEnd() {
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 083103c..89c44c8 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.DeleteDropTarget;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.IconCache;
 import com.android.launcher3.ItemInfo;
@@ -208,7 +209,7 @@
 
         // Compose the drag image
         Bitmap preview;
-        float scale = 1f;
+        final float scale;
         final Rect bounds = image.getBitmapBounds();
 
         if (createItemInfo instanceof PendingAddWidgetInfo) {
@@ -245,19 +246,14 @@
             scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / preview.getWidth();
         }
 
-        // Don't clip alpha values for the drag outline if we're using the default widget preview
-        boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
-                (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
+        // Since we are not going through the workspace for starting the drag, set drag related
+        // information on the workspace before starting the drag.
+        mLauncher.getWorkspace().prepareDragWithProvider(
+                new PendingItemPreviewProvider(v, createItemInfo, preview));
 
         // Start the drag
-        mLauncher.lockScreenOrientation();
         mDragController.startDrag(image, preview, this, createItemInfo,
-                bounds, DragController.DRAG_ACTION_COPY, scale);
-        // This call expects the extra empty screen to already be created, which is why we call it
-        // after mDragController.startDrag().
-        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, preview, clipAlpha);
-
-        preview.recycle();
+                bounds, scale, new DragOptions());
         return true;
     }
 
diff --git a/src_config/com/android/launcher3/config/FeatureFlags.java b/src_config/com/android/launcher3/config/FeatureFlags.java
index 69d8f0f..13acc4a 100644
--- a/src_config/com/android/launcher3/config/FeatureFlags.java
+++ b/src_config/com/android/launcher3/config/FeatureFlags.java
@@ -27,12 +27,14 @@
     // As opposed to the new spring-loaded workspace.
     public static boolean LAUNCHER3_LEGACY_WORKSPACE_DND = false;
     public static boolean LAUNCHER3_LEGACY_FOLDER_ICON = false;
-    public static boolean LAUNCHER3_USE_SYSTEM_DRAG_DRIVER = false;
+    public static boolean LAUNCHER3_USE_SYSTEM_DRAG_DRIVER = true;
     public static boolean LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW = false;
     public static boolean LAUNCHER3_ALL_APPS_PULL_UP = true;
 
-    // Feature flag to enable moving the QSB on the 0th screen of the workspace
+    // Feature flag to enable moving the QSB on the 0th screen of the workspace.
     public static final boolean QSB_ON_FIRST_SCREEN = true;
     // When enabled the all-apps icon is not added to the hotseat.
     public static final boolean NO_ALL_APPS_ICON = true;
+    // When enabled fling down gesture on the first workspace triggers search.
+    public static final boolean PULLDOWN_SEARCH = true;
 }
diff --git a/tests/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithmTest.java b/tests/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithmTest.java
new file mode 100644
index 0000000..4d0a7a9
--- /dev/null
+++ b/tests/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithmTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.allapps;
+
+import android.content.ComponentName;
+import android.test.InstrumentationTestCase;
+
+import com.android.launcher3.AppInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit tests for {@link DefaultAppSearchAlgorithm}
+ */
+public class DefaultAppSearchAlgorithmTest extends InstrumentationTestCase {
+
+    private List<AppInfo> mAppsList;
+    private DefaultAppSearchAlgorithm mAlgorithm;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mAppsList = new ArrayList<>();
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mAlgorithm = new DefaultAppSearchAlgorithm(mAppsList);
+            }
+        });
+    }
+
+    public void testMatches() {
+        assertTrue(mAlgorithm.matches(getInfo("white cow"), "cow"));
+        assertTrue(mAlgorithm.matches(getInfo("whiteCow"), "cow"));
+        assertTrue(mAlgorithm.matches(getInfo("whiteCOW"), "cow"));
+        assertTrue(mAlgorithm.matches(getInfo("whitecowCOW"), "cow"));
+        assertTrue(mAlgorithm.matches(getInfo("white2cow"), "cow"));
+
+        assertFalse(mAlgorithm.matches(getInfo("whitecow"), "cow"));
+        assertFalse(mAlgorithm.matches(getInfo("whitEcow"), "cow"));
+
+        assertTrue(mAlgorithm.matches(getInfo("whitecowCow"), "cow"));
+        assertTrue(mAlgorithm.matches(getInfo("whitecow cow"), "cow"));
+        assertFalse(mAlgorithm.matches(getInfo("whitecowcow"), "cow"));
+        assertFalse(mAlgorithm.matches(getInfo("whit ecowcow"), "cow"));
+
+        assertTrue(mAlgorithm.matches(getInfo("cats&dogs"), "dog"));
+        assertTrue(mAlgorithm.matches(getInfo("cats&Dogs"), "dog"));
+        assertTrue(mAlgorithm.matches(getInfo("cats&Dogs"), "&"));
+
+        assertTrue(mAlgorithm.matches(getInfo("2+43"), "43"));
+        assertFalse(mAlgorithm.matches(getInfo("2+43"), "3"));
+
+        assertTrue(mAlgorithm.matches(getInfo("Q"), "q"));
+        assertTrue(mAlgorithm.matches(getInfo("  Q"), "q"));
+    }
+
+    private AppInfo getInfo(String title) {
+        AppInfo info = new AppInfo();
+        info.title = title;
+        info.componentName = new ComponentName("Test", title);
+        return info;
+    }
+}