Merge "Fixing preloaded widget not getting used for animation" into ub-launcher3-burnaby
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index fce4691..f9f5fc2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -45,6 +45,10 @@
         android:protectionLevel="signature"
         />
     <permission
+        android:name="com.android.launcher3.permission.RECEIVE_UPDATE_ORIENTATION_BROADCASTS"
+        android:protectionLevel="signature"
+        />
+    <permission
         android:name="com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST"
         android:protectionLevel="signatureOrSystem" />
 
@@ -62,6 +66,7 @@
     <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
     <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />
     <uses-permission android:name="com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS" />
+    <uses-permission android:name="com.android.launcher3.permission.RECEIVE_UPDATE_ORIENTATION_BROADCASTS" />
     <uses-permission android:name="com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST" />
 
     <application
@@ -152,7 +157,8 @@
         <activity
             android:name="com.android.launcher3.SettingsActivity"
             android:label="@string/settings_button_text"
-            android:autoRemoveFromRecents="true">
+            android:autoRemoveFromRecents="true"
+            android:process=":settings_process">
         </activity>
 
         <!-- Debugging tools -->
diff --git a/WallpaperPicker/res/values-v21/styles.xml b/WallpaperPicker/res/values-v21/styles.xml
new file mode 100644
index 0000000..04f39de
--- /dev/null
+++ b/WallpaperPicker/res/values-v21/styles.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="WallpaperCropperActionBar" parent="@android:style/Widget.DeviceDefault.ActionBar">
+        <item name="android:displayOptions">showCustom</item>
+        <item name="android:background">#88000000</item>
+        <item name="android:contentInsetEnd">0dp</item>
+        <item name="android:contentInsetLeft">0dp</item>
+        <item name="android:contentInsetRight">0dp</item>
+        <item name="android:contentInsetStart">0dp</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
index 659c306..9415941 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -49,6 +49,7 @@
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnLayoutChangeListener;
@@ -891,6 +892,15 @@
 
     private void addLongPressHandler(View v) {
         v.setOnLongClickListener(mLongClickListener);
+
+        // Enable stylus button to also trigger long click.
+        final StylusEventHelper stylusEventHelper = new StylusEventHelper(v);
+        v.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View view, MotionEvent event) {
+                return stylusEventHelper.checkAndPerformStylusEvent(event);
+            }
+        });
     }
 
     private ArrayList<WallpaperTileInfo> findBundledWallpapers() {
diff --git a/res/drawable-hdpi/ic_info_launcher.png b/res/drawable-hdpi/ic_info_launcher.png
new file mode 100644
index 0000000..ec0cdd1
--- /dev/null
+++ b/res/drawable-hdpi/ic_info_launcher.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_normal.png b/res/drawable-hdpi/ic_launcher_info_normal.png
deleted file mode 100644
index 780d796..0000000
--- a/res/drawable-hdpi/ic_launcher_info_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_remove_normal.png b/res/drawable-hdpi/ic_launcher_remove_normal.png
deleted file mode 100644
index 91e19ca..0000000
--- a/res/drawable-hdpi/ic_launcher_remove_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_uninstall_normal.png b/res/drawable-hdpi/ic_launcher_uninstall_normal.png
deleted file mode 100644
index 7aea5d0..0000000
--- a/res/drawable-hdpi/ic_launcher_uninstall_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_remove_launcher.png b/res/drawable-hdpi/ic_remove_launcher.png
new file mode 100644
index 0000000..c081457
--- /dev/null
+++ b/res/drawable-hdpi/ic_remove_launcher.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_uninstall_launcher.png b/res/drawable-hdpi/ic_uninstall_launcher.png
new file mode 100644
index 0000000..3d8f726
--- /dev/null
+++ b/res/drawable-hdpi/ic_uninstall_launcher.png
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_inner.png b/res/drawable-hdpi/portal_ring_inner.png
new file mode 100644
index 0000000..c29b4aa
--- /dev/null
+++ b/res/drawable-hdpi/portal_ring_inner.png
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_inner_holo.png b/res/drawable-hdpi/portal_ring_inner_holo.png
deleted file mode 100644
index 857a01e..0000000
--- a/res/drawable-hdpi/portal_ring_inner_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_inner_nolip.png b/res/drawable-hdpi/portal_ring_inner_nolip.png
new file mode 100644
index 0000000..e2f06fe
--- /dev/null
+++ b/res/drawable-hdpi/portal_ring_inner_nolip.png
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_inner_nolip_holo.png b/res/drawable-hdpi/portal_ring_inner_nolip_holo.png
deleted file mode 100644
index 53df36a..0000000
--- a/res/drawable-hdpi/portal_ring_inner_nolip_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_outer.png b/res/drawable-hdpi/portal_ring_outer.png
new file mode 100644
index 0000000..e7b436b
--- /dev/null
+++ b/res/drawable-hdpi/portal_ring_outer.png
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_outer_holo.png b/res/drawable-hdpi/portal_ring_outer_holo.png
deleted file mode 100644
index b711cf3..0000000
--- a/res/drawable-hdpi/portal_ring_outer_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_rest.png b/res/drawable-hdpi/portal_ring_rest.png
index 2979b73..e3b1339 100644
--- a/res/drawable-hdpi/portal_ring_rest.png
+++ b/res/drawable-hdpi/portal_ring_rest.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_frame.9.png b/res/drawable-hdpi/widget_resize_frame.9.png
index 5772672..b0a7403 100644
--- a/res/drawable-hdpi/widget_resize_frame.9.png
+++ b/res/drawable-hdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_shadow.9.png b/res/drawable-hdpi/widget_resize_shadow.9.png
index a67da6e..6e2932d 100644
--- a/res/drawable-hdpi/widget_resize_shadow.9.png
+++ b/res/drawable-hdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_info_launcher.png b/res/drawable-mdpi/ic_info_launcher.png
new file mode 100644
index 0000000..c72d0c2
--- /dev/null
+++ b/res/drawable-mdpi/ic_info_launcher.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_normal.png b/res/drawable-mdpi/ic_launcher_info_normal.png
deleted file mode 100644
index 8c60159..0000000
--- a/res/drawable-mdpi/ic_launcher_info_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_remove_normal.png b/res/drawable-mdpi/ic_launcher_remove_normal.png
deleted file mode 100644
index 60829b9..0000000
--- a/res/drawable-mdpi/ic_launcher_remove_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_uninstall_normal.png b/res/drawable-mdpi/ic_launcher_uninstall_normal.png
deleted file mode 100644
index aefbc69..0000000
--- a/res/drawable-mdpi/ic_launcher_uninstall_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_remove_launcher.png b/res/drawable-mdpi/ic_remove_launcher.png
new file mode 100644
index 0000000..4a2c319
--- /dev/null
+++ b/res/drawable-mdpi/ic_remove_launcher.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_uninstall_launcher.png b/res/drawable-mdpi/ic_uninstall_launcher.png
new file mode 100644
index 0000000..af45669
--- /dev/null
+++ b/res/drawable-mdpi/ic_uninstall_launcher.png
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_inner.png b/res/drawable-mdpi/portal_ring_inner.png
new file mode 100644
index 0000000..99aaa60
--- /dev/null
+++ b/res/drawable-mdpi/portal_ring_inner.png
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_inner_holo.png b/res/drawable-mdpi/portal_ring_inner_holo.png
deleted file mode 100644
index 72e0af8..0000000
--- a/res/drawable-mdpi/portal_ring_inner_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_inner_nolip.png b/res/drawable-mdpi/portal_ring_inner_nolip.png
new file mode 100644
index 0000000..f981778
--- /dev/null
+++ b/res/drawable-mdpi/portal_ring_inner_nolip.png
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_inner_nolip_holo.png b/res/drawable-mdpi/portal_ring_inner_nolip_holo.png
deleted file mode 100644
index 483f0eb..0000000
--- a/res/drawable-mdpi/portal_ring_inner_nolip_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_outer.png b/res/drawable-mdpi/portal_ring_outer.png
new file mode 100644
index 0000000..c98f64b
--- /dev/null
+++ b/res/drawable-mdpi/portal_ring_outer.png
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_outer_holo.png b/res/drawable-mdpi/portal_ring_outer_holo.png
deleted file mode 100644
index e9b35f3..0000000
--- a/res/drawable-mdpi/portal_ring_outer_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_rest.png b/res/drawable-mdpi/portal_ring_rest.png
index d0a976e..5c33b42 100644
--- a/res/drawable-mdpi/portal_ring_rest.png
+++ b/res/drawable-mdpi/portal_ring_rest.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_frame.9.png b/res/drawable-mdpi/widget_resize_frame.9.png
index 8bc8a5c..856cec6 100644
--- a/res/drawable-mdpi/widget_resize_frame.9.png
+++ b/res/drawable-mdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_shadow.9.png b/res/drawable-mdpi/widget_resize_shadow.9.png
index 2bae2b6..02522f3 100644
--- a/res/drawable-mdpi/widget_resize_shadow.9.png
+++ b/res/drawable-mdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_info_launcher.png b/res/drawable-xhdpi/ic_info_launcher.png
new file mode 100644
index 0000000..076b59b
--- /dev/null
+++ b/res/drawable-xhdpi/ic_info_launcher.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_normal.png b/res/drawable-xhdpi/ic_launcher_info_normal.png
deleted file mode 100644
index 5c49816..0000000
--- a/res/drawable-xhdpi/ic_launcher_info_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_remove_normal.png b/res/drawable-xhdpi/ic_launcher_remove_normal.png
deleted file mode 100644
index 8188805..0000000
--- a/res/drawable-xhdpi/ic_launcher_remove_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_uninstall_normal.png b/res/drawable-xhdpi/ic_launcher_uninstall_normal.png
deleted file mode 100644
index a093f28..0000000
--- a/res/drawable-xhdpi/ic_launcher_uninstall_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_remove_launcher.png b/res/drawable-xhdpi/ic_remove_launcher.png
new file mode 100644
index 0000000..de05889
--- /dev/null
+++ b/res/drawable-xhdpi/ic_remove_launcher.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_uninstall_launcher.png b/res/drawable-xhdpi/ic_uninstall_launcher.png
new file mode 100644
index 0000000..dd50e88
--- /dev/null
+++ b/res/drawable-xhdpi/ic_uninstall_launcher.png
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_inner.png b/res/drawable-xhdpi/portal_ring_inner.png
new file mode 100644
index 0000000..7b6a8a0
--- /dev/null
+++ b/res/drawable-xhdpi/portal_ring_inner.png
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_inner_holo.png b/res/drawable-xhdpi/portal_ring_inner_holo.png
deleted file mode 100644
index f9acfa2..0000000
--- a/res/drawable-xhdpi/portal_ring_inner_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_inner_nolip.png b/res/drawable-xhdpi/portal_ring_inner_nolip.png
new file mode 100644
index 0000000..4b84436
--- /dev/null
+++ b/res/drawable-xhdpi/portal_ring_inner_nolip.png
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_inner_nolip_holo.png b/res/drawable-xhdpi/portal_ring_inner_nolip_holo.png
deleted file mode 100644
index eb2cf5f..0000000
--- a/res/drawable-xhdpi/portal_ring_inner_nolip_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_outer.png b/res/drawable-xhdpi/portal_ring_outer.png
new file mode 100644
index 0000000..79c1888
--- /dev/null
+++ b/res/drawable-xhdpi/portal_ring_outer.png
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_outer_holo.png b/res/drawable-xhdpi/portal_ring_outer_holo.png
deleted file mode 100644
index f32051d..0000000
--- a/res/drawable-xhdpi/portal_ring_outer_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_rest.png b/res/drawable-xhdpi/portal_ring_rest.png
index ff0369a..544a74f 100644
--- a/res/drawable-xhdpi/portal_ring_rest.png
+++ b/res/drawable-xhdpi/portal_ring_rest.png
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_frame.9.png b/res/drawable-xhdpi/widget_resize_frame.9.png
index e6cf0af..bf7cc6b 100644
--- a/res/drawable-xhdpi/widget_resize_frame.9.png
+++ b/res/drawable-xhdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_shadow.9.png b/res/drawable-xhdpi/widget_resize_shadow.9.png
index 99e9e78..96dee7f 100644
--- a/res/drawable-xhdpi/widget_resize_shadow.9.png
+++ b/res/drawable-xhdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_info_launcher.png b/res/drawable-xxhdpi/ic_info_launcher.png
new file mode 100644
index 0000000..386d091
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_info_launcher.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_normal.png b/res/drawable-xxhdpi/ic_launcher_info_normal.png
deleted file mode 100644
index c270be2..0000000
--- a/res/drawable-xxhdpi/ic_launcher_info_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_remove_normal.png b/res/drawable-xxhdpi/ic_launcher_remove_normal.png
deleted file mode 100644
index 5bc8f0c..0000000
--- a/res/drawable-xxhdpi/ic_launcher_remove_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_uninstall_normal.png b/res/drawable-xxhdpi/ic_launcher_uninstall_normal.png
deleted file mode 100644
index 4fce55b..0000000
--- a/res/drawable-xxhdpi/ic_launcher_uninstall_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_remove_launcher.png b/res/drawable-xxhdpi/ic_remove_launcher.png
new file mode 100644
index 0000000..7c28bb0
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_remove_launcher.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_uninstall_launcher.png b/res/drawable-xxhdpi/ic_uninstall_launcher.png
new file mode 100644
index 0000000..872e829
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_uninstall_launcher.png
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_inner.png b/res/drawable-xxhdpi/portal_ring_inner.png
new file mode 100644
index 0000000..d088a17
--- /dev/null
+++ b/res/drawable-xxhdpi/portal_ring_inner.png
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_inner_holo.png b/res/drawable-xxhdpi/portal_ring_inner_holo.png
deleted file mode 100644
index 8cd6a59..0000000
--- a/res/drawable-xxhdpi/portal_ring_inner_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_inner_nolip_holo.png b/res/drawable-xxhdpi/portal_ring_inner_nolip.png
similarity index 100%
rename from res/drawable-xxhdpi/portal_ring_inner_nolip_holo.png
rename to res/drawable-xxhdpi/portal_ring_inner_nolip.png
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_outer.png b/res/drawable-xxhdpi/portal_ring_outer.png
new file mode 100644
index 0000000..45ac040
--- /dev/null
+++ b/res/drawable-xxhdpi/portal_ring_outer.png
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_outer_holo.png b/res/drawable-xxhdpi/portal_ring_outer_holo.png
deleted file mode 100644
index 0aee4f0..0000000
--- a/res/drawable-xxhdpi/portal_ring_outer_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_frame.9.png b/res/drawable-xxhdpi/widget_resize_frame.9.png
index 7a49d01..7e189d4 100644
--- a/res/drawable-xxhdpi/widget_resize_frame.9.png
+++ b/res/drawable-xxhdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_shadow.9.png b/res/drawable-xxhdpi/widget_resize_shadow.9.png
index ae0f564..41c448b 100644
--- a/res/drawable-xxhdpi/widget_resize_shadow.9.png
+++ b/res/drawable-xxhdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_info_launcher.png b/res/drawable-xxxhdpi/ic_info_launcher.png
new file mode 100644
index 0000000..bf39e5b
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_info_launcher.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_info_normal.png b/res/drawable-xxxhdpi/ic_launcher_info_normal.png
deleted file mode 100644
index 270e15d..0000000
--- a/res/drawable-xxxhdpi/ic_launcher_info_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_remove_normal.png b/res/drawable-xxxhdpi/ic_launcher_remove_normal.png
deleted file mode 100644
index ed96c55..0000000
--- a/res/drawable-xxxhdpi/ic_launcher_remove_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_uninstall_normal.png b/res/drawable-xxxhdpi/ic_launcher_uninstall_normal.png
deleted file mode 100644
index 61490b9..0000000
--- a/res/drawable-xxxhdpi/ic_launcher_uninstall_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_remove_launcher.png b/res/drawable-xxxhdpi/ic_remove_launcher.png
new file mode 100644
index 0000000..7043be0
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_remove_launcher.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_uninstall_launcher.png b/res/drawable-xxxhdpi/ic_uninstall_launcher.png
new file mode 100644
index 0000000..77a3302
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_uninstall_launcher.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_inner.png b/res/drawable-xxxhdpi/portal_ring_inner.png
new file mode 100644
index 0000000..34a3599
--- /dev/null
+++ b/res/drawable-xxxhdpi/portal_ring_inner.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_inner_nolip.png b/res/drawable-xxxhdpi/portal_ring_inner_nolip.png
new file mode 100644
index 0000000..8cebb35
--- /dev/null
+++ b/res/drawable-xxxhdpi/portal_ring_inner_nolip.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_outer.png b/res/drawable-xxxhdpi/portal_ring_outer.png
new file mode 100644
index 0000000..d2df322
--- /dev/null
+++ b/res/drawable-xxxhdpi/portal_ring_outer.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_rest.png b/res/drawable-xxxhdpi/portal_ring_rest.png
new file mode 100644
index 0000000..11e92ee
--- /dev/null
+++ b/res/drawable-xxxhdpi/portal_ring_rest.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/widget_resize_frame.9.png b/res/drawable-xxxhdpi/widget_resize_frame.9.png
index 9b711f2..cb609ce 100644
--- a/res/drawable-xxxhdpi/widget_resize_frame.9.png
+++ b/res/drawable-xxxhdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/widget_resize_shadow.9.png b/res/drawable-xxxhdpi/widget_resize_shadow.9.png
index defb311..82c8b9c 100644
--- a/res/drawable-xxxhdpi/widget_resize_shadow.9.png
+++ b/res/drawable-xxxhdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index bf9296f..1c917bf 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -45,7 +45,7 @@
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:layout_gravity="end" />
+            android:layout_gravity="right" />
 
         <include
             android:id="@+id/search_drop_target_bar"
diff --git a/res/layout/all_apps_container.xml b/res/layout/all_apps_container.xml
index a20ab46..fc77cd3 100644
--- a/res/layout/all_apps_container.xml
+++ b/res/layout/all_apps_container.xml
@@ -38,6 +38,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="@dimen/all_apps_search_bar_height"
+        android:paddingBottom="@dimen/all_apps_prediction_bar_bottom_padding"
         android:orientation="horizontal"
         android:descendantFocusability="afterDescendants"
         android:focusable="true"
diff --git a/res/layout/all_apps_icon.xml b/res/layout/all_apps_icon.xml
index 10ed25c..0985e95 100644
--- a/res/layout/all_apps_icon.xml
+++ b/res/layout/all_apps_icon.xml
@@ -20,7 +20,7 @@
     android:id="@+id/icon"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:layout_gravity="left|center_vertical"
+    android:layout_gravity="center"
     android:paddingTop="@dimen/all_apps_icon_top_bottom_padding"
     android:paddingBottom="@dimen/all_apps_icon_top_bottom_padding"
     android:focusable="true"
diff --git a/res/layout/all_apps_prediction_bar_icon.xml b/res/layout/all_apps_prediction_bar_icon.xml
index 1e75d14..5f63f6b 100644
--- a/res/layout/all_apps_prediction_bar_icon.xml
+++ b/res/layout/all_apps_prediction_bar_icon.xml
@@ -19,7 +19,7 @@
     style="@style/Icon.AllApps"
     android:id="@+id/icon"
     android:layout_width="0dp"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
     android:layout_gravity="center"
     android:layout_weight="1"
     android:focusable="true"
diff --git a/res/layout/folder_icon.xml b/res/layout/folder_icon.xml
index d9a7671..237af68 100644
--- a/res/layout/folder_icon.xml
+++ b/res/layout/folder_icon.xml
@@ -26,7 +26,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:antialias="true"
-        android:src="@drawable/portal_ring_inner_holo"/>
+        android:src="@drawable/portal_ring_inner"/>
     <com.android.launcher3.BubbleTextView
         style="@style/Icon"
         android:id="@+id/folder_icon_name"
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
index af2c970..a1a62b3 100644
--- a/res/layout/widgets_view.xml
+++ b/res/layout/widgets_view.xml
@@ -39,7 +39,6 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:background="@drawable/quantum_panel_dark"
-            android:scrollbars="vertical"
             android:elevation="15dp"
             android:visibility="gone" />
 
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 994c192..daa98ef 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -15,8 +15,6 @@
 -->
 
 <resources>
-    <dimen name="app_icon_size">64dp</dimen>
-
 <!-- All Apps -->
     <dimen name="all_apps_container_inset">18dp</dimen>
     <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 89942f7..9d1e352 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -15,8 +15,6 @@
 -->
 
 <resources>
-    <dimen name="app_icon_size">72dp</dimen>
-
 <!-- All Apps -->
     <dimen name="all_apps_search_bar_height">54dp</dimen>
     <dimen name="all_apps_icon_top_bottom_padding">16dp</dimen>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 7950862..2184ead 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -15,7 +15,7 @@
 -->
 
 <resources>
-    <dimen name="app_icon_size">48dp</dimen>
+    <dimen name="app_icon_size">64dp</dimen>
 
 <!-- Dynamic Grid -->
     <dimen name="dynamic_grid_edge_margin">6dp</dimen>
@@ -58,12 +58,12 @@
     <dimen name="all_apps_grid_section_y_offset">8dp</dimen>
     <dimen name="all_apps_grid_section_text_size">24sp</dimen>
     <dimen name="all_apps_search_bar_height">52dp</dimen>
+    <dimen name="all_apps_search_bar_prediction_bar_padding">8dp</dimen>
     <dimen name="all_apps_icon_top_bottom_padding">8dp</dimen>
-    <dimen name="all_apps_icon_left_right_padding">18dp</dimen>
-    <dimen name="all_apps_prediction_icon_top_bottom_padding">12dp</dimen>
+    <dimen name="all_apps_icon_width_gap">24dp</dimen>
+    <dimen name="all_apps_prediction_bar_bottom_padding">16dp</dimen>
 
     <dimen name="all_apps_fast_scroll_bar_width">4dp</dimen>
-    <dimen name="all_apps_fast_scroll_bar_min_height">64dp</dimen>
     <dimen name="all_apps_fast_scroll_scrubber_touch_inset">-16dp</dimen>
     <dimen name="all_apps_fast_scroll_popup_size">72dp</dimen>
     <dimen name="all_apps_fast_scroll_text_size">48dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 440a537..305c310 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -27,6 +27,9 @@
     <!-- Permission to receive the com.android.launcher3.action.LAUNCH intent -->
     <string name="receive_launch_broadcasts_permission" translatable="false">com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS</string>
 
+    <!-- Permission to receive the com.android.launcher3.SCREEN_ORIENTATION_PREF_CHANGED intent -->
+    <string name="receive_update_orientation_broadcasts_permission" translatable="false">com.android.launcher3.permission.RECEIVE_UPDATE_ORIENTATION_BROADCASTS</string>
+
     <!-- Permission to receive the com.android.launcher3.action.FIRST_LOAD_COMPLETE intent -->
     <string name="receive_first_load_broadcast_permission" translatable="false">com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST</string>
 
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index 8d418f9..a207d9a 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -86,10 +86,8 @@
 
     private int mDownX;
     private int mDownY;
-    private int mLastX;
     private int mLastY;
     private int mScrollbarWidth;
-    private int mScrollbarMinHeight;
     private int mScrollbarInset;
     private Rect mBackgroundPadding = new Rect();
 
@@ -121,8 +119,6 @@
         mFastScrollTextPaint.setTextSize(res.getDimensionPixelSize(
                 R.dimen.all_apps_fast_scroll_text_size));
         mScrollbarWidth = res.getDimensionPixelSize(R.dimen.all_apps_fast_scroll_bar_width);
-        mScrollbarMinHeight =
-                res.getDimensionPixelSize(R.dimen.all_apps_fast_scroll_bar_min_height);
         mScrollbarInset =
                 res.getDimensionPixelSize(R.dimen.all_apps_fast_scroll_scrubber_touch_inset);
         setFastScrollerAlpha(mFastScrollAlpha);
@@ -173,7 +169,7 @@
         switch (action) {
             case MotionEvent.ACTION_DOWN:
                 // Keep track of the down positions
-                mDownX = mLastX = x;
+                mDownX = x;
                 mDownY = mLastY = y;
                 if (shouldStopScroll(ev)) {
                     stopScroll();
@@ -188,7 +184,6 @@
                     animateFastScrollerVisibility(true);
                 }
                 if (mDraggingFastScroller) {
-                    mLastX = x;
                     mLastY = y;
 
                     // Scroll to the right position, and update the section name
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index edf5021..6c13b4a 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -28,7 +28,6 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.KeyEvent;
@@ -36,7 +35,6 @@
 import android.view.ViewConfiguration;
 import android.view.ViewParent;
 import android.widget.TextView;
-
 import com.android.launcher3.IconCache.IconLoadRequest;
 import com.android.launcher3.model.PackageItemInfo;
 
@@ -54,15 +52,16 @@
     private static final float SHADOW_Y_OFFSET = 2.0f;
     private static final int SHADOW_LARGE_COLOUR = 0xDD000000;
     private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
-    static final float PADDING_V = 3.0f;
 
     private static final int DISPLAY_WORKSPACE = 0;
     private static final int DISPLAY_ALL_APPS = 1;
 
+    private final Launcher mLauncher;
     private Drawable mIcon;
     private final Drawable mBackground;
     private final CheckLongPressHelper mLongPressHelper;
     private final HolographicOutlineHelper mOutlineHelper;
+    private final StylusEventHelper mStylusEventHelper;
 
     private boolean mBackgroundSizeChanged;
 
@@ -92,8 +91,8 @@
 
     public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = ((Launcher) context).getDeviceProfile();
+        mLauncher = (Launcher) context;
+        DeviceProfile grid = mLauncher.getDeviceProfile();
 
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.BubbleTextView, defStyle, 0);
@@ -125,6 +124,7 @@
         }
 
         mLongPressHelper = new CheckLongPressHelper(this);
+        mStylusEventHelper = new StylusEventHelper(this);
 
         mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
         if (mCustomShadowsEnabled) {
@@ -142,7 +142,7 @@
             boolean promiseStateChanged) {
         Bitmap b = info.getIcon(iconCache);
 
-        FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
+        FastBitmapDrawable iconDrawable = mLauncher.createIconDrawable(b);
         iconDrawable.setGhostModeEnabled(info.isDisabled != 0);
 
         setIcon(iconDrawable, mIconSize);
@@ -158,7 +158,7 @@
     }
 
     public void applyFromApplicationInfo(AppInfo info) {
-        setIcon(Utilities.createIconDrawable(info.iconBitmap), mIconSize);
+        setIcon(mLauncher.createIconDrawable(info.iconBitmap), mIconSize);
         setText(info.title);
         if (info.contentDescription != null) {
             setContentDescription(info.contentDescription);
@@ -171,7 +171,7 @@
     }
 
     public void applyFromPackageItemInfo(PackageItemInfo info) {
-        setIcon(Utilities.createIconDrawable(info.iconBitmap), mIconSize);
+        setIcon(mLauncher.createIconDrawable(info.iconBitmap), mIconSize);
         setText(info.title);
         if (info.contentDescription != null) {
             setContentDescription(info.contentDescription);
@@ -183,6 +183,12 @@
         verifyHighRes();
     }
 
+    /**
+     * Overrides the default long press timeout.
+     */
+    public void setLongPressTimeout(int longPressTimeout) {
+        mLongPressHelper.setLongPressTimeout(longPressTimeout);
+    }
 
     @Override
     protected boolean setFrame(int left, int top, int right, int bottom) {
@@ -236,6 +242,12 @@
         // isPressed() on an ACTION_UP
         boolean result = super.onTouchEvent(event);
 
+        // Check for a stylus button press, if it occurs cancel any long press checks.
+        if (mStylusEventHelper.checkAndPerformStylusEvent(event)) {
+            mLongPressHelper.cancelLongPress();
+            result = true;
+        }
+
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 // So that the pressed outline is visible immediately on setStayPressed(),
@@ -245,7 +257,10 @@
                     mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
                 }
 
-                mLongPressHelper.postCheckForLongPress();
+                // If we're in a stylus button press, don't check for long press.
+                if (!mStylusEventHelper.inStylusButtonPressed()) {
+                    mLongPressHelper.postCheckForLongPress();
+                }
                 break;
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 09a71b0..b7f89d0 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -51,7 +51,6 @@
 
     protected Launcher mLauncher;
     private int mBottomDragPadding;
-    protected TextView mText;
     protected SearchDropTargetBar mSearchDropTargetBar;
 
     /** Whether this drop target is active for the current drag */
@@ -82,11 +81,9 @@
         mOriginalTextColor = getTextColors();
 
         // Remove the text in the Phone UI in landscape
-        int orientation = getResources().getConfiguration().orientation;
-        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            if (!LauncherAppState.getInstance().isScreenLarge()) {
-                setText("");
-            }
+        DeviceProfile grid = ((Launcher) getContext()).getDeviceProfile();
+        if (grid.isVerticalBarLayout()) {
+            setText("");
         }
     }
 
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index ff7bcc4..b5d0dca 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -95,6 +95,7 @@
     boolean[][] mTmpOccupied;
 
     private OnTouchListener mInterceptTouchListener;
+    private StylusEventHelper mStylusEventHelper;
 
     private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
     private int[] mFolderLeaveBehindCell = {-1, -1};
@@ -284,6 +285,8 @@
         mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap,
                 mCountX, mCountY);
 
+        mStylusEventHelper = new StylusEventHelper(this);
+
         mTouchFeedbackView = new ClickShadowView(context);
         addView(mTouchFeedbackView);
         addView(mShortcutsAndWidgets);
@@ -336,6 +339,20 @@
         return false;
     }
 
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean handled = super.onTouchEvent(ev);
+        // Stylus button press on a home screen should not switch between overview mode and
+        // the home screen mode, however, once in overview mode stylus button press should be
+        // enabled to allow rearranging the different home screens. So check what mode
+        // the workspace is in, and only perform stylus button presses while in overview mode.
+        if (mLauncher.mWorkspace.isInOverviewMode()
+                && mStylusEventHelper.checkAndPerformStylusEvent(ev)) {
+            return true;
+        }
+        return handled;
+    }
+
     public void enableHardwareLayer(boolean hasLayer) {
         mShortcutsAndWidgets.setLayerType(hasLayer ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, sPaint);
     }
diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java
index 381b678..483c622 100644
--- a/src/com/android/launcher3/CheckLongPressHelper.java
+++ b/src/com/android/launcher3/CheckLongPressHelper.java
@@ -21,9 +21,11 @@
 import com.android.launcher3.util.Thunk;
 
 public class CheckLongPressHelper {
+
     @Thunk View mView;
     @Thunk View.OnLongClickListener mListener;
     @Thunk boolean mHasPerformedLongPress;
+    private int mLongPressTimeout = 300;
     private CheckForLongPress mPendingCheckForLongPress;
 
     class CheckForLongPress implements Runnable {
@@ -53,14 +55,20 @@
         mListener = listener;
     }
 
+    /**
+     * Overrides the default long press timeout.
+     */
+    public void setLongPressTimeout(int longPressTimeout) {
+        mLongPressTimeout = longPressTimeout;
+    }
+
     public void postCheckForLongPress() {
         mHasPerformedLongPress = false;
 
         if (mPendingCheckForLongPress == null) {
             mPendingCheckForLongPress = new CheckForLongPress();
         }
-        mView.postDelayed(mPendingCheckForLongPress,
-                LauncherAppState.getInstance().getLongPressTimeout());
+        mView.postDelayed(mPendingCheckForLongPress, mLongPressTimeout);
     }
 
     public void cancelLongPress() {
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index fa6e74f..9c8659c 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -43,7 +43,7 @@
         // Get the hover color
         mHoverColor = getResources().getColor(R.color.delete_target_hover_tint);
 
-        setDrawable(R.drawable.ic_launcher_remove_normal);
+        setDrawable(R.drawable.ic_remove_launcher);
     }
 
     public static boolean supportsDrop(Object info) {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index bee6cb0..9c59dab 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -230,12 +230,12 @@
     public boolean updateAppsViewNumCols(Resources res, int containerWidth) {
         int appsViewLeftMarginPx =
                 res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
-        int allAppsCellPaddingPx =
-                res.getDimensionPixelSize(R.dimen.all_apps_icon_left_right_padding);
+        int allAppsCellWidthGap =
+                res.getDimensionPixelSize(R.dimen.all_apps_icon_width_gap);
         int availableAppsWidthPx = (containerWidth > 0) ? containerWidth : availableWidthPx;
         int numAppsCols = (availableAppsWidthPx - appsViewLeftMarginPx) /
-                (allAppsIconSizePx + 2 * allAppsCellPaddingPx);
-        int numPredictiveAppCols = isPhone ? 4 : numAppsCols;
+                (allAppsIconSizePx + allAppsCellWidthGap);
+        int numPredictiveAppCols = Math.max(inv.minAllAppsPredictionColumns, numAppsCols);
         if ((numAppsCols != allAppsNumCols) ||
                 (numPredictiveAppCols != allAppsNumPredictiveCols)) {
             allAppsNumCols = numAppsCols;
@@ -405,7 +405,8 @@
         View searchBar = launcher.getSearchBar();
         lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
         if (hasVerticalBarLayout) {
-            // Vertical search bar space
+            // Vertical search bar space -- The search bar is fixed in the layout to be on the left
+            //                              of the screen regardless of RTL
             lp.gravity = Gravity.LEFT;
             lp.width = searchBarSpaceHeightPx;
 
@@ -438,8 +439,9 @@
         View hotseat = launcher.findViewById(R.id.hotseat);
         lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams();
         if (hasVerticalBarLayout) {
-            // Vertical hotseat
-            lp.gravity = Gravity.END;
+            // Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the
+            //                     screen regardless of RTL
+            lp.gravity = Gravity.RIGHT;
             lp.width = hotseatBarHeightPx;
             lp.height = LayoutParams.MATCH_PARENT;
             hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index 41e053e..aaa14e6 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -50,7 +50,6 @@
 public class DragLayer extends InsettableFrameLayout {
 
     public static final int ANIMATION_END_DISAPPEAR = 0;
-    public static final int ANIMATION_END_FADE_OUT = 1;
     public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
 
     // Scrim color without any alpha component.
@@ -70,7 +69,6 @@
 
     // Variables relating to animation of views after drop
     private ValueAnimator mDropAnim = null;
-    private ValueAnimator mFadeOutAnim = null;
     private final TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
     @Thunk DragView mDropView = null;
     @Thunk int mAnchorViewInitialScrollX = 0;
@@ -762,7 +760,6 @@
             final int animationEndStyle, View anchorView) {
         // Clean up the previous animations
         if (mDropAnim != null) mDropAnim.cancel();
-        if (mFadeOutAnim != null) mFadeOutAnim.cancel();
 
         // Show the drop view if it was previously hidden
         mDropView = view;
@@ -790,9 +787,6 @@
                 case ANIMATION_END_DISAPPEAR:
                     clearAnimatedView();
                     break;
-                case ANIMATION_END_FADE_OUT:
-                    fadeOutDragView();
-                    break;
                 case ANIMATION_END_REMAIN_VISIBLE:
                     break;
                 }
@@ -816,31 +810,6 @@
         return mDropView;
     }
 
-    @Thunk void fadeOutDragView() {
-        mFadeOutAnim = new ValueAnimator();
-        mFadeOutAnim.setDuration(150);
-        mFadeOutAnim.setFloatValues(0f, 1f);
-        mFadeOutAnim.removeAllUpdateListeners();
-        mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final float percent = (Float) animation.getAnimatedValue();
-
-                float alpha = 1 - percent;
-                mDropView.setAlpha(alpha);
-            }
-        });
-        mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationEnd(Animator animation) {
-                if (mDropView != null) {
-                    mDragController.onDeferredEndDrag(mDropView);
-                }
-                mDropView = null;
-                invalidate();
-            }
-        });
-        mFadeOutAnim.start();
-    }
-
     @Override
     public void onChildViewAdded(View parent, View child) {
         super.onChildViewAdded(parent, child);
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index 70bb01a..57aec32 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -222,8 +222,8 @@
         if (keyCode == KeyEvent.KEYCODE_DPAD_UP &&
                 !profile.isVerticalBarLayout()) {
             matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout,
-                    true /* hotseat horizontal */, hotseat.getAllAppsButtonRank(),
-                    iconRank == hotseat.getAllAppsButtonRank() /* include all apps icon */);
+                    true /* hotseat horizontal */, profile.inv.hotseatAllAppsRank,
+                    iconRank == profile.inv.hotseatAllAppsRank /* include all apps icon */);
             iconIndex += iconParent.getChildCount();
             countX = iconLayout.getCountX();
             countY = iconLayout.getCountY() + hotseatLayout.getCountY();
@@ -231,8 +231,8 @@
         } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT &&
                 profile.isVerticalBarLayout()) {
             matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout,
-                    false /* hotseat horizontal */, hotseat.getAllAppsButtonRank(),
-                    iconRank == hotseat.getAllAppsButtonRank() /* include all apps icon */);
+                    false /* hotseat horizontal */, profile.inv.hotseatAllAppsRank,
+                    iconRank == profile.inv.hotseatAllAppsRank /* include all apps icon */);
             iconIndex += iconParent.getChildCount();
             countX = iconLayout.getCountX() + hotseatLayout.getCountX();
             countY = iconLayout.getCountY();
@@ -316,13 +316,13 @@
         // with the hotseat.
         if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && !profile.isVerticalBarLayout()) {
             matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, true /* horizontal */,
-                    hotseat.getAllAppsButtonRank(),
+                    profile.inv.hotseatAllAppsRank,
                     !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */);
             countY = countY + 1;
         } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
                 profile.isVerticalBarLayout()) {
             matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, false /* horizontal */,
-                    hotseat.getAllAppsButtonRank(),
+                    profile.inv.hotseatAllAppsRank,
                     !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */);
             countX = countX + 1;
         } else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index fcfb717..94f8fc8 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -29,6 +29,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Build;
+import android.os.Bundle;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
@@ -66,7 +67,8 @@
  */
 public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
         View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
-        View.OnFocusChangeListener, DragListener, UninstallSource, AccessibilityDragSource {
+        View.OnFocusChangeListener, DragListener, UninstallSource, AccessibilityDragSource,
+        Stats.LaunchSourceProvider {
     private static final String TAG = "Launcher.Folder";
 
     /**
@@ -923,7 +925,7 @@
             View v = list.get(i);
             ItemInfo info = (ItemInfo) v.getTag();
             LauncherModel.addItemToDatabase(mLauncher, info, mInfo.id, 0,
-                        info.cellX, info.cellY);
+                    info.cellX, info.cellY);
         }
     }
 
@@ -1338,6 +1340,14 @@
         outRect.right += mScrollAreaOffset;
     }
 
+    @Override
+    public void fillInLaunchSourceData(Bundle sourceData) {
+        // Fill in from the folder icon's launch source provider first
+        Stats.LaunchSourceUtils.populateSourceDataFromAncestorProvider(mFolderIcon, sourceData);
+        sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER, Stats.SUB_CONTAINER_FOLDER);
+        sourceData.putInt(Stats.SOURCE_EXTRA_SUB_CONTAINER_PAGE, mContent.getCurrentPage());
+    }
+
     private class OnScrollHintListener implements OnAlarmListener {
 
         private final DragObject mDragObject;
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index 8652eef..8d534d2 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -57,6 +57,7 @@
     @Thunk static boolean sStaticValuesDirty = true;
 
     private CheckLongPressHelper mLongPressHelper;
+    private StylusEventHelper mStylusEventHelper;
 
     // The number of icons to display in the
     public static final int NUM_ITEMS_IN_PREVIEW = 3;
@@ -128,6 +129,7 @@
 
     private void init() {
         mLongPressHelper = new CheckLongPressHelper(this);
+        mStylusEventHelper = new StylusEventHelper(this);
         setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
     }
 
@@ -220,8 +222,8 @@
                 DeviceProfile grid = launcher.getDeviceProfile();
                 sPreviewSize = grid.folderIconSizePx;
                 sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
-                sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo);
-                sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_nolip_holo);
+                sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer);
+                sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_nolip);
                 sSharedFolderLeaveBehind = res.getDrawable(R.drawable.portal_ring_rest);
                 sStaticValuesDirty = false;
             }
@@ -643,9 +645,10 @@
             final Runnable onCompleteRunnable) {
         final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
 
-        final float scale0 = 1.0f;
-        final float transX0 = (mAvailableSpaceInPreview - d.getIntrinsicWidth()) / 2;
-        final float transY0 = (mAvailableSpaceInPreview - d.getIntrinsicHeight()) / 2 + getPaddingTop();
+        float iconSize = mLauncher.getDeviceProfile().iconSizePx;
+        final float scale0 = iconSize / d.getIntrinsicWidth() ;
+        final float transX0 = (mAvailableSpaceInPreview - iconSize) / 2;
+        final float transY0 = (mAvailableSpaceInPreview - iconSize) / 2 + getPaddingTop();
         mAnimParams.drawable = d;
 
         ValueAnimator va = LauncherAnimUtils.ofFloat(this, 0f, 1.0f);
@@ -719,6 +722,12 @@
         // isPressed() on an ACTION_UP
         boolean result = super.onTouchEvent(event);
 
+        // Check for a stylus button press, if it occurs cancel any long press checks.
+        if (mStylusEventHelper.checkAndPerformStylusEvent(event)) {
+            mLongPressHelper.cancelLongPress();
+            return true;
+        }
+
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 mLongPressHelper.postCheckForLongPress();
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 7d90ba2..b7a5aa8 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -87,8 +87,8 @@
         LauncherAppState app = LauncherAppState.getInstance();
 
         InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
-        mMaxCountX = (int) profile.numFolderColumns;
-        mMaxCountY = (int) profile.numFolderRows;
+        mMaxCountX = profile.numFolderColumns;
+        mMaxCountY = profile.numFolderRows;
 
         mMaxItemsPerPage = mMaxCountX * mMaxCountY;
 
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index ce33164..ff4c93a 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -19,15 +19,16 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
-public class Hotseat extends FrameLayout {
+public class Hotseat extends FrameLayout
+        implements Stats.LaunchSourceProvider{
 
     private CellLayout mContent;
 
@@ -35,8 +36,7 @@
 
     private int mAllAppsButtonRank;
 
-    private boolean mTransposeLayoutWithOrientation;
-    private boolean mIsLandscape;
+    private final boolean mHasVerticalHotseat;
 
     public Hotseat(Context context) {
         this(context, null);
@@ -48,13 +48,8 @@
 
     public Hotseat(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-
-        Resources r = context.getResources();
-        mTransposeLayoutWithOrientation = 
-                r.getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
-        mIsLandscape = context.getResources().getConfiguration().orientation ==
-            Configuration.ORIENTATION_LANDSCAPE;
         mLauncher = (Launcher) context;
+        mHasVerticalHotseat = mLauncher.getDeviceProfile().isVerticalBarLayout();
     }
 
     CellLayout getLayout() {
@@ -76,26 +71,18 @@
         mContent.setOnLongClickListener(l);
     }
   
-    private boolean hasVerticalHotseat() {
-        return (mIsLandscape && mTransposeLayoutWithOrientation);
-    }
-
     /* Get the orientation invariant order of the item in the hotseat for persistence. */
     int getOrderInHotseat(int x, int y) {
-        return hasVerticalHotseat() ? (mContent.getCountY() - y - 1) : x;
+        return mHasVerticalHotseat ? (mContent.getCountY() - y - 1) : x;
     }
 
     /* Get the orientation specific coordinates given an invariant order in the hotseat. */
     int getCellXFromOrder(int rank) {
-        return hasVerticalHotseat() ? 0 : rank;
+        return mHasVerticalHotseat ? 0 : rank;
     }
 
     int getCellYFromOrder(int rank) {
-        return hasVerticalHotseat() ? (mContent.getCountY() - (rank + 1)) : 0;
-    }
-
-    public int getAllAppsButtonRank() {
-        return mAllAppsButtonRank;
+        return mHasVerticalHotseat ? (mContent.getCountY() - (rank + 1)) : 0;
     }
 
     public boolean isAllAppsButtonRank(int rank) {
@@ -130,7 +117,7 @@
                 inflater.inflate(R.layout.all_apps_button, mContent, false);
         Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);
 
-        Utilities.resizeIconDrawable(d);
+        mLauncher.resizeIconDrawable(d);
         allAppsButton.setCompoundDrawables(null, d, null, null);
 
         allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
@@ -160,4 +147,9 @@
         }
         return false;
     }
+
+    @Override
+    public void fillInLaunchSourceData(Bundle sourceData) {
+        sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOTSEAT);
+    }
 }
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index a16067d..3165337 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3;
 
-import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.ContentValues;
 import android.content.Context;
@@ -93,14 +92,11 @@
     @Thunk final Handler mWorkerHandler;
 
     public IconCache(Context context, InvariantDeviceProfile inv) {
-        ActivityManager activityManager =
-                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-
         mContext = context;
         mPackageManager = context.getPackageManager();
         mUserManager = UserManagerCompat.getInstance(mContext);
         mLauncherApps = LauncherAppsCompat.getInstance(mContext);
-        mIconDpi = activityManager.getLauncherLargeIconDensity();
+        mIconDpi = inv.fillResIconDpi;
         mIconDb = new IconDB(context);
 
         mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
@@ -136,10 +132,6 @@
         return getFullResDefaultActivityIcon();
     }
 
-    public int getFullResIconDpi() {
-        return mIconDpi;
-    }
-
     public Drawable getFullResIcon(ActivityInfo info) {
         Resources resources;
         try {
@@ -283,6 +275,7 @@
             ComponentName component = ComponentName.unflattenFromString(cn);
             PackageInfo info = pkgInfoMap.get(component.getPackageName());
             if (info == null) {
+                remove(component, user);
                 itemsToRemove.add(c.getInt(rowIndex));
                 continue;
             }
@@ -299,6 +292,7 @@
                 continue;
             }
             if (app == null) {
+                remove(component, user);
                 itemsToRemove.add(c.getInt(rowIndex));
             } else {
                 appsToUpdate.add(app);
@@ -570,9 +564,10 @@
      */
     private CacheEntry getEntryForPackageLocked(String packageName, UserHandleCompat user,
             boolean useLowResIcon) {
-        ComponentName cn = new ComponentName(packageName, EMPTY_CLASS_NAME);
+        ComponentName cn = new ComponentName(packageName, packageName + EMPTY_CLASS_NAME);
         ComponentKey cacheKey = new ComponentKey(cn, user);
         CacheEntry entry = mCache.get(cacheKey);
+
         if (entry == null || (entry.isLowResIcon && !useLowResIcon)) {
             entry = new CacheEntry();
             boolean entryUpdated = true;
@@ -744,7 +739,7 @@
     }
 
     private static final class IconDB extends SQLiteOpenHelper {
-        private final static int DB_VERSION = 4;
+        private final static int DB_VERSION = 5;
 
         private final static String TABLE_NAME = "icons";
         private final static String COLUMN_ROWID = "rowid";
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index 0f139fa..0ede2fc 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -41,7 +41,7 @@
         // Get the hover color
         mHoverColor = getResources().getColor(R.color.info_target_hover_tint);
 
-        setDrawable(R.drawable.ic_launcher_info_normal);
+        setDrawable(R.drawable.ic_info_launcher);
     }
 
     public static void startDetailsActivityForInfo(Object info, Launcher launcher) {
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 7f34593..ae204c4 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -35,6 +35,8 @@
     // This is a static that we use for the default icon size on a 4/5-inch phone
     private static float DEFAULT_ICON_SIZE_DP = 60;
 
+    private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
+
     // Constants that affects the interpolation curve between statically defined device profile
     // buckets.
     private static float KNEARESTNEIGHBOR = 3;
@@ -55,11 +57,18 @@
     public int numColumns;
 
     /**
+     * The minimum number of predicted apps in all apps.
+     */
+    int minAllAppsPredictionColumns;
+
+    /**
      * Number of icons per row and column in the folder.
      */
     public int numFolderRows;
     public int numFolderColumns;
     float iconSize;
+    int iconBitmapSize;
+    int fillResIconDpi;
     float iconTextSize;
 
     /**
@@ -80,11 +89,12 @@
 
     public InvariantDeviceProfile(InvariantDeviceProfile p) {
         this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns,
-                p.numFolderRows, p.numFolderColumns, p.iconSize, p.iconTextSize, p.numHotseatIcons,
-                p.hotseatIconSize, p.defaultLayoutId);
+                p.numFolderRows, p.numFolderColumns, p.minAllAppsPredictionColumns,
+                p.iconSize, p.iconTextSize, p.numHotseatIcons, p.hotseatIconSize,
+                p.defaultLayoutId);
     }
 
-    InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc,
+    InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, int maapc,
             float is, float its, float hs, float his, int dlId) {
         // Ensure that we have an odd number of hotseat items (since we need to place all apps)
         if (hs % 2 == 0) {
@@ -98,6 +108,7 @@
         numColumns = c;
         numFolderRows = fr;
         numFolderColumns = fc;
+        minAllAppsPredictionColumns = maapc;
         iconSize = is;
         iconTextSize = its;
         numHotseatIcons = hs;
@@ -133,10 +144,13 @@
         defaultLayoutId = closestProfile.defaultLayoutId;
         numFolderRows = closestProfile.numFolderRows;
         numFolderColumns = closestProfile.numFolderColumns;
+        minAllAppsPredictionColumns = closestProfile.minAllAppsPredictionColumns;
 
         iconSize = interpolatedDeviceProfileOut.iconSize;
+        iconBitmapSize = Utilities.pxFromDp(iconSize, dm);
         iconTextSize = interpolatedDeviceProfileOut.iconTextSize;
         hotseatIconSize = interpolatedDeviceProfileOut.hotseatIconSize;
+        fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
 
         // If the partner customization apk contains any grid overrides, apply them
         // Supported overrides: numRows, numColumns, iconSize
@@ -160,33 +174,56 @@
         // width, height, #rows, #columns, #folder rows, #folder columns,
         // iconSize, iconTextSize, #hotseat, #hotseatIconSize, defaultLayoutId.
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Super Short Stubby",
-                255, 300,     2, 3, 2, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
+                255, 300,     2, 3, 2, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Shorter Stubby",
-                255, 400,     3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
+                255, 400,     3, 3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Short Stubby",
-                275, 420,     3, 4, 3, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
+                275, 420,     3, 4, 3, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Stubby",
-                255, 450,     3, 4, 3, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
+                255, 450,     3, 4, 3, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus S",
-                296, 491.33f, 4, 4, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
+                296, 491.33f, 4, 4, 4, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 4",
-                335, 567,     4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
+                335, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 5",
-                359, 567,     4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
+                359, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Large Phone",
-                406, 694,     5, 5, 4, 4,  64, 14.4f,  5, 56, R.xml.default_workspace_5x5));
+                406, 694,     5, 5, 4, 4, 4, 64, 14.4f,  5, 56, R.xml.default_workspace_5x5));
         // The tablet profile is odd in that the landscape orientation
         // also includes the nav bar on the side
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 7",
-                575, 904,     5, 6, 4, 5, 72, 14.4f,  7, 60, R.xml.default_workspace_5x6));
+                575, 904,     5, 6, 4, 5, 4, 72, 14.4f,  7, 60, R.xml.default_workspace_5x6));
         // Larger tablet profiles always have system bars on the top & bottom
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 10",
-                727, 1207,    5, 6, 4, 5, 76, 14.4f,  7, 64, R.xml.default_workspace_5x6));
+                727, 1207,    5, 6, 4, 5, 4, 76, 14.4f,  7, 64, R.xml.default_workspace_5x6));
         predefinedDeviceProfiles.add(new InvariantDeviceProfile("20-inch Tablet",
-                1527, 2527,   7, 7, 6, 6, 100, 20,  7, 72, R.xml.default_workspace_4x4));
+                1527, 2527,   7, 7, 6, 6, 4, 100, 20,  7, 72, R.xml.default_workspace_4x4));
         return predefinedDeviceProfiles;
     }
 
+    private int getLauncherIconDensity(int requiredSize) {
+        // Densities typically defined by an app.
+        int[] densityBuckets = new int[] {
+                DisplayMetrics.DENSITY_LOW,
+                DisplayMetrics.DENSITY_MEDIUM,
+                DisplayMetrics.DENSITY_TV,
+                DisplayMetrics.DENSITY_HIGH,
+                DisplayMetrics.DENSITY_XHIGH,
+                DisplayMetrics.DENSITY_XXHIGH,
+                DisplayMetrics.DENSITY_XXXHIGH
+        };
+
+        int density = DisplayMetrics.DENSITY_XXXHIGH;
+        for (int i = densityBuckets.length - 1; i >= 0; i--) {
+            float expectedSize = ICON_SIZE_DEFINED_IN_APP_DP * densityBuckets[i]
+                    / DisplayMetrics.DENSITY_DEFAULT;
+            if (expectedSize >= requiredSize) {
+                density = densityBuckets[i];
+            }
+        }
+
+        return density;
+    }
 
     /**
      * Apply any Partner customization grid overrides.
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 9756727..54aa8de 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -403,22 +403,34 @@
     FocusIndicatorView mFocusHandler;
 
     @Thunk boolean mRotationEnabled = false;
-    private boolean mPreferenceObserverRegistered = false;
+    private boolean mScreenOrientationSettingReceiverRegistered = false;
 
-    final private SharedPreferences.OnSharedPreferenceChangeListener mSettingsObserver =
-            new SharedPreferences.OnSharedPreferenceChangeListener() {
-        @Override
-        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
-            if (Utilities.ALLOW_ROTATION_PREFERENCE_KEY.equals(key)) {
-                if (mRotationEnabled = sharedPreferences.getBoolean(
-                        Utilities.ALLOW_ROTATION_PREFERENCE_KEY, false)) {
-                    unlockScreenOrientation(true);
-                } else {
-                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
+    final private BroadcastReceiver mScreenOrientationSettingReceiver =
+            new BroadcastReceiver() {
+                @Thunk Runnable mUpdateOrientationRunnable = new Runnable() {
+                    public void run() {
+                        setOrientation();
+                    }
+                };
+
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    mRotationEnabled = intent.getBooleanExtra(
+                            Utilities.SCREEN_ROTATION_SETTING_EXTRA, false);
+                    if (!waitUntilResume(mUpdateOrientationRunnable, true)) {
+                        setOrientation();
+                    }
                 }
-            }
+            };
+
+    @Thunk void setOrientation() {
+        if (mRotationEnabled) {
+            unlockScreenOrientation(true);
+        } else {
+            setRequestedOrientation(
+                    ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
         }
-    };
+    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -453,9 +465,6 @@
                         app.getInvariantDeviceProfile().landscapeProfile
                             : app.getInvariantDeviceProfile().portraitProfile;
 
-        // TODO: Move this to icon cache.
-        Utilities.setIconSize(mDeviceProfile.iconSizePx);
-
         // the LauncherApplication should call this, but in case of Instrumentation it might not be present yet
         mSharedPrefs = getSharedPreferences(LauncherAppState.getSharedPreferencesKey(),
                 Context.MODE_PRIVATE);
@@ -523,16 +532,18 @@
         // In case we are on a device with locked rotation, we should look at preferences to check
         // if the user has specifically allowed rotation.
         if (!mRotationEnabled) {
-            getSharedPreferences(LauncherFiles.ROTATION_PREF_FILE,
-                    Context.MODE_MULTI_PROCESS).registerOnSharedPreferenceChangeListener(
-                    mSettingsObserver);
-            mPreferenceObserverRegistered = true;
+            String updateOrientationBroadcastPermission = getResources().getString(
+                    R.string.receive_update_orientation_broadcasts_permission);
+            registerReceiver(mScreenOrientationSettingReceiver,
+                    new IntentFilter(Utilities.SCREEN_ROTATION_SETTING_INTENT),
+                    updateOrientationBroadcastPermission, null);
+            mScreenOrientationSettingReceiverRegistered = true;
             mRotationEnabled = Utilities.isAllowRotationPrefEnabled(getApplicationContext());
         }
 
         // On large interfaces, or on devices that a user has specifically enabled screen rotation,
         // we want the screen to auto-rotate based on the current orientation
-        unlockScreenOrientation(true);
+        setOrientation();
 
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onCreate(savedInstanceState);
@@ -1531,7 +1542,6 @@
      * Add a shortcut to the workspace.
      *
      * @param data The intent describing the shortcut.
-     * @param cellInfo The position on screen where to create the shortcut.
      */
     private void completeAddShortcut(Intent data, long container, long screenId, int cellX,
             int cellY) {
@@ -1800,16 +1810,17 @@
         }
     }
 
-    private final Handler mHandler = new Handler() {
+    @Thunk final Handler mHandler = new Handler(new Handler.Callback() {
+
         @Override
-        public void handleMessage(Message msg) {
+        public boolean handleMessage(Message msg) {
             if (msg.what == ADVANCE_MSG) {
                 int i = 0;
                 for (View key: mWidgetsToAdvance.keySet()) {
                     final View v = key.findViewById(mWidgetsToAdvance.get(key).autoAdvanceViewId);
                     final int delay = mAdvanceStagger * i;
                     if (v instanceof Advanceable) {
-                       postDelayed(new Runnable() {
+                        mHandler.postDelayed(new Runnable() {
                            public void run() {
                                ((Advanceable) v).advance();
                            }
@@ -1819,8 +1830,9 @@
                 }
                 sendAdvanceMessage(mAdvanceInterval);
             }
+            return true;
         }
-    };
+    });
 
     void addWidgetToAutoAdvanceIfNeeded(View hostView, AppWidgetProviderInfo appWidgetInfo) {
         if (appWidgetInfo == null || appWidgetInfo.autoAdvanceViewId == -1) return;
@@ -2020,11 +2032,9 @@
     public void onDestroy() {
         super.onDestroy();
 
-        if (mPreferenceObserverRegistered) {
-            getSharedPreferences(LauncherFiles.ROTATION_PREF_FILE,
-                    Context.MODE_MULTI_PROCESS).unregisterOnSharedPreferenceChangeListener(
-                    mSettingsObserver);
-            mPreferenceObserverRegistered = false;
+        if (mScreenOrientationSettingReceiverRegistered) {
+            unregisterReceiver(mScreenOrientationSettingReceiver);
+            mScreenOrientationSettingReceiverRegistered = false;
         }
 
         // Remove all pending runnables
@@ -2337,7 +2347,7 @@
 
         Intent createShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
         createShortcutIntent.setComponent(componentName);
-        processShortcut(createShortcutIntent);
+        Utilities.startActivityForResultSafely(this, createShortcutIntent, REQUEST_CREATE_SHORTCUT);
     }
 
     /**
@@ -2397,14 +2407,6 @@
         }
     }
 
-    void processShortcut(Intent intent) {
-        Utilities.startActivityForResultSafely(this, intent, REQUEST_CREATE_SHORTCUT);
-    }
-
-    void processWallpaper(Intent intent) {
-        startActivityForResult(intent, REQUEST_PICK_WALLPAPER);
-    }
-
     FolderIcon addFolder(CellLayout layout, long container, final long screenId, int cellX,
             int cellY) {
         final FolderInfo folderInfo = new FolderInfo();
@@ -2552,13 +2554,6 @@
         }
     }
 
-    public void onClickPagedViewIcon(View v) {
-        startAppShortcutOrInfoActivity(v);
-        if (mLauncherCallbacks != null) {
-            mLauncherCallbacks.onClickPagedViewIcon(v);
-        }
-    }
-
     @SuppressLint("ClickableViewAccessibility")
     public boolean onTouch(View v, MotionEvent event) {
         return false;
@@ -2717,7 +2712,7 @@
         }
 
         boolean success = startActivitySafely(v, intent, tag);
-        mStats.recordLaunch(intent, shortcut);
+        mStats.recordLaunch(v, intent, shortcut);
 
         if (success && v instanceof BubbleTextView) {
             mWaitingForResume = (BubbleTextView) v;
@@ -2813,20 +2808,10 @@
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onClickSettingsButton(v);
         } else {
-            showSettingsActivity();
+            startActivity(new Intent(this, SettingsActivity.class));
         }
     }
 
-    public void onTouchDownAllAppsButton(View v) {
-        // Provide the same haptic feedback that the system offers for virtual keys.
-        v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
-    }
-
-    public void performHapticFeedbackOnTouchDown(View v) {
-        // Provide the same haptic feedback that the system offers for virtual keys.
-        v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
-    }
-
     public View.OnTouchListener getHapticFeedbackTouchListener() {
         if (mHapticFeedbackTouchListener == null) {
             mHapticFeedbackTouchListener = new View.OnTouchListener() {
@@ -2939,7 +2924,7 @@
         }
     }
 
-    boolean startActivity(View v, Intent intent, Object tag) {
+    private boolean startActivity(View v, Intent intent, Object tag) {
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         try {
             // Only launch using the new animation if the shortcut has not opted out (this is a
@@ -3010,7 +2995,7 @@
         return false;
     }
 
-    boolean startActivitySafely(View v, Intent intent, Object tag) {
+    private boolean startActivitySafely(View v, Intent intent, Object tag) {
         boolean success = false;
         if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
             Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
@@ -3677,7 +3662,7 @@
      *
      * @return {@code true} if we are currently paused. The caller might be able to skip some work
      */
-    private boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
+    @Thunk boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
         if (mPaused) {
             if (LOGD) Log.d(TAG, "Deferring update until onResume");
             if (deletePreviousRunnables) {
@@ -3776,10 +3761,6 @@
 
     @Override
     public void bindAddScreens(ArrayList<Long> orderedScreenIds) {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - bindAddScreens()", true);
-        Launcher.addDumpLog(TAG, "11683562 -   orderedScreenIds: " +
-                TextUtils.join(", ", orderedScreenIds), true);
         int count = orderedScreenIds.size();
         for (int i = 0; i < count; i++) {
             mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(orderedScreenIds.get(i));
@@ -4537,10 +4518,6 @@
         editor.apply();
     }
 
-    private void showSettingsActivity() {
-        startActivity(new Intent(this, SettingsActivity.class));
-    }
-
     /**
      * To be overridden by subclasses to indicate that there is an in-activity full-screen intro
      * screen that must be displayed and dismissed.
@@ -4685,6 +4662,23 @@
     }
 
     /**
+     * Returns a FastBitmapDrawable with the icon, accurately sized.
+     */
+    public FastBitmapDrawable createIconDrawable(Bitmap icon) {
+        FastBitmapDrawable d = new FastBitmapDrawable(icon);
+        d.setFilterBitmap(true);
+        resizeIconDrawable(d);
+        return d;
+    }
+
+    /**
+     * Resizes an icon drawable to the correct icon size.
+     */
+    public void resizeIconDrawable(Drawable icon) {
+        icon.setBounds(0, 0, mDeviceProfile.iconSizePx, mDeviceProfile.iconSizePx);
+    }
+
+    /**
      * Prints out out state for debugging.
      */
     public void dumpState() {
diff --git a/src/com/android/launcher3/LauncherAnimatorUpdateListener.java b/src/com/android/launcher3/LauncherAnimatorUpdateListener.java
deleted file mode 100644
index ec9fd4d..0000000
--- a/src/com/android/launcher3/LauncherAnimatorUpdateListener.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-
-abstract class LauncherAnimatorUpdateListener implements AnimatorUpdateListener {
-    public void onAnimationUpdate(ValueAnimator animation) {
-        final float b = (Float) animation.getAnimatedValue();
-        final float a = 1f - b;
-        onAnimationUpdate(a, b);
-    }
-
-    abstract void onAnimationUpdate(float a, float b);
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index d4b41e6..81d595a 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -25,6 +25,7 @@
 import android.content.res.Resources;
 import android.util.Log;
 
+import android.view.ViewConfiguration;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.PackageInstallerCompat;
@@ -40,10 +41,6 @@
     private final IconCache mIconCache;
     private final WidgetPreviewLoader mWidgetCache;
 
-    private final boolean mIsScreenLarge;
-    private final float mScreenDensity;
-    private final int mLongPressTimeout = 300;
-
     private boolean mWallpaperChangedSinceLastCheck;
 
     private static WeakReference<LauncherProvider> sLauncherProvider;
@@ -87,9 +84,6 @@
             MemoryTracker.startTrackingMe(sContext, "L");
         }
 
-        // set sIsScreenXLarge and mScreenDensity *before* creating icon cache
-        mIsScreenLarge = isScreenLarge(sContext.getResources());
-        mScreenDensity = sContext.getResources().getDisplayMetrics().density;
         mInvariantDeviceProfile = new InvariantDeviceProfile(sContext);
         mIconCache = new IconCache(sContext, mInvariantDeviceProfile);
         mWidgetCache = new WidgetPreviewLoader(sContext, mInvariantDeviceProfile, mIconCache);
@@ -151,6 +145,9 @@
         return mModel;
     }
 
+    /**
+     * TODO(winsonc, hyunyoungs): We need to respect this
+     */
     boolean shouldShowAppOrWidgetProvider(ComponentName componentName) {
         return mAppFilter == null || mAppFilter.shouldShowApp(componentName);
     }
@@ -170,29 +167,7 @@
     public WidgetPreviewLoader getWidgetCache() {
         return mWidgetCache;
     }
-
-    public boolean isScreenLarge() {
-        return mIsScreenLarge;
-    }
-
-    // Need a version that doesn't require an instance of LauncherAppState for the wallpaper picker
-    public static boolean isScreenLarge(Resources res) {
-        return res.getBoolean(R.bool.is_large_tablet);
-    }
-
-    public static boolean isScreenLandscape(Context context) {
-        return context.getResources().getConfiguration().orientation ==
-            Configuration.ORIENTATION_LANDSCAPE;
-    }
-
-    public float getScreenDensity() {
-        return mScreenDensity;
-    }
-
-    public int getLongPressTimeout() {
-        return mLongPressTimeout;
-    }
-
+    
     public void onWallpaperChanged() {
         mWallpaperChangedSinceLastCheck = true;
     }
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index 71fb2d2..cf461a5 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -36,6 +36,7 @@
     LayoutInflater mInflater;
 
     private CheckLongPressHelper mLongPressHelper;
+    private StylusEventHelper mStylusEventHelper;
     private Context mContext;
     private int mPreviousOrientation;
     private DragLayer mDragLayer;
@@ -46,6 +47,7 @@
         super(context);
         mContext = context;
         mLongPressHelper = new CheckLongPressHelper(this);
+        mStylusEventHelper = new StylusEventHelper(this);
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mDragLayer = ((Launcher) context).getDragLayer();
         setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
@@ -89,11 +91,17 @@
             return true;
         }
 
-        // Watch for longpress events at this level to make sure
-        // users can always pick up this widget
+        // Watch for longpress or stylus button press events at this level to
+        // make sure users can always pick up this widget
+        if (mStylusEventHelper.checkAndPerformStylusEvent(ev)) {
+            mLongPressHelper.cancelLongPress();
+            return true;
+        }
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN: {
-                mLongPressHelper.postCheckForLongPress();
+                if (!mStylusEventHelper.inStylusButtonPressed()) {
+                    mLongPressHelper.postCheckForLongPress();
+                }
                 mDragLayer.setTouchCompleteListener(this);
                 break;
             }
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index 7ca4fe3..85af92f 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -67,7 +67,8 @@
         if (isCustomWidget) {
             return cache.getFullResIcon(provider.getPackageName(), icon);
         }
-        return super.loadIcon(context, cache.getFullResIconDpi());
+        return super.loadIcon(context,
+                LauncherAppState.getInstance().getInvariantDeviceProfile().fillResIconDpi);
     }
 
     public String toString(PackageManager pm) {
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index a5f36ba..70e400b 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -56,6 +56,8 @@
     public void bindAllApplications(ArrayList<AppInfo> apps);
     public void onClickFolderIcon(View v);
     public void onClickAppShortcut(View v);
+
+    @Deprecated
     public void onClickPagedViewIcon(View v);
     public void onClickWallpaperPicker(View v);
     public void onClickSettingsButton(View v);
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 776c2bd..10b8648 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -1140,10 +1140,6 @@
      * a list of screen ids in the order that they should appear.
      */
     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);
-        Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);
-
         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);
         final ContentResolver cr = context.getContentResolver();
         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
@@ -1764,9 +1760,6 @@
         }
 
         private void loadWorkspace() {
-            // Log to disk
-            Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);
-
             final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
 
             final Context context = mContext;
@@ -2932,6 +2925,9 @@
                 }
             });
         }
+
+        // Reload widget list. No need to refresh, as we only want to update the icons and labels.
+        loadAndBindWidgetsAndShortcuts(mApp.getContext(), callbacks, false);
     }
 
     void enqueuePackageUpdated(PackageUpdatedTask task) {
@@ -3114,8 +3110,9 @@
                             // Update shortcuts which use iconResource.
                             if ((si.iconResource != null)
                                     && packageSet.contains(si.iconResource.packageName)) {
-                                Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName,
-                                        si.iconResource.resourceName, mIconCache, context);
+                                Bitmap icon = Utilities.createIconBitmap(
+                                        si.iconResource.packageName,
+                                        si.iconResource.resourceName, context);
                                 if (icon != null) {
                                     si.setIcon(icon);
                                     si.usingFallbackIcon = false;
@@ -3558,7 +3555,7 @@
             String resourceName = c.getString(iconResourceIndex);
             info.customIcon = false;
             // the resource
-            icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);
+            icon = Utilities.createIconBitmap(packageName, resourceName, context);
             // the db
             if (icon == null) {
                 icon = Utilities.createIconBitmap(c, iconIndex, context);
@@ -3612,7 +3609,7 @@
             if (extra instanceof ShortcutIconResource) {
                 iconResource = (ShortcutIconResource) extra;
                 icon = Utilities.createIconBitmap(iconResource.packageName,
-                        iconResource.resourceName, mIconCache, context);
+                        iconResource.resourceName, context);
             }
         }
 
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 45070d1..b590126 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -868,8 +868,6 @@
                 throw new RuntimeException("Error: max screen id was not initialized");
             }
             mMaxScreenId += 1;
-            // Log to disk
-            Launcher.addDumpLog(TAG, "11683562 - generateNewScreenId(): " + mMaxScreenId, true);
             return mMaxScreenId;
         }
 
diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java
index c8b27ef..08f8e56 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/PendingAppWidgetHostView.java
@@ -121,7 +121,7 @@
             //   2) Preload icon in the center
             //   3) Setup icon in the center and app icon in the top right corner.
             if (mDisabledForSafeMode) {
-                FastBitmapDrawable disabledIcon = Utilities.createIconDrawable(mIcon);
+                FastBitmapDrawable disabledIcon = mLauncher.createIconDrawable(mIcon);
                 disabledIcon.setGhostModeEnabled(true);
                 mCenterDrawable = disabledIcon;
                 mTopCornerDrawable = null;
@@ -134,7 +134,7 @@
                     sPreloaderTheme.applyStyle(R.style.PreloadIcon, true);
                 }
 
-                FastBitmapDrawable drawable = Utilities.createIconDrawable(mIcon);
+                FastBitmapDrawable drawable = mLauncher.createIconDrawable(mIcon);
                 mCenterDrawable = new PreloadIconDrawable(drawable, sPreloaderTheme);
                 mCenterDrawable.setCallback(this);
                 mTopCornerDrawable = null;
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index a1da1b6..27763f5 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -18,12 +18,14 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
+import android.preference.Preference;
 import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
 
 /**
- * Settings activity for Launcher. Currently implements the following setting:
- * LockToPortrait
+ * Settings activity for Launcher. Currently implements the following setting: Allow rotation
  */
 public class SettingsActivity extends Activity {
     @Override
@@ -41,13 +43,25 @@
      */
     @SuppressWarnings("WeakerAccess")
     public static class LauncherSettingsFragment extends PreferenceFragment {
-
         @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
-            getPreferenceManager().setSharedPreferencesMode(Context.MODE_PRIVATE);
+            getPreferenceManager().setSharedPreferencesMode(Context.MODE_MULTI_PROCESS);
             getPreferenceManager().setSharedPreferencesName(LauncherFiles.ROTATION_PREF_FILE);
             addPreferencesFromResource(R.xml.launcher_preferences);
         }
+
+        @Override
+        public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
+                                             Preference preference) {
+            boolean allowRotation = getPreferenceManager().getSharedPreferences().getBoolean(
+                    Utilities.ALLOW_ROTATION_PREFERENCE_KEY, false);
+            Intent rotationSetting = new Intent(Utilities.SCREEN_ROTATION_SETTING_INTENT);
+            String launchBroadcastPermission = getResources().getString(
+                            R.string.receive_update_orientation_broadcasts_permission);
+            rotationSetting.putExtra(Utilities.SCREEN_ROTATION_SETTING_EXTRA, allowRotation);
+            getActivity().sendBroadcast(rotationSetting, launchBroadcastPermission);
+            return true;
+        }
     }
 }
diff --git a/src/com/android/launcher3/Stats.java b/src/com/android/launcher3/Stats.java
index 9d06f75..cb0e252 100644
--- a/src/com/android/launcher3/Stats.java
+++ b/src/com/android/launcher3/Stats.java
@@ -20,9 +20,63 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.Bundle;
 import android.util.Log;
+import android.view.View;
+import android.view.ViewParent;
 
 public class Stats {
+
+    /**
+     * Implemented by containers to provide a launch source for a given child.
+     */
+    public interface LaunchSourceProvider {
+        void fillInLaunchSourceData(Bundle sourceData);
+    }
+
+    /**
+     * Helpers to add the source to a launch intent.
+     */
+    public static class LaunchSourceUtils {
+        /**
+         * Create a default bundle for LaunchSourceProviders to fill in their data.
+         */
+        public static Bundle createSourceData() {
+            Bundle sourceData = new Bundle();
+            sourceData.putString(SOURCE_EXTRA_CONTAINER, CONTAINER_HOMESCREEN);
+            // Have default container/sub container pages
+            sourceData.putInt(SOURCE_EXTRA_CONTAINER_PAGE, 0);
+            sourceData.putInt(SOURCE_EXTRA_SUB_CONTAINER_PAGE, 0);
+            return sourceData;
+        }
+
+        /**
+         * Finds the next launch source provider in the parents of the view hierarchy and populates
+         * the source data from that provider.
+         */
+        public static void populateSourceDataFromAncestorProvider(View v, Bundle sourceData) {
+            if (v == null) {
+                return;
+            }
+
+            Stats.LaunchSourceProvider provider = null;
+            ViewParent parent = v.getParent();
+            while (parent != null && parent instanceof View) {
+                if (parent instanceof Stats.LaunchSourceProvider) {
+                    provider = (Stats.LaunchSourceProvider) parent;
+                    break;
+                }
+                parent = parent.getParent();
+            }
+
+            if (provider != null) {
+                provider.fillInLaunchSourceData(sourceData);
+            } else if (LauncherAppState.isDogfoodBuild()) {
+                throw new RuntimeException("Expected LaunchSourceProvider");
+            }
+        }
+    }
+
     private static final boolean DEBUG_BROADCASTS = false;
 
     public static final String ACTION_LAUNCH = "com.android.launcher3.action.LAUNCH";
@@ -31,6 +85,22 @@
     public static final String EXTRA_SCREEN = "screen";
     public static final String EXTRA_CELLX = "cellX";
     public static final String EXTRA_CELLY = "cellY";
+    public static final String EXTRA_SOURCE = "source";
+
+    public static final String SOURCE_EXTRA_CONTAINER = "container";
+    public static final String SOURCE_EXTRA_CONTAINER_PAGE = "container_page";
+    public static final String SOURCE_EXTRA_SUB_CONTAINER = "sub_container";
+    public static final String SOURCE_EXTRA_SUB_CONTAINER_PAGE = "sub_container_page";
+
+    public static final String CONTAINER_SEARCH_BOX = "search_box";
+    public static final String CONTAINER_ALL_APPS = "all_apps";
+    public static final String CONTAINER_HOMESCREEN = "homescreen"; // aka. Workspace
+    public static final String CONTAINER_HOTSEAT = "hotseat";
+
+    public static final String SUB_CONTAINER_FOLDER = "folder";
+    public static final String SUB_CONTAINER_ALL_APPS_A_Z = "a-z";
+    public static final String SUB_CONTAINER_ALL_APPS_PREDICTION = "prediction";
+    public static final String SUB_CONTAINER_ALL_APPS_SEARCH = "search";
 
     private final Launcher mLauncher;
     private final String mLaunchBroadcastPermission;
@@ -56,11 +126,7 @@
         }
     }
 
-    public void recordLaunch(Intent intent) {
-        recordLaunch(intent, null);
-    }
-
-    public void recordLaunch(Intent intent, ShortcutInfo shortcut) {
+    public void recordLaunch(View v, Intent intent, ShortcutInfo shortcut) {
         intent = new Intent(intent);
         intent.setSourceBounds(null);
 
@@ -72,6 +138,10 @@
                     .putExtra(EXTRA_CELLX, shortcut.cellX)
                     .putExtra(EXTRA_CELLY, shortcut.cellY);
         }
+
+        Bundle sourceExtras = LaunchSourceUtils.createSourceData();
+        LaunchSourceUtils.populateSourceDataFromAncestorProvider(v, sourceExtras);
+        broadcastIntent.putExtra(EXTRA_SOURCE, sourceExtras);
         mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission);
     }
 }
diff --git a/src/com/android/launcher3/StylusEventHelper.java b/src/com/android/launcher3/StylusEventHelper.java
new file mode 100644
index 0000000..da46e6a
--- /dev/null
+++ b/src/com/android/launcher3/StylusEventHelper.java
@@ -0,0 +1,84 @@
+package com.android.launcher3;
+
+import com.android.launcher3.Utilities;
+
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+/**
+ * Helper for identifying when a stylus touches a view while the primary stylus button is pressed.
+ * This can occur in {@value MotionEvent#ACTION_DOWN} or {@value MotionEvent#ACTION_MOVE}. On a
+ * stylus button press this performs the view's {@link View#performLongClick()} method, if the view
+ * is long clickable.
+ */
+public class StylusEventHelper {
+    private boolean mIsButtonPressed;
+    private View mView;
+
+    public StylusEventHelper(View view) {
+        mView = view;
+    }
+
+    /**
+     * Call this in onTouchEvent method of a view to identify a stylus button press and perform a
+     * long click (if the view is long clickable).
+     *
+     * @param event The event to check for a stylus button press.
+     * @return Whether a stylus event occurred and was handled.
+     */
+    public boolean checkAndPerformStylusEvent(MotionEvent event) {
+        final float slop = ViewConfiguration.get(mView.getContext()).getScaledTouchSlop();
+
+        if (!mView.isLongClickable()) {
+            // We don't do anything unless the view is long clickable.
+            return false;
+        }
+
+        final boolean stylusButtonPressed = isStylusButtonPressed(event);
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mIsButtonPressed = false;
+                if (stylusButtonPressed && mView.performLongClick()) {
+                    mIsButtonPressed = true;
+                    return true;
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (Utilities.pointInView(mView, event.getX(), event.getY(), slop)) {
+                    if (!mIsButtonPressed && stylusButtonPressed && mView.performLongClick()) {
+                        mIsButtonPressed = true;
+                        return true;
+                    } else if (mIsButtonPressed && !stylusButtonPressed) {
+                        mIsButtonPressed = false;
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mIsButtonPressed = false;
+                break;
+        }
+        return false;
+    }
+
+    /**
+     * Whether a stylus button press is occurring.
+     */
+    public boolean inStylusButtonPressed() {
+        return mIsButtonPressed;
+    }
+
+    /**
+     * Identifies if the provided {@link MotionEvent} is a stylus with the primary stylus button
+     * pressed.
+     *
+     * @param event The event to check.
+     * @return Whether a stylus button press occurred.
+     */
+    public static boolean isStylusButtonPressed(MotionEvent event) {
+        return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
+                && event.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 4199390..0819f8c 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -28,7 +28,7 @@
         // Get the hover color
         mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
 
-        setDrawable(R.drawable.ic_launcher_uninstall_normal);
+        setDrawable(R.drawable.ic_uninstall_launcher);
     }
 
     @Override
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index a9cbf69..0cd980c 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -54,7 +54,6 @@
 import android.util.TypedValue;
 import android.view.View;
 import android.widget.Toast;
-
 import junit.framework.Assert;
 
 import java.io.ByteArrayOutputStream;
@@ -71,9 +70,6 @@
 
     private static final String TAG = "Launcher.Utilities";
 
-    private static int sIconWidth = -1;
-    private static int sIconHeight = -1;
-
     private static final Rect sOldBounds = new Rect();
     private static final Canvas sCanvas = new Canvas();
 
@@ -87,32 +83,18 @@
     static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
     static int sColorIndex = 0;
 
-    static int[] sLoc0 = new int[2];
-    static int[] sLoc1 = new int[2];
+    private static final int[] sLoc0 = new int[2];
+    private static final int[] sLoc1 = new int[2];
 
     // To turn on these properties, type
     // adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS]
-    static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate";
-    public static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
+    private static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate";
+    private static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
 
     public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
-
-    /**
-     * Returns a FastBitmapDrawable with the icon, accurately sized.
-     */
-    public static FastBitmapDrawable createIconDrawable(Bitmap icon) {
-        FastBitmapDrawable d = new FastBitmapDrawable(icon);
-        d.setFilterBitmap(true);
-        resizeIconDrawable(d);
-        return d;
-    }
-
-    /**
-     * Resizes an icon drawable to the correct icon size.
-     */
-    static void resizeIconDrawable(Drawable icon) {
-        icon.setBounds(0, 0, sIconWidth, sIconHeight);
-    }
+    public static final String SCREEN_ROTATION_SETTING_INTENT =
+            "come.android.launcher3.SCREEN_ORIENTATION_PREF_CHANGED";
+    public static final String SCREEN_ROTATION_SETTING_EXTRA = "screenRotationPref";
 
     public static boolean isPropertyEnabled(String propertyName) {
         return Log.isLoggable(propertyName, Log.VERBOSE);
@@ -141,7 +123,7 @@
         return Build.VERSION.SDK_INT >= 22;
     }
 
-    static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
+    public static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
         byte[] data = c.getBlob(iconIndex);
         try {
             return createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length), context);
@@ -154,7 +136,7 @@
      * Returns a bitmap suitable for the all apps view. If the package or the resource do not
      * exist, it returns null.
      */
-    static Bitmap createIconBitmap(String packageName, String resourceName, IconCache cache,
+    public static Bitmap createIconBitmap(String packageName, String resourceName,
             Context context) {
         PackageManager packageManager = context.getPackageManager();
         // the resource
@@ -163,7 +145,8 @@
             if (resources != null) {
                 final int id = resources.getIdentifier(resourceName, null, null);
                 return createIconBitmap(
-                        resources.getDrawableForDensity(id, cache.getFullResIconDpi()), context);
+                        resources.getDrawableForDensity(id, LauncherAppState.getInstance()
+                                .getInvariantDeviceProfile().fillResIconDpi), context);
             }
         } catch (Exception e) {
             // Icon not found.
@@ -171,16 +154,16 @@
         return null;
     }
 
+    private static int getIconBitmapSize() {
+        return LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
+    }
+
     /**
      * Returns a bitmap which is of the appropriate size to be displayed as an icon
      */
-    static Bitmap createIconBitmap(Bitmap icon, Context context) {
-        synchronized (sCanvas) { // we share the statics :-(
-            if (sIconWidth == -1) {
-                initStatics(context);
-            }
-        }
-        if (sIconWidth == icon.getWidth() && sIconHeight == icon.getHeight()) {
+    public static Bitmap createIconBitmap(Bitmap icon, Context context) {
+        final int iconBitmapSize = getIconBitmapSize();
+        if (iconBitmapSize == icon.getWidth() && iconBitmapSize == icon.getHeight()) {
             return icon;
         }
         return createIconBitmap(new BitmapDrawable(context.getResources(), icon), context);
@@ -190,13 +173,11 @@
      * Returns a bitmap suitable for the all apps view.
      */
     public static Bitmap createIconBitmap(Drawable icon, Context context) {
-        synchronized (sCanvas) { // we share the statics :-(
-            if (sIconWidth == -1) {
-                initStatics(context);
-            }
+        synchronized (sCanvas) {
+            final int iconBitmapSize = getIconBitmapSize();
 
-            int width = sIconWidth;
-            int height = sIconHeight;
+            int width = iconBitmapSize;
+            int height = iconBitmapSize;
 
             if (icon instanceof PaintDrawable) {
                 PaintDrawable painter = (PaintDrawable) icon;
@@ -223,8 +204,8 @@
             }
 
             // no intrinsic size --> use default size
-            int textureWidth = sIconWidth;
-            int textureHeight = sIconHeight;
+            int textureWidth = iconBitmapSize;
+            int textureHeight = iconBitmapSize;
 
             final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
                     Bitmap.Config.ARGB_8888);
@@ -354,15 +335,6 @@
                 localY < (v.getHeight() + slop);
     }
 
-    private static void initStatics(Context context) {
-        final Resources resources = context.getResources();
-        sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
-    }
-
-    public static void setIconSize(int widthPx) {
-        sIconWidth = sIconHeight = widthPx;
-    }
-
     public static void scaleRect(Rect r, float scale) {
         if (scale != 1.0f) {
             r.left = (int) (r.left * scale + 0.5f);
@@ -655,6 +627,16 @@
         return m.replaceAll("$1");
     }
 
+    /**
+     * Calculates the height of a given string at a specific text size.
+     */
+    public static float calculateTextHeight(float textSizePx) {
+        Paint p = new Paint();
+        p.setTextSize(textSizePx);
+        Paint.FontMetrics fm = p.getFontMetrics();
+        return -fm.top + fm.bottom;
+    }
+
     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     public static boolean isRtl(Resources res) {
         return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) &&
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index a621771..cfeced2 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -586,26 +586,26 @@
         protected Bitmap doInBackground(Void... params) {
             Bitmap unusedBitmap = null;
 
+            // If already cancelled before this gets to run in the background, then return early
+            if (isCancelled()) {
+                return null;
+            }
             synchronized (mUnusedBitmaps) {
-                // If already cancelled before this gets to run in the background, then return early
-                if (isCancelled()) {
-                    return null;
-                }
-                // Check if we can use a bitmap
+                // Check if we can re-use a bitmap
                 for (Bitmap candidate : mUnusedBitmaps) {
                     if (candidate != null && candidate.isMutable() &&
                             candidate.getWidth() == mPreviewWidth &&
                             candidate.getHeight() == mPreviewHeight) {
                         unusedBitmap = candidate;
+                        mUnusedBitmaps.remove(unusedBitmap);
                         break;
                     }
                 }
+            }
 
-                if (unusedBitmap == null) {
-                    unusedBitmap = Bitmap.createBitmap(mPreviewWidth, mPreviewHeight, Config.ARGB_8888);
-                } else {
-                    mUnusedBitmaps.remove(unusedBitmap);
-                }
+            // creating a bitmap is expensive. Do not do this inside synchronized block.
+            if (unusedBitmap == null) {
+                unusedBitmap = Bitmap.createBitmap(mPreviewWidth, mPreviewHeight, Config.ARGB_8888);
             }
             // If cancelled now, don't bother reading the preview from the DB
             if (isCancelled()) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 6d5affb..19195b4 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -28,6 +28,7 @@
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -42,6 +43,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcelable;
@@ -86,7 +88,7 @@
 public class Workspace extends PagedView
         implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
         DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,
-        Insettable, UninstallSource, AccessibilityDragSource {
+        Insettable, UninstallSource, AccessibilityDragSource, Stats.LaunchSourceProvider {
     private static final String TAG = "Launcher.Workspace";
 
     private static boolean ENFORCE_DRAG_EVENT_ORDER = false;
@@ -1618,7 +1620,7 @@
         // We should only update the drag layer background alpha if we are not in all apps or the
         // widgets tray
         if (mState == State.NORMAL) {
-            mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f);
+            mLauncher.getDragLayer().setBackgroundAlpha(progress == 1 ? 0 : progress * 0.8f);
         }
 
         if (mLauncher.getHotseat() != null) {
@@ -3967,7 +3969,7 @@
     @Override
     public boolean onEnterScrollArea(int x, int y, int direction) {
         // Ignore the scroll area if we are dragging over the hot seat
-        boolean isPortrait = !LauncherAppState.isScreenLandscape(getContext());
+        boolean isPortrait = !mLauncher.getDeviceProfile().isLandscape;
         if (mLauncher.getHotseat() != null && isPortrait) {
             Rect r = new Rect();
             mLauncher.getHotseat().getHitRect(r);
@@ -4461,6 +4463,12 @@
         mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
     }
 
+    @Override
+    public void fillInLaunchSourceData(Bundle sourceData) {
+        sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOMESCREEN);
+        sourceData.putInt(Stats.SOURCE_EXTRA_CONTAINER_PAGE, getCurrentPage());
+    }
+
     /**
      * Used as a workaround to ensure that the AppWidgetService receives the
      * PACKAGE_ADDED broadcast before updating widgets.
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 340066d..e360e88 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.content.Context;
@@ -335,17 +336,11 @@
                     }
                     if (mOldBackgroundAlphas[i] != 0 ||
                             mNewBackgroundAlphas[i] != 0) {
-                        ValueAnimator bgAnim =
+                        ValueAnimator bgAnim = ObjectAnimator.ofFloat(cl, "backgroundAlpha",
+                                mOldBackgroundAlphas[i], mNewBackgroundAlphas[i]);
                                 LauncherAnimUtils.ofFloat(cl, 0f, 1f);
                         bgAnim.setInterpolator(mZoomInInterpolator);
                         bgAnim.setDuration(duration);
-                        bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
-                            public void onAnimationUpdate(float a, float b) {
-                                cl.setBackgroundAlpha(
-                                        a * mOldBackgroundAlphas[i] +
-                                                b * mNewBackgroundAlphas[i]);
-                            }
-                        });
                         mStateAnimator.play(bgAnim);
                     }
                 }
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 84a6462..855a443 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -20,12 +20,14 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.InsetDrawable;
 import android.os.Build;
+import android.os.Bundle;
 import android.support.v7.widget.RecyclerView;
 import android.text.Editable;
 import android.text.TextWatcher;
@@ -57,6 +59,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherTransitionable;
 import com.android.launcher3.R;
+import com.android.launcher3.Stats;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.allapps.AppSearchManager.AppSearchResultCallback;
@@ -172,7 +175,7 @@
         TextWatcher, TextView.OnEditorActionListener, LauncherTransitionable,
         AlphabeticalAppsList.AdapterChangedCallback, AllAppsGridAdapter.PredictionBarSpacerCallbacks,
         View.OnTouchListener, View.OnClickListener, View.OnLongClickListener,
-        ViewTreeObserver.OnPreDrawListener, AppSearchResultCallback {
+        ViewTreeObserver.OnPreDrawListener, AppSearchResultCallback, Stats.LaunchSourceProvider {
 
     public static final boolean GRID_MERGE_SECTIONS = true;
 
@@ -237,11 +240,11 @@
         mLauncher = (Launcher) context;
         DeviceProfile grid = mLauncher.getDeviceProfile();
 
-        mContainerInset = context.getResources().getDimensionPixelSize(
-                R.dimen.all_apps_container_inset);
-        mPredictionBarHeight = grid.allAppsIconSizePx + grid.iconDrawablePaddingOriginalPx +
-                grid.allAppsIconTextSizePx +
-                2 * res.getDimensionPixelSize(R.dimen.all_apps_prediction_icon_top_bottom_padding);
+        mContainerInset = res.getDimensionPixelSize(R.dimen.all_apps_container_inset);
+        mPredictionBarHeight = (int) (grid.allAppsIconSizePx + grid.iconDrawablePaddingOriginalPx +
+                Utilities.calculateTextHeight(grid.allAppsIconTextSizePx) +
+                2 * res.getDimensionPixelSize(R.dimen.all_apps_icon_top_bottom_padding) +
+                res.getDimensionPixelSize(R.dimen.all_apps_prediction_bar_bottom_padding));
 
         mLayoutInflater = LayoutInflater.from(context);
 
@@ -430,6 +433,7 @@
                 icon = (BubbleTextView) mLayoutInflater.inflate(
                         R.layout.all_apps_prediction_bar_icon, mPredictionBarView, false);
                 icon.setFocusable(true);
+                icon.setLongPressTimeout(ViewConfiguration.get(getContext()).getLongPressTimeout());
                 mPredictionBarView.addView(icon);
             }
 
@@ -495,11 +499,11 @@
         int startMargin = grid.isPhone ? mContentMarginStart : 0;
         int inset = mFixedBounds.isEmpty() ? mContainerInset : mFixedBoundsContainerInset;
         if (isRtl) {
-            mAppsRecyclerView.setPadding(inset + mAppsRecyclerView.getScrollbarWidth(), inset,
-                    inset + startMargin, inset);
+            mAppsRecyclerView.setPadding(inset + mAppsRecyclerView.getScrollbarWidth(), 0,
+                    inset + startMargin, 0);
         } else {
-            mAppsRecyclerView.setPadding(inset + startMargin, inset,
-                    inset + mAppsRecyclerView.getScrollbarWidth(), inset);
+            mAppsRecyclerView.setPadding(inset + startMargin, 0,
+                    inset + mAppsRecyclerView.getScrollbarWidth(), 0);
         }
 
         // Update the header bar
@@ -870,6 +874,15 @@
         return false;
     }
 
+    @Override
+    public void fillInLaunchSourceData(Bundle sourceData) {
+        // Since the other cases are caught by the AllAppsRecyclerView LaunchSourceProvider, we just
+        // handle the prediction bar icons here
+        sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_ALL_APPS);
+        sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
+                Stats.SUB_CONTAINER_ALL_APPS_PREDICTION);
+    }
+
     /**
      * Returns the predicted app in the prediction bar given a set of local coordinates.
      */
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 307d940..4b8b2df 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -27,6 +27,7 @@
 import android.support.v7.widget.RecyclerView;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.widget.TextView;
 import com.android.launcher3.AppInfo;
@@ -139,7 +140,7 @@
 
                 if (shouldDrawItemDivider(holder, items) && !hasDrawnPredictedAppsDivider) {
                     // Draw the divider under the predicted apps
-                    int top = child.getTop() + child.getHeight();
+                    int top = child.getTop() + child.getHeight() - mPredictionBarBottomPadding / 2;
                     c.drawLine(mBackgroundPadding.left, top,
                             parent.getWidth() - mBackgroundPadding.right, top,
                             mPredictedAppsDividerPaint);
@@ -294,6 +295,7 @@
     private View.OnLongClickListener mIconLongClickListener;
     @Thunk final Rect mBackgroundPadding = new Rect();
     @Thunk int mPredictionBarHeight;
+    @Thunk int mPredictionBarBottomPadding;
     @Thunk int mAppsPerRow;
     @Thunk boolean mIsRtl;
     private String mEmptySearchText;
@@ -336,6 +338,8 @@
         mPredictedAppsDividerPaint.setStrokeWidth(Utilities.pxFromDp(1f, res.getDisplayMetrics()));
         mPredictedAppsDividerPaint.setColor(0x1E000000);
         mPredictedAppsDividerPaint.setAntiAlias(true);
+        mPredictionBarBottomPadding =
+                res.getDimensionPixelSize(R.dimen.all_apps_prediction_bar_bottom_padding);
     }
 
     /**
@@ -418,6 +422,8 @@
                 icon.setOnTouchListener(mTouchListener);
                 icon.setOnClickListener(mIconClickListener);
                 icon.setOnLongClickListener(mIconLongClickListener);
+                icon.setLongPressTimeout(ViewConfiguration.get(parent.getContext())
+                        .getLongPressTimeout());
                 icon.setFocusable(true);
                 return new ViewHolder(icon);
             default:
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index cc5add3..e1b5d91 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -18,14 +18,15 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
 import android.view.View;
-
 import com.android.launcher3.BaseRecyclerView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.Stats;
 import com.android.launcher3.Utilities;
 
 import java.util.List;
@@ -33,7 +34,8 @@
 /**
  * A RecyclerView with custom fast scroll support for the all apps view.
  */
-public class AllAppsRecyclerView extends BaseRecyclerView {
+public class AllAppsRecyclerView extends BaseRecyclerView
+        implements Stats.LaunchSourceProvider {
 
     private AlphabeticalAppsList mApps;
     private int mNumAppsPerRow;
@@ -125,6 +127,18 @@
         addOnItemTouchListener(this);
     }
 
+    @Override
+    public void fillInLaunchSourceData(Bundle sourceData) {
+        sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_ALL_APPS);
+        if (mApps.hasFilter()) {
+            sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
+                    Stats.SUB_CONTAINER_ALL_APPS_SEARCH);
+        } else {
+            sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
+                    Stats.SUB_CONTAINER_ALL_APPS_A_Z);
+        }
+    }
+
     /**
      * Maps the touch (from 0..1) to the adapter position that should be visible.
      */
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index aa5e907..e284f77 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -46,6 +46,7 @@
 
     public static final String TAG = "AlphabeticalAppsList";
     private static final boolean DEBUG = false;
+    private static final boolean DEBUG_PREDICTIONS = false;
 
     /**
      * Info about a section in the alphabetic list
@@ -477,6 +478,15 @@
         mAdapterItems.clear();
         mSections.clear();
 
+        if (DEBUG_PREDICTIONS) {
+            if (mPredictedAppComponents.isEmpty() && !mApps.isEmpty()) {
+                mPredictedAppComponents.add(mApps.get(0).componentName);
+                mPredictedAppComponents.add(mApps.get(0).componentName);
+                mPredictedAppComponents.add(mApps.get(0).componentName);
+                mPredictedAppComponents.add(mApps.get(0).componentName);
+            }
+        }
+
         // Process the predicted app components
         mPredictedApps.clear();
         if (mPredictedAppComponents != null && !mPredictedAppComponents.isEmpty() && !hasFilter()) {
diff --git a/src/com/android/launcher3/model/PackageItemInfo.java b/src/com/android/launcher3/model/PackageItemInfo.java
index 0f0134a..30f228c 100644
--- a/src/com/android/launcher3/model/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/PackageItemInfo.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.model;
 
-import android.content.ComponentName;
 import android.graphics.Bitmap;
 
 import com.android.launcher3.ItemInfo;
@@ -27,7 +26,6 @@
  * Represents a {@link Package} in the widget tray section.
  */
 public class PackageItemInfo extends ItemInfo {
-    private static final String TAG = "PackageInfo";
 
     /**
      * A bitmap version of the application icon.
@@ -35,12 +33,21 @@
     public Bitmap iconBitmap;
 
     /**
-     * Indicates whether we're using a low res icon
+     * Indicates whether we're using a low res icon.
      */
     public boolean usingLowResIcon;
 
+    /**
+     * Package name of the {@link ItemInfo}.
+     */
     public String packageName;
 
+    /**
+     * Character that is used as a section name for the {@link ItemInfo#title}.
+     * (e.g., "G" will be stored if title is "Google")
+     */
+    public String titleSectionName;
+
     int flags = 0;
 
     PackageItemInfo(String packageName) {
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index fdb9795..625d4d6 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -8,8 +8,8 @@
 import com.android.launcher3.IconCache;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
-
 import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AlphabeticIndexCompat;
 import com.android.launcher3.compat.UserHandleCompat;
 
 import java.util.ArrayList;
@@ -39,11 +39,13 @@
     private final Comparator mWidgetAndShortcutNameComparator;
     private final Comparator mAppNameComparator;
     private final IconCache mIconCache;
+    private AlphabeticIndexCompat mIndexer;
 
     public WidgetsModel(Context context) {
         mWidgetAndShortcutNameComparator = new WidgetsAndShortcutNameComparator(context);
         mAppNameComparator = (new AppNameComparator(context)).getAppInfoComparator();
         mIconCache = LauncherAppState.getInstance().getIconCache();
+        mIndexer = new AlphabeticIndexCompat(context);
     }
 
     private WidgetsModel(WidgetsModel model) {
@@ -62,6 +64,9 @@
 
     // Access methods that may be deleted if the private fields are made package-private.
     public PackageItemInfo getPackageItemInfo(int pos) {
+        if (pos >= mPackageItemInfos.size() || pos < 0) {
+            return null;
+        }
         return mPackageItemInfos.get(pos);
     }
 
@@ -112,6 +117,7 @@
                 pInfo = new PackageItemInfo(packageName);
                 mIconCache.getTitleAndIconForApp(packageName, UserHandleCompat.myUserHandle(),
                         true /* userLowResIcon */, pInfo);
+                pInfo.titleSectionName = mIndexer.computeSectionName(pInfo.title);
                 mWidgetsList.put(pInfo, widgetsShortcutsList);
                 tmpPackageItemInfos.put(packageName,  pInfo);
                 mPackageItemInfos.add(pInfo);
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 3ec1645..7496ea2 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -23,8 +23,10 @@
 import android.graphics.Bitmap;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
+import android.view.ViewPropertyAnimator;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -35,6 +37,7 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.R;
+import com.android.launcher3.StylusEventHelper;
 import com.android.launcher3.WidgetPreviewLoader;
 import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
@@ -73,6 +76,7 @@
 
     private WidgetPreviewLoader mWidgetPreviewLoader;
     private PreviewLoadRequest mActiveRequest;
+    private StylusEventHelper mStylusEventHelper;
 
     private Launcher mLauncher;
 
@@ -89,6 +93,7 @@
 
         final Resources r = context.getResources();
         mLauncher = (Launcher) context;
+        mStylusEventHelper = new StylusEventHelper(this);
 
         mDimensionsFormatString = r.getString(R.string.widget_dims_format);
         setContainerWidth();
@@ -171,7 +176,8 @@
         if (bitmap != null) {
             mWidgetImage.setBitmap(bitmap);
             mWidgetImage.setAlpha(0f);
-            mWidgetImage.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
+            ViewPropertyAnimator anim = mWidgetImage.animate();
+            anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
         }
     }
 
@@ -202,6 +208,15 @@
         return Math.min(size[0], info.spanX * cellWidth);
     }
 
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean handled = super.onTouchEvent(ev);
+        if (mStylusEventHelper.checkAndPerformStylusEvent(ev)) {
+            return true;
+        }
+        return handled;
+    }
+
     /**
      * Helper method to get the string info of the tag.
      */
diff --git a/src/com/android/launcher3/widget/WidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
index 6f8fd89..b0fbe1e 100644
--- a/src/com/android/launcher3/widget/WidgetImageView.java
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -64,6 +64,14 @@
         }
     }
 
+    /**
+     * Prevents the inefficient alpha view rendering.
+     */
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
     private void updateDstRectF() {
         if (mBitmap.getWidth() > getWidth()) {
             float scale = ((float) getWidth()) / mBitmap.getWidth();
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index aa139cb..51f2a5f 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -20,6 +20,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView.State;
 import android.util.AttributeSet;
@@ -90,7 +91,6 @@
         mDragController = mLauncher.getDragController();
         mAdapter = new WidgetsListAdapter(context, this, this, mLauncher);
         mIconCache = (LauncherAppState.getInstance()).getIconCache();
-
         if (DEBUG) {
             Log.d(TAG, "WidgetsContainerView constructor");
         }
@@ -243,6 +243,7 @@
             Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.activityInfo);
             preview = Utilities.createIconBitmap(icon, mLauncher);
             createItemInfo.spanX = createItemInfo.spanY = 1;
+            scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / preview.getWidth();
         }
 
         // Don't clip alpha values for the drag outline if we're using the default widget preview
@@ -344,6 +345,23 @@
             setPadding(mFixedBounds.left, mFixedBounds.top, getMeasuredWidth() - mFixedBounds.right,
                     mFixedBounds.bottom);
         }
+
+        int inset = mFixedBounds.isEmpty() ? mView.getScrollbarWidth() : mFixedBoundsContainerInset;
+        mView.setPadding(inset + mView.getScrollbarWidth(), inset,
+                inset, inset);
+    }
+
+    @Override
+    protected void onUpdateBackgrounds() {
+        InsetDrawable background;
+        // Update the background of the reveal view and list to be inset with the fixed bound
+        // insets instead of the default insets
+        // TODO: Use quantum_panel instead of quantum_panel_shape.
+        int inset = mFixedBounds.isEmpty() ? mView.getScrollbarWidth() : mFixedBoundsContainerInset;
+        background = new InsetDrawable(
+                getContext().getResources().getDrawable(R.drawable.quantum_panel_shape),
+                inset, 0, inset, 0);
+        mView.updateBackgroundPadding(background);
     }
 
     /**
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index bef2559..4aa3323 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -19,20 +19,25 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.LinearLayoutManager;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
+import android.view.View;
 
 import com.android.launcher3.BaseRecyclerView;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AlphabeticIndexCompat;
 import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.model.PackageItemInfo;
 
 /**
  * The widgets recycler view.
  */
 public class WidgetsRecyclerView extends BaseRecyclerView {
 
+    private static final String TAG = "WidgetsRecyclerView";
     private WidgetsModel mWidgets;
     private Rect mBackgroundPadding = new Rect();
+    private PackageItemInfo mLastPackageItemInfo;
 
     public WidgetsRecyclerView(Context context) {
         this(context, null);
@@ -68,8 +73,17 @@
      */
     @Override
     public String scrollToPositionAtProgress(float touchFraction) {
-        // Ensure that we have any sections
-        return "";
+        float pos = mWidgets.getPackageSize() * touchFraction;
+
+        int posInt = (int) pos;
+        LinearLayoutManager layoutManager = ((LinearLayoutManager) getLayoutManager());
+        getCurScrollState(scrollPosState);
+        layoutManager.scrollToPositionWithOffset((int) pos,
+                (int) (scrollPosState.rowHeight * ((float) posInt - pos)));
+
+        posInt = (int) ((touchFraction == 1)? pos -1 : pos);
+        PackageItemInfo p = mWidgets.getPackageItemInfo(posInt);
+        return p.titleSectionName;
     }
 
     /**
@@ -78,19 +92,41 @@
     @Override
     public void updateVerticalScrollbarBounds() {
         int rowCount = mWidgets.getPackageSize();
+        verticalScrollbarBounds.setEmpty();
 
-        // Skip early if there are no items.
+        // Skip early if, there are no items.
         if (rowCount == 0) {
+            return;
+        }
+
+        // Skip early if, there no child laid out in the container.
+        getCurScrollState(scrollPosState);
+        if (scrollPosState.rowIndex < 0) {
+            return;
+        }
+
+        int actualHeight = getHeight() - getPaddingTop() - getPaddingBottom();
+        int totalScrollHeight = rowCount * scrollPosState.rowHeight;
+        // Skip early if the height of all the rows are actually less than the container height.
+        if (totalScrollHeight < actualHeight) {
             verticalScrollbarBounds.setEmpty();
             return;
         }
 
-        int x, y;
-        getCurScrollState(scrollPosState);
-        if (scrollPosState.rowIndex < 0) {
-            verticalScrollbarBounds.setEmpty();
+        int scrollbarHeight = (int) (actualHeight / ((float) totalScrollHeight / actualHeight));
+        int availableY = totalScrollHeight - actualHeight;
+        int availableScrollY = actualHeight - scrollbarHeight;
+        int y = (scrollPosState.rowIndex * scrollPosState.rowHeight)
+                - scrollPosState.rowTopOffset;
+        y = getPaddingTop() +
+                (int) (((float) (getPaddingTop() + y) / availableY) * availableScrollY);
+
+        // Calculate the position and size of the scroll bar.
+        int x = getWidth() - getScrollbarWidth() - mBackgroundPadding.right;
+        if (Utilities.isRtl(getResources())) {
+            x = mBackgroundPadding.left;
         }
-        // TODO
+        verticalScrollbarBounds.set(x, y, x + getScrollbarWidth(), y + scrollbarHeight);
     }
 
     /**
@@ -107,6 +143,11 @@
         if (rowCount == 0) {
             return;
         }
-        // TODO
+        View child = getChildAt(0);
+        int position = getChildPosition(child);
+
+        stateOut.rowIndex = position;
+        stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child);
+        stateOut.rowHeight = child.getHeight();
     }
 }
\ No newline at end of file