Merge "Use FastJNI for trivial MotionEvent native methods"
diff --git a/api/current.txt b/api/current.txt
index ef18bf9..3637f14 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -241,10 +241,8 @@
     field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
     field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba
     field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
-    field public static final int activityHeight = 16844021; // 0x10104f5
     field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
     field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
-    field public static final int activityWidth = 16844020; // 0x10104f4
     field public static final int addPrintersActivity = 16843750; // 0x10103e6
     field public static final int addStatesFromChildren = 16842992; // 0x10100f0
     field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -323,7 +321,7 @@
     field public static final int buttonBarNeutralButtonStyle = 16843914; // 0x101048a
     field public static final int buttonBarPositiveButtonStyle = 16843913; // 0x1010489
     field public static final int buttonBarStyle = 16843566; // 0x101032e
-    field public static final int buttonGravity = 16844029; // 0x10104fd
+    field public static final int buttonGravity = 16844030; // 0x10104fe
     field public static final int buttonStyle = 16842824; // 0x1010048
     field public static final int buttonStyleInset = 16842826; // 0x101004a
     field public static final int buttonStyleSmall = 16842825; // 0x1010049
@@ -373,7 +371,7 @@
     field public static final int codes = 16843330; // 0x1010242
     field public static final int collapseColumns = 16843083; // 0x101014b
     field public static final int collapseContentDescription = 16843984; // 0x10104d0
-    field public static final int collapseIcon = 16844030; // 0x10104fe
+    field public static final int collapseIcon = 16844031; // 0x10104ff
     field public static final int color = 16843173; // 0x10101a5
     field public static final int colorAccent = 16843829; // 0x1010435
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
@@ -414,7 +412,7 @@
     field public static final int contentInsetRight = 16843862; // 0x1010456
     field public static final int contentInsetStart = 16843859; // 0x1010453
     field public static final int contextClickable = 16844007; // 0x10104e7
-    field public static final int contextPopupMenuStyle = 16844032; // 0x1010500
+    field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
@@ -673,8 +671,10 @@
     field public static final int indicatorStart = 16843729; // 0x10103d1
     field public static final int inflatedId = 16842995; // 0x10100f3
     field public static final int initOrder = 16842778; // 0x101001a
+    field public static final int initialHeight = 16844021; // 0x10104f5
     field public static final int initialKeyguardLayout = 16843714; // 0x10103c2
     field public static final int initialLayout = 16843345; // 0x1010251
+    field public static final int initialWidth = 16844020; // 0x10104f4
     field public static final int innerRadius = 16843359; // 0x101025f
     field public static final int innerRadiusRatio = 16843163; // 0x101019b
     field public static final deprecated int inputMethod = 16843112; // 0x1010168
@@ -780,7 +780,7 @@
     field public static final int layout_y = 16843136; // 0x1010180
     field public static final int left = 16843181; // 0x10101ad
     field public static final int letterSpacing = 16843958; // 0x10104b6
-    field public static final int level = 16844031; // 0x10104ff
+    field public static final int level = 16844032; // 0x1010500
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
     field public static final int lines = 16843092; // 0x1010154
@@ -813,7 +813,7 @@
     field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
     field public static final int matchOrder = 16843855; // 0x101044f
     field public static final int max = 16843062; // 0x1010136
-    field public static final int maxButtonHeight = 16844028; // 0x10104fc
+    field public static final int maxButtonHeight = 16844029; // 0x10104fd
     field public static final int maxDate = 16843584; // 0x1010340
     field public static final int maxEms = 16843095; // 0x1010157
     field public static final int maxHeight = 16843040; // 0x1010120
@@ -841,6 +841,7 @@
     field public static final int minResizeWidth = 16843669; // 0x1010395
     field public static final int minSdkVersion = 16843276; // 0x101020c
     field public static final int minWidth = 16843071; // 0x101013f
+    field public static final int minimalSize = 16844022; // 0x10104f6
     field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
     field public static final int minimumVerticalAngle = 16843902; // 0x101047e
     field public static final int mipMap = 16843725; // 0x10103cd
@@ -997,7 +998,7 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
-    field public static final int resizeableActivity = 16844022; // 0x10104f6
+    field public static final int resizeableActivity = 16844023; // 0x10104f7
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1221,7 +1222,7 @@
     field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
-    field public static final int textAppearancePopupMenuHeader = 16844033; // 0x1010501
+    field public static final int textAppearancePopupMenuHeader = 16844034; // 0x1010502
     field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
     field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
     field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -1290,11 +1291,11 @@
     field public static final int tintMode = 16843771; // 0x10103fb
     field public static final int title = 16843233; // 0x10101e1
     field public static final int titleCondensed = 16843234; // 0x10101e2
-    field public static final int titleMargin = 16844023; // 0x10104f7
-    field public static final int titleMarginBottom = 16844027; // 0x10104fb
-    field public static final int titleMarginEnd = 16844025; // 0x10104f9
-    field public static final int titleMarginStart = 16844024; // 0x10104f8
-    field public static final int titleMarginTop = 16844026; // 0x10104fa
+    field public static final int titleMargin = 16844024; // 0x10104f8
+    field public static final int titleMarginBottom = 16844028; // 0x10104fc
+    field public static final int titleMarginEnd = 16844026; // 0x10104fa
+    field public static final int titleMarginStart = 16844025; // 0x10104f9
+    field public static final int titleMarginTop = 16844027; // 0x10104fb
     field public static final int titleTextAppearance = 16843822; // 0x101042e
     field public static final int titleTextColor = 16844003; // 0x10104e3
     field public static final int titleTextStyle = 16843512; // 0x10102f8
@@ -2876,6 +2877,7 @@
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
     method public abstract long getStartDelay();
+    method public long getTotalDuration();
     method public boolean isPaused();
     method public abstract boolean isRunning();
     method public boolean isStarted();
@@ -2891,6 +2893,7 @@
     method public void setupEndValues();
     method public void setupStartValues();
     method public void start();
+    field public static final long DURATION_INFINITE = -1L; // 0xffffffffffffffffL
   }
 
   public static abstract interface Animator.AnimatorListener {
@@ -8922,8 +8925,8 @@
     field public int configChanges;
     field public int documentLaunchMode;
     field public int flags;
-    field public android.content.pm.ActivityInfo.InitialLayout initialLayout;
     field public int launchMode;
+    field public android.content.pm.ActivityInfo.Layout layout;
     field public int maxRecents;
     field public java.lang.String parentActivityName;
     field public java.lang.String permission;
@@ -8936,11 +8939,12 @@
     field public int uiOptions;
   }
 
-  public static final class ActivityInfo.InitialLayout {
-    ctor public ActivityInfo.InitialLayout(int, float, int, float, int);
+  public static final class ActivityInfo.Layout {
+    ctor public ActivityInfo.Layout(int, float, int, float, int, int);
     field public final int gravity;
     field public final int height;
     field public final float heightFraction;
+    field public final int minimalSize;
     field public final int width;
     field public final float widthFraction;
   }
@@ -18173,6 +18177,24 @@
   public class MtpEvent {
     ctor public MtpEvent();
     method public int getEventCode();
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
   }
 
   public final class MtpObjectInfo {
diff --git a/api/system-current.txt b/api/system-current.txt
index 0b216bdd..076815e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -333,10 +333,8 @@
     field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
     field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba
     field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
-    field public static final int activityHeight = 16844021; // 0x10104f5
     field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
     field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
-    field public static final int activityWidth = 16844020; // 0x10104f4
     field public static final int addPrintersActivity = 16843750; // 0x10103e6
     field public static final int addStatesFromChildren = 16842992; // 0x10100f0
     field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -415,7 +413,7 @@
     field public static final int buttonBarNeutralButtonStyle = 16843914; // 0x101048a
     field public static final int buttonBarPositiveButtonStyle = 16843913; // 0x1010489
     field public static final int buttonBarStyle = 16843566; // 0x101032e
-    field public static final int buttonGravity = 16844029; // 0x10104fd
+    field public static final int buttonGravity = 16844030; // 0x10104fe
     field public static final int buttonStyle = 16842824; // 0x1010048
     field public static final int buttonStyleInset = 16842826; // 0x101004a
     field public static final int buttonStyleSmall = 16842825; // 0x1010049
@@ -465,7 +463,7 @@
     field public static final int codes = 16843330; // 0x1010242
     field public static final int collapseColumns = 16843083; // 0x101014b
     field public static final int collapseContentDescription = 16843984; // 0x10104d0
-    field public static final int collapseIcon = 16844030; // 0x10104fe
+    field public static final int collapseIcon = 16844031; // 0x10104ff
     field public static final int color = 16843173; // 0x10101a5
     field public static final int colorAccent = 16843829; // 0x1010435
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
@@ -506,7 +504,7 @@
     field public static final int contentInsetRight = 16843862; // 0x1010456
     field public static final int contentInsetStart = 16843859; // 0x1010453
     field public static final int contextClickable = 16844007; // 0x10104e7
-    field public static final int contextPopupMenuStyle = 16844032; // 0x1010500
+    field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
@@ -765,8 +763,10 @@
     field public static final int indicatorStart = 16843729; // 0x10103d1
     field public static final int inflatedId = 16842995; // 0x10100f3
     field public static final int initOrder = 16842778; // 0x101001a
+    field public static final int initialHeight = 16844021; // 0x10104f5
     field public static final int initialKeyguardLayout = 16843714; // 0x10103c2
     field public static final int initialLayout = 16843345; // 0x1010251
+    field public static final int initialWidth = 16844020; // 0x10104f4
     field public static final int innerRadius = 16843359; // 0x101025f
     field public static final int innerRadiusRatio = 16843163; // 0x101019b
     field public static final deprecated int inputMethod = 16843112; // 0x1010168
@@ -872,7 +872,7 @@
     field public static final int layout_y = 16843136; // 0x1010180
     field public static final int left = 16843181; // 0x10101ad
     field public static final int letterSpacing = 16843958; // 0x10104b6
-    field public static final int level = 16844031; // 0x10104ff
+    field public static final int level = 16844032; // 0x1010500
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
     field public static final int lines = 16843092; // 0x1010154
@@ -905,7 +905,7 @@
     field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
     field public static final int matchOrder = 16843855; // 0x101044f
     field public static final int max = 16843062; // 0x1010136
-    field public static final int maxButtonHeight = 16844028; // 0x10104fc
+    field public static final int maxButtonHeight = 16844029; // 0x10104fd
     field public static final int maxDate = 16843584; // 0x1010340
     field public static final int maxEms = 16843095; // 0x1010157
     field public static final int maxHeight = 16843040; // 0x1010120
@@ -933,6 +933,7 @@
     field public static final int minResizeWidth = 16843669; // 0x1010395
     field public static final int minSdkVersion = 16843276; // 0x101020c
     field public static final int minWidth = 16843071; // 0x101013f
+    field public static final int minimalSize = 16844022; // 0x10104f6
     field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
     field public static final int minimumVerticalAngle = 16843902; // 0x101047e
     field public static final int mipMap = 16843725; // 0x10103cd
@@ -1089,7 +1090,7 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
-    field public static final int resizeableActivity = 16844022; // 0x10104f6
+    field public static final int resizeableActivity = 16844023; // 0x10104f7
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1317,7 +1318,7 @@
     field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
-    field public static final int textAppearancePopupMenuHeader = 16844033; // 0x1010501
+    field public static final int textAppearancePopupMenuHeader = 16844034; // 0x1010502
     field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
     field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
     field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -1386,11 +1387,11 @@
     field public static final int tintMode = 16843771; // 0x10103fb
     field public static final int title = 16843233; // 0x10101e1
     field public static final int titleCondensed = 16843234; // 0x10101e2
-    field public static final int titleMargin = 16844023; // 0x10104f7
-    field public static final int titleMarginBottom = 16844027; // 0x10104fb
-    field public static final int titleMarginEnd = 16844025; // 0x10104f9
-    field public static final int titleMarginStart = 16844024; // 0x10104f8
-    field public static final int titleMarginTop = 16844026; // 0x10104fa
+    field public static final int titleMargin = 16844024; // 0x10104f8
+    field public static final int titleMarginBottom = 16844028; // 0x10104fc
+    field public static final int titleMarginEnd = 16844026; // 0x10104fa
+    field public static final int titleMarginStart = 16844025; // 0x10104f9
+    field public static final int titleMarginTop = 16844027; // 0x10104fb
     field public static final int titleTextAppearance = 16843822; // 0x101042e
     field public static final int titleTextColor = 16844003; // 0x10104e3
     field public static final int titleTextStyle = 16843512; // 0x10102f8
@@ -2975,6 +2976,7 @@
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
     method public abstract long getStartDelay();
+    method public long getTotalDuration();
     method public boolean isPaused();
     method public abstract boolean isRunning();
     method public boolean isStarted();
@@ -2990,6 +2992,7 @@
     method public void setupEndValues();
     method public void setupStartValues();
     method public void start();
+    field public static final long DURATION_INFINITE = -1L; // 0xffffffffffffffffL
   }
 
   public static abstract interface Animator.AnimatorListener {
@@ -9179,8 +9182,8 @@
     field public int configChanges;
     field public int documentLaunchMode;
     field public int flags;
-    field public android.content.pm.ActivityInfo.InitialLayout initialLayout;
     field public int launchMode;
+    field public android.content.pm.ActivityInfo.Layout layout;
     field public int maxRecents;
     field public java.lang.String parentActivityName;
     field public java.lang.String permission;
@@ -9193,11 +9196,12 @@
     field public int uiOptions;
   }
 
-  public static final class ActivityInfo.InitialLayout {
-    ctor public ActivityInfo.InitialLayout(int, float, int, float, int);
+  public static final class ActivityInfo.Layout {
+    ctor public ActivityInfo.Layout(int, float, int, float, int, int);
     field public final int gravity;
     field public final int height;
     field public final float heightFraction;
+    field public final int minimalSize;
     field public final int width;
     field public final float widthFraction;
   }
@@ -19685,6 +19689,24 @@
   public class MtpEvent {
     ctor public MtpEvent();
     method public int getEventCode();
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
   }
 
   public final class MtpObjectInfo {
@@ -25721,7 +25743,8 @@
     ctor public UserHandle(android.os.Parcel);
     method public int describeContents();
     method public int getIdentifier();
-    method public boolean isOwner();
+    method public deprecated boolean isOwner();
+    method public boolean isSystem();
     method public static int myUserId();
     method public static android.os.UserHandle readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 4a13136..81da6af 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -2033,7 +2033,7 @@
         }
 
         try {
-            mAm.resizeStack(stackId, bounds);
+            mAm.resizeStack(stackId, bounds, false);
             Thread.sleep(delayMs);
         } catch (RemoteException e) {
             showError("Error: resizing stack " + e);
@@ -2127,8 +2127,8 @@
             }
 
             // Resize stacks
-            mAm.resizeStack(currentStackInfo.stackId, currentStackBounds);
-            mAm.resizeStack(newStackInfo.stackId, newStackBounds);
+            mAm.resizeStack(currentStackInfo.stackId, currentStackBounds, false);
+            mAm.resizeStack(newStackInfo.stackId, newStackBounds, false);
         } catch (RemoteException e) {
         }
     }
diff --git a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java
index d1f7a00..c9b9e58 100644
--- a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java
+++ b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java
@@ -168,7 +168,12 @@
         final IPackageManager pm = ActivityThread.getPackageManager();
         final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
-        final int uid = pm.getPackageUid(packageName, userId);
+        final int uid;
+        if ("root".equals(packageName)) {
+            uid = 0;
+        } else {
+            uid = pm.getPackageUid(packageName, userId);
+        }
         if (uid < 0) {
             System.err.println("Error: No UID for " + packageName + " in user " + userId);
             return;
@@ -211,7 +216,12 @@
         final IPackageManager pm = ActivityThread.getPackageManager();
         final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
-        final int uid = pm.getPackageUid(packageName, userId);
+        final int uid;
+        if ("root".equals(packageName)) {
+            uid = 0;
+        } else {
+            uid = pm.getPackageUid(packageName, userId);
+        }
         if (uid < 0) {
             System.err.println("Error: No UID for " + packageName + " in user " + userId);
             return;
diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp
index 41395f1..9d60ee1 100644
--- a/cmds/idmap/create.cpp
+++ b/cmds/idmap/create.cpp
@@ -41,7 +41,7 @@
             ALOGD("error: fchmod %s: %s\n", path, strerror(errno));
             goto fail;
         }
-        if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX | LOCK_NB)) != 0) {
+        if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX)) != 0) {
             ALOGD("error: flock %s: %s\n", path, strerror(errno));
             goto fail;
         }
diff --git a/cmds/idmap/idmap.cpp b/cmds/idmap/idmap.cpp
index 90cfa2c..3ab1915 100644
--- a/cmds/idmap/idmap.cpp
+++ b/cmds/idmap/idmap.cpp
@@ -13,7 +13,8 @@
       idmap --help \n\
       idmap --fd target overlay fd \n\
       idmap --path target overlay idmap \n\
-      idmap --scan dir-to-scan target-to-look-for target dir-to-hold-idmaps \n\
+      idmap --scan target-package-name-to-look-for path-to-target-apk dir-to-hold-idmaps \\\
+                   dir-to-scan [additional-dir-to-scan [additional-dir-to-scan [...]]]\n\
       idmap --inspect idmap \n\
 \n\
 DESCRIPTION \n\
@@ -49,9 +50,9 @@
               'overlay' (path to apk); write results to 'idmap' (path). \n\
 \n\
       --scan: non-recursively search directory 'dir-to-scan' (path) for overlay packages with \n\
-              target package 'target-to-look-for' (package name) present at 'target' (path to \n\
-              apk). For each overlay package found, create an idmap file in 'dir-to-hold-idmaps' \n\
-              (path). \n\
+              target package 'target-package-name-to-look-for' (package name) present at\n\
+              'path-to-target-apk' (path to apk). For each overlay package found, create an\n\
+              idmap file in 'dir-to-hold-idmaps' (path). \n\
 \n\
       --inspect: decode the binary format of 'idmap' (path) and display the contents in a \n\
                  debug-friendly format. \n\
@@ -166,19 +167,14 @@
         return idmap_create_path(target_apk_path, overlay_apk_path, idmap_path);
     }
 
-    int maybe_scan(const char *overlay_dir, const char *target_package_name,
-            const char *target_apk_path, const char *idmap_dir)
+    int maybe_scan(const char *target_package_name, const char *target_apk_path,
+            const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
     {
         if (!verify_root_or_system()) {
             fprintf(stderr, "error: permission denied: not user root or user system\n");
             return -1;
         }
 
-        if (!verify_directory_readable(overlay_dir)) {
-            ALOGD("error: no read access to %s: %s\n", overlay_dir, strerror(errno));
-            return -1;
-        }
-
         if (!verify_file_readable(target_apk_path)) {
             ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno));
             return -1;
@@ -189,7 +185,16 @@
             return -1;
         }
 
-        return idmap_scan(overlay_dir, target_package_name, target_apk_path, idmap_dir);
+        const size_t N = overlay_dirs->size();
+        for (size_t i = 0; i < N; i++) {
+            const char *dir = overlay_dirs->itemAt(i);
+            if (!verify_directory_readable(dir)) {
+                ALOGD("error: no read access to %s: %s\n", dir, strerror(errno));
+                return -1;
+            }
+        }
+
+        return idmap_scan(target_package_name, target_apk_path, idmap_dir, overlay_dirs);
     }
 
     int maybe_inspect(const char *idmap_path)
@@ -230,8 +235,12 @@
         return maybe_create_path(argv[2], argv[3], argv[4]);
     }
 
-    if (argc == 6 && !strcmp(argv[1], "--scan")) {
-        return maybe_scan(argv[2], argv[3], argv[4], argv[5]);
+    if (argc >= 6 && !strcmp(argv[1], "--scan")) {
+        android::Vector<const char *> v;
+        for (int i = 5; i < argc; i++) {
+            v.push(argv[i]);
+        }
+        return maybe_scan(argv[2], argv[3], argv[4], &v);
     }
 
     if (argc == 3 && !strcmp(argv[1], "--inspect")) {
diff --git a/cmds/idmap/idmap.h b/cmds/idmap/idmap.h
index f507dd8..8d4210b 100644
--- a/cmds/idmap/idmap.h
+++ b/cmds/idmap/idmap.h
@@ -1,9 +1,11 @@
+
 #ifndef _IDMAP_H_
 #define _IDMAP_H_
 
 #define LOG_TAG "idmap"
 
 #include <utils/Log.h>
+#include <utils/Vector.h>
 
 #include <errno.h>
 #include <stdio.h>
@@ -26,8 +28,8 @@
 // Regarding target_package_name: the idmap_scan implementation should
 // be able to extract this from the manifest in target_apk_path,
 // simplifying the external API.
-int idmap_scan(const char *overlay_dir, const char *target_package_name,
-        const char *target_apk_path, const char *idmap_dir);
+int idmap_scan(const char *target_package_name, const char *target_apk_path,
+        const char *idmap_dir, const android::Vector<const char *> *overlay_dirs);
 
 int idmap_inspect(const char *idmap_path);
 
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index 612a7eb..f1b2f9e 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -25,8 +25,7 @@
 
         bool operator<(Overlay const& rhs) const
         {
-            // Note: order is reversed by design
-            return rhs.priority < priority;
+            return rhs.priority > priority;
         }
 
         String8 apk_path;
@@ -167,8 +166,8 @@
     }
 }
 
-int idmap_scan(const char *overlay_dir, const char *target_package_name,
-        const char *target_apk_path, const char *idmap_dir)
+int idmap_scan(const char *target_package_name, const char *target_apk_path,
+        const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
 {
     String8 filename = String8(idmap_dir);
     filename.appendPath("overlays.list");
@@ -176,45 +175,49 @@
         return EXIT_FAILURE;
     }
 
-    DIR *dir = opendir(overlay_dir);
-    if (dir == NULL) {
-        return EXIT_FAILURE;
-    }
-
     SortedVector<Overlay> overlayVector;
-    struct dirent *dirent;
-    while ((dirent = readdir(dir)) != NULL) {
-        struct stat st;
-        char overlay_apk_path[PATH_MAX + 1];
-        snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
-        if (stat(overlay_apk_path, &st) < 0) {
-            continue;
-        }
-        if (!S_ISREG(st.st_mode)) {
-            continue;
+    const size_t N = overlay_dirs->size();
+    for (size_t i = 0; i < N; ++i) {
+        const char *overlay_dir = overlay_dirs->itemAt(i);
+        DIR *dir = opendir(overlay_dir);
+        if (dir == NULL) {
+            return EXIT_FAILURE;
         }
 
-        int priority = parse_apk(overlay_apk_path, target_package_name);
-        if (priority < 0) {
-            continue;
+        struct dirent *dirent;
+        while ((dirent = readdir(dir)) != NULL) {
+            struct stat st;
+            char overlay_apk_path[PATH_MAX + 1];
+            snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
+            if (stat(overlay_apk_path, &st) < 0) {
+                continue;
+            }
+            if (!S_ISREG(st.st_mode)) {
+                continue;
+            }
+
+            int priority = parse_apk(overlay_apk_path, target_package_name);
+            if (priority < 0) {
+                continue;
+            }
+
+            String8 idmap_path(idmap_dir);
+            idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
+            idmap_path.append("@idmap");
+
+            if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
+                ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
+                        target_apk_path, overlay_apk_path, idmap_path.string());
+                continue;
+            }
+
+            Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
+            overlayVector.add(overlay);
         }
 
-        String8 idmap_path(idmap_dir);
-        idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
-        idmap_path.append("@idmap");
-
-        if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
-            ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
-                    target_apk_path, overlay_apk_path, idmap_path.string());
-            continue;
-        }
-
-        Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
-        overlayVector.add(overlay);
+        closedir(dir);
     }
 
-    closedir(dir);
-
     if (!writePackagesList(filename.string(), overlayVector)) {
         return EXIT_FAILURE;
     }
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 393956f..3f8e311 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -283,7 +283,7 @@
             } else if (args.length == 2) {
                 if (args[0].equalsIgnoreCase("-p")) {
                     validCommand = true;
-                    return displayPackageFilePath(args[1]);
+                    return displayPackageFilePath(args[1], UserHandle.USER_OWNER);
                 }
             }
             return 1;
@@ -767,12 +767,25 @@
     }
 
     private int runPath() {
+        int userId = UserHandle.USER_OWNER;
+        String option = nextOption();
+        if (option != null && option.equals("--user")) {
+            String optionData = nextOptionData();
+            if (optionData == null || !isNumber(optionData)) {
+                System.err.println("Error: no USER_ID specified");
+                showUsage();
+                return 1;
+            } else {
+                userId = Integer.parseInt(optionData);
+            }
+        }
+
         String pkg = nextArg();
         if (pkg == null) {
             System.err.println("Error: no package specified");
             return 1;
         }
-        return displayPackageFilePath(pkg);
+        return displayPackageFilePath(pkg, userId);
     }
 
     private int runDump() {
@@ -1637,7 +1650,7 @@
     }
 
     private int runClear() {
-        int userId = 0;
+        int userId = UserHandle.USER_OWNER;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
@@ -1709,7 +1722,7 @@
     }
 
     private int runSetEnabledSetting(int state) {
-        int userId = 0;
+        int userId = UserHandle.USER_OWNER;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
@@ -1758,7 +1771,7 @@
     }
 
     private int runSetHiddenSetting(boolean state) {
-        int userId = 0;
+        int userId = UserHandle.USER_OWNER;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
@@ -1963,9 +1976,9 @@
      * Displays the package file for a package.
      * @param pckg
      */
-    private int displayPackageFilePath(String pckg) {
+    private int displayPackageFilePath(String pckg, int userId) {
         try {
-            PackageInfo info = mPm.getPackageInfo(pckg, 0, 0);
+            PackageInfo info = mPm.getPackageInfo(pckg, 0, userId);
             if (info != null && info.applicationInfo != null) {
                 System.out.print("package:");
                 System.out.println(info.applicationInfo.sourceDir);
@@ -2104,7 +2117,7 @@
         System.err.println("       pm list features");
         System.err.println("       pm list libraries");
         System.err.println("       pm list users");
-        System.err.println("       pm path PACKAGE");
+        System.err.println("       pm path [--user USER_ID] PACKAGE");
         System.err.println("       pm dump PACKAGE");
         System.err.println("       pm install [-lrtsfd] [-i PACKAGE] [--user USER_ID] [PATH]");
         System.err.println("       pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]");
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index d331c2a..844063c 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -28,7 +28,6 @@
 
     /**
      * The value used to indicate infinite duration (e.g. when Animators repeat infinitely).
-     * @hide
      */
     public static final long DURATION_INFINITE = -1;
     /**
@@ -191,11 +190,18 @@
     /**
      * Gets the total duration of the animation, accounting for animation sequences, start delay,
      * and repeating. Return {@link #DURATION_INFINITE} if the duration is infinite.
-     * @hide
-     * TODO: Unhide
+     *
+     * @return  Total time an animation takes to finish, starting from the time {@link #start()}
+     *          is called. {@link #DURATION_INFINITE} will be returned if the animation or any
+     *          child animation repeats infinite times.
      */
     public long getTotalDuration() {
-        return getStartDelay() + getDuration();
+        long duration = getDuration();
+        if (duration == DURATION_INFINITE) {
+            return DURATION_INFINITE;
+        } else {
+            return getStartDelay() + duration;
+        }
     }
 
     /**
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index d444638..1ab55dd 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -1030,9 +1030,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
     @Override
     public long getTotalDuration() {
         updateAnimatorsDuration();
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 9b905bd..6f65889 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -126,12 +126,6 @@
             new AccelerateDecelerateInterpolator();
 
     /**
-     * Used to indicate whether the animation is currently playing in reverse. This causes the
-     * elapsed fraction to be inverted to calculate the appropriate values.
-     */
-    private boolean mPlayingBackwards = false;
-
-    /**
      * Flag to indicate whether this animator is playing in reverse mode, specifically
      * by being started or interrupted by a call to reverse(). This flag is different than
      * mPlayingBackwards, which indicates merely whether the current iteration of the
@@ -141,13 +135,13 @@
     private boolean mReversing;
 
     /**
-     * This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the
-     * repeatCount (if repeatCount!=INFINITE), the animation ends
+     * Tracks the overall fraction of the animation, ranging from 0 to mRepeatCount + 1
      */
-    private int mCurrentIteration = 0;
+    private float mOverallFraction = 0f;
 
     /**
      * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction().
+     * This is calculated by interpolating the fraction (range: [0, 1]) in the current iteration.
      */
     private float mCurrentFraction = 0f;
 
@@ -195,12 +189,12 @@
     //
 
     // How long the animation should last in ms
-    private long mUnscaledDuration = 300;
-    private long mDuration = (long)(mUnscaledDuration * sDurationScale);
+    private long mDuration = 300;
 
-    // The amount of time in ms to delay starting the animation after start() is called
-    long mStartDelay = 0;
-    private long mUnscaledStartDelay = 0;
+    // The amount of time in ms to delay starting the animation after start() is called. Note
+    // that this start delay is unscaled. When there is a duration scale set on the animator, the
+    // scaling factor will be applied to this delay.
+    private long mStartDelay = 0;
 
     // The number of times the animation will repeat. The default is 0, which means the animation
     // will play only once
@@ -524,13 +518,12 @@
             throw new IllegalArgumentException("Animators cannot have negative duration: " +
                     duration);
         }
-        mUnscaledDuration = duration;
-        updateScaledDuration();
+        mDuration = duration;
         return this;
     }
 
-    private void updateScaledDuration() {
-        mDuration = (long)(mUnscaledDuration * sDurationScale);
+    private long getScaledDuration() {
+        return (long)(mDuration * sDurationScale);
     }
 
     /**
@@ -540,18 +533,15 @@
      */
     @Override
     public long getDuration() {
-        return mUnscaledDuration;
+        return mDuration;
     }
 
-    /**
-     * @hide
-     */
     @Override
     public long getTotalDuration() {
         if (mRepeatCount == INFINITE) {
             return DURATION_INFINITE;
         } else {
-            return mUnscaledStartDelay + (mUnscaledDuration * (mRepeatCount + 1));
+            return mStartDelay + (mDuration * (mRepeatCount + 1));
         }
     }
 
@@ -566,7 +556,7 @@
      * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
      */
     public void setCurrentPlayTime(long playTime) {
-        float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration : 1;
+        float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
         setCurrentFraction(fraction);
     }
 
@@ -589,37 +579,82 @@
      */
     public void setCurrentFraction(float fraction) {
         initAnimation();
-        if (fraction < 0) {
-            fraction = 0;
-        }
-        int iteration = (int) fraction;
-        if (fraction == 1) {
-            iteration -= 1;
-        } else if (fraction > 1) {
-            if (iteration < (mRepeatCount + 1) || mRepeatCount == INFINITE) {
-                if (mRepeatMode == REVERSE) {
-                    mPlayingBackwards = (iteration % 2) != 0;
-                }
-                fraction = fraction % 1f;
-            } else {
-                fraction = 1;
-                iteration -= 1;
-            }
-        } else {
-            mPlayingBackwards = mReversing;
-        }
-        mCurrentIteration = iteration;
-        long seekTime = (long) (mDuration * fraction);
+        fraction = clampFraction(fraction);
+        long seekTime = (long) (getScaledDuration() * fraction);
         long currentTime = AnimationUtils.currentAnimationTimeMillis();
         mStartTime = currentTime - seekTime;
         mStartTimeCommitted = true; // do not allow start time to be compensated for jank
         if (!mRunning) {
             mSeekFraction = fraction;
         }
-        if (mPlayingBackwards) {
-            fraction = 1f - fraction;
+        mOverallFraction = fraction;
+        final float currentIterationFraction = getCurrentIterationFraction(fraction);
+        animateValue(currentIterationFraction);
+    }
+
+    /**
+     * Calculates current iteration based on the overall fraction. The overall fraction will be
+     * in the range of [0, mRepeatCount + 1]. Both current iteration and fraction in the current
+     * iteration can be derived from it.
+     */
+    private int getCurrentIteration(float fraction) {
+        fraction = clampFraction(fraction);
+        // If the overall fraction is a positive integer, we consider the current iteration to be
+        // complete. In other words, the fraction for the current iteration would be 1, and the
+        // current iteration would be overall fraction - 1.
+        double iteration = Math.floor(fraction);
+        if (fraction == iteration && fraction > 0) {
+            iteration--;
         }
-        animateValue(fraction);
+        return (int) iteration;
+    }
+
+    /**
+     * Calculates the fraction of the current iteration, taking into account whether the animation
+     * should be played backwards. E.g. When the animation is played backwards in an iteration,
+     * the fraction for that iteration will go from 1f to 0f.
+     */
+    private float getCurrentIterationFraction(float fraction) {
+        fraction = clampFraction(fraction);
+        int iteration = getCurrentIteration(fraction);
+        float currentFraction = fraction - iteration;
+        return shouldPlayBackward(iteration) ? 1f - currentFraction : currentFraction;
+    }
+
+    /**
+     * Clamps fraction into the correct range: [0, mRepeatCount + 1]. If repeat count is infinite,
+     * no upper bound will be set for the fraction.
+     *
+     * @param fraction fraction to be clamped
+     * @return fraction clamped into the range of [0, mRepeatCount + 1]
+     */
+    private float clampFraction(float fraction) {
+        if (fraction < 0) {
+            fraction = 0;
+        } else if (mRepeatCount != INFINITE) {
+            fraction = Math.min(fraction, mRepeatCount + 1);
+        }
+        return fraction;
+    }
+
+    /**
+     * Calculates the direction of animation playing (i.e. forward or backward), based on 1)
+     * whether the entire animation is being reversed, 2) repeat mode applied to the current
+     * iteration.
+     */
+    private boolean shouldPlayBackward(int iteration) {
+        if (iteration > 0 && mRepeatMode == REVERSE &&
+                (iteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) {
+            // if we were seeked to some other iteration in a reversing animator,
+            // figure out the correct direction to start playing based on the iteration
+            if (mReversing) {
+                return (iteration % 2) == 0;
+            } else {
+                return (iteration % 2) != 0;
+            }
+        } else {
+            return mReversing;
+        }
     }
 
     /**
@@ -636,9 +671,10 @@
             return 0;
         }
         if (mSeekFraction >= 0) {
-            return (long) (mUnscaledDuration * mSeekFraction);
+            return (long) (mDuration * mSeekFraction);
         }
-        return AnimationUtils.currentAnimationTimeMillis() - mStartTime;
+        float durationScale = sDurationScale == 0 ? 1 : sDurationScale;
+        return (long) ((AnimationUtils.currentAnimationTimeMillis() - mStartTime) / durationScale);
     }
 
     /**
@@ -649,7 +685,7 @@
      */
     @Override
     public long getStartDelay() {
-        return mUnscaledStartDelay;
+        return mStartDelay;
     }
 
     /**
@@ -660,8 +696,7 @@
      */
     @Override
     public void setStartDelay(long startDelay) {
-        this.mStartDelay = (long)(startDelay * sDurationScale);
-        mUnscaledStartDelay = startDelay;
+        mStartDelay = startDelay;
     }
 
     /**
@@ -907,40 +942,27 @@
             throw new AndroidRuntimeException("Animators may only be run on Looper threads");
         }
         mReversing = playBackwards;
-        mPlayingBackwards = playBackwards;
-        if (playBackwards && mSeekFraction != -1) {
-            if (mSeekFraction == 0 && mCurrentIteration == 0) {
-                // special case: reversing from seek-to-0 should act as if not seeked at all
-                mSeekFraction = 0;
-            } else if (mRepeatCount == INFINITE) {
-                mSeekFraction = 1 - (mSeekFraction % 1);
+        // Special case: reversing from seek-to-0 should act as if not seeked at all.
+        if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
+            if (mRepeatCount == INFINITE) {
+                // Calculate the fraction of the current iteration.
+                float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
+                mSeekFraction = 1 - fraction;
             } else {
-                mSeekFraction = 1 + mRepeatCount - (mCurrentIteration + mSeekFraction);
-            }
-            mCurrentIteration = (int) mSeekFraction;
-            mSeekFraction = mSeekFraction % 1;
-        }
-        if (mCurrentIteration > 0 && mRepeatMode == REVERSE &&
-                (mCurrentIteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) {
-            // if we were seeked to some other iteration in a reversing animator,
-            // figure out the correct direction to start playing based on the iteration
-            if (playBackwards) {
-                mPlayingBackwards = (mCurrentIteration % 2) == 0;
-            } else {
-                mPlayingBackwards = (mCurrentIteration % 2) != 0;
+                mSeekFraction = 1 + mRepeatCount - mSeekFraction;
             }
         }
         mStarted = true;
         mPaused = false;
         mRunning = false;
         mAnimationEndRequested = false;
-        updateScaledDuration(); // in case the scale factor has changed since creation time
         AnimationHandler animationHandler = AnimationHandler.getInstance();
-        animationHandler.addAnimationFrameCallback(this, mStartDelay);
+        animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
 
         if (mStartDelay == 0) {
             // If there's no start delay, init the animation and notify start listeners right away
-            // Otherwise, postpone this until the first frame after the start delay.
+            // to be consistent with the previous behavior. Otherwise, postpone this until the first
+            // frame after the start delay.
             startAnimation();
             setCurrentFraction(mSeekFraction == -1 ? 0 : mSeekFraction);
         }
@@ -993,7 +1015,7 @@
         } else if (!mInitialized) {
             initAnimation();
         }
-        animateValue(mPlayingBackwards ? 0f : 1f);
+        animateValue(shouldPlayBackward(mRepeatCount) ? 0f : 1f);
         endAnimation();
     }
 
@@ -1034,11 +1056,10 @@
      */
     @Override
     public void reverse() {
-        mPlayingBackwards = !mPlayingBackwards;
         if (mRunning) {
             long currentTime = AnimationUtils.currentAnimationTimeMillis();
             long currentPlayTime = currentTime - mStartTime;
-            long timeLeft = mDuration - currentPlayTime;
+            long timeLeft = getScaledDuration() - currentPlayTime;
             mStartTime = currentTime - timeLeft;
             mStartTimeCommitted = true; // do not allow start time to be compensated for jank
             mReversing = !mReversing;
@@ -1085,10 +1106,8 @@
         mRunning = false;
         mStarted = false;
         mStartListenersCalled = false;
-        mPlayingBackwards = false;
         mReversing = false;
         mLastFrameTime = 0;
-        mCurrentIteration = 0;
         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
             Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
                     System.identityHashCode(this));
@@ -1106,6 +1125,11 @@
         }
         initAnimation();
         mRunning = true;
+        if (mSeekFraction >= 0) {
+            mOverallFraction = mSeekFraction;
+        } else {
+            mOverallFraction = 0f;
+        }
         if (mListeners != null) {
             notifyStartListeners();
         }
@@ -1151,40 +1175,26 @@
     boolean animateBasedOnTime(long currentTime) {
         boolean done = false;
         if (mRunning) {
-            float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
-            if (mDuration == 0 && mRepeatCount != INFINITE) {
-                // Skip to the end
-                mCurrentIteration = mRepeatCount;
-                if (!mReversing) {
-                    mPlayingBackwards = false;
-                }
-            }
-            if (fraction >= 1f) {
-                if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
-                    // Time to repeat
-                    if (mListeners != null) {
-                        int numListeners = mListeners.size();
-                        for (int i = 0; i < numListeners; ++i) {
-                            mListeners.get(i).onAnimationRepeat(this);
-                        }
+            final float fraction = getScaledDuration() > 0 ?
+                    (float)(currentTime - mStartTime) / getScaledDuration() : 1f;
+            final float lastFraction = mOverallFraction;
+            final boolean newIteration = (int) fraction > (int) lastFraction;
+            final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
+                    (mRepeatCount != INFINITE);
+            if (newIteration && !lastIterationFinished) {
+                // Time to repeat
+                if (mListeners != null) {
+                    int numListeners = mListeners.size();
+                    for (int i = 0; i < numListeners; ++i) {
+                        mListeners.get(i).onAnimationRepeat(this);
                     }
-                    if (mRepeatMode == REVERSE) {
-                        mPlayingBackwards = !mPlayingBackwards;
-                    }
-                    mCurrentIteration += (int) fraction;
-                    fraction = fraction % 1f;
-                    mStartTime += mDuration;
-                    // Note: We do not need to update the value of mStartTimeCommitted here
-                    // since we just added a duration offset.
-                } else {
-                    done = true;
-                    fraction = Math.min(fraction, 1.0f);
                 }
+            } else if (lastIterationFinished) {
+                done = true;
             }
-            if (mPlayingBackwards) {
-                fraction = 1f - fraction;
-            }
-            animateValue(fraction);
+            mOverallFraction = clampFraction(fraction);
+            float currentIterationFraction = getCurrentIterationFraction(mOverallFraction);
+            animateValue(currentIterationFraction);
         }
         return done;
     }
@@ -1207,7 +1217,7 @@
             if (mSeekFraction < 0) {
                 mStartTime = frameTime;
             } else {
-                long seekTime = (long) (mDuration * mSeekFraction);
+                long seekTime = (long) (getScaledDuration() * mSeekFraction);
                 mStartTime = frameTime - seekTime;
                 mSeekFraction = -1;
             }
@@ -1285,9 +1295,7 @@
             anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(mUpdateListeners);
         }
         anim.mSeekFraction = -1;
-        anim.mPlayingBackwards = false;
         anim.mReversing = false;
-        anim.mCurrentIteration = 0;
         anim.mInitialized = false;
         anim.mStarted = false;
         anim.mRunning = false;
@@ -1299,6 +1307,7 @@
         anim.mAnimationEndRequested = false;
         anim.mPauseTime = 0;
         anim.mLastFrameTime = 0;
+        anim.mOverallFraction = 0;
         anim.mCurrentFraction = 0;
 
         PropertyValuesHolder[] oldValues = mValues;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index faa3a43..b97f947 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -757,9 +757,10 @@
 
         case RESIZE_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            int stackId = data.readInt();
+            final int stackId = data.readInt();
             Rect r = Rect.CREATOR.createFromParcel(data);
-            resizeStack(stackId, r);
+            final boolean allowResizeInDockedMode = data.readInt() == 1;
+            resizeStack(stackId, r, allowResizeInDockedMode);
             reply.writeNoException();
             return true;
         }
@@ -3554,13 +3555,15 @@
         reply.recycle();
     }
     @Override
-    public void resizeStack(int stackId, Rect r) throws RemoteException
+    public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode)
+            throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(stackId);
         r.writeToParcel(data, 0);
+        data.writeInt(allowResizeInDockedMode ? 1 : 0);
         mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f29dba2..e500e15 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1646,7 +1646,8 @@
             return false;
         }
         if (!forceAllowOnExternal
-                && app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+                && (app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY
+                        || app.installLocation == PackageInfo.INSTALL_LOCATION_UNSPECIFIED)) {
             return false;
         }
 
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index e23620d..c26a44c 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -143,7 +143,7 @@
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
     public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop)
             throws RemoteException;
-    public void resizeStack(int stackId, Rect bounds) throws RemoteException;
+    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) throws RemoteException;
     public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
     public List<StackInfo> getAllStackInfos() throws RemoteException;
     public StackInfo getStackInfo(int stackId) throws RemoteException;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index e5cfbf3..3f02f17 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -647,20 +647,18 @@
 
     /**
      * Open a private file associated with this Context's application package
-     * for writing.  Creates the file if it doesn't already exist.
-     *
-     * <p>No permissions are required to invoke this method, since it uses internal
-     * storage.
+     * for writing. Creates the file if it doesn't already exist.
+     * <p>
+     * No additional permissions are required for the calling app to read or
+     * write the returned file.
      *
      * @param name The name of the file to open; can not contain path
-     *             separators.
-     * @param mode Operating mode.  Use 0 or {@link #MODE_PRIVATE} for the
-     * default operation, {@link #MODE_APPEND} to append to an existing file,
-     * {@link #MODE_WORLD_READABLE} and {@link #MODE_WORLD_WRITEABLE} to control
-     * permissions.
-     *
+     *            separators.
+     * @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the
+     *            default operation, {@link #MODE_APPEND} to append to an
+     *            existing file, {@link #MODE_WORLD_READABLE} and
+     *            {@link #MODE_WORLD_WRITEABLE} to control permissions.
      * @return The resulting {@link FileOutputStream}.
-     *
      * @see #MODE_APPEND
      * @see #MODE_PRIVATE
      * @see #MODE_WORLD_READABLE
@@ -693,6 +691,9 @@
     /**
      * Returns the absolute path on the filesystem where a file created with
      * {@link #openFileOutput} is stored.
+     * <p>
+     * The returned path may change over time if the calling app is moved to an
+     * adopted storage device, so only relative paths should be persisted.
      *
      * @param name The name of the file for which you would like to get
      *          its path.
@@ -706,14 +707,16 @@
     public abstract File getFileStreamPath(String name);
 
     /**
-     * Returns the absolute path to the directory on the filesystem where
-     * files created with {@link #openFileOutput} are stored.
-     *
-     * <p>No permissions are required to read or write to the returned path, since this
-     * path is internal storage.
+     * Returns the absolute path to the directory on the filesystem where files
+     * created with {@link #openFileOutput} are stored.
+     * <p>
+     * The returned path may change over time if the calling app is moved to an
+     * adopted storage device, so only relative paths should be persisted.
+     * <p>
+     * No additional permissions are required for the calling app to read or
+     * write files under the returned path.
      *
      * @return The path of the directory holding application files.
-     *
      * @see #openFileOutput
      * @see #getFileStreamPath
      * @see #getDir
@@ -722,17 +725,19 @@
 
     /**
      * Returns the absolute path to the directory on the filesystem similar to
-     * {@link #getFilesDir()}.  The difference is that files placed under this
-     * directory will be excluded from automatic backup to remote storage.  See
+     * {@link #getFilesDir()}. The difference is that files placed under this
+     * directory will be excluded from automatic backup to remote storage. See
      * {@link android.app.backup.BackupAgent BackupAgent} for a full discussion
      * of the automatic backup mechanism in Android.
+     * <p>
+     * The returned path may change over time if the calling app is moved to an
+     * adopted storage device, so only relative paths should be persisted.
+     * <p>
+     * No additional permissions are required for the calling app to read or
+     * write files under the returned path.
      *
-     * <p>No permissions are required to read or write to the returned path, since this
-     * path is internal storage.
-     *
-     * @return The path of the directory holding application files that will not be
-     *         automatically backed up to remote storage.
-     *
+     * @return The path of the directory holding application files that will not
+     *         be automatically backed up to remote storage.
      * @see #openFileOutput
      * @see #getFileStreamPath
      * @see #getDir
@@ -741,200 +746,256 @@
     public abstract File getNoBackupFilesDir();
 
     /**
-     * Returns the absolute path to the directory on the primary external filesystem
-     * (that is somewhere on {@link android.os.Environment#getExternalStorageDirectory()
-     * Environment.getExternalStorageDirectory()}) where the application can
-     * place persistent files it owns.  These files are internal to the
-     * applications, and not typically visible to the user as media.
-     *
-     * <p>This is like {@link #getFilesDir()} in that these
-     * files will be deleted when the application is uninstalled, however there
-     * are some important differences:
-     *
+     * Returns the absolute path to the directory on the primary shared/external
+     * storage device where the application can place persistent files it owns.
+     * These files are internal to the applications, and not typically visible
+     * to the user as media.
+     * <p>
+     * This is like {@link #getFilesDir()} in that these files will be deleted
+     * when the application is uninstalled, however there are some important
+     * differences:
      * <ul>
-     * <li>External files are not always available: they will disappear if the
-     * user mounts the external storage on a computer or removes it.  See the
-     * APIs on {@link android.os.Environment} for information in the storage state.
-     * <li>There is no security enforced with these files.  For example, any application
-     * holding {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to
+     * <li>Shared storage may not always be available, since removable media can
+     * be ejected by the user. Media state can be checked using
+     * {@link Environment#getExternalStorageState(File)}.
+     * <li>There is no security enforced with these files. For example, any
+     * application holding
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to
      * these files.
      * </ul>
-     *
-     * <p>Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
+     * <p>
+     * If a shared storage device is emulated (as determined by
+     * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+     * backed by a private user data partition, which means there is little
+     * benefit to storing data here instead of the private directories returned
+     * by {@link #getFilesDir()}, etc.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
      * are required to read or write to the returned path; it's always
-     * accessible to the calling app.  This only applies to paths generated for
-     * package name of the calling application.  To access paths belonging
-     * to other packages, {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
-     * and/or {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required.
-     *
-     * <p>On devices with multiple users (as described by {@link UserManager}),
-     * each user has their own isolated external storage. Applications only
-     * have access to the external storage for the user they're running as.</p>
-     *
-     * <p>Here is an example of typical code to manipulate a file in
-     * an application's private storage:</p>
-     *
+     * accessible to the calling app. This only applies to paths generated for
+     * package name of the calling application. To access paths belonging to
+     * other packages,
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} and/or
+     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required.
+     * <p>
+     * On devices with multiple users (as described by {@link UserManager}),
+     * each user has their own isolated shared storage. Applications only have
+     * access to the shared storage for the user they're running as.
+     * <p>
+     * The returned path may change over time if different shared storage media
+     * is inserted, so only relative paths should be persisted.
+     * <p>
+     * Here is an example of typical code to manipulate a file in an
+     * application's shared storage:
+     * </p>
      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
      * private_file}
-     *
-     * <p>If you supply a non-null <var>type</var> to this function, the returned
-     * file will be a path to a sub-directory of the given type.  Though these files
-     * are not automatically scanned by the media scanner, you can explicitly
-     * add them to the media database with
-     * {@link android.media.MediaScannerConnection#scanFile(Context, String[], String[],
-     *      android.media.MediaScannerConnection.OnScanCompletedListener)
-     *      MediaScannerConnection.scanFile}.
-     * Note that this is not the same as
+     * <p>
+     * If you supply a non-null <var>type</var> to this function, the returned
+     * file will be a path to a sub-directory of the given type. Though these
+     * files are not automatically scanned by the media scanner, you can
+     * explicitly add them to the media database with
+     * {@link android.media.MediaScannerConnection#scanFile(Context, String[], String[], android.media.MediaScannerConnection.OnScanCompletedListener)
+     * MediaScannerConnection.scanFile}. Note that this is not the same as
      * {@link android.os.Environment#getExternalStoragePublicDirectory
      * Environment.getExternalStoragePublicDirectory()}, which provides
-     * directories of media shared by all applications.  The
-     * directories returned here are
-     * owned by the application, and their contents will be removed when the
-     * application is uninstalled.  Unlike
+     * directories of media shared by all applications. The directories returned
+     * here are owned by the application, and their contents will be removed
+     * when the application is uninstalled. Unlike
      * {@link android.os.Environment#getExternalStoragePublicDirectory
-     * Environment.getExternalStoragePublicDirectory()}, the directory
-     * returned here will be automatically created for you.
-     *
-     * <p>Here is an example of typical code to manipulate a picture in
-     * an application's private storage and add it to the media database:</p>
-     *
+     * Environment.getExternalStoragePublicDirectory()}, the directory returned
+     * here will be automatically created for you.
+     * <p>
+     * Here is an example of typical code to manipulate a picture in an
+     * application's shared storage and add it to the media database:
+     * </p>
      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
      * private_picture}
      *
-     * @param type The type of files directory to return.  May be null for
-     * the root of the files directory or one of
-     * the following Environment constants for a subdirectory:
-     * {@link android.os.Environment#DIRECTORY_MUSIC},
-     * {@link android.os.Environment#DIRECTORY_PODCASTS},
-     * {@link android.os.Environment#DIRECTORY_RINGTONES},
-     * {@link android.os.Environment#DIRECTORY_ALARMS},
-     * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
-     * {@link android.os.Environment#DIRECTORY_PICTURES}, or
-     * {@link android.os.Environment#DIRECTORY_MOVIES}.
-     *
-     * @return The path of the directory holding application files
-     * on external storage.  Returns null if external storage is not currently
-     * mounted so it could not ensure the path exists; you will need to call
-     * this method again when it is available.
-     *
+     * @param type The type of files directory to return. May be {@code null}
+     *            for the root of the files directory or one of the following
+     *            constants for a subdirectory:
+     *            {@link android.os.Environment#DIRECTORY_MUSIC},
+     *            {@link android.os.Environment#DIRECTORY_PODCASTS},
+     *            {@link android.os.Environment#DIRECTORY_RINGTONES},
+     *            {@link android.os.Environment#DIRECTORY_ALARMS},
+     *            {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
+     *            {@link android.os.Environment#DIRECTORY_PICTURES}, or
+     *            {@link android.os.Environment#DIRECTORY_MOVIES}.
+     * @return the absolute path to application-specific directory. May return
+     *         {@code null} if shared storage is not currently available.
      * @see #getFilesDir
-     * @see android.os.Environment#getExternalStoragePublicDirectory
+     * @see #getExternalFilesDirs(String)
+     * @see Environment#getExternalStorageState(File)
+     * @see Environment#isExternalStorageEmulated(File)
+     * @see Environment#isExternalStorageRemovable(File)
      */
     @Nullable
     public abstract File getExternalFilesDir(@Nullable String type);
 
     /**
      * Returns absolute paths to application-specific directories on all
-     * external storage devices where the application can place persistent files
-     * it owns. These files are internal to the application, and not typically
-     * visible to the user as media.
+     * shared/external storage devices where the application can place
+     * persistent files it owns. These files are internal to the application,
+     * and not typically visible to the user as media.
      * <p>
-     * This is like {@link #getFilesDir()} in that these files will be deleted when
-     * the application is uninstalled, however there are some important differences:
+     * This is like {@link #getFilesDir()} in that these files will be deleted
+     * when the application is uninstalled, however there are some important
+     * differences:
      * <ul>
-     * <li>External files are not always available: they will disappear if the
-     * user mounts the external storage on a computer or removes it.
-     * <li>There is no security enforced with these files.
+     * <li>Shared storage may not always be available, since removable media can
+     * be ejected by the user. Media state can be checked using
+     * {@link Environment#getExternalStorageState(File)}.
+     * <li>There is no security enforced with these files. For example, any
+     * application holding
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to
+     * these files.
      * </ul>
      * <p>
-     * External storage devices returned here are considered a permanent part of
-     * the device, including both emulated external storage and physical media
-     * slots, such as SD cards in a battery compartment. The returned paths do
-     * not include transient devices, such as USB flash drives.
+     * If a shared storage device is emulated (as determined by
+     * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+     * backed by a private user data partition, which means there is little
+     * benefit to storing data here instead of the private directories returned
+     * by {@link #getFilesDir()}, etc.
      * <p>
-     * An application may store data on any or all of the returned devices.  For
+     * Shared storage devices returned here are considered a stable part of the
+     * device, including physical media slots under a protective cover. The
+     * returned paths do not include transient devices, such as USB flash drives
+     * connected to handheld devices.
+     * <p>
+     * An application may store data on any or all of the returned devices. For
      * example, an app may choose to store large files on the device with the
      * most available space, as measured by {@link StatFs}.
      * <p>
-     * No permissions are required to read or write to the returned paths; they
-     * are always accessible to the calling app.  Write access outside of these
-     * paths on secondary external storage devices is not available.
+     * No additional permissions are required for the calling app to read or
+     * write files under the returned path. Write access outside of these paths
+     * on secondary external storage devices is not available.
      * <p>
-     * The first path returned is the same as {@link #getExternalFilesDir(String)}.
-     * Returned paths may be {@code null} if a storage device is unavailable.
+     * The returned path may change over time if different shared storage media
+     * is inserted, so only relative paths should be persisted.
      *
+     * @param type The type of files directory to return. May be {@code null}
+     *            for the root of the files directory or one of the following
+     *            constants for a subdirectory:
+     *            {@link android.os.Environment#DIRECTORY_MUSIC},
+     *            {@link android.os.Environment#DIRECTORY_PODCASTS},
+     *            {@link android.os.Environment#DIRECTORY_RINGTONES},
+     *            {@link android.os.Environment#DIRECTORY_ALARMS},
+     *            {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
+     *            {@link android.os.Environment#DIRECTORY_PICTURES}, or
+     *            {@link android.os.Environment#DIRECTORY_MOVIES}.
+     * @return the absolute paths to application-specific directories. Some
+     *         individual paths may be {@code null} if that shared storage is
+     *         not currently available. The first path returned is the same as
+     *         {@link #getExternalFilesDir(String)}.
      * @see #getExternalFilesDir(String)
      * @see Environment#getExternalStorageState(File)
+     * @see Environment#isExternalStorageEmulated(File)
+     * @see Environment#isExternalStorageRemovable(File)
      */
     public abstract File[] getExternalFilesDirs(String type);
 
     /**
-     * Return the primary external storage directory where this application's OBB
-     * files (if there are any) can be found. Note if the application does not have
-     * any OBB files, this directory may not exist.
+     * Return the primary shared/external storage directory where this
+     * application's OBB files (if there are any) can be found. Note if the
+     * application does not have any OBB files, this directory may not exist.
      * <p>
-     * This is like {@link #getFilesDir()} in that these files will be deleted when
-     * the application is uninstalled, however there are some important differences:
+     * This is like {@link #getFilesDir()} in that these files will be deleted
+     * when the application is uninstalled, however there are some important
+     * differences:
      * <ul>
-     * <li>External files are not always available: they will disappear if the
-     * user mounts the external storage on a computer or removes it.
-     * <li>There is no security enforced with these files.  For example, any application
-     * holding {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to
+     * <li>Shared storage may not always be available, since removable media can
+     * be ejected by the user. Media state can be checked using
+     * {@link Environment#getExternalStorageState(File)}.
+     * <li>There is no security enforced with these files. For example, any
+     * application holding
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to
      * these files.
      * </ul>
      * <p>
      * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
      * are required to read or write to the returned path; it's always
-     * accessible to the calling app.  This only applies to paths generated for
-     * package name of the calling application.  To access paths belonging
-     * to other packages, {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
-     * and/or {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required.
+     * accessible to the calling app. This only applies to paths generated for
+     * package name of the calling application. To access paths belonging to
+     * other packages,
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} and/or
+     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required.
      * <p>
      * On devices with multiple users (as described by {@link UserManager}),
      * multiple users may share the same OBB storage location. Applications
      * should ensure that multiple instances running under different users don't
      * interfere with each other.
+     *
+     * @return the absolute path to application-specific directory. May return
+     *         {@code null} if shared storage is not currently available.
+     * @see #getObbDirs()
+     * @see Environment#getExternalStorageState(File)
+     * @see Environment#isExternalStorageEmulated(File)
+     * @see Environment#isExternalStorageRemovable(File)
      */
     public abstract File getObbDir();
 
     /**
      * Returns absolute paths to application-specific directories on all
-     * external storage devices where the application's OBB files (if there are
-     * any) can be found. Note if the application does not have any OBB files,
-     * these directories may not exist.
+     * shared/external storage devices where the application's OBB files (if
+     * there are any) can be found. Note if the application does not have any
+     * OBB files, these directories may not exist.
      * <p>
-     * This is like {@link #getFilesDir()} in that these files will be deleted when
-     * the application is uninstalled, however there are some important differences:
+     * This is like {@link #getFilesDir()} in that these files will be deleted
+     * when the application is uninstalled, however there are some important
+     * differences:
      * <ul>
-     * <li>External files are not always available: they will disappear if the
-     * user mounts the external storage on a computer or removes it.
-     * <li>There is no security enforced with these files.
+     * <li>Shared storage may not always be available, since removable media can
+     * be ejected by the user. Media state can be checked using
+     * {@link Environment#getExternalStorageState(File)}.
+     * <li>There is no security enforced with these files. For example, any
+     * application holding
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to
+     * these files.
      * </ul>
      * <p>
-     * External storage devices returned here are considered a permanent part of
-     * the device, including both emulated external storage and physical media
-     * slots, such as SD cards in a battery compartment. The returned paths do
-     * not include transient devices, such as USB flash drives.
+     * Shared storage devices returned here are considered a stable part of the
+     * device, including physical media slots under a protective cover. The
+     * returned paths do not include transient devices, such as USB flash drives
+     * connected to handheld devices.
      * <p>
-     * An application may store data on any or all of the returned devices.  For
+     * An application may store data on any or all of the returned devices. For
      * example, an app may choose to store large files on the device with the
      * most available space, as measured by {@link StatFs}.
      * <p>
-     * No permissions are required to read or write to the returned paths; they
-     * are always accessible to the calling app.  Write access outside of these
-     * paths on secondary external storage devices is not available.
-     * <p>
-     * The first path returned is the same as {@link #getObbDir()}.
-     * Returned paths may be {@code null} if a storage device is unavailable.
+     * No additional permissions are required for the calling app to read or
+     * write files under the returned path. Write access outside of these paths
+     * on secondary external storage devices is not available.
      *
+     * @return the absolute paths to application-specific directories. Some
+     *         individual paths may be {@code null} if that shared storage is
+     *         not currently available. The first path returned is the same as
+     *         {@link #getObbDir()}
      * @see #getObbDir()
      * @see Environment#getExternalStorageState(File)
+     * @see Environment#isExternalStorageEmulated(File)
+     * @see Environment#isExternalStorageRemovable(File)
      */
     public abstract File[] getObbDirs();
 
     /**
-     * Returns the absolute path to the application specific cache directory
-     * on the filesystem. These files will be ones that get deleted first when the
-     * device runs low on storage.
-     * There is no guarantee when these files will be deleted.
-     *
+     * Returns the absolute path to the application specific cache directory on
+     * the filesystem. These files will be ones that get deleted first when the
+     * device runs low on storage. There is no guarantee when these files will
+     * be deleted.
+     * <p>
      * <strong>Note: you should not <em>rely</em> on the system deleting these
      * files for you; you should always have a reasonable maximum, such as 1 MB,
      * for the amount of space you consume with cache files, and prune those
      * files when exceeding that space.</strong>
+     * <p>
+     * The returned path may change over time if the calling app is moved to an
+     * adopted storage device, so only relative paths should be persisted.
+     * <p>
+     * Apps require no extra permissions to read or write to the returned path,
+     * since this path lives in their private storage.
      *
      * @return The path of the directory holding application cache files.
-     *
      * @see #openFileOutput
      * @see #getFileStreamPath
      * @see #getDir
@@ -950,6 +1011,9 @@
      * This location is optimal for storing compiled or optimized code generated
      * by your application at runtime.
      * <p>
+     * The returned path may change over time if the calling app is moved to an
+     * adopted storage device, so only relative paths should be persisted.
+     * <p>
      * Apps require no extra permissions to read or write to the returned path,
      * since this path lives in their private storage.
      *
@@ -958,120 +1022,161 @@
     public abstract File getCodeCacheDir();
 
     /**
-     * Returns the absolute path to the directory on the primary external filesystem
-     * (that is somewhere on {@link android.os.Environment#getExternalStorageDirectory()
-     * Environment.getExternalStorageDirectory()} where the application can
-     * place cache files it owns. These files are internal to the application, and
-     * not typically visible to the user as media.
-     *
-     * <p>This is like {@link #getCacheDir()} in that these
-     * files will be deleted when the application is uninstalled, however there
-     * are some important differences:
-     *
+     * Returns absolute path to application-specific directory on the primary
+     * shared/external storage device where the application can place cache
+     * files it owns. These files are internal to the application, and not
+     * typically visible to the user as media.
+     * <p>
+     * This is like {@link #getCacheDir()} in that these files will be deleted
+     * when the application is uninstalled, however there are some important
+     * differences:
      * <ul>
-     * <li>The platform does not always monitor the space available in external
-     * storage, and thus may not automatically delete these files.  Currently
-     * the only time files here will be deleted by the platform is when running
-     * on {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} or later and
-     * {@link android.os.Environment#isExternalStorageEmulated()
-     * Environment.isExternalStorageEmulated()} returns true.  Note that you should
-     * be managing the maximum space you will use for these anyway, just like
-     * with {@link #getCacheDir()}.
-     * <li>External files are not always available: they will disappear if the
-     * user mounts the external storage on a computer or removes it.  See the
-     * APIs on {@link android.os.Environment} for information in the storage state.
-     * <li>There is no security enforced with these files.  For example, any application
-     * holding {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to
+     * <li>The platform does not always monitor the space available in shared
+     * storage, and thus may not automatically delete these files. Apps should
+     * always manage the maximum space used in this location. Currently the only
+     * time files here will be deleted by the platform is when running on
+     * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} or later and
+     * {@link Environment#isExternalStorageEmulated(File)} returns true.
+     * <li>Shared storage may not always be available, since removable media can
+     * be ejected by the user. Media state can be checked using
+     * {@link Environment#getExternalStorageState(File)}.
+     * <li>There is no security enforced with these files. For example, any
+     * application holding
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to
      * these files.
      * </ul>
-     *
-     * <p>Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
+     * <p>
+     * If a shared storage device is emulated (as determined by
+     * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+     * backed by a private user data partition, which means there is little
+     * benefit to storing data here instead of the private directory returned by
+     * {@link #getCacheDir()}.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
      * are required to read or write to the returned path; it's always
-     * accessible to the calling app.  This only applies to paths generated for
-     * package name of the calling application.  To access paths belonging
-     * to other packages, {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
-     * and/or {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required.
+     * accessible to the calling app. This only applies to paths generated for
+     * package name of the calling application. To access paths belonging to
+     * other packages,
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} and/or
+     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required.
+     * <p>
+     * On devices with multiple users (as described by {@link UserManager}),
+     * each user has their own isolated shared storage. Applications only have
+     * access to the shared storage for the user they're running as.
+     * <p>
+     * The returned path may change over time if different shared storage media
+     * is inserted, so only relative paths should be persisted.
      *
-     * <p>On devices with multiple users (as described by {@link UserManager}),
-     * each user has their own isolated external storage. Applications only
-     * have access to the external storage for the user they're running as.</p>
-     *
-     * @return The path of the directory holding application cache files
-     * on external storage.  Returns null if external storage is not currently
-     * mounted so it could not ensure the path exists; you will need to call
-     * this method again when it is available.
-     *
+     * @return the absolute path to application-specific directory. May return
+     *         {@code null} if shared storage is not currently available.
      * @see #getCacheDir
+     * @see #getExternalCacheDirs()
+     * @see Environment#getExternalStorageState(File)
+     * @see Environment#isExternalStorageEmulated(File)
+     * @see Environment#isExternalStorageRemovable(File)
      */
     @Nullable
     public abstract File getExternalCacheDir();
 
     /**
      * Returns absolute paths to application-specific directories on all
-     * external storage devices where the application can place cache files it
-     * owns. These files are internal to the application, and not typically
-     * visible to the user as media.
+     * shared/external storage devices where the application can place cache
+     * files it owns. These files are internal to the application, and not
+     * typically visible to the user as media.
      * <p>
-     * This is like {@link #getCacheDir()} in that these files will be deleted when
-     * the application is uninstalled, however there are some important differences:
+     * This is like {@link #getCacheDir()} in that these files will be deleted
+     * when the application is uninstalled, however there are some important
+     * differences:
      * <ul>
-     * <li>External files are not always available: they will disappear if the
-     * user mounts the external storage on a computer or removes it.
-     * <li>There is no security enforced with these files.
+     * <li>The platform does not always monitor the space available in shared
+     * storage, and thus may not automatically delete these files. Apps should
+     * always manage the maximum space used in this location. Currently the only
+     * time files here will be deleted by the platform is when running on
+     * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} or later and
+     * {@link Environment#isExternalStorageEmulated(File)} returns true.
+     * <li>Shared storage may not always be available, since removable media can
+     * be ejected by the user. Media state can be checked using
+     * {@link Environment#getExternalStorageState(File)}.
+     * <li>There is no security enforced with these files. For example, any
+     * application holding
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to
+     * these files.
      * </ul>
      * <p>
-     * External storage devices returned here are considered a permanent part of
-     * the device, including both emulated external storage and physical media
-     * slots, such as SD cards in a battery compartment. The returned paths do
-     * not include transient devices, such as USB flash drives.
+     * If a shared storage device is emulated (as determined by
+     * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+     * backed by a private user data partition, which means there is little
+     * benefit to storing data here instead of the private directory returned by
+     * {@link #getCacheDir()}.
      * <p>
-     * An application may store data on any or all of the returned devices.  For
+     * Shared storage devices returned here are considered a stable part of the
+     * device, including physical media slots under a protective cover. The
+     * returned paths do not include transient devices, such as USB flash drives
+     * connected to handheld devices.
+     * <p>
+     * An application may store data on any or all of the returned devices. For
      * example, an app may choose to store large files on the device with the
      * most available space, as measured by {@link StatFs}.
      * <p>
-     * No permissions are required to read or write to the returned paths; they
-     * are always accessible to the calling app.  Write access outside of these
-     * paths on secondary external storage devices is not available.
+     * No additional permissions are required for the calling app to read or
+     * write files under the returned path. Write access outside of these paths
+     * on secondary external storage devices is not available.
      * <p>
-     * The first path returned is the same as {@link #getExternalCacheDir()}.
-     * Returned paths may be {@code null} if a storage device is unavailable.
+     * The returned paths may change over time if different shared storage media
+     * is inserted, so only relative paths should be persisted.
      *
+     * @return the absolute paths to application-specific directories. Some
+     *         individual paths may be {@code null} if that shared storage is
+     *         not currently available. The first path returned is the same as
+     *         {@link #getExternalCacheDir()}.
      * @see #getExternalCacheDir()
      * @see Environment#getExternalStorageState(File)
+     * @see Environment#isExternalStorageEmulated(File)
+     * @see Environment#isExternalStorageRemovable(File)
      */
     public abstract File[] getExternalCacheDirs();
 
     /**
      * Returns absolute paths to application-specific directories on all
-     * external storage devices where the application can place media files.
-     * These files are scanned and made available to other apps through
+     * shared/external storage devices where the application can place media
+     * files. These files are scanned and made available to other apps through
      * {@link MediaStore}.
      * <p>
      * This is like {@link #getExternalFilesDirs} in that these files will be
      * deleted when the application is uninstalled, however there are some
      * important differences:
      * <ul>
-     * <li>External files are not always available: they will disappear if the
-     * user mounts the external storage on a computer or removes it.
-     * <li>There is no security enforced with these files.
+     * <li>Shared storage may not always be available, since removable media can
+     * be ejected by the user. Media state can be checked using
+     * {@link Environment#getExternalStorageState(File)}.
+     * <li>There is no security enforced with these files. For example, any
+     * application holding
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} can write to
+     * these files.
      * </ul>
      * <p>
-     * External storage devices returned here are considered a permanent part of
-     * the device, including both emulated external storage and physical media
-     * slots, such as SD cards in a battery compartment. The returned paths do
-     * not include transient devices, such as USB flash drives.
+     * Shared storage devices returned here are considered a stable part of the
+     * device, including physical media slots under a protective cover. The
+     * returned paths do not include transient devices, such as USB flash drives
+     * connected to handheld devices.
      * <p>
      * An application may store data on any or all of the returned devices. For
      * example, an app may choose to store large files on the device with the
      * most available space, as measured by {@link StatFs}.
      * <p>
-     * No permissions are required to read or write to the returned paths; they
-     * are always accessible to the calling app. Write access outside of these
-     * paths on secondary external storage devices is not available.
+     * No additional permissions are required for the calling app to read or
+     * write files under the returned path. Write access outside of these paths
+     * on secondary external storage devices is not available.
      * <p>
-     * Returned paths may be {@code null} if a storage device is unavailable.
+     * The returned paths may change over time if different shared storage media
+     * is inserted, so only relative paths should be persisted.
      *
+     * @return the absolute paths to application-specific directories. Some
+     *         individual paths may be {@code null} if that shared storage is
+     *         not currently available.
      * @see Environment#getExternalStorageState(File)
+     * @see Environment#isExternalStorageEmulated(File)
+     * @see Environment#isExternalStorageRemovable(File)
      */
     public abstract File[] getExternalMediaDirs();
 
@@ -1094,6 +1199,12 @@
      * created through a File object will only be accessible by your own
      * application; you can only set the mode of the entire directory, not
      * of individual files.
+     * <p>
+     * The returned path may change over time if the calling app is moved to an
+     * adopted storage device, so only relative paths should be persisted.
+     * <p>
+     * Apps require no extra permissions to read or write to the returned path,
+     * since this path lives in their private storage.
      *
      * @param name Name of the directory to retrieve.  This is a directory
      * that is created as part of your application data.
@@ -1177,6 +1288,9 @@
     /**
      * Returns the absolute path on the filesystem where a database created with
      * {@link #openOrCreateDatabase} is stored.
+     * <p>
+     * The returned path may change over time if the calling app is moved to an
+     * adopted storage device, so only relative paths should be persisted.
      *
      * @param name The name of the database for which you would like to get
      *          its path.
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index a121b4d..3853772 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -67,7 +67,7 @@
      * The launch mode style requested by the activity.  From the
      * {@link android.R.attr#launchMode} attribute, one of
      * {@link #LAUNCH_MULTIPLE},
-     * {@link #LAUNCH_SINGLE_TOP}, {@link #LAUNCH_SINGLE_TASK}, or 
+     * {@link #LAUNCH_SINGLE_TOP}, {@link #LAUNCH_SINGLE_TASK}, or
      * {@link #LAUNCH_SINGLE_INSTANCE}.
      */
     public int launchMode;
@@ -140,7 +140,7 @@
      * Activity.  From the "permission" attribute.
      */
     public String permission;
-    
+
     /**
      * The affinity this activity has for another task in the system.  The
      * string here is the name of the task, often the package name of the
@@ -148,13 +148,13 @@
      * {@link android.R.attr#taskAffinity} attribute.
      */
     public String taskAffinity;
-    
+
     /**
      * If this is an activity alias, this is the real activity class to run
      * for it.  Otherwise, this is null.
      */
     public String targetActivity;
-    
+
     /**
      * Bit in {@link #flags} indicating whether this activity is able to
      * run in multiple processes.  If
@@ -362,7 +362,7 @@
      * the {@link android.R.attr#screenOrientation} attribute.
      */
     public static final int SCREEN_ORIENTATION_SENSOR = 4;
-  
+
     /**
      * Constant corresponding to <code>nosensor</code> in
      * the {@link android.R.attr#screenOrientation} attribute.
@@ -427,7 +427,7 @@
      * The preferred screen orientation this activity would like to run in.
      * From the {@link android.R.attr#screenOrientation} attribute, one of
      * {@link #SCREEN_ORIENTATION_UNSPECIFIED},
-     * {@link #SCREEN_ORIENTATION_LANDSCAPE}, 
+     * {@link #SCREEN_ORIENTATION_LANDSCAPE},
      * {@link #SCREEN_ORIENTATION_PORTRAIT},
      * {@link #SCREEN_ORIENTATION_USER},
      * {@link #SCREEN_ORIENTATION_BEHIND},
@@ -445,7 +445,7 @@
      */
     @ScreenOrientation
     public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
-    
+
     /**
      * Bit in {@link #configChanges} that indicates that the activity
      * can itself handle changes to the IMSI MCC.  Set from the
@@ -552,7 +552,7 @@
      * constant starts at the high bits.
      */
     public static final int CONFIG_FONT_SCALE = 0x40000000;
-    
+
     /** @hide
      * Unfortunately the constants for config changes in native code are
      * different from ActivityInfo. :(  Here are the values we should use for the
@@ -702,7 +702,7 @@
      */
     public int lockTaskLaunchMode;
 
-    public InitialLayout initialLayout;
+    public Layout layout;
 
     public ActivityInfo() {
     }
@@ -724,7 +724,7 @@
         maxRecents = orig.maxRecents;
         resizeable = orig.resizeable;
         lockTaskLaunchMode = orig.lockTaskLaunchMode;
-        initialLayout = orig.initialLayout;
+        layout = orig.layout;
     }
 
     /**
@@ -771,10 +771,10 @@
         }
         pw.println(prefix + "resizeable=" + resizeable + " lockTaskLaunchMode="
                 + lockTaskLaunchModeToString(lockTaskLaunchMode));
-        if (initialLayout != null) {
-            pw.println(prefix + "initialLayout=" + initialLayout.width + "|"
-                    + initialLayout.widthFraction + ", " + initialLayout.height + "|"
-                    + initialLayout.heightFraction + ", " + initialLayout.gravity);
+        if (layout != null) {
+            pw.println(prefix + "initialLayout=" + layout.width + "|"
+                    + layout.widthFraction + ", " + layout.height + "|"
+                    + layout.heightFraction + ", " + layout.gravity);
         }
         super.dumpBack(pw, prefix);
     }
@@ -807,13 +807,14 @@
         dest.writeInt(maxRecents);
         dest.writeInt(resizeable ? 1 : 0);
         dest.writeInt(lockTaskLaunchMode);
-        if (initialLayout != null) {
+        if (layout != null) {
             dest.writeInt(1);
-            dest.writeInt(initialLayout.width);
-            dest.writeFloat(initialLayout.widthFraction);
-            dest.writeInt(initialLayout.height);
-            dest.writeFloat(initialLayout.heightFraction);
-            dest.writeInt(initialLayout.gravity);
+            dest.writeInt(layout.width);
+            dest.writeFloat(layout.widthFraction);
+            dest.writeInt(layout.height);
+            dest.writeFloat(layout.heightFraction);
+            dest.writeInt(layout.gravity);
+            dest.writeInt(layout.minimalSize);
         } else {
             dest.writeInt(0);
         }
@@ -848,26 +849,28 @@
         resizeable = (source.readInt() == 1);
         lockTaskLaunchMode = source.readInt();
         if (source.readInt() == 1) {
-            initialLayout = new InitialLayout(source);
+            layout = new Layout(source);
         }
     }
 
-    public static final class InitialLayout {
-        public InitialLayout(int width, float widthFraction, int height, float heightFraction,
-                int gravity) {
+    public static final class Layout {
+        public Layout(int width, float widthFraction, int height, float heightFraction, int gravity,
+                int minimalSize) {
             this.width = width;
             this.widthFraction = widthFraction;
             this.height = height;
             this.heightFraction = heightFraction;
             this.gravity = gravity;
+            this.minimalSize = minimalSize;
         }
 
-        InitialLayout(Parcel source) {
+        Layout(Parcel source) {
             width = source.readInt();
             widthFraction = source.readFloat();
             height = source.readInt();
             heightFraction = source.readFloat();
             gravity = source.readInt();
+            minimalSize = source.readInt();
         }
 
         public final int width;
@@ -875,5 +878,6 @@
         public final int height;
         public final float heightFraction;
         public final int gravity;
+        public final int minimalSize;
     }
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 1a8602b..bf54415 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -128,7 +128,7 @@
         public final String name;
         public final int sdkVersion;
         public final int fileVersion;
-        
+
         public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
             this.name = name;
             this.sdkVersion = sdkVersion;
@@ -215,10 +215,10 @@
         final int iconRes;
         final int logoRes;
         final int bannerRes;
-        
+
         String tag;
         TypedArray sa;
-        
+
         ParsePackageItemArgs(Package _owner, String[] _outError,
                 int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes) {
             owner = _owner;
@@ -230,14 +230,14 @@
             bannerRes = _bannerRes;
         }
     }
-    
+
     static class ParseComponentArgs extends ParsePackageItemArgs {
         final String[] sepProcesses;
         final int processRes;
         final int descriptionRes;
         final int enabledRes;
         int flags;
-        
+
         ParseComponentArgs(Package _owner, String[] _outError,
                 int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes,
                 String[] _sepProcesses, int _processRes,
@@ -349,7 +349,7 @@
     private ParseComponentArgs mParseActivityAliasArgs;
     private ParseComponentArgs mParseServiceArgs;
     private ParseComponentArgs mParseProviderArgs;
-    
+
     /** If set to true, we will only allow package files that exactly match
      *  the DTD.  Otherwise, we try to get as much from the package as we
      *  can without failing.  This should normally be set to false, to
@@ -1456,7 +1456,7 @@
         int supportsXLargeScreens = 1;
         int resizeable = 1;
         int anyDensity = 1;
-        
+
         int outerDepth = parser.getDepth();
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -1612,7 +1612,7 @@
                     String minCode = null;
                     int targetVers = 0;
                     String targetCode = null;
-                    
+
                     TypedValue val = sa.peekValue(
                             com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
                     if (val != null) {
@@ -1623,7 +1623,7 @@
                             targetVers = minVers = val.data;
                         }
                     }
-                    
+
                     val = sa.peekValue(
                             com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
                     if (val != null) {
@@ -1634,7 +1634,7 @@
                             targetVers = val.data;
                         }
                     }
-                    
+
                     sa.recycle();
 
                     if (minCode != null) {
@@ -1663,7 +1663,7 @@
                         mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
                         return null;
                     }
-                    
+
                     if (targetCode != null) {
                         boolean allowedCodename = false;
                         for (String codename : SDK_CODENAMES) {
@@ -1730,9 +1730,9 @@
                         anyDensity);
 
                 sa.recycle();
-                
+
                 XmlUtils.skipCurrentTag(parser);
-                
+
             } else if (tagName.equals("protected-broadcast")) {
                 sa = res.obtainAttributes(attrs,
                         com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
@@ -1754,12 +1754,12 @@
                 }
 
                 XmlUtils.skipCurrentTag(parser);
-                
+
             } else if (tagName.equals("instrumentation")) {
                 if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
                     return null;
                 }
-                
+
             } else if (tagName.equals("original-package")) {
                 sa = res.obtainAttributes(attrs,
                         com.android.internal.R.styleable.AndroidManifestOriginalPackage);
@@ -1777,7 +1777,7 @@
                 sa.recycle();
 
                 XmlUtils.skipCurrentTag(parser);
-                
+
             } else if (tagName.equals("adopt-permissions")) {
                 sa = res.obtainAttributes(attrs,
                         com.android.internal.R.styleable.AndroidManifestOriginalPackage);
@@ -1795,12 +1795,12 @@
                 }
 
                 XmlUtils.skipCurrentTag(parser);
-                
+
             } else if (tagName.equals("uses-gl-texture")) {
                 // Just skip this tag
                 XmlUtils.skipCurrentTag(parser);
                 continue;
-                
+
             } else if (tagName.equals("compatible-screens")) {
                 // Just skip this tag
                 XmlUtils.skipCurrentTag(parser);
@@ -1808,12 +1808,12 @@
             } else if (tagName.equals("supports-input")) {
                 XmlUtils.skipCurrentTag(parser);
                 continue;
-                
+
             } else if (tagName.equals("eat-comment")) {
                 // Just skip this tag
                 XmlUtils.skipCurrentTag(parser);
                 continue;
-                
+
             } else if (RIGID_PARSER) {
                 outError[0] = "Bad element under <manifest>: "
                     + parser.getName();
@@ -2017,7 +2017,7 @@
         }
         return proc.intern();
     }
-    
+
     private static String buildProcessName(String pkg, String defProc,
             CharSequence procSeq, int flags, String[] separateProcesses,
             String[] outError) {
@@ -2226,7 +2226,7 @@
         }
 
         sa.recycle();
-        
+
         if (!parseAllMetaData(res, parser, attrs, "<permission-group>", perm,
                 outError)) {
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
@@ -2265,7 +2265,7 @@
         if (perm.info.group != null) {
             perm.info.group = perm.info.group.intern();
         }
-        
+
         perm.info.descriptionRes = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestPermission_description,
                 0);
@@ -2296,7 +2296,7 @@
                 return null;
             }
         }
-        
+
         if (!parseAllMetaData(res, parser, attrs, "<permission>", perm,
                 outError)) {
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
@@ -2329,7 +2329,7 @@
         }
 
         sa.recycle();
-        
+
         int index = perm.info.name.indexOf('.');
         if (index > 0) {
             index = perm.info.name.indexOf('.', index+1);
@@ -2371,9 +2371,9 @@
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
             mParseInstrumentationArgs.tag = "<instrumentation>";
         }
-        
+
         mParseInstrumentationArgs.sa = sa;
-        
+
         Instrumentation a = new Instrumentation(mParseInstrumentationArgs,
                 new InstrumentationInfo());
         if (outError[0] != null) {
@@ -2650,10 +2650,10 @@
             }
             ai.processName = buildProcessName(ai.packageName, null, pname,
                     flags, mSeparateProcesses, outError);
-    
+
             ai.enabled = sa.getBoolean(
                     com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
-            
+
             if (sa.getBoolean(
                     com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
                 ai.flags |= ApplicationInfo.FLAG_IS_GAME;
@@ -3022,7 +3022,7 @@
             outInfo.icon = iconVal;
             outInfo.nonLocalizedLabel = null;
         }
-        
+
         int logoVal = sa.getResourceId(logoRes, 0);
         if (logoVal != 0) {
             outInfo.logo = logoVal;
@@ -3061,11 +3061,11 @@
                     R.styleable.AndroidManifestActivity_description,
                     R.styleable.AndroidManifestActivity_enabled);
         }
-        
+
         mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
         mParseActivityArgs.sa = sa;
         mParseActivityArgs.flags = flags;
-        
+
         Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
         if (outError[0] != null) {
             sa.recycle();
@@ -3236,7 +3236,7 @@
                 outError[0] = "Heavy-weight applications can not have receivers in main process";
             }
         }
-        
+
         if (outError[0] != null) {
             return null;
         }
@@ -3282,8 +3282,8 @@
                         outError)) == null) {
                     return null;
                 }
-            } else if (!receiver && parser.getName().equals("initial-layout")) {
-                parseInitialLayout(res, attrs, a);
+            } else if (!receiver && parser.getName().equals("layout")) {
+                parseLayout(res, attrs, a);
             } else {
                 if (!RIGID_PARSER) {
                     Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
@@ -3316,41 +3316,44 @@
         return a;
     }
 
-    private void parseInitialLayout(Resources res, AttributeSet attrs, Activity a) {
+    private void parseLayout(Resources res, AttributeSet attrs, Activity a) {
         TypedArray sw = res.obtainAttributes(attrs,
-                com.android.internal.R.styleable.AndroidManifestInitialLayout);
+                com.android.internal.R.styleable.AndroidManifestLayout);
         int width = -1;
         float widthFraction = -1f;
         int height = -1;
         float heightFraction = -1f;
         final int widthType = sw.getType(
-                com.android.internal.R.styleable.AndroidManifestInitialLayout_activityWidth);
+                com.android.internal.R.styleable.AndroidManifestLayout_initialWidth);
         if (widthType == TypedValue.TYPE_FRACTION) {
             widthFraction = sw.getFraction(
-                    com.android.internal.R.styleable.AndroidManifestInitialLayout_activityWidth,
+                    com.android.internal.R.styleable.AndroidManifestLayout_initialWidth,
                     1, 1, -1);
         } else if (widthType == TypedValue.TYPE_DIMENSION) {
             width = sw.getDimensionPixelSize(
-                    com.android.internal.R.styleable.AndroidManifestInitialLayout_activityWidth,
+                    com.android.internal.R.styleable.AndroidManifestLayout_initialWidth,
                     -1);
         }
         final int heightType = sw.getType(
-                com.android.internal.R.styleable.AndroidManifestInitialLayout_activityHeight);
+                com.android.internal.R.styleable.AndroidManifestLayout_initialHeight);
         if (heightType == TypedValue.TYPE_FRACTION) {
             heightFraction = sw.getFraction(
-                    com.android.internal.R.styleable.AndroidManifestInitialLayout_activityHeight,
+                    com.android.internal.R.styleable.AndroidManifestLayout_initialHeight,
                     1, 1, -1);
         } else if (heightType == TypedValue.TYPE_DIMENSION) {
             height = sw.getDimensionPixelSize(
-                    com.android.internal.R.styleable.AndroidManifestInitialLayout_activityHeight,
+                    com.android.internal.R.styleable.AndroidManifestLayout_initialHeight,
                     -1);
         }
         int gravity = sw.getInt(
-                com.android.internal.R.styleable.AndroidManifestInitialLayout_gravity,
+                com.android.internal.R.styleable.AndroidManifestLayout_gravity,
                 Gravity.CENTER);
+        int minimalSize = sw.getDimensionPixelSize(
+                com.android.internal.R.styleable.AndroidManifestLayout_minimalSize,
+                -1);
         sw.recycle();
-        a.info.initialLayout = new ActivityInfo.InitialLayout(width, widthFraction,
-                height, heightFraction, gravity);
+        a.info.layout = new ActivityInfo.Layout(width, widthFraction,
+                height, heightFraction, gravity, minimalSize);
     }
 
     private Activity parseActivityAlias(Package owner, Resources res,
@@ -3388,10 +3391,10 @@
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
             mParseActivityAliasArgs.tag = "<activity-alias>";
         }
-        
+
         mParseActivityAliasArgs.sa = sa;
         mParseActivityAliasArgs.flags = flags;
-        
+
         Activity target = null;
 
         final int NA = owner.activities.size();
@@ -3432,7 +3435,7 @@
         info.uiOptions = target.info.uiOptions;
         info.parentActivityName = target.info.parentActivityName;
         info.maxRecents = target.info.maxRecents;
-        info.initialLayout = target.info.initialLayout;
+        info.layout = target.info.layout;
 
         Activity a = new Activity(mParseActivityAliasArgs, info);
         if (outError[0] != null) {
@@ -3540,10 +3543,10 @@
                     com.android.internal.R.styleable.AndroidManifestProvider_enabled);
             mParseProviderArgs.tag = "<provider>";
         }
-        
+
         mParseProviderArgs.sa = sa;
         mParseProviderArgs.flags = flags;
-        
+
         Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
         if (outError[0] != null) {
             sa.recycle();
@@ -3632,7 +3635,7 @@
                 return null;
             }
         }
-        
+
         if (cpname == null) {
             outError[0] = "<provider> does not include authorities attribute";
             return null;
@@ -3675,7 +3678,7 @@
                         outInfo.metaData, outError)) == null) {
                     return false;
                 }
-                
+
             } else if (parser.getName().equals("grant-uri-permission")) {
                 TypedArray sa = res.obtainAttributes(attrs,
                         com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
@@ -3699,7 +3702,7 @@
                 if (str != null) {
                     pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
                 }
-                
+
                 sa.recycle();
 
                 if (pa != null) {
@@ -3746,7 +3749,7 @@
                 if (writePermission == null) {
                     writePermission = permission;
                 }
-                
+
                 boolean havePerm = false;
                 if (readPermission != null) {
                     readPermission = readPermission.intern();
@@ -3769,7 +3772,7 @@
                         return false;
                     }
                 }
-                
+
                 String path = sa.getNonConfigurationString(
                         com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0);
                 if (path != null) {
@@ -3852,10 +3855,10 @@
                     com.android.internal.R.styleable.AndroidManifestService_enabled);
             mParseServiceArgs.tag = "<service>";
         }
-        
+
         mParseServiceArgs.sa = sa;
         mParseServiceArgs.flags = flags;
-        
+
         Service s = new Service(mParseServiceArgs, new ServiceInfo());
         if (outError[0] != null) {
             sa.recycle();
@@ -3912,7 +3915,7 @@
                 return null;
             }
         }
-        
+
         int outerDepth = parser.getDepth();
         int type;
         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4010,7 +4013,7 @@
         }
 
         name = name.intern();
-        
+
         TypedValue v = sa.peekValue(
                 com.android.internal.R.styleable.AndroidManifestMetaData_resource);
         if (v != null && v.resourceId != 0) {
@@ -4152,7 +4155,7 @@
 
         outInfo.icon = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
-        
+
         outInfo.logo = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
 
@@ -4373,7 +4376,7 @@
         public ArrayList<String> mOriginalPackages = null;
         public String mRealPackage = null;
         public ArrayList<String> mAdoptPermissions = null;
-        
+
         // We store the application meta-data independently to avoid multiple unwanted references
         public Bundle mAppMetaData = null;
 
@@ -4382,7 +4385,7 @@
 
         // The version name declared for this package.
         public String mVersionName;
-        
+
         // The shared user id that this package wants to use.
         public String mSharedUserId;
 
@@ -4604,7 +4607,7 @@
 
         ComponentName componentName;
         String componentShortName;
-        
+
         public Component(Package _owner) {
             owner = _owner;
             intents = null;
@@ -4636,7 +4639,7 @@
                 outInfo.icon = iconVal;
                 outInfo.nonLocalizedLabel = null;
             }
-            
+
             int logoVal = args.sa.getResourceId(args.logoRes, 0);
             if (logoVal != 0) {
                 outInfo.logo = logoVal;
@@ -4676,11 +4679,11 @@
                         owner.applicationInfo.processName, pname,
                         args.flags, args.sepProcesses, args.outError);
             }
-            
+
             if (args.descriptionRes != 0) {
                 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
             }
-            
+
             outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
         }
 
@@ -4691,7 +4694,7 @@
             componentName = clone.componentName;
             componentShortName = clone.componentShortName;
         }
-        
+
         public ComponentName getComponentName() {
             if (componentName != null) {
                 return componentName;
@@ -4716,7 +4719,7 @@
             componentShortName = null;
         }
     }
-    
+
     public final static class Permission extends Component<IntentInfo> {
         public final PermissionInfo info;
         public boolean tree;
@@ -4731,7 +4734,7 @@
             super(_owner);
             info = _info;
         }
-        
+
         public void setPackageName(String packageName) {
             super.setPackageName(packageName);
             info.packageName = packageName;
@@ -4922,7 +4925,7 @@
             info = _info;
             info.applicationInfo = args.owner.applicationInfo;
         }
-        
+
         public void setPackageName(String packageName) {
             super.setPackageName(packageName);
             info.packageName = packageName;
@@ -4976,7 +4979,7 @@
             info = _info;
             info.applicationInfo = args.owner.applicationInfo;
         }
-        
+
         public void setPackageName(String packageName) {
             super.setPackageName(packageName);
             info.packageName = packageName;
@@ -5019,7 +5022,7 @@
             info.applicationInfo = args.owner.applicationInfo;
             syncable = false;
         }
-        
+
         public Provider(Provider existingProvider) {
             super(existingProvider);
             this.info = existingProvider.info;
@@ -5070,7 +5073,7 @@
             super(args, _info);
             info = _info;
         }
-        
+
         public void setPackageName(String packageName) {
             super.setPackageName(packageName);
             info.packageName = packageName;
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index c8b45c7..c6ae14e 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -67,4 +67,6 @@
     // Input device vibrator control.
     void vibrate(int deviceId, in long[] pattern, int repeat, IBinder token);
     void cancelVibrate(int deviceId, IBinder token);
+
+    void setPointerIconShape(int shapeId);
 }
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index bae5757..3949d97 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -757,6 +757,22 @@
         }
     }
 
+    /**
+     * Changes the mouse pointer's icon shape into the specified id.
+     *
+     * @param iconId The id of the pointer graphic, as a value between
+     * {@link PointerIcon.STYLE_ARROW} and {@link PointerIcon.STYLE_GRABBING}.
+     *
+     * @hide
+     */
+    public void setPointerIconShape(int iconId) {
+        try {
+            mIm.setPointerIconShape(iconId);
+        } catch (RemoteException ex) {
+            // Do nothing.
+        }
+    }
+
     private void populateInputDevicesLocked() {
         if (mInputDevicesChangedListener == null) {
             final InputDevicesChangedListener listener = new InputDevicesChangedListener();
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 3f40484..a83e722 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -50,12 +50,13 @@
     public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
 
     /* RULE_* are not masks and they must be exclusive */
+    public static final int RULE_UNKNOWN = -1;
     /** All network traffic should be allowed. */
-    public static final int RULE_ALLOW_ALL = 0x0;
+    public static final int RULE_ALLOW_ALL = 0;
     /** Reject traffic on metered networks. */
-    public static final int RULE_REJECT_METERED = 0x1;
+    public static final int RULE_REJECT_METERED = 1;
     /** Reject traffic on all networks. */
-    public static final int RULE_REJECT_ALL = 0x2;
+    public static final int RULE_REJECT_ALL = 2;
 
     public static final int FIREWALL_RULE_DEFAULT = 0;
     public static final int FIREWALL_RULE_ALLOW = 1;
@@ -326,25 +327,4 @@
         // nothing found above; we can apply policy to UID
         return true;
     }
-
-    /** {@hide} */
-    public static void dumpPolicy(PrintWriter fout, int policy) {
-        fout.write("[");
-        if ((policy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
-            fout.write("REJECT_METERED_BACKGROUND");
-        }
-        fout.write("]");
-    }
-
-    /** {@hide} */
-    public static void dumpRules(PrintWriter fout, int rules) {
-        fout.write("[");
-        if ((rules & RULE_REJECT_METERED) != 0) {
-            fout.write("REJECT_METERED");
-        } else if ((rules & RULE_REJECT_ALL) != 0) {
-            fout.write("REJECT_ALL");
-        }
-        fout.write("]");
-    }
-
 }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 85041ad..f7c8662 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -577,7 +577,7 @@
         public static final int KITKAT = 19;
 
         /**
-         * Android 4.4W: KitKat for watches, snacks on the run.
+         * June 2014: Android 4.4W. KitKat for watches, snacks on the run.
          *
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
@@ -595,7 +595,7 @@
         public static final int L = 21;
 
         /**
-         * Lollipop.  A flat one with beautiful shadows.  But still tasty.
+         * November 2014: Lollipop.  A flat one with beautiful shadows.  But still tasty.
          *
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
@@ -626,12 +626,38 @@
         public static final int LOLLIPOP = 21;
 
         /**
-         * Lollipop with an extra sugar coating on the outside!
+         * March 2015: Lollipop with an extra sugar coating on the outside!
          */
         public static final int LOLLIPOP_MR1 = 22;
 
         /**
-         * M comes after L.
+         * M is for Marshmallow!
+         *
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li> Runtime permissions.  Dangerous permissions are no longer granted at
+         * install time, but must be requested by the application at runtime through
+         * {@link android.app.Activity#requestPermissions}.</li>
+         * <li> Bluetooth and Wi-Fi scanning now requires holding the location permission.</li>
+         * <li> {@link android.app.AlarmManager#setTimeZone AlarmManager.setTimeZone} will fail if
+         * the given timezone is non-Olson.</li>
+         * <li> Activity transitions will only return shared
+         * elements mapped in the returned view hierarchy back to the calling activity.</li>
+         * <li> {@link android.view.View} allows a number of behaviors that may break
+         * existing apps: Canvas throws an exception if restore() is called too many times,
+         * widgets may return a hint size when returning UNSPECIFIED measure specs, and it
+         * will respect the attributes {@link android.R.attr#foreground},
+         * {@link android.R.attr#foregroundGravity}, {@link android.R.attr#foregroundTint}, and
+         * {@link android.R.attr#foregroundTintMode}.</li>
+         * <li> {@link android.view.MotionEvent#getButtonState MotionEvent.getButtonState}
+         * will no longer report {@link android.view.MotionEvent#BUTTON_PRIMARY}
+         * and {@link android.view.MotionEvent#BUTTON_SECONDARY} as synonyms for
+         * {@link android.view.MotionEvent#BUTTON_STYLUS_PRIMARY} and
+         * {@link android.view.MotionEvent#BUTTON_STYLUS_SECONDARY}.</li>
+         * <li> {@link android.widget.ScrollView} now respects the layout param margins
+         * when measuring.</li>
+         * </ul>
          */
         public static final int M = 23;
 
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 97b85e2..fdd34f5 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -471,7 +471,7 @@
        *     </tbody>
        * </table>
        */
-        public String getMemoryStat(String statName) {
+       public String getMemoryStat(String statName) {
             switch(statName) {
                 case "summary.java-heap":
                     return Integer.toString(getSummaryJavaHeap());
@@ -1538,7 +1538,13 @@
 
     /**
      * Retrieves information about this processes memory usages. This information is broken down by
-     * how much is in use by dalivk, the native heap, and everything else.
+     * how much is in use by dalvik, the native heap, and everything else.
+     *
+     * <p><b>Note:</b> this method directly retrieves memory information for the give process
+     * from low-level data available to it.  It may not be able to retrieve information about
+     * some protected allocations, such as graphics.  If you want to be sure you can see
+     * all information about allocations by the process, use instead
+     * {@link android.app.ActivityManager#getProcessMemoryInfo(int[])}.</p>
      */
     public static native void getMemoryInfo(MemoryInfo memoryInfo);
 
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 64d6da5..f346fe7 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -276,8 +276,8 @@
     }
 
     /**
-     * Return the primary external storage directory. This directory may not
-     * currently be accessible if it has been mounted by the user on their
+     * Return the primary shared/external storage directory. This directory may
+     * not currently be accessible if it has been mounted by the user on their
      * computer, has been removed from the device, or some other problem has
      * happened. You can determine its current state with
      * {@link #getExternalStorageState()}.
@@ -291,12 +291,15 @@
      * filesystem on a computer.</em>
      * <p>
      * On devices with multiple users (as described by {@link UserManager}),
-     * each user has their own isolated external storage. Applications only have
-     * access to the external storage for the user they're running as.
+     * each user has their own isolated shared storage. Applications only have
+     * access to the shared storage for the user they're running as.
      * <p>
-     * In devices with multiple "external" storage directories, this directory
-     * represents the "primary" external storage that the user will interact
+     * In devices with multiple shared/external storage directories, this
+     * directory represents the primary storage that the user will interact
      * with. Access to secondary storage is available through
+     * {@link Context#getExternalFilesDirs(String)},
+     * {@link Context#getExternalCacheDirs()}, and
+     * {@link Context#getExternalMediaDirs()}.
      * <p>
      * Applications should not directly use this top-level directory, in order
      * to avoid polluting the user's root namespace. Any files that are private
@@ -315,8 +318,9 @@
      * <p>
      * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your
      * application only needs to store internal data, consider using
-     * {@link Context#getExternalFilesDir(String)} or
-     * {@link Context#getExternalCacheDir()}, which require no permissions to
+     * {@link Context#getExternalFilesDir(String)},
+     * {@link Context#getExternalCacheDir()}, or
+     * {@link Context#getExternalMediaDirs()}, which require no permissions to
      * read or write.
      * <p>
      * This path may change between platform versions, so applications should
@@ -325,8 +329,7 @@
      * Here is an example of typical code to monitor the state of external
      * storage:
      * <p>
-     * {@sample
-     * development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
+     * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
      * monitor_storage}
      *
      * @see #getExternalStorageState()
@@ -446,32 +449,32 @@
     public static String DIRECTORY_DOCUMENTS = "Documents";
 
     /**
-     * Get a top-level public external storage directory for placing files of
-     * a particular type.  This is where the user will typically place and
-     * manage their own files, so you should be careful about what you put here
-     * to ensure you don't erase their files or get in the way of their own
+     * Get a top-level shared/external storage directory for placing files of a
+     * particular type. This is where the user will typically place and manage
+     * their own files, so you should be careful about what you put here to
+     * ensure you don't erase their files or get in the way of their own
      * organization.
-     * 
-     * <p>On devices with multiple users (as described by {@link UserManager}),
-     * each user has their own isolated external storage. Applications only
-     * have access to the external storage for the user they're running as.</p>
-     *
-     * <p>Here is an example of typical code to manipulate a picture on
-     * the public external storage:</p>
-     * 
+     * <p>
+     * On devices with multiple users (as described by {@link UserManager}),
+     * each user has their own isolated shared storage. Applications only have
+     * access to the shared storage for the user they're running as.
+     * </p>
+     * <p>
+     * Here is an example of typical code to manipulate a picture on the public
+     * shared storage:
+     * </p>
      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
      * public_picture}
      * 
-     * @param type The type of storage directory to return.  Should be one of
-     * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
-     * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
-     * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
-     * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
-     * {@link #DIRECTORY_DCIM}.  May not be null.
-     * 
-     * @return Returns the File path for the directory.  Note that this
-     * directory may not yet exist, so you must make sure it exists before
-     * using it such as with {@link File#mkdirs File.mkdirs()}.
+     * @param type The type of storage directory to return. Should be one of
+     *            {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
+     *            {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
+     *            {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
+     *            {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
+     *            {@link #DIRECTORY_DCIM}. May not be null.
+     * @return Returns the File path for the directory. Note that this directory
+     *         may not yet exist, so you must make sure it exists before using
+     *         it such as with {@link File#mkdirs File.mkdirs()}.
      */
     public static File getExternalStoragePublicDirectory(String type) {
         throwIfUserRequired();
@@ -623,7 +626,7 @@
     public static final String MEDIA_EJECTING = "ejecting";
 
     /**
-     * Returns the current state of the primary "external" storage device.
+     * Returns the current state of the primary shared/external storage media.
      * 
      * @see #getExternalStorageDirectory()
      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
@@ -646,8 +649,8 @@
     }
 
     /**
-     * Returns the current state of the storage device that provides the given
-     * path.
+     * Returns the current state of the shared/external storage media at the
+     * given path.
      *
      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
      *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
@@ -665,7 +668,8 @@
     }
 
     /**
-     * Returns whether the primary "external" storage device is removable.
+     * Returns whether the primary shared/external storage media is physically
+     * removable.
      *
      * @return true if the storage device can be removed (such as an SD card),
      *         or false if the storage device is built in and cannot be
@@ -678,8 +682,8 @@
     }
 
     /**
-     * Returns whether the storage device that provides the given path is
-     * removable.
+     * Returns whether the shared/external storage media at the given path is
+     * physically removable.
      *
      * @return true if the storage device can be removed (such as an SD card),
      *         or false if the storage device is built in and cannot be
@@ -697,9 +701,15 @@
     }
 
     /**
-     * Returns whether the primary "external" storage device is emulated. If
-     * true, data stored on this device will be stored on a portion of the
-     * internal storage system.
+     * Returns whether the primary shared/external storage media is emulated.
+     * <p>
+     * The contents of emulated storage devices are backed by a private user
+     * data partition, which means there is little benefit to apps storing data
+     * here instead of the private directories returned by
+     * {@link Context#getFilesDir()}, etc.
+     * <p>
+     * This returns true when emulated storage is backed by either internal
+     * storage or an adopted storage device.
      *
      * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName,
      *      boolean)
@@ -711,9 +721,16 @@
     }
 
     /**
-     * Returns whether the storage device that provides the given path is
-     * emulated. If true, data stored on this device will be stored on a portion
-     * of the internal storage system.
+     * Returns whether the shared/external storage media at the given path is
+     * emulated.
+     * <p>
+     * The contents of emulated storage devices are backed by a private user
+     * data partition, which means there is little benefit to apps storing data
+     * here instead of the private directories returned by
+     * {@link Context#getFilesDir()}, etc.
+     * <p>
+     * This returns true when emulated storage is backed by either internal
+     * storage or an adopted storage device.
      *
      * @throws IllegalArgumentException if the path is not a valid storage
      *             device.
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 4c19ddd..3ade170 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -46,6 +46,7 @@
     List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
     boolean canAddMoreManagedProfiles(int userId);
     UserInfo getProfileParent(int userHandle);
+    boolean isSameProfileGroup(int userId, int otherUserId);
     UserInfo getUserInfo(int userHandle);
     long getUserCreationTime(int userHandle);
     boolean isRestricted();
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 796addc..95da438 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -270,13 +270,24 @@
      * Returns true if this UserHandle refers to the owner user; false otherwise.
      * @return true if this UserHandle refers to the owner user; false otherwise.
      * @hide
-     * TODO: find an alternative to this Api.
+     * @deprecated please use {@link #isSystem()} or check for
+     * {@link android.content.pm.UserInfo#isPrimary()}
+     * {@link android.content.pm.UserInfo#isAdmin()} based on your particular use case.
      */
     @SystemApi
     public boolean isOwner() {
         return this.equals(OWNER);
     }
 
+    /**
+     * @return true if this UserHandle refers to the system user; false otherwise.
+     * @hide
+     */
+    @SystemApi
+    public boolean isSystem() {
+        return this.equals(SYSTEM);
+    }
+
     /** @hide */
     public UserHandle(int h) {
         mHandle = h;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d178d20..1c1575e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1093,6 +1093,22 @@
     }
 
     /**
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @param userId one of the two user ids to check.
+     * @param otherUserId one of the two user ids to check.
+     * @return true if the two user ids are in the same profile group.
+     * @hide
+     */
+    public boolean isSameProfileGroup(int userId, int otherUserId) {
+        try {
+            return mService.isSameProfileGroup(userId, otherUserId);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get user list", re);
+            return false;
+        }
+    }
+
+    /**
      * Returns list of the profiles of userHandle including
      * userHandle itself.
      * Note that this returns only enabled.
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 979c828..2445bc2 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -383,6 +383,7 @@
                 final IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
                 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
                 filter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
+                filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
                 mContext.registerReceiver(this, filter);
             } else {
                 mContext.unregisterReceiver(this);
@@ -395,13 +396,7 @@
             if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) {
                 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
                 int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
-                final boolean streamMatch = mNotificationOrRing ? isNotificationOrRing(streamType)
-                        : (streamType == mStreamType);
-                if (mSeekBar != null && streamMatch && streamValue != -1) {
-                    final boolean muted = mAudioManager.isStreamMute(mStreamType)
-                            || streamValue == 0;
-                    mUiHandler.postUpdateSlider(streamValue, mLastAudibleStreamVolume, muted);
-                }
+                updateVolumeSlider(streamType, streamValue);
             } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
                 if (mNotificationOrRing) {
                     mRingerMode = mAudioManager.getRingerModeInternal();
@@ -409,10 +404,24 @@
                 if (mAffectedByRingerMode) {
                     updateSlider();
                 }
+            } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) {
+                int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+                int streamVolume = mAudioManager.getStreamVolume(streamType);
+                updateVolumeSlider(streamType, streamVolume);
             } else if (NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED.equals(action)) {
                 mZenMode = mNotificationManager.getZenMode();
                 updateSlider();
             }
         }
+
+        private void updateVolumeSlider(int streamType, int streamValue) {
+            final boolean streamMatch = mNotificationOrRing ? isNotificationOrRing(streamType)
+                    : (streamType == mStreamType);
+            if (mSeekBar != null && streamMatch && streamValue != -1) {
+                final boolean muted = mAudioManager.isStreamMute(mStreamType)
+                        || streamValue == 0;
+                mUiHandler.postUpdateSlider(streamValue, mLastAudibleStreamVolume, muted);
+            }
+        }
     }
 }
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index e054a61..2c49d16 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -68,6 +68,7 @@
     public static final int[] MINUTE_BUCKETS = generateMinuteBuckets();
     private static final int SECONDS_MS = 1000;
     private static final int MINUTES_MS = 60 * SECONDS_MS;
+    private static final int DAY_MINUTES = 24 * 60;
     private static final int ZERO_VALUE_MS = 10 * SECONDS_MS;
 
     private static final boolean DEFAULT_ALLOW_CALLS = true;
@@ -561,14 +562,6 @@
         return tryParseLong(val, defValue);
     }
 
-    public ArraySet<String> getAutomaticRuleNames() {
-        final ArraySet<String> rt = new ArraySet<String>();
-        for (int i = 0; i < automaticRules.size(); i++) {
-            rt.add(automaticRules.valueAt(i).name);
-        }
-        return rt;
-    }
-
     @Override
     public int describeContents() {
         return 0;
@@ -661,40 +654,65 @@
             boolean shortVersion) {
         final long now = System.currentTimeMillis();
         final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS;
-        return toTimeCondition(context, now + millis, minutesFromNow, now, userHandle,
-                shortVersion);
+        return toTimeCondition(context, now + millis, minutesFromNow, userHandle, shortVersion);
     }
 
-    public static Condition toTimeCondition(Context context, long time, int minutes, long now,
+    public static Condition toTimeCondition(Context context, long time, int minutes,
             int userHandle, boolean shortVersion) {
-        final int num, summaryResId, line1ResId;
+        final int num;
+        String summary, line1, line2;
+        final CharSequence formattedTime = getFormattedTime(context, time, minutes, userHandle);
+        final Resources res = context.getResources();
         if (minutes < 60) {
             // display as minutes
             num = minutes;
-            summaryResId = shortVersion ? R.plurals.zen_mode_duration_minutes_summary_short
+            int summaryResId = shortVersion ? R.plurals.zen_mode_duration_minutes_summary_short
                     : R.plurals.zen_mode_duration_minutes_summary;
-            line1ResId = shortVersion ? R.plurals.zen_mode_duration_minutes_short
+            summary = res.getQuantityString(summaryResId, num, num, formattedTime);
+            int line1ResId = shortVersion ? R.plurals.zen_mode_duration_minutes_short
                     : R.plurals.zen_mode_duration_minutes;
-        } else {
+            line1 = res.getQuantityString(line1ResId, num, num, formattedTime);
+            line2 = res.getString(R.string.zen_mode_until, formattedTime);
+        } else if (minutes < DAY_MINUTES) {
             // display as hours
             num =  Math.round(minutes / 60f);
-            summaryResId = shortVersion ? R.plurals.zen_mode_duration_hours_summary_short
+            int summaryResId = shortVersion ? R.plurals.zen_mode_duration_hours_summary_short
                     : R.plurals.zen_mode_duration_hours_summary;
-            line1ResId = shortVersion ? R.plurals.zen_mode_duration_hours_short
+            summary = res.getQuantityString(summaryResId, num, num, formattedTime);
+            int line1ResId = shortVersion ? R.plurals.zen_mode_duration_hours_short
                     : R.plurals.zen_mode_duration_hours;
+            line1 = res.getQuantityString(line1ResId, num, num, formattedTime);
+            line2 = res.getString(R.string.zen_mode_until, formattedTime);
+        } else {
+            // display as day/time
+            summary = line1 = line2 = res.getString(R.string.zen_mode_until, formattedTime);
         }
-        final String skeleton = DateFormat.is24HourFormat(context, userHandle) ? "Hm" : "hma";
-        final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
-        final CharSequence formattedTime = DateFormat.format(pattern, time);
-        final Resources res = context.getResources();
-        final String summary = res.getQuantityString(summaryResId, num, num, formattedTime);
-        final String line1 = res.getQuantityString(line1ResId, num, num, formattedTime);
-        final String line2 = res.getString(R.string.zen_mode_until, formattedTime);
         final Uri id = toCountdownConditionId(time);
         return new Condition(id, summary, line1, line2, 0, Condition.STATE_TRUE,
                 Condition.FLAG_RELEVANT_NOW);
     }
 
+    public static Condition toNextAlarmCondition(Context context, long now, long alarm,
+            int userHandle) {
+        int minutes = Math.round((alarm-now) / (float) MINUTES_MS);
+        final CharSequence formattedTime = getFormattedTime(context, alarm, minutes, userHandle);
+        final Resources res = context.getResources();
+        final String line1 = res.getString(R.string.zen_mode_alarm, formattedTime);
+        final Uri id = toCountdownConditionId(alarm);
+        return new Condition(id, "", line1, "", 0, Condition.STATE_TRUE,
+                Condition.FLAG_RELEVANT_NOW);
+    }
+
+    private static CharSequence getFormattedTime(Context context, long time, int minutes,
+            int userHandle) {
+        String skeleton = DateFormat.is24HourFormat(context, userHandle) ? "Hm" : "hma";
+        if (minutes > DAY_MINUTES) {
+            skeleton = "EEE " + (DateFormat.is24HourFormat(context, userHandle) ? "Hm" : "hma");
+        }
+        final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
+        return DateFormat.format(pattern, time);
+    }
+
     // ==== Built-in system conditions ====
 
     public static final String SYSTEM_AUTHORITY = "android";
@@ -900,11 +918,6 @@
         return UUID.randomUUID().toString().replace("-", "");
     }
 
-    public static String getConditionLine1(Context context, ZenModeConfig config,
-            int userHandle, boolean shortVersion) {
-        return getConditionLine(context, config, userHandle, true /*useLine1*/, shortVersion);
-    }
-
     public static String getConditionSummary(Context context, ZenModeConfig config,
             int userHandle, boolean shortVersion) {
         return getConditionLine(context, config, userHandle, false /*useLine1*/, shortVersion);
@@ -923,8 +936,8 @@
             if (time > 0) {
                 final long now = System.currentTimeMillis();
                 final long span = time - now;
-                c = toTimeCondition(context,
-                        time, Math.round(span / (float) MINUTES_MS), now, userHandle, shortVersion);
+                c = toTimeCondition(context, time, Math.round(span / (float) MINUTES_MS),
+                        userHandle, shortVersion);
             }
             final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary;
             return TextUtils.isEmpty(rt) ? "" : rt;
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index cc4598d..bae51d3 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -766,6 +766,15 @@
     }
 
     /**
+     * Sets the current pointer shape.
+     * @param pointerShape the id of the pointer icon.
+     * @hide
+     */
+    public void setPointerShape(int pointerShape) {
+        InputManager.getInstance().setPointerIconShape(pointerShape);
+    }
+
+    /**
      * Provides information about the range of values for a particular {@link MotionEvent} axis.
      *
      * @see InputDevice#getMotionRange(int)
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index cf35ce5..88e9a95 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -48,6 +48,12 @@
     /** Style constant: Null icon.  It has no bitmap. */
     public static final int STYLE_NULL = 0;
 
+    /** Style constant: no icons are specified. If all views uses this, then falls back
+     * to the default style, but this is helpful to distinguish a view explicitly want
+     * to have the default icon.
+     */
+    public static final int STYLE_NOT_SPECIFIED = 1;
+
     /** Style constant: Arrow icon.  (Default mouse pointer) */
     public static final int STYLE_ARROW = 1000;
 
@@ -60,12 +66,74 @@
     /** {@hide} Style constant: Spot anchor icon for touchpads. */
     public static final int STYLE_SPOT_ANCHOR = 2002;
 
+    // Style constants for additional predefined icons for mice.
+    /** Style constant: context-menu. */
+    public static final int STYLE_CONTEXT_MENU = 1001;
+
+    /** Style constant: hand. */
+    public static final int STYLE_HAND = 1002;
+
+    /** Style constant: help. */
+    public static final int STYLE_HELP = 1003;
+
+    /** Style constant: wait. */
+    public static final int STYLE_WAIT = 1004;
+
+    /** Style constant: cell. */
+    public static final int STYLE_CELL = 1006;
+
+    /** Style constant: crosshair. */
+    public static final int STYLE_CROSSHAIR = 1007;
+
+    /** Style constant: text. */
+    public static final int STYLE_TEXT = 1008;
+
+    /** Style constant: vertical-text. */
+    public static final int STYLE_VERTICAL_TEXT = 1009;
+
+    /** Style constant: alias (indicating an alias of/shortcut to something is
+      * to be created. */
+    public static final int STYLE_ALIAS = 1010;
+
+    /** Style constant: copy. */
+    public static final int STYLE_COPY = 1011;
+
+    /** Style constant: no-drop. */
+    public static final int STYLE_NO_DROP = 1012;
+
+    /** Style constant: all-scroll. */
+    public static final int STYLE_ALL_SCROLL = 1013;
+
+    /** Style constant: horizontal double arrow mainly for resizing. */
+    public static final int STYLE_HORIZONTAL_DOUBLE_ARROW = 1014;
+
+    /** Style constant: vertical double arrow mainly for resizing. */
+    public static final int STYLE_VERTICAL_DOUBLE_ARROW = 1015;
+
+    /** Style constant: diagonal double arrow -- top-right to bottom-left. */
+    public static final int STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016;
+
+    /** Style constant: diagonal double arrow -- top-left to bottom-right. */
+    public static final int STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017;
+
+    /** Style constant: zoom-in. */
+    public static final int STYLE_ZOOM_IN = 1018;
+
+    /** Style constant: zoom-out. */
+    public static final int STYLE_ZOOM_OUT = 1019;
+
+    /** Style constant: grab. */
+    public static final int STYLE_GRAB = 1020;
+
+    /** Style constant: grabbing. */
+    public static final int STYLE_GRABBING = 1021;
+
     // OEM private styles should be defined starting at this range to avoid
     // conflicts with any system styles that may be defined in the future.
     private static final int STYLE_OEM_FIRST = 10000;
 
-    // The default pointer icon.
-    private static final int STYLE_DEFAULT = STYLE_ARROW;
+    /** {@hide} The default pointer icon. */
+    public static final int STYLE_DEFAULT = STYLE_ARROW;
 
     private static final PointerIcon gNullIcon = new PointerIcon(STYLE_NULL);
 
@@ -434,6 +502,49 @@
                 return com.android.internal.R.styleable.Pointer_pointerIconSpotTouch;
             case STYLE_SPOT_ANCHOR:
                 return com.android.internal.R.styleable.Pointer_pointerIconSpotAnchor;
+            case STYLE_HAND:
+                return com.android.internal.R.styleable.Pointer_pointerIconHand;
+            case STYLE_CONTEXT_MENU:
+                return com.android.internal.R.styleable.Pointer_pointerIconContextMenu;
+            case STYLE_HELP:
+                return com.android.internal.R.styleable.Pointer_pointerIconHelp;
+            case STYLE_WAIT:
+                // falls back to the default icon because no animation support.
+                return com.android.internal.R.styleable.Pointer_pointerIconArrow;
+            case STYLE_CELL:
+                return com.android.internal.R.styleable.Pointer_pointerIconCell;
+            case STYLE_CROSSHAIR:
+                return com.android.internal.R.styleable.Pointer_pointerIconCrosshair;
+            case STYLE_TEXT:
+                return com.android.internal.R.styleable.Pointer_pointerIconText;
+            case STYLE_VERTICAL_TEXT:
+                return com.android.internal.R.styleable.Pointer_pointerIconVerticalText;
+            case STYLE_ALIAS:
+                return com.android.internal.R.styleable.Pointer_pointerIconAlias;
+            case STYLE_COPY:
+                return com.android.internal.R.styleable.Pointer_pointerIconCopy;
+            case STYLE_ALL_SCROLL:
+                return com.android.internal.R.styleable.Pointer_pointerIconAllScroll;
+            case STYLE_NO_DROP:
+                return com.android.internal.R.styleable.Pointer_pointerIconNodrop;
+            case STYLE_HORIZONTAL_DOUBLE_ARROW:
+                return com.android.internal.R.styleable.Pointer_pointerIconHorizontalDoubleArrow;
+            case STYLE_VERTICAL_DOUBLE_ARROW:
+                return com.android.internal.R.styleable.Pointer_pointerIconVerticalDoubleArrow;
+            case STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW:
+                return com.android.internal.R.styleable.
+                        Pointer_pointerIconTopRightDiagonalDoubleArrow;
+            case STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW:
+                return com.android.internal.R.styleable.
+                        Pointer_pointerIconTopLeftDiagonalDoubleArrow;
+            case STYLE_ZOOM_IN:
+                return com.android.internal.R.styleable.Pointer_pointerIconZoomIn;
+            case STYLE_ZOOM_OUT:
+                return com.android.internal.R.styleable.Pointer_pointerIconZoomOut;
+            case STYLE_GRAB:
+                return com.android.internal.R.styleable.Pointer_pointerIconGrab;
+            case STYLE_GRABBING:
+                return com.android.internal.R.styleable.Pointer_pointerIconGrabbing;
             default:
                 return 0;
         }
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 2a3756d..7747580 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -336,9 +336,6 @@
         return mUnscaledDuration;
     }
 
-    /**
-     * @hide
-     */
     @Override
     public long getTotalDuration() {
         return mUnscaledDuration + mUnscaledStartDelay;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2c7a436..4bc2112 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2408,7 +2408,13 @@
      *                            1      PFLAG3_APPLYING_INSETS
      *                           1       PFLAG3_FITTING_SYSTEM_WINDOWS
      *                          1        PFLAG3_NESTED_SCROLLING_ENABLED
-     *                         1         PFLAG3_ASSIST_BLOCKED
+     *                         1         PFLAG3_SCROLL_INDICATOR_TOP
+     *                        1          PFLAG3_SCROLL_INDICATOR_BOTTOM
+     *                       1           PFLAG3_SCROLL_INDICATOR_LEFT
+     *                      1            PFLAG3_SCROLL_INDICATOR_RIGHT
+     *                     1             PFLAG3_SCROLL_INDICATOR_START
+     *                    1              PFLAG3_SCROLL_INDICATOR_END
+     *                   1               PFLAG3_ASSIST_BLOCKED
      * |-------|-------|-------|-------|
      */
 
@@ -2602,7 +2608,7 @@
      * <p>Indicates that we are allowing {@link ViewStructure} to traverse
      * into this view.<p>
      */
-    static final int PFLAG3_ASSIST_BLOCKED = 0x100;
+    static final int PFLAG3_ASSIST_BLOCKED = 0x4000;
 
     /**
      * Always allow a user to over-scroll this view, provided it is a
@@ -20989,6 +20995,11 @@
         }
     }
 
+    /** @hide */
+    public int getPointerShape(MotionEvent event, float x, float y) {
+        return PointerIcon.STYLE_NOT_SPECIFIED;
+    }
+
     //
     // Properties
     //
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 475ce2f..7c7ad91 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1715,6 +1715,36 @@
         return false;
     }
 
+    /** @hide */
+    @Override
+    public int getPointerShape(MotionEvent event, float x, float y) {
+        // Check what the child under the pointer says about the pointer.
+        final int childrenCount = mChildrenCount;
+        if (childrenCount != 0) {
+            final ArrayList<View> preorderedList = buildOrderedChildList();
+            final boolean customOrder = preorderedList == null
+                    && isChildrenDrawingOrderEnabled();
+            final View[] children = mChildren;
+            for (int i = childrenCount - 1; i >= 0; i--) {
+                final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
+                final View child = (preorderedList == null)
+                        ? children[childIndex] : preorderedList.get(childIndex);
+                PointF point = getLocalPoint();
+                if (isTransformedTouchPointInView(x, y, child, point)) {
+                    final int pointerShape = child.getPointerShape(event, point.x, point.y);
+                    if (pointerShape != PointerIcon.STYLE_NOT_SPECIFIED) {
+                        return pointerShape;
+                    }
+                    break;
+                }
+            }
+        }
+
+        // The pointer is not a child or the child has no preferences, returning the default
+        // implementation.
+        return super.getPointerShape(event, x, y);
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -4606,7 +4636,6 @@
     }
 
     private void removeViewInternal(int index, View view) {
-
         if (mTransition != null) {
             mTransition.removeChild(this, view);
         }
@@ -4699,12 +4728,17 @@
     }
 
     private void removeViewsInternal(int start, int count) {
+        final int end = start + count;
+
+        if (start < 0 || count < 0 || end > mChildrenCount) {
+            throw new IndexOutOfBoundsException();
+        }
+
         final View focused = mFocused;
         final boolean detach = mAttachInfo != null;
         boolean clearChildFocus = false;
 
         final View[] children = mChildren;
-        final int end = start + count;
 
         for (int i = start; i < end; i++) {
             final View view = children[i];
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3d10289..13b6a42 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -37,6 +37,7 @@
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
+import android.hardware.input.InputManager;
 import android.media.AudioManager;
 import android.os.Binder;
 import android.os.Build;
@@ -324,6 +325,8 @@
     private long mFpsPrevTime = -1;
     private int mFpsNumFrames;
 
+    private int mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
+
     /**
      * see {@link #playSoundEffect(int)}
      */
@@ -4168,6 +4171,30 @@
         private int processPointerEvent(QueuedInputEvent q) {
             final MotionEvent event = (MotionEvent)q.mEvent;
 
+            if (event.getPointerCount() == 1
+                    && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+                if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
+                        || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
+                    // Other apps or the window manager may change the icon shape outside of
+                    // this app, therefore the icon shape has to be reset on enter/exit event.
+                    mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
+                }
+
+                final float x = event.getX();
+                final float y = event.getY();
+                if (x >= 0 && x < mView.getWidth() && y >= 0 && y < mView.getHeight()) {
+                    int pointerShape = mView.getPointerShape(event, x, y);
+                    if (pointerShape == PointerIcon.STYLE_NOT_SPECIFIED) {
+                        pointerShape = PointerIcon.STYLE_DEFAULT;
+                    }
+
+                    if (mPointerIconShape != pointerShape) {
+                        mPointerIconShape = pointerShape;
+                        event.getDevice().setPointerShape(pointerShape);
+                    }
+                }
+            }
+
             mAttachInfo.mUnbufferedDispatchRequested = false;
             boolean handled = mView.dispatchPointerEvent(event);
             if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 13544851..d9ec866 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -666,7 +666,7 @@
     void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
         CharSequence curTitle = wp.getTitle();
         if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
-            wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
             if (wp.token == null) {
                 View decor = peekDecorView();
                 if (decor != null) {
@@ -674,24 +674,38 @@
                 }
             }
             if (curTitle == null || curTitle.length() == 0) {
-                String title;
+                final StringBuilder title = new StringBuilder(32);
                 if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA) {
-                    title="Media";
+                    title.append("Media");
                 } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY) {
-                    title="MediaOvr";
+                    title.append("MediaOvr");
                 } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
-                    title="Panel";
+                    title.append("Panel");
                 } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL) {
-                    title="SubPanel";
+                    title.append("SubPanel");
                 } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL) {
-                    title="AboveSubPanel";
+                    title.append("AboveSubPanel");
                 } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG) {
-                    title="AtchDlg";
+                    title.append("AtchDlg");
                 } else {
-                    title=Integer.toString(wp.type);
+                    title.append(wp.type);
                 }
                 if (mAppName != null) {
-                    title += ":" + mAppName;
+                    title.append(":").append(mAppName);
+                }
+                wp.setTitle(title);
+            }
+        } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
+                wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
+            // We don't set the app token to this system window because the life cycles should be
+            // independent. If an app creates a system window and then the app goes to the stopped
+            // state, the system window should not be affected (can still show and receive input
+            // events).
+            if (curTitle == null || curTitle.length() == 0) {
+                final StringBuilder title = new StringBuilder(32);
+                title.append("Sys").append(wp.type);
+                if (mAppName != null) {
+                    title.append(":").append(mAppName);
                 }
                 wp.setTitle(title);
             }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index aaf6052..d20c729 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -22,6 +22,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Bundle;
@@ -38,7 +39,7 @@
  * instance of it is created by the window manager when it starts up, and allows
  * customization of window layering, special window types, key dispatching, and
  * layout.
- * 
+ *
  * <p>Because this provides deep interaction with the system window manager,
  * specific methods on this interface can be called from a variety of contexts
  * with various restrictions on what they can do.  These are encoded through
@@ -47,9 +48,9 @@
  * is attached to a method, then it is not called with any locks and may be
  * called from the main window manager thread or another thread calling into
  * the window manager.
- * 
+ *
  * <p>The current suffixes are:
- * 
+ *
  * <dl>
  * <dt> Ti <dd> Called from the input thread.  This is the thread that
  * collects pending input events and dispatches them to the appropriate window.
@@ -71,7 +72,7 @@
  * acquired by the window manager while it holds the window lock, so this is
  * even more restrictive than <var>Lw</var>.
  * </dl>
- * 
+ *
  * @hide
  */
 public interface WindowManagerPolicy {
@@ -138,7 +139,7 @@
          * Perform standard frame computation.  The result can be obtained with
          * getFrame() if so desired.  Must be called with the window manager
          * lock held.
-         * 
+         *
          * @param parentFrame The frame of the parent container this window
          * is in, used for computing its basic position.
          * @param displayFrame The frame of the overall display in which this
@@ -168,18 +169,18 @@
         /**
          * Retrieve the current frame of the window that has been assigned by
          * the window manager.  Must be called with the window manager lock held.
-         * 
+         *
          * @return Rect The rectangle holding the window frame.
          */
         public Rect getFrameLw();
 
         /**
-         * Retrieve the current frame of the window that is actually shown.
+         * Retrieve the current position of the window that is actually shown.
          * Must be called with the window manager lock held.
-         * 
-         * @return Rect The rectangle holding the shown window frame.
+         *
+         * @return Point The point holding the shown window position.
          */
-        public RectF getShownFrameLw();
+        public Point getShownPositionLw();
 
         /**
          * Retrieve the frame of the display that this window was last
@@ -206,7 +207,7 @@
          * account for screen decorations such as a status bar or soft
          * keyboard.  Must be called with the
          * window manager lock held.
-         * 
+         *
          * @return Rect The rectangle holding the content frame.
          */
         public Rect getContentFrameLw();
@@ -218,7 +219,7 @@
          * content frame to account for transient UI elements blocking it
          * such as an input method's candidates UI.  Must be called with the
          * window manager lock held.
-         * 
+         *
          * @return Rect The rectangle holding the visible frame.
          */
         public Rect getVisibleFrameLw();
@@ -229,12 +230,12 @@
          * layout of other windows.
          */
         public boolean getGivenInsetsPendingLw();
-        
+
         /**
          * Retrieve the insets given by this window's client for the content
          * area of windows behind it.  Must be called with the
          * window manager lock held.
-         * 
+         *
          * @return Rect The left, top, right, and bottom insets, relative
          * to the window's frame, of the actual contents.
          */
@@ -244,7 +245,7 @@
          * Retrieve the insets given by this window's client for the visible
          * area of windows behind it.  Must be called with the
          * window manager lock held.
-         * 
+         *
          * @return Rect The left, top, right, and bottom insets, relative
          * to the window's frame, of the actual visible area.
          */
@@ -252,7 +253,7 @@
 
         /**
          * Retrieve the current LayoutParams of the window.
-         * 
+         *
          * @return WindowManager.LayoutParams The window's internal LayoutParams
          *         instance.
          */
@@ -298,12 +299,12 @@
         public boolean isVoiceInteraction();
 
         /**
-         * Return true if, at any point, the application token associated with 
-         * this window has actually displayed any windows.  This is most useful 
-         * with the "starting up" window to determine if any windows were 
-         * displayed when it is closed. 
-         * 
-         * @return Returns true if one or more windows have been displayed, 
+         * Return true if, at any point, the application token associated with
+         * this window has actually displayed any windows.  This is most useful
+         * with the "starting up" window to determine if any windows were
+         * displayed when it is closed.
+         *
+         * @return Returns true if one or more windows have been displayed,
          *         else false.
          */
         public boolean hasAppShownWindows();
@@ -314,17 +315,17 @@
          * that will remove the surface.
          */
         boolean isVisibleLw();
-        
+
         /**
          * Like {@link #isVisibleLw}, but also counts a window that is currently
          * "hidden" behind the keyguard as visible.  This allows us to apply
          * things like window flags that impact the keyguard.
          */
         boolean isVisibleOrBehindKeyguardLw();
-        
+
         /**
-         * Is this window currently visible to the user on-screen?  It is 
-         * displayed either if it is visible or it is currently running an 
+         * Is this window currently visible to the user on-screen?  It is
+         * displayed either if it is visible or it is currently running an
          * animation before no longer being visible.  Must be called with the
          * window manager lock held.
          */
@@ -350,7 +351,7 @@
         boolean isDrawnLw();
 
         /**
-         * Returns true if this window has been shown on screen at some time in 
+         * Returns true if this window has been shown on screen at some time in
          * the past.  Must be called with the window manager lock held.
          */
         public boolean hasDrawnLw();
@@ -362,7 +363,7 @@
          * Returns true if {@link #showLw} was last called for the window.
          */
         public boolean hideLw(boolean doAnimation);
-        
+
         /**
          * Can be called to undo the effect of {@link #hideLw}, allowing a
          * window to be shown as long as the window manager and client would
@@ -479,7 +480,7 @@
 
     // NOTE: screen off reasons are in order of significance, with more
     // important ones lower than less important ones.
-    
+
     /** Screen turned off because of a device admin */
     public final int OFF_BECAUSE_OF_ADMIN = 1;
     /** Screen turned off because of power button */
@@ -498,10 +499,10 @@
     /** When not otherwise specified by the activity's screenOrientation, rotation is set by
      * the user. */
     public final int USER_ROTATION_LOCKED = 1;
-    
+
     /**
      * Perform initialization of the policy.
-     * 
+     *
      * @param context The system context we are running in.
      */
     public void init(Context context, IWindowManager windowManager,
@@ -526,11 +527,11 @@
 
     /**
      * Check permissions when adding a window.
-     * 
+     *
      * @param attrs The window's LayoutParams.
      * @param outAppOp First element will be filled with the app op corresponding to
      *                 this window, or OP_NONE.
-     *  
+     *
      * @return {@link WindowManagerGlobal#ADD_OKAY} if the add can proceed;
      *      else an error code, usually
      *      {@link WindowManagerGlobal#ADD_PERMISSION_DENIED}, to abort the add.
@@ -551,21 +552,21 @@
      * Sanitize the layout parameters coming from a client.  Allows the policy
      * to do things like ensure that windows of a specific type can't take
      * input focus.
-     * 
+     *
      * @param attrs The window layout parameters to be modified.  These values
      * are modified in-place.
      */
     public void adjustWindowParamsLw(WindowManager.LayoutParams attrs);
-    
+
     /**
      * After the window manager has computed the current configuration based
      * on its knowledge of the display and input devices, it gives the policy
      * a chance to adjust the information contained in it.  If you want to
      * leave it as-is, simply do nothing.
-     * 
+     *
      * <p>This method may be called by any thread in the window manager, but
      * no internal locks in the window manager will be held.
-     * 
+     *
      * @param config The Configuration being computed, for you to change as
      * desired.
      * @param keyboardPresence Flags that indicate whether internal or external
@@ -575,13 +576,13 @@
      */
     public void adjustConfigurationLw(Configuration config, int keyboardPresence,
             int navigationPresence);
-    
+
     /**
      * Assign a window type to a layer.  Allows you to control how different
      * kinds of windows are ordered on-screen.
-     * 
+     *
      * @param type The type of window being assigned.
-     * 
+     *
      * @return int An arbitrary integer used to order windows, with lower
      *         numbers below higher ones.
      */
@@ -591,9 +592,9 @@
      * Return how to Z-order sub-windows in relation to the window they are
      * attached to.  Return positive to have them ordered in front, negative for
      * behind.
-     * 
+     *
      * @param type The sub-window type code.
-     * 
+     *
      * @return int Layer in relation to the attached window, where positive is
      *         above and negative is below.
      */
@@ -669,19 +670,19 @@
      * manager (using the normal window manager APIs) that will be shown until
      * the application displays its own window.  This is called without the
      * window manager locked so that you can call back into it.
-     * 
+     *
      * @param appToken Token of the application being started.
-     * @param packageName The name of the application package being started. 
+     * @param packageName The name of the application package being started.
      * @param theme Resource defining the application's overall visual theme.
      * @param nonLocalizedLabel The default title label of the application if
      *        no data is found in the resource.
      * @param labelRes The resource ID the application would like to use as its name.
      * @param icon The resource ID the application would like to use as its icon.
      * @param windowFlags Window layout flags.
-     * 
+     *
      * @return Optionally you can return the View that was used to create the
      *         window, for easy removal in removeStartingWindow.
-     * 
+     *
      * @see #removeStartingWindow
      */
     public View addStartingWindow(IBinder appToken, String packageName,
@@ -694,15 +695,15 @@
      * that application.  You should at this point remove the window from the
      * window manager.  This is called without the window manager locked so
      * that you can call back into it.
-     * 
+     *
      * <p>Note: due to the nature of these functions not being called with the
      * window manager locked, you must be prepared for this function to be
      * called multiple times and/or an initial time with a null View window
      * even if you previously returned one.
-     * 
+     *
      * @param appToken Token of the application that has started.
      * @param window Window View that was returned by createStartingWindow.
-     * 
+     *
      * @see #addStartingWindow
      */
     public void removeStartingWindow(IBinder appToken, View window);
@@ -711,10 +712,10 @@
      * Prepare for a window being added to the window manager.  You can throw an
      * exception here to prevent the window being added, or do whatever setup
      * you need to keep track of the window.
-     * 
+     *
      * @param win The window being added.
-     * @param attrs The window's LayoutParams. 
-     *  
+     * @param attrs The window's LayoutParams.
+     *
      * @return {@link WindowManagerGlobal#ADD_OKAY} if the add can proceed, else an
      *         error code to abort the add.
      */
@@ -724,7 +725,7 @@
     /**
      * Called when a window is being removed from a window manager.  Must not
      * throw an exception -- clean up as much as possible.
-     * 
+     *
      * @param win The window being removed.
      */
     public void removeWindowLw(WindowState win);
@@ -733,12 +734,12 @@
      * Control the animation to run when a window's state changes.  Return a
      * non-0 number to force the animation to a specific resource ID, or 0
      * to use the default animation.
-     * 
+     *
      * @param win The window that is changing.
      * @param transit What is happening to the window: {@link #TRANSIT_ENTER},
      *                {@link #TRANSIT_EXIT}, {@link #TRANSIT_SHOW}, or
      *                {@link #TRANSIT_HIDE}.
-     * 
+     *
      * @return Resource ID of the actual animation to use, or 0 for none.
      */
     public int selectAnimationLw(WindowState win, int transit);
@@ -747,8 +748,8 @@
      * Determine the animation to run for a rotation transition based on the
      * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
      * and whether it is currently fullscreen and frontmost.
-     * 
-     * @param anim The exiting animation resource id is stored in anim[0], the 
+     *
+     * @param anim The exiting animation resource id is stored in anim[0], the
      * entering animation resource id is stored in anim[1].
      */
     public void selectRotationAnimationLw(int anim[]);
@@ -814,7 +815,7 @@
      * <p>Allows you to define
      * behavior for keys that can not be overridden by applications.
      * This method is called from the input thread, with no locks held.
-     * 
+     *
      * @param win The window that currently has focus.  This is where the key
      *            event will normally go.
      * @param event The key event.
@@ -832,7 +833,7 @@
      *
      * <p>Allows you to define default global behavior for keys that were not handled
      * by applications.  This method is called from the input thread, with no locks held.
-     * 
+     *
      * @param win The window that currently has focus.  This is where the key
      *            event will normally go.
      * @param event The key event.
@@ -844,7 +845,7 @@
 
     /**
      * Called when layout of the windows is about to start.
-     * 
+     *
      * @param isDefaultDisplay true if window is on {@link Display#DEFAULT_DISPLAY}.
      * @param displayWidth The current full width of the screen.
      * @param displayHeight The current full height of the screen.
@@ -872,7 +873,7 @@
      * Called for each window attached to the window manager as layout is
      * proceeding.  The implementation of this function must take care of
      * setting the window's frame, either here or in finishLayout().
-     * 
+     *
      * @param win The window being positioned.
      * @param attached For sub-windows, the window it is attached to; this
      *                 window will already have had layoutWindow() called on it
@@ -880,7 +881,7 @@
      */
     public void layoutWindowLw(WindowState win, WindowState attached);
 
-    
+
     /**
      * Return the insets for the areas covered by system windows. These values
      * are computed on the most recent layout, so they are not guaranteed to
@@ -912,10 +913,10 @@
     static final int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004;
     /** Need to recompute animations */
     static final int FINISH_LAYOUT_REDO_ANIM = 0x0008;
-    
+
     /**
      * Called following layout of all windows before each window has policy applied.
-     * 
+     *
      * @param displayWidth The current full width of the screen.
      * @param displayHeight The current full height of the screen.
      */
@@ -936,7 +937,7 @@
      * to each window. If in this function you do
      * something that may have modified the animation state of another window,
      * be sure to return non-zero in order to perform another pass through layout.
-     *  
+     *
      * @return Return any bit set of {@link #FINISH_LAYOUT_REDO_LAYOUT},
      * {@link #FINISH_LAYOUT_REDO_CONFIG}, {@link #FINISH_LAYOUT_REDO_WALLPAPER},
      * or {@link #FINISH_LAYOUT_REDO_ANIM}.
@@ -1150,7 +1151,7 @@
      * the system should go into safe mode.
      */
     public void setSafeMode(boolean safeMode);
-    
+
     /**
      * Called when the system is mostly done booting.
      */
@@ -1184,14 +1185,14 @@
      * this point the display is active.
      */
     public void enableScreenAfterBoot();
-    
+
     public void setCurrentOrientationLw(@ActivityInfo.ScreenOrientation int newOrientation);
-    
+
     /**
      * Call from application to perform haptic feedback on its window.
      */
     public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always);
-    
+
     /**
      * Called when we have started keeping the screen on because a window
      * requesting this has become visible.
@@ -1205,21 +1206,21 @@
     public void keepScreenOnStoppedLw();
 
     /**
-     * Gets the current user rotation mode. 
+     * Gets the current user rotation mode.
      *
      * @return The rotation mode.
      *
      * @see WindowManagerPolicy#USER_ROTATION_LOCKED
-     * @see WindowManagerPolicy#USER_ROTATION_FREE 
+     * @see WindowManagerPolicy#USER_ROTATION_FREE
      */
     @UserRotationMode
     public int getUserRotationMode();
 
     /**
-     * Inform the policy that the user has chosen a preferred orientation ("rotation lock"). 
+     * Inform the policy that the user has chosen a preferred orientation ("rotation lock").
      *
      * @param mode One of {@link WindowManagerPolicy#USER_ROTATION_LOCKED} or
-     *             {@link WindowManagerPolicy#USER_ROTATION_FREE}. 
+     *             {@link WindowManagerPolicy#USER_ROTATION_FREE}.
      * @param rotation One of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
      *                 {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
      */
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 11d0f4a..4ac547a 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -429,7 +429,8 @@
 
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + "mId=" + mId
-                + " mSettingsActivityName=" + mSettingsActivityName);
+                + " mSettingsActivityName=" + mSettingsActivityName
+                + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod);
         pw.println(prefix + "mIsDefaultResId=0x"
                 + Integer.toHexString(mIsDefaultResId));
         pw.println(prefix + "Service:");
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0712052..1aeb9c93 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -116,6 +116,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.view.View;
 import android.view.ViewParent;
 import android.view.ViewStructure;
@@ -5905,6 +5906,17 @@
         return mLayout != null ? mLayout.getHeight() : 0;
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public int getPointerShape(MotionEvent event, float x, float y) {
+        if (isTextSelectable() || isTextEditable()) {
+            return PointerIcon.STYLE_TEXT;
+        }
+        return super.getPointerShape(event, x, y);
+    }
+
     @Override
     public boolean onKeyPreIme(int keyCode, KeyEvent event) {
         // Note: If the IME is in fullscreen mode and IMS#mExtractEditText is in text action mode,
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 255e23a..f462a47 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1017,7 +1017,15 @@
                             final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f)
                                     .setInterpolator(mInterpolator);
                             mServiceTargetScale[i] = rs;
-                            rs.startAnimation();
+                        }
+
+                        // Start the animations in a separate loop.
+                        // The process of starting animations will result in
+                        // binding views to set up initial values, and we must
+                        // have ALL of the new RowScale objects created above before
+                        // we get started.
+                        for (int i = oldRCount; i < rcount; i++) {
+                            mServiceTargetScale[i].startAnimation();
                         }
                     }
 
@@ -1097,17 +1105,19 @@
 
             for (int i = 0; i < mColumnCount; i++) {
                 final View v = mChooserListAdapter.createView(row);
+                final int column = i;
                 v.setOnClickListener(new OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        startSelected(holder.itemIndex, false, true);
+                        startSelected(holder.itemIndices[column], false, true);
                     }
                 });
                 v.setOnLongClickListener(new OnLongClickListener() {
                     @Override
                     public boolean onLongClick(View v) {
                         showAppDetails(
-                                mChooserListAdapter.resolveInfoForPosition(holder.itemIndex, true));
+                                mChooserListAdapter.resolveInfoForPosition(
+                                        holder.itemIndices[column], true));
                         return true;
                     }
                 });
@@ -1165,8 +1175,8 @@
                 final View v = holder.cells[i];
                 if (start + i <= end) {
                     v.setVisibility(View.VISIBLE);
-                    holder.itemIndex = start + i;
-                    mChooserListAdapter.bindView(holder.itemIndex, v);
+                    holder.itemIndices[i] = start + i;
+                    mChooserListAdapter.bindView(holder.itemIndices[i], v);
                 } else {
                     v.setVisibility(View.GONE);
                 }
@@ -1197,11 +1207,12 @@
         final View[] cells;
         final ViewGroup row;
         int measuredRowHeight;
-        int itemIndex;
+        int[] itemIndices;
 
         public RowViewHolder(ViewGroup row, int cellCount) {
             this.row = row;
             this.cells = new View[cellCount];
+            this.itemIndices = new int[cellCount];
         }
 
         public void measure() {
@@ -1389,7 +1400,7 @@
                 final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView);
                 int height = ((RowViewHolder) (v.getTag())).measuredRowHeight;
 
-                offset += (int) (height * mChooserRowAdapter.getRowScale(pos) * chooserTargetRows);
+                offset += (int) (height * mChooserRowAdapter.getRowScale(pos));
 
                 if (vt >= 0) {
                     mCachedViewType = vt;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index aaa89df..9a5cde6 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -70,6 +70,7 @@
     private static final String TAG = "Zygote";
 
     private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
+    private static final String PROPERTY_RUNNING_IN_CONTAINER = "ro.boot.container";
 
     private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
 
@@ -503,7 +504,6 @@
     private static boolean startSystemServer(String abiList, String socketName)
             throws MethodAndArgsCaller, RuntimeException {
         long capabilities = posixCapabilitiesAsBits(
-            OsConstants.CAP_BLOCK_SUSPEND,
             OsConstants.CAP_KILL,
             OsConstants.CAP_NET_ADMIN,
             OsConstants.CAP_NET_BIND_SERVICE,
@@ -515,6 +515,10 @@
             OsConstants.CAP_SYS_TIME,
             OsConstants.CAP_SYS_TTY_CONFIG
         );
+        /* Containers run without this capability, so avoid setting it in that case */
+        if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
+            capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
+        }
         /* Hardcoded command line to start the system server */
         String args[] = {
             "--setuid=1000",
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index ab372d3..75ad916a 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -3705,13 +3705,14 @@
         }
 
         /**
-         * Returns true if the Window is free floating and has a shadow. Note that non overlapping
-         * windows do not have a shadow since it could not be seen anyways (a small screen / tablet
+         * Returns true if the Window is free floating and has a shadow (although at some times
+         * it might not be displaying it, e.g. during a resize). Note that non overlapping windows
+         * do not have a shadow since it could not be seen anyways (a small screen / tablet
          * "tiles" the windows side by side but does not overlap them).
          * @return Returns true when the window has a shadow created by the non client decor.
          **/
         private boolean windowHasShadow() {
-            return windowHasNonClientDecor() && getElevation() > 0;
+            return windowHasNonClientDecor() && nonClientDecorHasShadow(mWindow.mWorkspaceId);
         }
 
         void setWindow(PhoneWindow phoneWindow) {
@@ -5417,7 +5418,7 @@
      * @param workspaceId The Id of the workspace which contains this window.
      * @Return Returns true if the window should show a shadow.
      **/
-    private boolean nonClientDecorHasShadow(int workspaceId) {
+    private static boolean nonClientDecorHasShadow(int workspaceId) {
         return workspaceId == FREEFORM_WORKSPACE_STACK_ID;
     }
 
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 614e82f..c94bc64 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
 
 #include <private/android_filesystem_config.h> // for AID_SYSTEM
 
@@ -171,11 +172,32 @@
                     exit(1);
                 }
 
-                execl(AssetManager::IDMAP_BIN, AssetManager::IDMAP_BIN, "--scan",
-                        AssetManager::OVERLAY_DIR, AssetManager::TARGET_PACKAGE_NAME,
-                        AssetManager::TARGET_APK_PATH, AssetManager::IDMAP_DIR, (char*)NULL);
-                ALOGE("failed to execl for idmap: %s", strerror(errno));
-                exit(1); // should never get here
+                // Generic idmap parameters
+                const char* argv[7];
+                int argc = 0;
+                struct stat st;
+
+                memset(argv, NULL, sizeof(argv));
+                argv[argc++] = AssetManager::IDMAP_BIN;
+                argv[argc++] = "--scan";
+                argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
+                argv[argc++] = AssetManager::TARGET_APK_PATH;
+                argv[argc++] = AssetManager::IDMAP_DIR;
+
+                // Directories to scan for overlays
+                // /vendor/overlay
+                if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
+                    argv[argc++] = AssetManager::OVERLAY_DIR;
+                 }
+
+                // Finally, invoke idmap (if any overlay directory exists)
+                if (argc > 5) {
+                    execv(AssetManager::IDMAP_BIN, (char* const*)argv);
+                    ALOGE("failed to execl for idmap: %s", strerror(errno));
+                    exit(1); // should never get here
+                } else {
+                    exit(0);
+                }
             }
             break;
         default: // parent
diff --git a/core/jni/android_view_PointerIcon.h b/core/jni/android_view_PointerIcon.h
index 3bfd645..86f288d 100644
--- a/core/jni/android_view_PointerIcon.h
+++ b/core/jni/android_view_PointerIcon.h
@@ -31,6 +31,27 @@
     POINTER_ICON_STYLE_CUSTOM = -1,
     POINTER_ICON_STYLE_NULL = 0,
     POINTER_ICON_STYLE_ARROW = 1000,
+    POINTER_ICON_STYLE_CONTEXT_MENU = 1001,
+    POINTER_ICON_STYLE_HAND = 1002,
+    POINTER_ICON_STYLE_HELP = 1003,
+    POINTER_ICON_STYLE_WAIT = 1004,
+    POINTER_ICON_STYLE_CELL = 1006,
+    POINTER_ICON_STYLE_CROSSHAIR = 1007,
+    POINTER_ICON_STYLE_TEXT = 1008,
+    POINTER_ICON_STYLE_VERTICAL_TEXT = 1009,
+    POINTER_ICON_STYLE_ALIAS = 1010,
+    POINTER_ICON_STYLE_COPY = 1011,
+    POINTER_ICON_STYLE_NO_DROP = 1012,
+    POINTER_ICON_STYLE_ALL_SCROLL = 1013,
+    POINTER_ICON_STYLE_HORIZONTAL_DOUBLE_ARROW = 1014,
+    POINTER_ICON_STYLE_VERTICAL_DOUBLE_ARROW = 1015,
+    POINTER_ICON_STYLE_TOP_RIGHT_DOUBLE_ARROW = 1016,
+    POINTER_ICON_STYLE_TOP_LEFT_DOUBLE_ARROW = 1017,
+    POINTER_ICON_STYLE_ZOOM_IN = 1018,
+    POINTER_ICON_STYLE_ZOOM_OUT = 1019,
+    POINTER_ICON_STYLE_GRAB = 1020,
+    POINTER_ICON_STYLE_GRABBING = 1021,
+
     POINTER_ICON_STYLE_SPOT_HOVER = 2000,
     POINTER_ICON_STYLE_SPOT_TOUCH = 2001,
     POINTER_ICON_STYLE_SPOT_ANCHOR = 2002,
diff --git a/core/res/res/drawable-mdpi/pointer_alias.png b/core/res/res/drawable-mdpi/pointer_alias.png
new file mode 100644
index 0000000..8f61a39
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_alias.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_all_scroll.png b/core/res/res/drawable-mdpi/pointer_all_scroll.png
new file mode 100644
index 0000000..a897ef4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_all_scroll.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_cell.png b/core/res/res/drawable-mdpi/pointer_cell.png
new file mode 100644
index 0000000..b521389
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_cell.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_context_menu.png b/core/res/res/drawable-mdpi/pointer_context_menu.png
new file mode 100644
index 0000000..4e1ba4e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_context_menu.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_copy.png b/core/res/res/drawable-mdpi/pointer_copy.png
new file mode 100644
index 0000000..7d41036
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_copy.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_crosshair.png b/core/res/res/drawable-mdpi/pointer_crosshair.png
new file mode 100644
index 0000000..8a06c77
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_crosshair.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_grab.png b/core/res/res/drawable-mdpi/pointer_grab.png
new file mode 100644
index 0000000..0e0ea2e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_grab.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_grabbing.png b/core/res/res/drawable-mdpi/pointer_grabbing.png
new file mode 100644
index 0000000..9deb64c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_grabbing.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_hand.png b/core/res/res/drawable-mdpi/pointer_hand.png
new file mode 100644
index 0000000..c614d9e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_hand.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_help.png b/core/res/res/drawable-mdpi/pointer_help.png
new file mode 100644
index 0000000..d54b2b1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_help.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png b/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png
new file mode 100644
index 0000000..a2951a9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_horizontal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_nodrop.png b/core/res/res/drawable-mdpi/pointer_nodrop.png
new file mode 100644
index 0000000..ad13c66
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_nodrop.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_text.png b/core/res/res/drawable-mdpi/pointer_text.png
new file mode 100644
index 0000000..34d1698
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_text.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png b/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png
new file mode 100644
index 0000000..b0cd92c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_top_left_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png b/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png
new file mode 100644
index 0000000..f8d3527
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_top_right_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png b/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png
new file mode 100644
index 0000000..48c9379
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_vertical_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_vertical_text.png b/core/res/res/drawable-mdpi/pointer_vertical_text.png
new file mode 100644
index 0000000..9fcbcba
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_vertical_text.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_zoom_in.png b/core/res/res/drawable-mdpi/pointer_zoom_in.png
new file mode 100644
index 0000000..17c4e66
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_zoom_in.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_zoom_out.png b/core/res/res/drawable-mdpi/pointer_zoom_out.png
new file mode 100644
index 0000000..742f705
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_zoom_out.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_alias.png b/core/res/res/drawable-xhdpi/pointer_alias.png
new file mode 100644
index 0000000..fe0fd25
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_alias.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_all_scroll.png b/core/res/res/drawable-xhdpi/pointer_all_scroll.png
new file mode 100644
index 0000000..e2374ec
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_all_scroll.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_cell.png b/core/res/res/drawable-xhdpi/pointer_cell.png
new file mode 100644
index 0000000..4ca09e3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_cell.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_context_menu.png b/core/res/res/drawable-xhdpi/pointer_context_menu.png
new file mode 100644
index 0000000..05a59f8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_context_menu.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_copy.png b/core/res/res/drawable-xhdpi/pointer_copy.png
new file mode 100644
index 0000000..f28a3e9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_copy.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_crosshair.png b/core/res/res/drawable-xhdpi/pointer_crosshair.png
new file mode 100644
index 0000000..86c649c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_crosshair.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_grab.png b/core/res/res/drawable-xhdpi/pointer_grab.png
new file mode 100644
index 0000000..b5c28ba
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_grab.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_grabbing.png b/core/res/res/drawable-xhdpi/pointer_grabbing.png
new file mode 100644
index 0000000..6aba589
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_grabbing.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_hand.png b/core/res/res/drawable-xhdpi/pointer_hand.png
new file mode 100644
index 0000000..486cb24
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_hand.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_help.png b/core/res/res/drawable-xhdpi/pointer_help.png
new file mode 100644
index 0000000..98a6632
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_help.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png
new file mode 100644
index 0000000..299ae11
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_nodrop.png b/core/res/res/drawable-xhdpi/pointer_nodrop.png
new file mode 100644
index 0000000..c56bfbb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_nodrop.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_text.png b/core/res/res/drawable-xhdpi/pointer_text.png
new file mode 100644
index 0000000..0cebeae
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_text.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png
new file mode 100644
index 0000000..5454a8b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png
new file mode 100644
index 0000000..a4268e4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png
new file mode 100644
index 0000000..95ca954
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_vertical_text.png b/core/res/res/drawable-xhdpi/pointer_vertical_text.png
new file mode 100644
index 0000000..a07d091
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_vertical_text.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_zoom_in.png b/core/res/res/drawable-xhdpi/pointer_zoom_in.png
new file mode 100644
index 0000000..9c29fcb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_zoom_in.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_zoom_out.png b/core/res/res/drawable-xhdpi/pointer_zoom_out.png
new file mode 100644
index 0000000..710552b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_zoom_out.png
Binary files differ
diff --git a/core/res/res/drawable/pointer_alias_icon.xml b/core/res/res/drawable/pointer_alias_icon.xml
new file mode 100644
index 0000000..8ba9301
--- /dev/null
+++ b/core/res/res/drawable/pointer_alias_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_alias"
+    android:hotSpotX="8dp"
+    android:hotSpotY="6dp" />
diff --git a/core/res/res/drawable/pointer_all_scroll_icon.xml b/core/res/res/drawable/pointer_all_scroll_icon.xml
new file mode 100644
index 0000000..e946948
--- /dev/null
+++ b/core/res/res/drawable/pointer_all_scroll_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_all_scroll"
+    android:hotSpotX="11dp"
+    android:hotSpotY="11dp" />
diff --git a/core/res/res/drawable/pointer_cell_icon.xml b/core/res/res/drawable/pointer_cell_icon.xml
new file mode 100644
index 0000000..da1e320
--- /dev/null
+++ b/core/res/res/drawable/pointer_cell_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_cell"
+    android:hotSpotX="11dp"
+    android:hotSpotY="11dp" />
diff --git a/core/res/res/drawable/pointer_context_menu_icon.xml b/core/res/res/drawable/pointer_context_menu_icon.xml
new file mode 100644
index 0000000..330b627
--- /dev/null
+++ b/core/res/res/drawable/pointer_context_menu_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_context_menu"
+    android:hotSpotX="4dp"
+    android:hotSpotY="4dp" />
diff --git a/core/res/res/drawable/pointer_copy_icon.xml b/core/res/res/drawable/pointer_copy_icon.xml
new file mode 100644
index 0000000..e299db5
--- /dev/null
+++ b/core/res/res/drawable/pointer_copy_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_copy"
+    android:hotSpotX="9dp"
+    android:hotSpotY="9dp" />
diff --git a/core/res/res/drawable/pointer_crosshair_icon.xml b/core/res/res/drawable/pointer_crosshair_icon.xml
new file mode 100644
index 0000000..3b96a8a
--- /dev/null
+++ b/core/res/res/drawable/pointer_crosshair_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_crosshair"
+    android:hotSpotX="12dp"
+    android:hotSpotY="12dp" />
diff --git a/core/res/res/drawable/pointer_grab_icon.xml b/core/res/res/drawable/pointer_grab_icon.xml
new file mode 100644
index 0000000..d437b3a
--- /dev/null
+++ b/core/res/res/drawable/pointer_grab_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_grab"
+    android:hotSpotX="8dp"
+    android:hotSpotY="5dp" />
diff --git a/core/res/res/drawable/pointer_grabbing_icon.xml b/core/res/res/drawable/pointer_grabbing_icon.xml
new file mode 100644
index 0000000..38f4c3a
--- /dev/null
+++ b/core/res/res/drawable/pointer_grabbing_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_grabbing"
+    android:hotSpotX="9dp"
+    android:hotSpotY="9dp" />
diff --git a/core/res/res/drawable/pointer_hand_icon.xml b/core/res/res/drawable/pointer_hand_icon.xml
new file mode 100644
index 0000000..3d90b88
--- /dev/null
+++ b/core/res/res/drawable/pointer_hand_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_hand"
+    android:hotSpotX="9dp"
+    android:hotSpotY="4dp" />
diff --git a/core/res/res/drawable/pointer_help_icon.xml b/core/res/res/drawable/pointer_help_icon.xml
new file mode 100644
index 0000000..49ae554
--- /dev/null
+++ b/core/res/res/drawable/pointer_help_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_help"
+    android:hotSpotX="4dp"
+    android:hotSpotY="4dp" />
diff --git a/core/res/res/drawable/pointer_horizontal_double_arrow_icon.xml b/core/res/res/drawable/pointer_horizontal_double_arrow_icon.xml
new file mode 100644
index 0000000..5a5ad9e
--- /dev/null
+++ b/core/res/res/drawable/pointer_horizontal_double_arrow_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_horizontal_double_arrow"
+    android:hotSpotX="11dp"
+    android:hotSpotY="12dp" />
diff --git a/core/res/res/drawable/pointer_nodrop_icon.xml b/core/res/res/drawable/pointer_nodrop_icon.xml
new file mode 100644
index 0000000..955b40f
--- /dev/null
+++ b/core/res/res/drawable/pointer_nodrop_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_nodrop"
+    android:hotSpotX="9dp"
+    android:hotSpotY="9dp" />
diff --git a/core/res/res/drawable/pointer_text_icon.xml b/core/res/res/drawable/pointer_text_icon.xml
new file mode 100644
index 0000000..d948c89
--- /dev/null
+++ b/core/res/res/drawable/pointer_text_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_text"
+    android:hotSpotX="12dp"
+    android:hotSpotY="12dp" />
diff --git a/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_icon.xml b/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_icon.xml
new file mode 100644
index 0000000..de5efe2
--- /dev/null
+++ b/core/res/res/drawable/pointer_top_left_diagonal_double_arrow_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_top_left_diagonal_double_arrow"
+    android:hotSpotX="11dp"
+    android:hotSpotY="11dp" />
diff --git a/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_icon.xml b/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_icon.xml
new file mode 100644
index 0000000..e87b526
--- /dev/null
+++ b/core/res/res/drawable/pointer_top_right_diagonal_double_arrow_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_top_right_diagonal_double_arrow"
+    android:hotSpotX="12dp"
+    android:hotSpotY="11dp" />
diff --git a/core/res/res/drawable/pointer_vertical_double_arrow_icon.xml b/core/res/res/drawable/pointer_vertical_double_arrow_icon.xml
new file mode 100644
index 0000000..5759079
--- /dev/null
+++ b/core/res/res/drawable/pointer_vertical_double_arrow_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_vertical_double_arrow"
+    android:hotSpotX="11dp"
+    android:hotSpotY="12dp" />
diff --git a/core/res/res/drawable/pointer_vertical_text_icon.xml b/core/res/res/drawable/pointer_vertical_text_icon.xml
new file mode 100644
index 0000000..3b48dc8
--- /dev/null
+++ b/core/res/res/drawable/pointer_vertical_text_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_vertical_text"
+    android:hotSpotX="12dp"
+    android:hotSpotY="11dp" />
diff --git a/core/res/res/drawable/pointer_zoom_in_icon.xml b/core/res/res/drawable/pointer_zoom_in_icon.xml
new file mode 100644
index 0000000..e2dcb49
--- /dev/null
+++ b/core/res/res/drawable/pointer_zoom_in_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_zoom_in"
+    android:hotSpotX="10dp"
+    android:hotSpotY="10dp" />
diff --git a/core/res/res/drawable/pointer_zoom_out_icon.xml b/core/res/res/drawable/pointer_zoom_out_icon.xml
new file mode 100644
index 0000000..b805df3
--- /dev/null
+++ b/core/res/res/drawable/pointer_zoom_out_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_zoom_out"
+    android:hotSpotX="10dp"
+    android:hotSpotY="10dp" />
diff --git a/core/res/res/drawable/spinner_background_material.xml b/core/res/res/drawable/spinner_background_material.xml
index d37f5b7..c2a2a26 100644
--- a/core/res/res/drawable/spinner_background_material.xml
+++ b/core/res/res/drawable/spinner_background_material.xml
@@ -17,18 +17,18 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android"
             android:paddingMode="stack"
             android:paddingStart="0dp"
-            android:paddingEnd="24dp"
+            android:paddingEnd="48dp"
             android:paddingLeft="0dp"
             android:paddingRight="0dp">
     <item
-        android:gravity="end|center_vertical"
-        android:width="24dp"
-        android:height="24dp"
+        android:gravity="end|fill_vertical"
+        android:width="48dp"
         android:drawable="@drawable/control_background_40dp_material" />
 
     <item
         android:drawable="@drawable/ic_spinner_caret"
         android:gravity="end|center_vertical"
         android:width="24dp"
-        android:height="24dp" />
+        android:height="24dp"
+        android:end="12dp" />
 </layer-list>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 60f0502..9c420c2 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -143,7 +143,7 @@
     <string name="fcError" msgid="3327560126588500777">"Forbindelsesproblemer eller ugyldig funktionskode."</string>
     <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
     <string name="httpError" msgid="7956392511146698522">"Der opstod en netværksfejl."</string>
-    <string name="httpErrorLookup" msgid="4711687456111963163">"Webadressen kunne ikke findes."</string>
+    <string name="httpErrorLookup" msgid="4711687456111963163">"Webadressen blev ikke fundet."</string>
     <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Ordningen for webstedsgodkendelse understøttes ikke."</string>
     <string name="httpErrorAuth" msgid="1435065629438044534">"Der kunne ikke godkendes."</string>
     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Godkendelse via proxyserveren mislykkedes."</string>
@@ -155,7 +155,7 @@
     <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Der kunne ikke oprettes en sikker forbindelse."</string>
     <string name="httpErrorBadUrl" msgid="3636929722728881972">"Siden kunne ikke åbnes, fordi webadressen er ugyldig."</string>
     <string name="httpErrorFile" msgid="2170788515052558676">"Der kunne ikke fås adgang til filen."</string>
-    <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Den ønskede fil kunne ikke findes."</string>
+    <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Den ønskede fil blev ikke fundet."</string>
     <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Der behandles for mange anmodninger. Prøv igen senere."</string>
     <string name="notification_title" msgid="8967710025036163822">"Loginfejl for <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"Synkroniser"</string>
@@ -248,7 +248,7 @@
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"undersøge indholdet i et vindue, du interagerer med."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"aktivere Udforsk ved berøring"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"De emner, der trykkes på, læses højt, og skærmen kan udforskes ved hjælp af bevægelser."</string>
-    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"aktivere forbedrede webhjælpefunktioner"</string>
+    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Aktivér udvidede webhjælpefunktioner"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Der installeres muligvis scripts for at gøre appindhold mere tilgængeligt."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"observere tekst, du skriver"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Dette omfatter personlige data såsom kreditkortnumre og adgangskoder."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index c13ef14..54100d5 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -223,7 +223,7 @@
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
-    <string name="android_system_label" msgid="6577375335728551336">"Android系统"</string>
+    <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"个人"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"工作"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"通讯录"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a6eb68b..b818fe0 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7605,6 +7605,44 @@
         <attr name="pointerIconSpotTouch" format="reference" />
         <!-- Reference to a pointer icon drawable with STYLE_SPOT_ANCHOR -->
         <attr name="pointerIconSpotAnchor" format="reference" />
+        <!-- Reference to a pointer drawable with STYLE_CONTEXT_MENU -->
+        <attr name="pointerIconContextMenu" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_HAND -->
+        <attr name="pointerIconHand" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_HELP -->
+        <attr name="pointerIconHelp" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_CELL -->
+        <attr name="pointerIconCell" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_CROSSHAIR -->
+        <attr name="pointerIconCrosshair" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_TEXT -->
+        <attr name="pointerIconText" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_VERTICAL_TEXT -->
+        <attr name="pointerIconVerticalText" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_ALIAS -->
+        <attr name="pointerIconAlias" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_COPY -->
+        <attr name="pointerIconCopy" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_NODROP -->
+        <attr name="pointerIconNodrop" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_ALL_SCROLL -->
+        <attr name="pointerIconAllScroll" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_HORIZONTAL_DOUBLE_ARROW -->
+        <attr name="pointerIconHorizontalDoubleArrow" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_VERTICAL_DOUBLE_ARROW -->
+        <attr name="pointerIconVerticalDoubleArrow" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW -->
+        <attr name="pointerIconTopRightDiagonalDoubleArrow" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW -->
+        <attr name="pointerIconTopLeftDiagonalDoubleArrow" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_ZOOM_IN -->
+        <attr name="pointerIconZoomIn" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_ZOOM_OUT -->
+        <attr name="pointerIconZoomOut" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_GRAB -->
+        <attr name="pointerIconGrab" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_GRABBING -->
+        <attr name="pointerIconGrabbing" format="reference"/>
     </declare-styleable>
 
     <declare-styleable name="PointerIcon">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 091d57f..322ac4f 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2093,6 +2093,10 @@
             <enum name="hdpi" value="240" />
             <!-- An extra high density screen, approximately 320dpi. -->
             <enum name="xhdpi" value="320" />
+            <!-- An extra extra high density screen, approximately 480dpi. -->
+            <enum name="xxhdpi" value="480" />
+            <!-- An extra extra extra high density screen, approximately 640dpi. -->
+            <enum name="xxxhdpi" value="640" />
         </attr>
     </declare-styleable>
 
@@ -2193,18 +2197,25 @@
       <attr name="name" />
     </declare-styleable>
 
-    <!-- <code>initial-layout</code> tag allows configuring the initial layout for the activity
-         within multi-window environment. -->
-    <declare-styleable name="AndroidManifestInitialLayout" parent="AndroidManifestActivity">
+    <!-- <code>layout</code> tag allows configuring the layout for the activity within multi-window
+         environment. -->
+    <declare-styleable name="AndroidManifestLayout" parent="AndroidManifestActivity">
         <!-- Initial width of the activity. Can be either a fixed value or fraction, in which case
              the width will be constructed as a fraction of the total available width. -->
-        <attr name="activityWidth" format="dimension|fraction" />
+        <attr name="initialWidth" format="dimension|fraction" />
         <!-- Initial height of the activity. Can be either a fixed value or fraction, in which case
              the height will be constructed as a fraction of the total available height. -->
-        <attr name="activityHeight" format="dimension|fraction" />
+        <attr name="initialHeight" format="dimension|fraction" />
         <!-- Where to initially position the activity inside the available space. Uses constants
              defined in {@link android.view.Gravity}. -->
         <attr name="gravity" />
+        <!-- Minimal height of the activity.
+
+             <p>NOTE: A task's root activity value is applied to all additional activities launched
+             in the task. That is if the root activity of a task set minimal size, then the system
+             will set the same minimal size on all other activities in the task. It will also
+             ignore any other minimal size attributes of non-root activities. -->
+        <attr name="minimalSize" format="dimension" />
     </declare-styleable>
 
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 24d760f..f833719 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -938,6 +938,9 @@
     <!-- Is the device capable of hot swapping an UICC Card -->
     <bool name="config_hotswapCapable">false</bool>
 
+    <!-- Component name of the ICC hotswap prompt for restart dialog -->
+    <string name="config_iccHotswapPromptForRestartDialogComponent" translateable="false">@null</string>
+
     <!-- Enable puk unlockscreen by default.
          If unlock screen is disabled, the puk should be unlocked through Emergency Dialer -->
     <bool name="config_enable_puk_unlock_screen">true</bool>
@@ -2318,7 +2321,7 @@
 
     <!-- Flag indicating device support for EAP SIM, AKA, AKA' -->
     <bool name="config_eap_sim_based_auth_supported">true</bool>
- 
+
     <!-- How long history of previous vibrations should be kept for the dumpsys. -->
     <integer name="config_previousVibrationsDumpLimit">20</integer>
 
@@ -2349,4 +2352,8 @@
     <!-- Name of the component to handle network policy notifications. If present,
          disables NetworkPolicyManagerService's presentation of data-usage notifications. -->
     <string translatable="false" name="config_networkPolicyNotificationComponent"></string>
+
+    <!-- The fraction of display size (lower of height and width) that will be used to determine
+         the default minimal size for resizeable tasks. -->
+    <fraction name="config_displayFractionForDefaultMinimalSizeOfResizeableTask">25%</fraction>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f4d0b39..957cb50 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2662,8 +2662,9 @@
 
     <public type="attr" name="listMenuViewStyle" />
     <public type="attr" name="subMenuArrow" />
-    <public type="attr" name="activityWidth" />
-    <public type="attr" name="activityHeight" />
+    <public type="attr" name="initialWidth" />
+    <public type="attr" name="initialHeight" />
+    <public type="attr" name="minimalSize" />
     <public type="attr" name="resizeableActivity" />
     <public type="attr" name="titleMargin" />
     <public type="attr" name="titleMarginStart" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index af5c74d..40cd097 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3993,6 +3993,9 @@
     <!-- Zen mode condition - line two: ending time. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_until">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
 
+    <!-- Zen mode condition - line one: Until next alarm. [CHAR LIMIT=NONE] -->
+    <string name="zen_mode_alarm">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g> (next alarm)</string>
+
     <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_forever">Until you turn this off</string>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 11c4cc0..b831df8 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1336,6 +1336,33 @@
         <item name="pointerIconSpotHover">@drawable/pointer_spot_hover_icon</item>
         <item name="pointerIconSpotTouch">@drawable/pointer_spot_touch_icon</item>
         <item name="pointerIconSpotAnchor">@drawable/pointer_spot_anchor_icon</item>
+        <item name="pointerIconHand">@drawable/pointer_hand_icon</item>
+        <item name="pointerIconContextMenu">@drawable/pointer_context_menu_icon</item>
+        <item name="pointerIconHelp">@drawable/pointer_help_icon</item>
+        <item name="pointerIconCell">@drawable/pointer_cell_icon</item>
+        <item name="pointerIconCrosshair">@drawable/pointer_crosshair_icon</item>
+        <item name="pointerIconText">@drawable/pointer_text_icon</item>
+        <item name="pointerIconVerticalText">@drawable/pointer_vertical_text_icon</item>
+        <item name="pointerIconAlias">@drawable/pointer_alias_icon</item>
+        <item name="pointerIconCopy">@drawable/pointer_copy_icon</item>
+        <item name="pointerIconAllScroll">@drawable/pointer_all_scroll_icon</item>
+        <item name="pointerIconNodrop">@drawable/pointer_nodrop_icon</item>
+        <item name="pointerIconHorizontalDoubleArrow">
+            @drawable/pointer_horizontal_double_arrow_icon
+        </item>
+        <item name="pointerIconVerticalDoubleArrow">
+            @drawable/pointer_vertical_double_arrow_icon
+        </item>
+        <item name="pointerIconTopRightDiagonalDoubleArrow">
+            @drawable/pointer_top_right_diagonal_double_arrow_icon
+        </item>
+        <item name="pointerIconTopLeftDiagonalDoubleArrow">
+            @drawable/pointer_top_left_diagonal_double_arrow_icon
+        </item>
+        <item name="pointerIconZoomIn">@drawable/pointer_zoom_in_icon</item>
+        <item name="pointerIconZoomOut">@drawable/pointer_zoom_out_icon</item>
+        <item name="pointerIconGrab">@drawable/pointer_grab_icon</item>
+        <item name="pointerIconGrabbing">@drawable/pointer_grabbing_icon</item>
     </style>
 
     <!-- Wifi dialog styles -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 06de81d..1239b87 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1686,6 +1686,7 @@
   <java-symbol type="id" name="replace_app_icon" />
   <java-symbol type="id" name="replace_message" />
   <java-symbol type="fraction" name="config_dimBehindFadeDuration" />
+  <java-symbol type="fraction" name="config_displayFractionForDefaultMinimalSizeOfResizeableTask" />
   <java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
   <java-symbol type="integer" name="config_autoBrightnessBrighteningLightDebounce"/>
   <java-symbol type="integer" name="config_autoBrightnessDarkeningLightDebounce"/>
@@ -2078,6 +2079,7 @@
   <java-symbol type="string" name="zen_mode_default_events_name" />
   <java-symbol type="array" name="config_system_condition_providers" />
   <java-symbol type="string" name="muted_by" />
+  <java-symbol type="string" name="zen_mode_alarm" />
 
   <java-symbol type="string" name="select_day" />
   <java-symbol type="string" name="select_year" />
@@ -2326,4 +2328,6 @@
   <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
 
   <java-symbol type="drawable" name="platlogo_m" />
+
+  <java-symbol type="string" name="config_iccHotswapPromptForRestartDialogComponent" />
 </resources>
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index 6d20503..7164747 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -618,7 +618,7 @@
     }
 
     @SmallTest
-    public void testASeek() throws Throwable {
+    public void testSeek() throws Throwable {
         final MyListener l1 = new MyListener();
         final MyListener l2 = new MyListener();
         final MyUpdateListener updateListener1 = new MyUpdateListener();
@@ -757,6 +757,227 @@
 
     }
 
+    @SmallTest
+    public void testSeekWhileRunning() throws Throwable {
+        // Seek one animator to the beginning and the other one to the end when they are running.
+        final MyListener l1 = new MyListener();
+        final MyListener l2 = new MyListener();
+        a1.addListener(l1);
+        a2.addListener(l2);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(l1.startCalled);
+                assertFalse(l2.startCalled);
+                assertEquals(0f, a1.getAnimatedFraction());
+                assertEquals(0f, a2.getAnimatedFraction());
+                a1.start();
+                a2.start();
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(l1.endCalled);
+                assertFalse(l2.endCalled);
+                assertTrue(a1.isRunning());
+                assertTrue(a2.isRunning());
+                // During the run, seek one to the beginning, the other to the end
+                a1.setCurrentFraction(0f);
+                a2.setCurrentFraction(1f);
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Check that a2 has finished due to the seeking, but a1 hasn't finished.
+                assertFalse(l1.endCalled);
+                assertTrue(l2.endCalled);
+                assertEquals(1f, a2.getAnimatedFraction());
+            }
+        });
+
+        Thread.sleep(a1.getTotalDuration());
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // By now a1 should finish also.
+                assertTrue(l1.endCalled);
+                assertEquals(1f, a1.getAnimatedFraction());
+            }
+        });
+    }
+
+    @SmallTest
+    public void testZeroDuration() throws Throwable {
+        // Run two animators with zero duration, with one running forward and the other one
+        // backward. Check that the animations start and finish with the correct end fractions.
+        a1.setDuration(0);
+        a2.setDuration(0);
+
+        // Set a fraction on an animation with 0-duration
+        final ValueAnimator a3 = ValueAnimator.ofInt(0, 100);
+        a3.setDuration(0);
+        a3.setCurrentFraction(1.0f);
+        assertEquals(1.0f, a3.getAnimatedFraction());
+
+        final MyListener l1 = new MyListener();
+        final MyListener l2 = new MyListener();
+        final MyListener l3 = new MyListener();
+        a1.addListener(l1);
+        a2.addListener(l2);
+        a3.addListener(l3);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(l1.startCalled);
+                assertFalse(l2.startCalled);
+                assertFalse(l3.startCalled);
+                assertFalse(l1.endCalled);
+                assertFalse(l2.endCalled);
+                assertFalse(l3.endCalled);
+                a1.start();
+                a2.reverse();
+                a3.start();
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Check that the animators have started and finished with the right values.
+                assertTrue(l1.startCalled);
+                assertTrue(l2.startCalled);
+                assertTrue(l3.startCalled);
+                assertTrue(l1.endCalled);
+                assertTrue(l2.endCalled);
+                assertTrue(l3.endCalled);
+                assertEquals(1.0f, a1.getAnimatedFraction());
+                assertEquals(0f, a2.getAnimatedFraction());
+                assertEquals(1f, a3.getAnimatedFraction());
+                assertEquals(A1_END_VALUE, a1.getAnimatedValue());
+                assertEquals(A2_START_VALUE, a2.getAnimatedValue());
+                assertEquals(100, a3.getAnimatedValue());
+            }
+        });
+    }
+
+    @SmallTest
+    public void testZeroScale() throws Throwable {
+        // Test whether animations would end properly when the scale is forced to be zero
+        float scale = ValueAnimator.getDurationScale();
+        ValueAnimator.setDurationScale(0f);
+
+        // Run two animators, one of which has a start delay, after setting the duration scale to 0
+        a1.setStartDelay(200);
+        final MyListener l1 =  new MyListener();
+        final MyListener l2 = new MyListener();
+        a1.addListener(l1);
+        a2.addListener(l2);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(l1.startCalled);
+                assertFalse(l2.startCalled);
+                assertFalse(l1.endCalled);
+                assertFalse(l2.endCalled);
+
+                a1.start();
+                a2.start();
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(l1.startCalled);
+                assertTrue(l2.startCalled);
+                assertTrue(l1.endCalled);
+                assertTrue(l2.endCalled);
+            }
+        });
+
+        // Restore duration scale
+        ValueAnimator.setDurationScale(scale);
+    }
+
+    @SmallTest
+    public void testReverse() throws Throwable {
+        // Prolong animators duration so that we can do multiple checks during their run
+        final ValueAnimator a3 = ValueAnimator.ofInt(0, 100);
+        a1.setDuration(400);
+        a2.setDuration(600);
+        a3.setDuration(400);
+        final MyListener l1 = new MyListener();
+        final MyListener l2 = new MyListener();
+        final MyListener l3 = new MyListener();
+        a1.addListener(l1);
+        a2.addListener(l2);
+        a3.addListener(l3);
+
+        // Reverse three animators, seek one to the beginning and another to the end, and force
+        // to end the third one during reversing.
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(l1.startCalled);
+                assertFalse(l2.startCalled);
+                assertFalse(l3.startCalled);
+                assertFalse(l1.endCalled);
+                assertFalse(l2.endCalled);
+                assertFalse(l3.endCalled);
+                a1.reverse();
+                a2.reverse();
+                a3.reverse();
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(l1.startCalled);
+                assertTrue(l2.startCalled);
+                assertTrue(l3.startCalled);
+
+                a1.setCurrentFraction(0f);
+                a2.setCurrentFraction(1f);
+                a3.end();
+
+                // Check that the fraction has been set, and the getter returns the correct values.
+                assertEquals(1f, a1.getAnimatedFraction());
+                assertEquals(0f, a2.getAnimatedFraction());
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+
+        // By now, a2 should have finished due to the seeking. It wouldn't have finished otherwise.
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Check that both animations have started, and a2 has finished.
+                assertFalse(l1.endCalled);
+                assertTrue(l2.endCalled);
+                assertTrue(l3.endCalled);
+            }
+        });
+        Thread.sleep(a1.getTotalDuration());
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Verify that a1 has finished as well.
+                assertTrue(l1.endCalled);
+                assertEquals(0f, a1.getAnimatedFraction());
+                assertEquals(0f, a2.getAnimatedFraction());
+                assertEquals(0f, a3.getAnimatedFraction());
+            }
+        });
+    }
+
     class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener {
         boolean wasRunning = false;
         long firstRunningFrameTime = -1;
diff --git a/data/keyboards/Vendor_0079_Product_0011.kl b/data/keyboards/Vendor_0079_Product_0011.kl
index 2ae2a01..32f8c82 100644
--- a/data/keyboards/Vendor_0079_Product_0011.kl
+++ b/data/keyboards/Vendor_0079_Product_0011.kl
@@ -12,10 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Classic NES Controller
+# Classic [S]NES Controller
 
+key 288 BUTTON_X
 key 289 BUTTON_A
 key 290 BUTTON_B
+key 291 BUTTON_Y
+key 292 BUTTON_L1
+key 293 BUTTON_R1
 key 297 BUTTON_START
 key 296 BUTTON_SELECT
 
diff --git a/docs/html/guide/topics/manifest/compatible-screens-element.jd b/docs/html/guide/topics/manifest/compatible-screens-element.jd
index 3606b15..de921d2 100644
--- a/docs/html/guide/topics/manifest/compatible-screens-element.jd
+++ b/docs/html/guide/topics/manifest/compatible-screens-element.jd
@@ -9,7 +9,7 @@
 <pre>
 &lt;<a href="#compatible-screens">compatible-screens</a>&gt;
     &lt;<a href="#screen">screen</a> android:<a href="#screenSize">screenSize</a>=["small" | "normal" | "large" | "xlarge"]
-            android:<a href="#screenDensity">screenDensity</a>=["ldpi" | "mdpi" | "hdpi" | "xhdpi"] /&gt;
+            android:<a href="#screenDensity">screenDensity</a>=["ldpi" | "mdpi" | "hdpi" | "xhdpi" | "xxhdpi" | "xxxhdpi"] /&gt;
     ...
 &lt;/compatible-screens&gt;
 </pre>
@@ -94,11 +94,9 @@
             <li>{@code mdpi}</li>
             <li>{@code hdpi}</li>
             <li>{@code xhdpi}</li>
+            <li>{@code xxhdpi}</li>
+            <li>{@code xxxhdpi}</li>
           </ul>
-          <p class="note"><strong>Note:</strong> This attribute currently does not accept
-          {@code xxhdpi} as a valid value, but you can instead specify {@code 480}
-          as the value, which is the approximate threshold for xhdpi screens.</p>
-
           <p>For information about the different screen densities, see <a
 href="{@docRoot}guide/practices/screens_support.html#range">Supporting Multiple Screens</a>.</p>
         </dd>
@@ -110,8 +108,8 @@
 <dt>example</dt>
 <dd>
 <p>If your application is compatible with only small and normal screens, regardless
-of screen density, then you must specify eight different {@code &lt;screen&gt;} elements,
-because each screen size has four different density configurations. You must declare each one of
+of screen density, then you must specify twelve different {@code &lt;screen&gt;} elements,
+because each screen size has six different density configurations. You must declare each one of
 these; any combination of size and density that you do <em>not</em> specify is considered a screen
 configuration with which your application is <em>not</em> compatible. Here's what the manifest
 entry looks like if your application is compatible with only small and normal screens:</p>
@@ -125,11 +123,15 @@
         &lt;screen android:screenSize="small" android:screenDensity="mdpi" />
         &lt;screen android:screenSize="small" android:screenDensity="hdpi" />
         &lt;screen android:screenSize="small" android:screenDensity="xhdpi" />
+        &lt;screen android:screenSize="small" android:screenDensity="xxhdpi" />
+        &lt;screen android:screenSize="small" android:screenDensity="xxxhdpi" />
         &lt;!-- all normal size screens -->
         &lt;screen android:screenSize="normal" android:screenDensity="ldpi" />
         &lt;screen android:screenSize="normal" android:screenDensity="mdpi" />
         &lt;screen android:screenSize="normal" android:screenDensity="hdpi" />
         &lt;screen android:screenSize="normal" android:screenDensity="xhdpi" />
+        &lt;screen android:screenSize="normal" android:screenDensity="xxhdpi" />
+        &lt;screen android:screenSize="normal" android:screenDensity="xxxhdpi" />
     &lt;/compatible-screens>
     &lt;application ... >
         ...
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index dc258db..0375a2f 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -42,9 +42,9 @@
 JDK 6 or higher (the JRE alone is not sufficient)&mdash;JDK 7 is required when
 developing for Android 5.0 and higher. To check if you
 have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
-If the JDK is not available or the version is lower than 6,
-<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html" class="external-link"
->go download JDK</a>.</p>
+If the JDK is not available or the version is lower than version 6, download the 
+<a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html" class="external-link"
+>Java SE Development Kit 7</a>.</p>
 
 
 <div class="procedure-box">
diff --git a/graphics/java/android/graphics/Point.java b/graphics/java/android/graphics/Point.java
index e0d8ccc..3bd17fa 100644
--- a/graphics/java/android/graphics/Point.java
+++ b/graphics/java/android/graphics/Point.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.io.PrintWriter;
+
 
 /**
  * Point holds two integer coordinates
@@ -95,6 +97,11 @@
         return "Point(" + x + ", " + y + ")";
     }
 
+    /** @hide */
+    public void printShortString(PrintWriter pw) {
+        pw.println("["); pw.print(x); pw.print(","); pw.print(y); pw.print("]");
+    }
+
     /**
      * Parcelable interface methods
      */
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 8011b59..6f548bc 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,6 +2,8 @@
 include $(CLEAR_VARS)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
+HWUI_NEW_OPS := false
+
 hwui_src_files := \
     font/CacheTexture.cpp \
     font/Font.cpp \
@@ -85,6 +87,17 @@
     -Wall -Wno-unused-parameter -Wunreachable-code \
     -ffast-math -O3 -Werror
 
+
+ifeq (true, $(HWUI_NEW_OPS))
+    hwui_src_files += \
+        BakedOpRenderer.cpp \
+        OpReorderer.cpp \
+        RecordingCanvas.cpp
+
+    hwui_cflags += -DHWUI_NEW_OPS
+
+endif
+
 ifndef HWUI_COMPILE_SYMBOLS
     hwui_cflags += -fvisibility=hidden
 endif
@@ -172,6 +185,13 @@
     unit_tests/LinearAllocatorTests.cpp \
     unit_tests/StringUtilsTests.cpp
 
+ifeq (true, $(HWUI_NEW_OPS))
+    LOCAL_SRC_FILES += \
+        unit_tests/BakedOpStateTests.cpp \
+        unit_tests/RecordingCanvasTests.cpp \
+        unit_tests/OpReordererTests.cpp
+endif
+
 include $(BUILD_NATIVE_TEST)
 
 # ------------------------
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
new file mode 100644
index 0000000..4d9f9b4
--- /dev/null
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#include "BakedOpRenderer.h"
+
+#include "Caches.h"
+#include "Glop.h"
+#include "GlopBuilder.h"
+#include "renderstate/RenderState.h"
+#include "utils/GLUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+Texture* BakedOpRenderer::Info::getTexture(const SkBitmap* bitmap) {
+    Texture* texture = renderState.assetAtlas().getEntryTexture(bitmap);
+    if (!texture) {
+        return caches.textureCache.get(bitmap);
+    }
+    return texture;
+}
+
+void BakedOpRenderer::Info::renderGlop(const BakedOpState& state, const Glop& glop) {
+    bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
+    renderState.scissor().setEnabled(useScissor);
+    if (useScissor) {
+        const Rect& clip = state.computedState.clipRect;
+        renderState.scissor().set(clip.left, viewportHeight - clip.bottom,
+            clip.getWidth(), clip.getHeight());
+    }
+    renderState.render(glop, orthoMatrix);
+    didDraw = true;
+}
+
+void BakedOpRenderer::startFrame(Info& info) {
+    info.renderState.setViewport(info.viewportWidth, info.viewportHeight);
+    info.renderState.blend().syncEnabled();
+    Caches::getInstance().clearGarbage();
+
+    if (!info.opaque) {
+        // TODO: partial invalidate!
+        info.renderState.scissor().setEnabled(false);
+        glClear(GL_COLOR_BUFFER_BIT);
+        info.didDraw = true;
+    }
+}
+void BakedOpRenderer::endFrame(Info& info) {
+    info.caches.pathCache.trim();
+    info.caches.tessellationCache.trim();
+
+#if DEBUG_OPENGL
+    GLUtils::dumpGLErrors();
+#endif
+
+#if DEBUG_MEMORY_USAGE
+    info.caches.dumpMemoryUsage();
+#else
+    if (Properties::debugLevel & kDebugMemory) {
+        info.caches.dumpMemoryUsage();
+    }
+#endif
+}
+
+void BakedOpRenderer::onRenderNodeOp(Info*, const RenderNodeOp&, const BakedOpState&) {
+    LOG_ALWAYS_FATAL("unsupported operation");
+}
+
+void BakedOpRenderer::onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) {
+    info->caches.textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
+    Texture* texture = info->getTexture(op.bitmap);
+    if (!texture) return;
+    const AutoTexture autoCleanup(texture);
+
+    const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
+            ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
+    Glop glop;
+    GlopBuilder(info->renderState, info->caches, &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshTexturedUnitQuad(texture->uvMapper)
+            .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
+            .setTransform(state.computedState.transform, TransformFlags::None)
+            .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+            .build();
+    info->renderGlop(state, glop);
+}
+
+void BakedOpRenderer::onRectOp(Info* info, const RectOp& op, const BakedOpState& state) {
+    Glop glop;
+    GlopBuilder(info->renderState, info->caches, &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshUnitQuad()
+            .setFillPaint(*op.paint, state.alpha)
+            .setTransform(state.computedState.transform, TransformFlags::None)
+            .setModelViewMapUnitToRect(op.unmappedBounds)
+            .build();
+    info->renderGlop(state, glop);
+}
+
+void BakedOpRenderer::onSimpleRectsOp(Info* info, const SimpleRectsOp& op, const BakedOpState& state) {
+    Glop glop;
+    GlopBuilder(info->renderState, info->caches, &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4)
+            .setFillPaint(*op.paint, state.alpha)
+            .setTransform(state.computedState.transform, TransformFlags::None)
+            .setModelViewOffsetRect(0, 0, op.unmappedBounds)
+            .build();
+    info->renderGlop(state, glop);
+}
+
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
new file mode 100644
index 0000000..b8b4426
--- /dev/null
+++ b/libs/hwui/BakedOpRenderer.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_BAKED_OP_RENDERER_H
+#define ANDROID_HWUI_BAKED_OP_RENDERER_H
+
+#include "BakedOpState.h"
+#include "Matrix.h"
+
+namespace android {
+namespace uirenderer {
+
+class Caches;
+struct Glop;
+class RenderState;
+
+class BakedOpRenderer {
+public:
+    class Info {
+    public:
+        Info(Caches& caches, RenderState& renderState, int viewportWidth, int viewportHeight, bool opaque)
+                : renderState(renderState)
+                , caches(caches)
+                , opaque(opaque)
+                , viewportWidth(viewportWidth)
+                , viewportHeight(viewportHeight) {
+            orthoMatrix.loadOrtho(viewportWidth, viewportHeight);
+        }
+
+        Texture* getTexture(const SkBitmap* bitmap);
+
+        void renderGlop(const BakedOpState& state, const Glop& glop);
+        RenderState& renderState;
+        Caches& caches;
+
+        bool didDraw = false;
+        bool opaque;
+
+
+        // where should these live? layer state object?
+        int viewportWidth;
+        int viewportHeight;
+        Matrix4 orthoMatrix;
+    };
+
+    static void startFrame(Info& info);
+    static void endFrame(Info& info);
+
+    /**
+     * Declare all "onBitmapOp(...)" style function for every op type.
+     *
+     * These functions will perform the actual rendering of the individual operations in OpenGL,
+     * given the transform/clip and other state built into the BakedOpState object passed in.
+     */
+    #define BAKED_OP_RENDERER_METHOD(Type) static void on##Type(Info* info, const Type& op, const BakedOpState& state);
+    MAP_OPS(BAKED_OP_RENDERER_METHOD);
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_BAKED_OP_RENDERER_H
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
new file mode 100644
index 0000000..e2201ca
--- /dev/null
+++ b/libs/hwui/BakedOpState.h
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_BAKED_OP_STATE_H
+#define ANDROID_HWUI_BAKED_OP_STATE_H
+
+#include "Matrix.h"
+#include "RecordedOp.h"
+#include "Rect.h"
+#include "Snapshot.h"
+
+namespace android {
+namespace uirenderer {
+
+namespace OpClipSideFlags {
+    enum {
+        None = 0x0,
+        Left = 0x1,
+        Top = 0x2,
+        Right = 0x4,
+        Bottom = 0x8,
+        Full = 0xF,
+        // ConservativeFull = 0x1F  needed?
+    };
+}
+
+/**
+ * Holds the resolved clip, transform, and bounds of a recordedOp, when replayed with a snapshot
+ */
+class ResolvedRenderState {
+public:
+    // TODO: remove the mapRects/matrix multiply when snapshot & recorded transforms are translates
+    ResolvedRenderState(const Snapshot& snapshot, const RecordedOp& recordedOp) {
+        /* TODO: benchmark a fast path for translate-only matrices, such as:
+        if (CC_LIKELY(snapshot.transform->getType() == Matrix4::kTypeTranslate
+                && recordedOp.localMatrix.getType() == Matrix4::kTypeTranslate)) {
+            float translateX = snapshot.transform->getTranslateX() + recordedOp.localMatrix.getTranslateX();
+            float translateY = snapshot.transform->getTranslateY() + recordedOp.localMatrix.getTranslateY();
+            transform.loadTranslate(translateX, translateY, 0);
+
+            // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
+            clipRect = recordedOp.localClipRect;
+            clipRect.translate(translateX, translateY);
+            clipRect.doIntersect(snapshot.getClipRect());
+            clipRect.snapToPixelBoundaries();
+
+            // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
+            clippedBounds = recordedOp.unmappedBounds;
+            clippedBounds.translate(translateX, translateY);
+        } ... */
+
+        // resolvedMatrix = parentMatrix * localMatrix
+        transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
+
+        // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
+        clipRect = recordedOp.localClipRect;
+        snapshot.transform->mapRect(clipRect);
+        clipRect.doIntersect(snapshot.getClipRect());
+        clipRect.snapToPixelBoundaries();
+
+        // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
+        clippedBounds = recordedOp.unmappedBounds;
+        transform.mapRect(clippedBounds);
+
+        if (clipRect.left > clippedBounds.left) clipSideFlags |= OpClipSideFlags::Left;
+        if (clipRect.top > clippedBounds.top) clipSideFlags |= OpClipSideFlags::Top;
+        if (clipRect.right < clippedBounds.right) clipSideFlags |= OpClipSideFlags::Right;
+        if (clipRect.bottom < clippedBounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
+        clippedBounds.doIntersect(clipRect);
+
+        /**
+         * TODO: once we support complex clips, we may want to reject to avoid that work where
+         * possible. Should we:
+         * 1 - quickreject based on clippedBounds, quick early (duplicating logic in resolvedOp)
+         * 2 - merge stuff into tryConstruct factory method, so it can handle quickRejection
+         *         and early return null in one place.
+         */
+    }
+    Matrix4 transform;
+    Rect clipRect;
+    int clipSideFlags = 0;
+    Rect clippedBounds;
+};
+
+/**
+ * Self-contained op wrapper, containing all resolved state required to draw the op.
+ *
+ * Stashed pointers within all point to longer lived objects, with no ownership implied.
+ */
+class BakedOpState {
+public:
+    static BakedOpState* tryConstruct(LinearAllocator& allocator,
+            const Snapshot& snapshot, const RecordedOp& recordedOp) {
+        BakedOpState* bakedOp = new (allocator) BakedOpState(
+                snapshot, recordedOp);
+        if (bakedOp->computedState.clippedBounds.isEmpty()) {
+            // bounds are empty, so op is rejected
+            allocator.rewindIfLastAlloc(bakedOp);
+            return nullptr;
+        }
+        return bakedOp;
+    }
+
+    static void* operator new(size_t size, LinearAllocator& allocator) {
+        return allocator.alloc(size);
+    }
+
+    // computed state:
+    const ResolvedRenderState computedState;
+
+    // simple state (straight pointer/value storage):
+    const float alpha;
+    const RoundRectClipState* roundRectClipState;
+    const ProjectionPathMask* projectionPathMask;
+    const RecordedOp* op;
+
+private:
+    BakedOpState(const Snapshot& snapshot, const RecordedOp& recordedOp)
+            : computedState(snapshot, recordedOp)
+            , alpha(snapshot.alpha)
+            , roundRectClipState(snapshot.roundRectClipState)
+            , projectionPathMask(snapshot.projectionPathMask)
+            , op(&recordedOp) {}
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_BAKED_OP_STATE_H
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 0c29a9e..a1825c5 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -528,7 +528,7 @@
     int insertBatchIndex = mBatches.size();
     if (!mBatches.empty()) {
         if (state->mBounds.isEmpty()) {
-            // don't know the bounds for op, so add to last batch and start from scratch on next op
+            // don't know the bounds for op, so create new batch and start from scratch on next op
             DrawBatch* b = new DrawBatch(deferInfo);
             b->add(op, state, deferInfo.opaqueOverBounds);
             mBatches.push_back(b);
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 7873fbd..2d5979f 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -49,7 +49,7 @@
 
 class DeferredDisplayState {
 public:
-    /** static void* operator new(size_t size); PURPOSELY OMITTED **/
+    static void* operator new(size_t size) = delete;
     static void* operator new(size_t size, LinearAllocator& allocator) {
         return allocator.alloc(size);
     }
@@ -61,7 +61,6 @@
     bool mClipValid;
     Rect mClip;
     int mClipSideFlags; // specifies which sides of the bounds are clipped, unclipped if cleared
-    bool mClipped;
     mat4 mMatrix;
     float mAlpha;
     const RoundRectClipState* mRoundRectClipState;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index ee51da2..793d8c0 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -21,7 +21,13 @@
 
 #include "Debug.h"
 #include "DisplayList.h"
+#include "RenderNode.h"
+
+#if HWUI_NEW_OPS
+#include "RecordedOp.h"
+#else
 #include "DisplayListOp.h"
+#endif
 
 namespace android {
 namespace uirenderer {
@@ -61,8 +67,8 @@
     regions.clear();
 }
 
-size_t DisplayListData::addChild(DrawRenderNodeOp* op) {
-    mReferenceHolders.push_back(op->renderNode());
+size_t DisplayListData::addChild(NodeOpType* op) {
+    mReferenceHolders.push_back(op->renderNode);
     size_t index = mChildren.size();
     mChildren.push_back(op);
     return index;
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 0bdb816..80ff96a 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -55,12 +55,19 @@
 class Rect;
 class Layer;
 
-class ClipRectOp;
-class SaveLayerOp;
-class SaveOp;
-class RestoreToCountOp;
+#if HWUI_NEW_OPS
+struct RecordedOp;
+struct RenderNodeOp;
+
+typedef RecordedOp BaseOpType;
+typedef RenderNodeOp NodeOpType;
+#else
 class DrawRenderNodeOp;
 
+typedef DisplayListOp BaseOpType;
+typedef DrawRenderNodeOp NodeOpType;
+#endif
+
 /**
  * Holds data used in the playback a tree of DisplayLists.
  */
@@ -107,6 +114,7 @@
  */
 class DisplayListData {
     friend class DisplayListCanvas;
+    friend class RecordingCanvas;
 public:
     struct Chunk {
         // range of included ops in DLD::displayListOps
@@ -139,11 +147,14 @@
     Vector<Functor*> functors;
 
     const std::vector<Chunk>& getChunks() const {
-        return chunks;
+            return chunks;
+    }
+    const std::vector<BaseOpType*>& getOps() const {
+        return ops;
     }
 
-    size_t addChild(DrawRenderNodeOp* childOp);
-    const std::vector<DrawRenderNodeOp*>& children() { return mChildren; }
+    size_t addChild(NodeOpType* childOp);
+    const std::vector<NodeOpType*>& children() { return mChildren; }
 
     void ref(VirtualLightRefBase* prop) {
         mReferenceHolders.push_back(prop);
@@ -157,10 +168,12 @@
     }
 
 private:
+    std::vector<BaseOpType*> ops;
+
     std::vector< sp<VirtualLightRefBase> > mReferenceHolders;
 
     // list of children display lists for quick, non-drawing traversal
-    std::vector<DrawRenderNodeOp*> mChildren;
+    std::vector<NodeOpType*> mChildren;
 
     std::vector<Chunk> chunks;
 
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 77bde86..a1adb80 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -514,8 +514,12 @@
 }
 
 size_t DisplayListCanvas::addOpAndUpdateChunk(DisplayListOp* op) {
-    int insertIndex = mDisplayListData->displayListOps.size();
-    mDisplayListData->displayListOps.push_back(op);
+    int insertIndex = mDisplayListData->ops.size();
+#if HWUI_NEW_OPS
+    LOG_ALWAYS_FATAL("unsupported");
+#else
+    mDisplayListData->ops.push_back(op);
+#endif
     if (mDeferredBarrierType != kBarrier_None) {
         // op is first in new chunk
         mDisplayListData->chunks.emplace_back();
@@ -558,16 +562,18 @@
 
 size_t DisplayListCanvas::addRenderNodeOp(DrawRenderNodeOp* op) {
     int opIndex = addDrawOp(op);
+#if !HWUI_NEW_OPS
     int childIndex = mDisplayListData->addChild(op);
 
     // update the chunk's child indices
     DisplayListData::Chunk& chunk = mDisplayListData->chunks.back();
     chunk.endChildIndex = childIndex + 1;
 
-    if (op->renderNode()->stagingProperties().isProjectionReceiver()) {
+    if (op->renderNode->stagingProperties().isProjectionReceiver()) {
         // use staging property, since recording on UI thread
         mDisplayListData->projectionReceiveIndex = opIndex;
     }
+#endif
     return opIndex;
 }
 
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index ddfc533f..1f6282d 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1397,25 +1397,26 @@
 class DrawRenderNodeOp : public DrawBoundedOp {
     friend class RenderNode; // grant RenderNode access to info of child
     friend class DisplayListData; // grant DisplayListData access to info of child
+    friend class DisplayListCanvas;
 public:
     DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent, bool clipIsSimple)
             : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr)
-            , mRenderNode(renderNode)
+            , renderNode(renderNode)
             , mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple())
             , mTransformFromParent(transformFromParent)
             , mSkipInOrderDraw(false) {}
 
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
             bool useQuickReject) override {
-        if (mRenderNode->isRenderable() && !mSkipInOrderDraw) {
-            mRenderNode->defer(deferStruct, level + 1);
+        if (renderNode->isRenderable() && !mSkipInOrderDraw) {
+            renderNode->defer(deferStruct, level + 1);
         }
     }
 
     virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
             bool useQuickReject) override {
-        if (mRenderNode->isRenderable() && !mSkipInOrderDraw) {
-            mRenderNode->replay(replayStruct, level + 1);
+        if (renderNode->isRenderable() && !mSkipInOrderDraw) {
+            renderNode->replay(replayStruct, level + 1);
         }
     }
 
@@ -1424,18 +1425,16 @@
     }
 
     virtual void output(int level, uint32_t logFlags) const override {
-        OP_LOG("Draw RenderNode %p %s", mRenderNode, mRenderNode->getName());
-        if (mRenderNode && (logFlags & kOpLogFlag_Recurse)) {
-            mRenderNode->output(level + 1);
+        OP_LOG("Draw RenderNode %p %s", renderNode, renderNode->getName());
+        if (renderNode && (logFlags & kOpLogFlag_Recurse)) {
+            renderNode->output(level + 1);
         }
     }
 
     virtual const char* name() override { return "DrawRenderNode"; }
 
-    RenderNode* renderNode() { return mRenderNode; }
-
 private:
-    RenderNode* mRenderNode;
+    RenderNode* renderNode;
 
     /**
      * This RenderNode was drawn into a DisplayList with the canvas in a state that will likely
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index fa166ae..d2da851 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -461,12 +461,12 @@
 // Transform
 ////////////////////////////////////////////////////////////////////////////////
 
-void GlopBuilder::setTransform(const Matrix4& canvas,
-        const int transformFlags) {
+GlopBuilder& GlopBuilder::setTransform(const Matrix4& canvas, const int transformFlags) {
     TRIGGER_STAGE(kTransformStage);
 
     mOutGlop->transform.canvas = canvas;
     mOutGlop->transform.transformFlags = transformFlags;
+    return *this;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -632,5 +632,42 @@
     mOutGlop->transform.meshTransform().mapRect(mOutGlop->bounds);
 }
 
+void GlopBuilder::dump(const Glop& glop) {
+    ALOGD("Glop Mesh");
+    const Glop::Mesh& mesh = glop.mesh;
+    ALOGD("    primitive mode: %d", mesh.primitiveMode);
+    ALOGD("    indices: buffer obj %x, indices %p", mesh.indices.bufferObject, mesh.indices.indices);
+
+    const Glop::Mesh::Vertices& vertices = glop.mesh.vertices;
+    ALOGD("    vertices: buffer obj %x, flags %x, pos %p, tex %p, clr %p, stride %d",
+            vertices.bufferObject, vertices.attribFlags,
+            vertices.position, vertices.texCoord, vertices.color, vertices.stride);
+    ALOGD("    element count: %d", mesh.elementCount);
+
+    ALOGD("Glop Fill");
+    const Glop::Fill& fill = glop.fill;
+    ALOGD("    program %p", fill.program);
+    if (fill.texture.texture) {
+        ALOGD("    texture %p, target %d, filter %d, clamp %d",
+                fill.texture.texture, fill.texture.target, fill.texture.filter, fill.texture.clamp);
+        if (fill.texture.textureTransform) {
+            fill.texture.textureTransform->dump("texture transform");
+        }
+    }
+    ALOGD_IF(fill.colorEnabled, "    color (argb) %.2f %.2f %.2f %.2f",
+            fill.color.a, fill.color.r, fill.color.g, fill.color.b);
+    ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None,
+            "    filterMode %d", (int)fill.filterMode);
+    ALOGD_IF(fill.skiaShaderData.skiaShaderType, "    shader type %d",
+            fill.skiaShaderData.skiaShaderType);
+
+    ALOGD("Glop transform");
+    glop.transform.modelView.dump("model view");
+    glop.transform.canvas.dump("canvas");
+
+    ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst);
+    ALOGD("Glop bounds " RECT_STRING, RECT_ARGS(glop.bounds));
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 8d05570..6f5802e 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -71,9 +71,9 @@
     GlopBuilder& setFillTextureLayer(Layer& layer, float alpha);
 
     GlopBuilder& setTransform(const Snapshot& snapshot, const int transformFlags) {
-        setTransform(*snapshot.transform, transformFlags);
-        return *this;
+        return setTransform(*snapshot.transform, transformFlags);
     }
+    GlopBuilder& setTransform(const Matrix4& canvas, const int transformFlags);
 
     GlopBuilder& setModelViewMapUnitToRect(const Rect destination);
     GlopBuilder& setModelViewMapUnitToRectSnap(const Rect destination);
@@ -98,11 +98,12 @@
     GlopBuilder& setRoundRectClipState(const RoundRectClipState* roundRectClipState);
 
     void build();
+
+    static void dump(const Glop& glop);
 private:
     void setFill(int color, float alphaScale,
             SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage,
             const SkShader* shader, const SkColorFilter* colorFilter);
-    void setTransform(const Matrix4& canvas, const int transformFlags);
 
     enum StageFlags {
         kInitialStage = 0,
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index ed517ac..c017638 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -126,6 +126,9 @@
     void loadMultiply(const Matrix4& u, const Matrix4& v);
 
     void loadOrtho(float left, float right, float bottom, float top, float near, float far);
+    void loadOrtho(int width, int height) {
+        loadOrtho(0, width, height, 0, -1, 1);
+    }
 
     uint8_t getType() const;
 
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
new file mode 100644
index 0000000..2e02306
--- /dev/null
+++ b/libs/hwui/OpReorderer.cpp
@@ -0,0 +1,405 @@
+/*
+ * 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.
+ */
+
+#include "OpReorderer.h"
+
+#include "utils/PaintUtils.h"
+#include "RenderNode.h"
+
+#include "SkCanvas.h"
+#include "utils/Trace.h"
+
+namespace android {
+namespace uirenderer {
+
+class BatchBase {
+
+public:
+    BatchBase(batchid_t batchId, BakedOpState* op, bool merging)
+        : mBatchId(batchId)
+        , mMerging(merging) {
+        mBounds = op->computedState.clippedBounds;
+        mOps.push_back(op);
+    }
+
+    bool intersects(const Rect& rect) const {
+        if (!rect.intersects(mBounds)) return false;
+
+        for (const BakedOpState* op : mOps) {
+            if (rect.intersects(op->computedState.clippedBounds)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    batchid_t getBatchId() const { return mBatchId; }
+    bool isMerging() const { return mMerging; }
+
+    const std::vector<BakedOpState*>& getOps() const { return mOps; }
+
+    void dump() const {
+        ALOGD("    Batch %p, merging %d, bounds " RECT_STRING, this, mMerging, RECT_ARGS(mBounds));
+    }
+protected:
+    batchid_t mBatchId;
+    Rect mBounds;
+    std::vector<BakedOpState*> mOps;
+    bool mMerging;
+};
+
+class OpBatch : public BatchBase {
+public:
+    static void* operator new(size_t size, LinearAllocator& allocator) {
+        return allocator.alloc(size);
+    }
+
+    OpBatch(batchid_t batchId, BakedOpState* op)
+            : BatchBase(batchId, op, false) {
+    }
+
+    void batchOp(BakedOpState* op) {
+        mBounds.unionWith(op->computedState.clippedBounds);
+        mOps.push_back(op);
+    }
+};
+
+class MergingOpBatch : public BatchBase {
+public:
+    static void* operator new(size_t size, LinearAllocator& allocator) {
+        return allocator.alloc(size);
+    }
+
+    MergingOpBatch(batchid_t batchId, BakedOpState* op)
+            : BatchBase(batchId, op, true) {
+    }
+
+    /*
+     * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds
+     * and clip side flags. Positive bounds delta means new bounds fit in old.
+     */
+    static inline bool checkSide(const int currentFlags, const int newFlags, const int side,
+            float boundsDelta) {
+        bool currentClipExists = currentFlags & side;
+        bool newClipExists = newFlags & side;
+
+        // if current is clipped, we must be able to fit new bounds in current
+        if (boundsDelta > 0 && currentClipExists) return false;
+
+        // if new is clipped, we must be able to fit current bounds in new
+        if (boundsDelta < 0 && newClipExists) return false;
+
+        return true;
+    }
+
+    static bool paintIsDefault(const SkPaint& paint) {
+        return paint.getAlpha() == 255
+                && paint.getColorFilter() == nullptr
+                && paint.getShader() == nullptr;
+    }
+
+    static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) {
+        return a.getAlpha() == b.getAlpha()
+                && a.getColorFilter() == b.getColorFilter()
+                && a.getShader() == b.getShader();
+    }
+
+    /*
+     * Checks if a (mergeable) op can be merged into this batch
+     *
+     * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is
+     * important to consider all paint attributes used in the draw calls in deciding both a) if an
+     * op tries to merge at all, and b) if the op can merge with another set of ops
+     *
+     * False positives can lead to information from the paints of subsequent merged operations being
+     * dropped, so we make simplifying qualifications on the ops that can merge, per op type.
+     */
+    bool canMergeWith(BakedOpState* op) const {
+        bool isTextBatch = getBatchId() == OpBatchType::Text
+                || getBatchId() == OpBatchType::ColorText;
+
+        // Overlapping other operations is only allowed for text without shadow. For other ops,
+        // multiDraw isn't guaranteed to overdraw correctly
+        if (!isTextBatch || PaintUtils::hasTextShadow(op->op->paint)) {
+            if (intersects(op->computedState.clippedBounds)) return false;
+        }
+
+        const BakedOpState* lhs = op;
+        const BakedOpState* rhs = mOps[0];
+
+        if (!MathUtils::areEqual(lhs->alpha, rhs->alpha)) return false;
+
+        // Identical round rect clip state means both ops will clip in the same way, or not at all.
+        // As the state objects are const, we can compare their pointers to determine mergeability
+        if (lhs->roundRectClipState != rhs->roundRectClipState) return false;
+        if (lhs->projectionPathMask != rhs->projectionPathMask) return false;
+
+        /* Clipping compatibility check
+         *
+         * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its
+         * clip for that side.
+         */
+        const int currentFlags = mClipSideFlags;
+        const int newFlags = op->computedState.clipSideFlags;
+        if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) {
+            const Rect& opBounds = op->computedState.clippedBounds;
+            float boundsDelta = mBounds.left - opBounds.left;
+            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false;
+            boundsDelta = mBounds.top - opBounds.top;
+            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false;
+
+            // right and bottom delta calculation reversed to account for direction
+            boundsDelta = opBounds.right - mBounds.right;
+            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false;
+            boundsDelta = opBounds.bottom - mBounds.bottom;
+            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false;
+        }
+
+        const SkPaint* newPaint = op->op->paint;
+        const SkPaint* oldPaint = mOps[0]->op->paint;
+
+        if (newPaint == oldPaint) {
+            // if paints are equal, then modifiers + paint attribs don't need to be compared
+            return true;
+        } else if (newPaint && !oldPaint) {
+            return paintIsDefault(*newPaint);
+        } else if (!newPaint && oldPaint) {
+            return paintIsDefault(*oldPaint);
+        }
+        return paintsAreEquivalent(*newPaint, *oldPaint);
+    }
+
+    void mergeOp(BakedOpState* op) {
+        mBounds.unionWith(op->computedState.clippedBounds);
+        mOps.push_back(op);
+
+        const int newClipSideFlags = op->computedState.clipSideFlags;
+        mClipSideFlags |= newClipSideFlags;
+
+        const Rect& opClip = op->computedState.clipRect;
+        if (newClipSideFlags & OpClipSideFlags::Left) mClipRect.left = opClip.left;
+        if (newClipSideFlags & OpClipSideFlags::Top) mClipRect.top = opClip.top;
+        if (newClipSideFlags & OpClipSideFlags::Right) mClipRect.right = opClip.right;
+        if (newClipSideFlags & OpClipSideFlags::Bottom) mClipRect.bottom = opClip.bottom;
+    }
+
+private:
+    int mClipSideFlags = 0;
+    Rect mClipRect;
+};
+
+class NullClient: public CanvasStateClient {
+    void onViewportInitialized() override {}
+    void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
+    GLuint getTargetFbo() const override { return 0; }
+};
+static NullClient sNullClient;
+
+OpReorderer::OpReorderer()
+        : mCanvasState(sNullClient) {
+}
+
+void OpReorderer::defer(const SkRect& clip, int viewportWidth, int viewportHeight,
+        const std::vector< sp<RenderNode> >& nodes) {
+    mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
+            clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
+            Vector3());
+    for (const sp<RenderNode>& node : nodes) {
+        if (node->nothingToDraw()) continue;
+
+        // TODO: dedupe this code with onRenderNode()
+        mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+        if (node->applyViewProperties(mCanvasState)) {
+            // not rejected do ops...
+            const DisplayListData& data = node->getDisplayListData();
+            deferImpl(data.getChunks(), data.getOps());
+        }
+        mCanvasState.restore();
+    }
+}
+
+void OpReorderer::defer(int viewportWidth, int viewportHeight,
+        const std::vector<DisplayListData::Chunk>& chunks, const std::vector<RecordedOp*>& ops) {
+    ATRACE_NAME("prepare drawing commands");
+    mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
+            0, 0, viewportWidth, viewportHeight, Vector3());
+    deferImpl(chunks, ops);
+}
+
+/**
+ * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods.
+ *
+ * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. E.g. a
+ * BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&)
+ */
+#define OP_RECIEVER(Type) \
+        [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); },
+void OpReorderer::deferImpl(const std::vector<DisplayListData::Chunk>& chunks,
+        const std::vector<RecordedOp*>& ops) {
+    static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = {
+        MAP_OPS(OP_RECIEVER)
+    };
+    for (const DisplayListData::Chunk& chunk : chunks) {
+        for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
+            const RecordedOp* op = ops[opIndex];
+            receivers[op->opId](*this, *op);
+        }
+    }
+}
+
+void OpReorderer::replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) {
+    ATRACE_NAME("flush drawing commands");
+    for (const BatchBase* batch : mBatches) {
+        // TODO: different behavior based on batch->isMerging()
+        for (const BakedOpState* op : batch->getOps()) {
+            receivers[op->op->opId](arg, *op->op, *op);
+        }
+    }
+}
+
+BakedOpState* OpReorderer::bakeOpState(const RecordedOp& recordedOp) {
+    return BakedOpState::tryConstruct(mAllocator, *mCanvasState.currentSnapshot(), recordedOp);
+}
+
+void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
+    if (op.renderNode->nothingToDraw()) {
+        return;
+    }
+    mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+
+    // apply state from RecordedOp
+    mCanvasState.concatMatrix(op.localMatrix);
+    mCanvasState.clipRect(op.localClipRect.left, op.localClipRect.top,
+            op.localClipRect.right, op.localClipRect.bottom, SkRegion::kIntersect_Op);
+
+    // apply RenderProperties state
+    if (op.renderNode->applyViewProperties(mCanvasState)) {
+        // not rejected do ops...
+        const DisplayListData& data = op.renderNode->getDisplayListData();
+        deferImpl(data.getChunks(), data.getOps());
+    }
+    mCanvasState.restore();
+}
+
+static batchid_t tessellatedBatchId(const SkPaint& paint) {
+    return paint.getPathEffect()
+            ? OpBatchType::AlphaMaskTexture
+            : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
+}
+
+void OpReorderer::onBitmapOp(const BitmapOp& op) {
+    BakedOpState* bakedStateOp = bakeOpState(op);
+    if (!bakedStateOp) return; // quick rejected
+
+    mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID();
+    // TODO: AssetAtlas
+
+    deferMergeableOp(bakedStateOp, OpBatchType::Bitmap, mergeId);
+}
+
+void OpReorderer::onRectOp(const RectOp& op) {
+    BakedOpState* bakedStateOp = bakeOpState(op);
+    if (!bakedStateOp) return; // quick rejected
+    deferUnmergeableOp(bakedStateOp, tessellatedBatchId(*op.paint));
+}
+
+void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) {
+    BakedOpState* bakedStateOp = bakeOpState(op);
+    if (!bakedStateOp) return; // quick rejected
+    deferUnmergeableOp(bakedStateOp, OpBatchType::Vertices);
+}
+
+// iterate back toward target to see if anything drawn since should overlap the new op
+// if no target, merging ops still interate to find similar batch to insert after
+void OpReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds,
+        BatchBase** targetBatch, size_t* insertBatchIndex) const {
+    for (int i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) {
+        BatchBase* overBatch = mBatches[i];
+
+        if (overBatch == *targetBatch) break;
+
+        // TODO: also consider shader shared between batch types
+        if (batchId == overBatch->getBatchId()) {
+            *insertBatchIndex = i + 1;
+            if (!*targetBatch) break; // found insert position, quit
+        }
+
+        if (overBatch->intersects(clippedBounds)) {
+            // NOTE: it may be possible to optimize for special cases where two operations
+            // of the same batch/paint could swap order, such as with a non-mergeable
+            // (clipped) and a mergeable text operation
+            *targetBatch = nullptr;
+            break;
+        }
+    }
+}
+
+void OpReorderer::deferUnmergeableOp(BakedOpState* op, batchid_t batchId) {
+    OpBatch* targetBatch = mBatchLookup[batchId];
+
+    size_t insertBatchIndex = mBatches.size();
+    if (targetBatch) {
+        locateInsertIndex(batchId, op->computedState.clippedBounds,
+                (BatchBase**)(&targetBatch), &insertBatchIndex);
+    }
+
+    if (targetBatch) {
+        targetBatch->batchOp(op);
+    } else  {
+        // new non-merging batch
+        targetBatch = new (mAllocator) OpBatch(batchId, op);
+        mBatchLookup[batchId] = targetBatch;
+        mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
+    }
+}
+
+// insertion point of a new batch, will hopefully be immediately after similar batch
+// (generally, should be similar shader)
+void OpReorderer::deferMergeableOp(BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
+    MergingOpBatch* targetBatch = nullptr;
+
+    // Try to merge with any existing batch with same mergeId
+    auto getResult = mMergingBatches[batchId].find(mergeId);
+    if (getResult != mMergingBatches[batchId].end()) {
+        targetBatch = getResult->second;
+        if (!targetBatch->canMergeWith(op)) {
+            targetBatch = nullptr;
+        }
+    }
+
+    size_t insertBatchIndex = mBatches.size();
+    locateInsertIndex(batchId, op->computedState.clippedBounds,
+            (BatchBase**)(&targetBatch), &insertBatchIndex);
+
+    if (targetBatch) {
+        targetBatch->mergeOp(op);
+    } else  {
+        // new merging batch
+        targetBatch = new (mAllocator) MergingOpBatch(batchId, op);
+        mMergingBatches[batchId].insert(std::make_pair(mergeId, targetBatch));
+
+        mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
+    }
+}
+
+void OpReorderer::dump() {
+    for (const BatchBase* batch : mBatches) {
+        batch->dump();
+    }
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
new file mode 100644
index 0000000..395a1ba
--- /dev/null
+++ b/libs/hwui/OpReorderer.h
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_OP_REORDERER_H
+#define ANDROID_HWUI_OP_REORDERER_H
+
+#include "BakedOpState.h"
+#include "CanvasState.h"
+#include "DisplayList.h"
+#include "RecordedOp.h"
+
+#include <vector>
+#include <unordered_map>
+
+struct SkRect;
+
+namespace android {
+namespace uirenderer {
+
+class BakedOpState;
+class BatchBase;
+class MergingOpBatch;
+class OpBatch;
+class Rect;
+
+typedef int batchid_t;
+typedef const void* mergeid_t;
+
+namespace OpBatchType {
+    enum {
+        None = 0, // Don't batch
+        Bitmap,
+        Patch,
+        AlphaVertices,
+        Vertices,
+        AlphaMaskTexture,
+        Text,
+        ColorText,
+
+        Count // must be last
+    };
+}
+
+class OpReorderer {
+public:
+    OpReorderer();
+
+    // TODO: not final, just presented this way for simplicity. Layers too?
+    void defer(const SkRect& clip, int viewportWidth, int viewportHeight,
+            const std::vector< sp<RenderNode> >& nodes);
+
+    void defer(int viewportWidth, int viewportHeight,
+            const std::vector<DisplayListData::Chunk>& chunks, const std::vector<RecordedOp*>& ops);
+    typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpReceiver;
+
+    /**
+     * replayBakedOps() is templated based on what class will recieve ops being replayed.
+     *
+     * It constructs a lookup array of lambdas, which allows a recorded BakeOpState to use
+     * state->op->opId to lookup a receiver that will be called when the op is replayed.
+     *
+     * For example a BitmapOp would resolve, via the lambda lookup, to calling:
+     *
+     * StaticReceiver::onBitmapOp(Arg* arg, const BitmapOp& op, const BakedOpState& state);
+     */
+#define BAKED_OP_RECEIVER(Type) \
+    [](void* internalArg, const RecordedOp& op, const BakedOpState& state) { \
+        StaticReceiver::on##Type(static_cast<Arg*>(internalArg), static_cast<const Type&>(op), state); \
+    },
+    template <typename StaticReceiver, typename Arg>
+    void replayBakedOps(Arg* arg) {
+        static BakedOpReceiver receivers[] = {
+            MAP_OPS(BAKED_OP_RECEIVER)
+        };
+        StaticReceiver::startFrame(*arg);
+        replayBakedOpsImpl((void*)arg, receivers);
+        StaticReceiver::endFrame(*arg);
+    }
+private:
+    BakedOpState* bakeOpState(const RecordedOp& recordedOp);
+
+    void deferImpl(const std::vector<DisplayListData::Chunk>& chunks,
+            const std::vector<RecordedOp*>& ops);
+
+    void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers);
+
+    /**
+     * Declares all OpReorderer::onXXXXOp() methods for every RecordedOp type.
+     *
+     * These private methods are called from within deferImpl to defer each individual op
+     * type differently.
+     */
+#define INTERNAL_OP_HANDLER(Type) \
+    void on##Type(const Type& op);
+    MAP_OPS(INTERNAL_OP_HANDLER)
+
+    // iterate back toward target to see if anything drawn since should overlap the new op
+    // if no target, merging ops still iterate to find similar batch to insert after
+    void locateInsertIndex(int batchId, const Rect& clippedBounds,
+            BatchBase** targetBatch, size_t* insertBatchIndex) const;
+
+    void deferUnmergeableOp(BakedOpState* op, batchid_t batchId);
+
+    // insertion point of a new batch, will hopefully be immediately after similar batch
+    // (generally, should be similar shader)
+    void deferMergeableOp(BakedOpState* op, batchid_t batchId, mergeid_t mergeId);
+
+    void dump();
+
+    std::vector<BatchBase*> mBatches;
+
+    /**
+     * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen
+     * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not
+     * collide, which avoids the need to resolve mergeid collisions.
+     */
+    std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatches[OpBatchType::Count];
+
+    // Maps batch ids to the most recent *non-merging* batch of that id
+    OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr };
+    CanvasState mCanvasState;
+
+    // contains ResolvedOps and Batches
+    LinearAllocator mAllocator;
+
+    int mEarliestBatchIndex = 0;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_OP_REORDERER_H
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
new file mode 100644
index 0000000..a69f030
--- /dev/null
+++ b/libs/hwui/RecordedOp.h
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_RECORDED_OP_H
+#define ANDROID_HWUI_RECORDED_OP_H
+
+#include "utils/LinearAllocator.h"
+#include "Rect.h"
+#include "Matrix.h"
+
+#include "SkXfermode.h"
+
+class SkBitmap;
+class SkPaint;
+
+namespace android {
+namespace uirenderer {
+
+class RenderNode;
+struct Vertex;
+
+/**
+ * The provided macro is executed for each op type in order, with the results separated by commas.
+ *
+ * This serves as the authoritative list of ops, used for generating ID enum, and ID based LUTs.
+ */
+#define MAP_OPS(OP_FN) \
+        OP_FN(BitmapOp) \
+        OP_FN(RectOp) \
+        OP_FN(RenderNodeOp) \
+        OP_FN(SimpleRectsOp)
+
+// Generate OpId enum
+#define IDENTITY_FN(Type) Type,
+namespace RecordedOpId {
+    enum {
+        MAP_OPS(IDENTITY_FN)
+        Count,
+    };
+}
+static_assert(RecordedOpId::BitmapOp == 0,
+        "First index must be zero for LUTs to work");
+
+#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint
+#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect
+#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, paint)
+#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, nullptr)
+
+struct RecordedOp {
+    /* ID from RecordedOpId - generally used for jumping into function tables */
+    const int opId;
+
+    /* bounds in *local* space, without accounting for DisplayList transformation */
+    const Rect unmappedBounds;
+
+    /* transform in recording space (vs DisplayList origin) */
+    const Matrix4 localMatrix;
+
+    /* clip in recording space */
+    const Rect localClipRect;
+
+    /* optional paint, stored in base object to simplify merging logic */
+    const SkPaint* paint;
+protected:
+    RecordedOp(unsigned int opId, BASE_PARAMS)
+            : opId(opId)
+            , unmappedBounds(unmappedBounds)
+            , localMatrix(localMatrix)
+            , localClipRect(localClipRect)
+            , paint(paint) {}
+};
+
+struct RenderNodeOp : RecordedOp {
+    RenderNodeOp(BASE_PARAMS_PAINTLESS, RenderNode* renderNode)
+            : SUPER_PAINTLESS(RenderNodeOp)
+            , renderNode(renderNode) {}
+    RenderNode * renderNode; // not const, since drawing modifies it (somehow...)
+};
+
+struct BitmapOp : RecordedOp {
+    BitmapOp(BASE_PARAMS, const SkBitmap* bitmap)
+            : SUPER(BitmapOp)
+            , bitmap(bitmap) {}
+    const SkBitmap* bitmap;
+    // TODO: asset atlas/texture id lookup?
+};
+
+struct RectOp : RecordedOp {
+    RectOp(BASE_PARAMS)
+            : SUPER(RectOp) {}
+};
+
+struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)
+    SimpleRectsOp(BASE_PARAMS, Vertex* vertices, size_t vertexCount)
+            : SUPER(SimpleRectsOp)
+            , vertices(vertices)
+            , vertexCount(vertexCount) {}
+    Vertex* vertices;
+    const size_t vertexCount;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_RECORDED_OP_H
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
new file mode 100644
index 0000000..c4debd6
--- /dev/null
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -0,0 +1,402 @@
+/*
+ * 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.
+ */
+
+#include "RecordingCanvas.h"
+
+#include "RecordedOp.h"
+#include "RenderNode.h"
+
+namespace android {
+namespace uirenderer {
+
+RecordingCanvas::RecordingCanvas(size_t width, size_t height)
+        : mState(*this)
+        , mResourceCache(ResourceCache::getInstance()) {
+    reset(width, height);
+}
+
+RecordingCanvas::~RecordingCanvas() {
+    LOG_ALWAYS_FATAL_IF(mDisplayListData,
+            "Destroyed a RecordingCanvas during a record!");
+}
+
+void RecordingCanvas::reset(int width, int height) {
+    LOG_ALWAYS_FATAL_IF(mDisplayListData,
+            "prepareDirty called a second time during a recording!");
+    mDisplayListData = new DisplayListData();
+
+    mState.initializeSaveStack(width, height, 0, 0, width, height, Vector3());
+
+    mDeferredBarrierType = kBarrier_InOrder;
+    mState.setDirtyClip(false);
+    mRestoreSaveCount = -1;
+}
+
+DisplayListData* RecordingCanvas::finishRecording() {
+    mPaintMap.clear();
+    mRegionMap.clear();
+    mPathMap.clear();
+    DisplayListData* data = mDisplayListData;
+    mDisplayListData = nullptr;
+    mSkiaCanvasProxy.reset(nullptr);
+    return data;
+}
+
+SkCanvas* RecordingCanvas::asSkCanvas() {
+    LOG_ALWAYS_FATAL_IF(!mDisplayListData,
+            "attempting to get an SkCanvas when we are not recording!");
+    if (!mSkiaCanvasProxy) {
+        mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this));
+    }
+
+    // SkCanvas instances default to identity transform, but should inherit
+    // the state of this Canvas; if this code was in the SkiaCanvasProxy
+    // constructor, we couldn't cache mSkiaCanvasProxy.
+    SkMatrix parentTransform;
+    getMatrix(&parentTransform);
+    mSkiaCanvasProxy.get()->setMatrix(parentTransform);
+
+    return mSkiaCanvasProxy.get();
+}
+
+// ----------------------------------------------------------------------------
+// android/graphics/Canvas state operations
+// ----------------------------------------------------------------------------
+// Save (layer)
+int RecordingCanvas::save(SkCanvas::SaveFlags flags) {
+    return mState.save((int) flags);
+}
+
+void RecordingCanvas::RecordingCanvas::restore() {
+    if (mRestoreSaveCount < 0) {
+        restoreToCount(getSaveCount() - 1);
+        return;
+    }
+
+    mRestoreSaveCount--;
+    mState.restore();
+}
+
+void RecordingCanvas::restoreToCount(int saveCount) {
+    mRestoreSaveCount = saveCount;
+    mState.restoreToCount(saveCount);
+}
+
+int RecordingCanvas::saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
+        SkCanvas::SaveFlags flags) {
+    LOG_ALWAYS_FATAL("TODO");
+    return 0;
+}
+
+// Matrix
+void RecordingCanvas::rotate(float degrees) {
+    if (degrees == 0) return;
+
+    mState.rotate(degrees);
+}
+
+void RecordingCanvas::scale(float sx, float sy) {
+    if (sx == 1 && sy == 1) return;
+
+    mState.scale(sx, sy);
+}
+
+void RecordingCanvas::skew(float sx, float sy) {
+    mState.skew(sx, sy);
+}
+
+void RecordingCanvas::translate(float dx, float dy) {
+    if (dx == 0 && dy == 0) return;
+
+    mState.translate(dx, dy, 0);
+}
+
+// Clip
+bool RecordingCanvas::getClipBounds(SkRect* outRect) const {
+    Rect bounds = mState.getLocalClipBounds();
+    *outRect = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom);
+    return !(outRect->isEmpty());
+}
+bool RecordingCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
+    return mState.quickRejectConservative(left, top, right, bottom);
+}
+bool RecordingCanvas::quickRejectPath(const SkPath& path) const {
+    SkRect bounds = path.getBounds();
+    return mState.quickRejectConservative(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
+}
+bool RecordingCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
+    return mState.clipRect(left, top, right, bottom, op);
+}
+bool RecordingCanvas::clipPath(const SkPath* path, SkRegion::Op op) {
+    return mState.clipPath(path, op);
+}
+bool RecordingCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
+    return mState.clipRegion(region, op);
+}
+
+// ----------------------------------------------------------------------------
+// android/graphics/Canvas draw operations
+// ----------------------------------------------------------------------------
+void RecordingCanvas::drawColor(int color, SkXfermode::Mode mode) {
+    SkPaint paint;
+    paint.setColor(color);
+    paint.setXfermodeMode(mode);
+    drawPaint(paint);
+}
+
+void RecordingCanvas::drawPaint(const SkPaint& paint) {
+    // TODO: more efficient recording?
+    Matrix4 identity;
+    identity.loadIdentity();
+
+    addOp(new (alloc()) RectOp(
+            mState.getRenderTargetClipBounds(),
+            identity,
+            mState.getRenderTargetClipBounds(),
+            refPaint(&paint)));
+}
+
+// Geometry
+void RecordingCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+void RecordingCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+void RecordingCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
+    addOp(new (alloc()) RectOp(
+            Rect(left, top, right, bottom),
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            refPaint(&paint)));
+}
+
+void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) {
+    if (rects == nullptr) return;
+
+    Vertex* rectData = (Vertex*) mDisplayListData->allocator.alloc(vertexCount * sizeof(Vertex));
+    Vertex* vertex = rectData;
+
+    float left = FLT_MAX;
+    float top = FLT_MAX;
+    float right = FLT_MIN;
+    float bottom = FLT_MIN;
+    for (int index = 0; index < vertexCount; index += 4) {
+        float l = rects[index + 0];
+        float t = rects[index + 1];
+        float r = rects[index + 2];
+        float b = rects[index + 3];
+
+        Vertex::set(vertex++, l, t);
+        Vertex::set(vertex++, r, t);
+        Vertex::set(vertex++, l, b);
+        Vertex::set(vertex++, r, b);
+
+        left = std::min(left, l);
+        top = std::min(top, t);
+        right = std::max(right, r);
+        bottom = std::max(bottom, b);
+    }
+    addOp(new (alloc()) SimpleRectsOp(
+            Rect(left, top, right, bottom),
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            refPaint(paint), rectData, vertexCount));
+}
+
+void RecordingCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
+    if (paint.getStyle() == SkPaint::kFill_Style
+            && (!paint.isAntiAlias() || mState.currentTransform()->isSimple())) {
+        int count = 0;
+        Vector<float> rects;
+        SkRegion::Iterator it(region);
+        while (!it.done()) {
+            const SkIRect& r = it.rect();
+            rects.push(r.fLeft);
+            rects.push(r.fTop);
+            rects.push(r.fRight);
+            rects.push(r.fBottom);
+            count += 4;
+            it.next();
+        }
+        drawSimpleRects(rects.array(), count, &paint);
+    } else {
+        SkRegion::Iterator it(region);
+        while (!it.done()) {
+            const SkIRect& r = it.rect();
+            drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
+            it.next();
+        }
+    }
+}
+void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
+            float rx, float ry, const SkPaint& paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+
+// Bitmap-based
+void RecordingCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) {
+    save(SkCanvas::kMatrix_SaveFlag);
+    translate(left, top);
+    drawBitmap(&bitmap, paint);
+    restore();
+}
+
+void RecordingCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
+                            const SkPaint* paint) {
+    if (matrix.isIdentity()) {
+        drawBitmap(&bitmap, paint);
+    } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask))
+            && MathUtils::isPositive(matrix.getScaleX())
+            && MathUtils::isPositive(matrix.getScaleY())) {
+        // SkMatrix::isScaleTranslate() not available in L
+        SkRect src;
+        SkRect dst;
+        bitmap.getBounds(&src);
+        matrix.mapRect(&dst, src);
+        drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
+                   dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+    } else {
+        save(SkCanvas::kMatrix_SaveFlag);
+        concat(matrix);
+        drawBitmap(&bitmap, paint);
+        restore();
+    }
+}
+void RecordingCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
+            float srcRight, float srcBottom, float dstLeft, float dstTop,
+            float dstRight, float dstBottom, const SkPaint* paint) {
+    if (srcLeft == 0 && srcTop == 0
+            && srcRight == bitmap.width()
+            && srcBottom == bitmap.height()
+            && (srcBottom - srcTop == dstBottom - dstTop)
+            && (srcRight - srcLeft == dstRight - dstLeft)) {
+        // transform simple rect to rect drawing case into position bitmap ops, since they merge
+        save(SkCanvas::kMatrix_SaveFlag);
+        translate(dstLeft, dstTop);
+        drawBitmap(&bitmap, paint);
+        restore();
+    } else {
+        LOG_ALWAYS_FATAL("TODO!");
+    }
+}
+void RecordingCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
+            const float* vertices, const int* colors, const SkPaint* paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+void RecordingCanvas::drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
+            float dstLeft, float dstTop, float dstRight, float dstBottom,
+            const SkPaint* paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+
+// Text
+void RecordingCanvas::drawText(const uint16_t* glyphs, const float* positions, int count,
+            const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop,
+            float boundsRight, float boundsBottom, float totalAdvance) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+void RecordingCanvas::drawPosText(const uint16_t* text, const float* positions, int count,
+            int posCount, const SkPaint& paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+            float hOffset, float vOffset, const SkPaint& paint) {
+    LOG_ALWAYS_FATAL("TODO!");
+}
+
+void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
+    addOp(new (alloc()) BitmapOp(
+            Rect(0, 0, bitmap->width(), bitmap->height()),
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            refPaint(paint), refBitmap(*bitmap)));
+}
+void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
+    RenderNodeOp* op = new (alloc()) RenderNodeOp(
+            Rect(0, 0, renderNode->getWidth(), renderNode->getHeight()), // are these safe? they're theoretically dynamic
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            renderNode);
+    int opIndex = addOp(op);
+    int childIndex = mDisplayListData->addChild(op);
+
+    // update the chunk's child indices
+    DisplayListData::Chunk& chunk = mDisplayListData->chunks.back();
+    chunk.endChildIndex = childIndex + 1;
+
+    if (renderNode->stagingProperties().isProjectionReceiver()) {
+        // use staging property, since recording on UI thread
+        mDisplayListData->projectionReceiveIndex = opIndex;
+    }
+}
+
+size_t RecordingCanvas::addOp(RecordedOp* op) {
+    // TODO: validate if "addDrawOp" quickrejection logic is useful before adding
+    int insertIndex = mDisplayListData->ops.size();
+    mDisplayListData->ops.push_back(op);
+    if (mDeferredBarrierType != kBarrier_None) {
+        // op is first in new chunk
+        mDisplayListData->chunks.emplace_back();
+        DisplayListData::Chunk& newChunk = mDisplayListData->chunks.back();
+        newChunk.beginOpIndex = insertIndex;
+        newChunk.endOpIndex = insertIndex + 1;
+        newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder);
+
+        int nextChildIndex = mDisplayListData->children().size();
+        newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
+        mDeferredBarrierType = kBarrier_None;
+    } else {
+        // standard case - append to existing chunk
+        mDisplayListData->chunks.back().endOpIndex = insertIndex + 1;
+    }
+    return insertIndex;
+}
+
+void RecordingCanvas::refBitmapsInShader(const SkShader* shader) {
+    if (!shader) return;
+
+    // If this paint has an SkShader that has an SkBitmap add
+    // it to the bitmap pile
+    SkBitmap bitmap;
+    SkShader::TileMode xy[2];
+    if (shader->asABitmap(&bitmap, nullptr, xy) == SkShader::kDefault_BitmapType) {
+        refBitmap(bitmap);
+        return;
+    }
+    SkShader::ComposeRec rec;
+    if (shader->asACompose(&rec)) {
+        refBitmapsInShader(rec.fShaderA);
+        refBitmapsInShader(rec.fShaderB);
+        return;
+    }
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
new file mode 100644
index 0000000..ed299e5
--- /dev/null
+++ b/libs/hwui/RecordingCanvas.h
@@ -0,0 +1,300 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_RECORDING_CANVAS_H
+#define ANDROID_HWUI_RECORDING_CANVAS_H
+
+#include "Canvas.h"
+#include "CanvasState.h"
+#include "DisplayList.h"
+#include "utils/LinearAllocator.h"
+#include "utils/NinePatch.h"
+#include "ResourceCache.h"
+#include "SkiaCanvasProxy.h"
+#include "Snapshot.h"
+
+#include "SkDrawFilter.h"
+#include <vector>
+
+namespace android {
+namespace uirenderer {
+
+class OpReceiver;
+struct RecordedOp;
+
+class RecordingCanvas: public Canvas, public CanvasStateClient {
+public:
+    RecordingCanvas(size_t width, size_t height);
+    virtual ~RecordingCanvas();
+
+    void reset(int width, int height);
+    DisplayListData* finishRecording();
+
+// ----------------------------------------------------------------------------
+// MISC HWUI OPERATIONS - TODO: CATEGORIZE
+// ----------------------------------------------------------------------------
+    void insertReorderBarrier(bool enableReorder) {}
+    void drawRenderNode(RenderNode* renderNode);
+
+// ----------------------------------------------------------------------------
+// CanvasStateClient interface
+// ----------------------------------------------------------------------------
+    virtual void onViewportInitialized() override {}
+    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override {}
+    virtual GLuint getTargetFbo() const override { return -1; }
+
+// ----------------------------------------------------------------------------
+// android/graphics/Canvas interface
+// ----------------------------------------------------------------------------
+    virtual SkCanvas* asSkCanvas() override;
+
+    virtual void setBitmap(const SkBitmap& bitmap) override {
+        LOG_ALWAYS_FATAL("RecordingCanvas is not backed by a bitmap.");
+    }
+
+    virtual bool isOpaque() override { return false; }
+    virtual int width() override { return mState.getWidth(); }
+    virtual int height() override { return mState.getHeight(); }
+
+    virtual void setHighContrastText(bool highContrastText) override {
+        mHighContrastText = highContrastText;
+    }
+    virtual bool isHighContrastText() override { return mHighContrastText; }
+
+// ----------------------------------------------------------------------------
+// android/graphics/Canvas state operations
+// ----------------------------------------------------------------------------
+    // Save (layer)
+    virtual int getSaveCount() const override { return mState.getSaveCount(); }
+    virtual int save(SkCanvas::SaveFlags flags) override;
+    virtual void restore() override;
+    virtual void restoreToCount(int saveCount) override;
+
+    virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
+        SkCanvas::SaveFlags flags) override;
+    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
+            int alpha, SkCanvas::SaveFlags flags) override {
+        SkPaint paint;
+        paint.setAlpha(alpha);
+        return saveLayer(left, top, right, bottom, &paint, flags);
+    }
+
+    // Matrix
+    virtual void getMatrix(SkMatrix* outMatrix) const override { mState.getMatrix(outMatrix); }
+    virtual void setMatrix(const SkMatrix& matrix) override { mState.setMatrix(matrix); }
+
+    virtual void concat(const SkMatrix& matrix) override { mState.concatMatrix(matrix); }
+    virtual void rotate(float degrees) override;
+    virtual void scale(float sx, float sy) override;
+    virtual void skew(float sx, float sy) override;
+    virtual void translate(float dx, float dy) override;
+
+    // Clip
+    virtual bool getClipBounds(SkRect* outRect) const override;
+    virtual bool quickRejectRect(float left, float top, float right, float bottom) const override;
+    virtual bool quickRejectPath(const SkPath& path) const override;
+
+    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) override;
+    virtual bool clipPath(const SkPath* path, SkRegion::Op op) override;
+    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) override;
+
+    // Misc
+    virtual SkDrawFilter* getDrawFilter() override { return mDrawFilter.get(); }
+    virtual void setDrawFilter(SkDrawFilter* filter) override {
+        mDrawFilter.reset(SkSafeRef(filter));
+    }
+
+// ----------------------------------------------------------------------------
+// android/graphics/Canvas draw operations
+// ----------------------------------------------------------------------------
+    virtual void drawColor(int color, SkXfermode::Mode mode) override;
+    virtual void drawPaint(const SkPaint& paint) override;
+
+    // Geometry
+    virtual void drawPoint(float x, float y, const SkPaint& paint) override {
+        float points[2] = { x, y };
+        drawPoints(points, 2, paint);
+    }
+    virtual void drawPoints(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawLine(float startX, float startY, float stopX, float stopY,
+            const SkPaint& paint) override {
+        float points[4] = { startX, startY, stopX, stopY };
+        drawLines(points, 4, paint);
+    }
+    virtual void drawLines(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
+    virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override;
+    virtual void drawRoundRect(float left, float top, float right, float bottom,
+            float rx, float ry, const SkPaint& paint) override;
+    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
+    virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint) override;
+    virtual void drawArc(float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override;
+    virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
+    virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
+            const float* verts, const float* tex, const int* colors,
+            const uint16_t* indices, int indexCount, const SkPaint& paint) override
+        { /* RecordingCanvas does not support drawVertices(); ignore */ }
+
+    // Bitmap-based
+    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) override;
+    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
+                            const SkPaint* paint) override;
+    virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
+            float srcRight, float srcBottom, float dstLeft, float dstTop,
+            float dstRight, float dstBottom, const SkPaint* paint) override;
+    virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
+            const float* vertices, const int* colors, const SkPaint* paint) override;
+    virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
+            float dstLeft, float dstTop, float dstRight, float dstBottom,
+            const SkPaint* paint) override;
+
+    // Text
+    virtual void drawText(const uint16_t* glyphs, const float* positions, int count,
+            const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop,
+            float boundsRight, float boundsBottom, float totalAdvance) override;
+    virtual void drawPosText(const uint16_t* text, const float* positions, int count,
+            int posCount, const SkPaint& paint) override;
+    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+            float hOffset, float vOffset, const SkPaint& paint) override;
+    virtual bool drawTextAbsolutePos() const override { return false; }
+
+private:
+    enum DeferredBarrierType {
+        kBarrier_None,
+        kBarrier_InOrder,
+        kBarrier_OutOfOrder,
+    };
+
+    void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
+    void drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint);
+
+
+    size_t addOp(RecordedOp* op);
+// ----------------------------------------------------------------------------
+// lazy object copy
+// ----------------------------------------------------------------------------
+    LinearAllocator& alloc() { return mDisplayListData->allocator; }
+
+    void refBitmapsInShader(const SkShader* shader);
+
+    template<class T>
+    inline const T* refBuffer(const T* srcBuffer, int32_t count) {
+        if (!srcBuffer) return nullptr;
+
+        T* dstBuffer = (T*) mDisplayListData->allocator.alloc(count * sizeof(T));
+        memcpy(dstBuffer, srcBuffer, count * sizeof(T));
+        return dstBuffer;
+    }
+
+    inline char* refText(const char* text, size_t byteLength) {
+        return (char*) refBuffer<uint8_t>((uint8_t*)text, byteLength);
+    }
+
+    inline const SkPath* refPath(const SkPath* path) {
+        if (!path) return nullptr;
+
+        // The points/verbs within the path are refcounted so this copy operation
+        // is inexpensive and maintains the generationID of the original path.
+        const SkPath* cachedPath = new SkPath(*path);
+        mDisplayListData->pathResources.push_back(cachedPath);
+        return cachedPath;
+    }
+
+    inline const SkPaint* refPaint(const SkPaint* paint) {
+        if (!paint) return nullptr;
+
+        // If there is a draw filter apply it here and store the modified paint
+        // so that we don't need to modify the paint every time we access it.
+        SkTLazy<SkPaint> filteredPaint;
+        if (mDrawFilter.get()) {
+            filteredPaint.set(*paint);
+            mDrawFilter->filter(filteredPaint.get(), SkDrawFilter::kPaint_Type);
+            paint = filteredPaint.get();
+        }
+
+        // compute the hash key for the paint and check the cache.
+        const uint32_t key = paint->getHash();
+        const SkPaint* cachedPaint = mPaintMap.valueFor(key);
+        // In the unlikely event that 2 unique paints have the same hash we do a
+        // object equality check to ensure we don't erroneously dedup them.
+        if (cachedPaint == nullptr || *cachedPaint != *paint) {
+            cachedPaint = new SkPaint(*paint);
+            std::unique_ptr<const SkPaint> copy(cachedPaint);
+            mDisplayListData->paints.push_back(std::move(copy));
+
+            // replaceValueFor() performs an add if the entry doesn't exist
+            mPaintMap.replaceValueFor(key, cachedPaint);
+            refBitmapsInShader(cachedPaint->getShader());
+        }
+
+        return cachedPaint;
+    }
+
+    inline const SkRegion* refRegion(const SkRegion* region) {
+        if (!region) {
+            return region;
+        }
+
+        const SkRegion* cachedRegion = mRegionMap.valueFor(region);
+        // TODO: Add generation ID to SkRegion
+        if (cachedRegion == nullptr) {
+            std::unique_ptr<const SkRegion> copy(new SkRegion(*region));
+            cachedRegion = copy.get();
+            mDisplayListData->regions.push_back(std::move(copy));
+
+            // replaceValueFor() performs an add if the entry doesn't exist
+            mRegionMap.replaceValueFor(region, cachedRegion);
+        }
+
+        return cachedRegion;
+    }
+
+    inline const SkBitmap* refBitmap(const SkBitmap& bitmap) {
+        // Note that this assumes the bitmap is immutable. There are cases this won't handle
+        // correctly, such as creating the bitmap from scratch, drawing with it, changing its
+        // contents, and drawing again. The only fix would be to always copy it the first time,
+        // which doesn't seem worth the extra cycles for this unlikely case.
+        SkBitmap* localBitmap = new (alloc()) SkBitmap(bitmap);
+        alloc().autoDestroy(localBitmap);
+        mDisplayListData->bitmapResources.push_back(localBitmap);
+        return localBitmap;
+    }
+
+    inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) {
+        mDisplayListData->patchResources.push_back(patch);
+        mResourceCache.incrementRefcount(patch);
+        return patch;
+    }
+
+    DefaultKeyedVector<uint32_t, const SkPaint*> mPaintMap;
+    DefaultKeyedVector<const SkPath*, const SkPath*> mPathMap;
+    DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap;
+
+    CanvasState mState;
+    std::unique_ptr<SkiaCanvasProxy> mSkiaCanvasProxy;
+    ResourceCache& mResourceCache;
+    DeferredBarrierType mDeferredBarrierType = kBarrier_None;
+    DisplayListData* mDisplayListData = nullptr;
+    bool mHighContrastText = false;
+    SkAutoTUnref<SkDrawFilter> mDrawFilter;
+    int mRestoreSaveCount = -1;
+}; // class RecordingCanvas
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_RECORDING_CANVAS_H
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index bf1b4d0..28586fa 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -25,6 +25,9 @@
 
 #include "DamageAccumulator.h"
 #include "Debug.h"
+#if HWUI_NEW_OPS
+#include "RecordedOp.h"
+#endif
 #include "DisplayListOp.h"
 #include "LayerRenderer.h"
 #include "OpenGLRenderer.h"
@@ -46,8 +49,8 @@
                 mLayer->wasBuildLayered ? "true" : "false");
     }
     if (mDisplayListData) {
-        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
-            mDisplayListData->children()[i]->mRenderNode->debugDumpLayers(prefix);
+        for (auto&& child : mDisplayListData->children()) {
+            child->renderNode->debugDumpLayers(prefix);
         }
     }
 }
@@ -94,12 +97,16 @@
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
     properties().debugOutputProperties(level);
-    int flags = DisplayListOp::kOpLogFlag_Recurse;
+
     if (mDisplayListData) {
+#if HWUI_NEW_OPS
+        LOG_ALWAYS_FATAL("op dumping unsupported");
+#else
         // TODO: consider printing the chunk boundaries here
-        for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
-            mDisplayListData->displayListOps[i]->output(level, flags);
+        for (auto&& op : mDisplayListData->getOps()) {
+            op->output(level, DisplayListOp::kOpLogFlag_Recurse);
         }
+#endif
     }
 
     ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
@@ -172,7 +179,7 @@
     pnode->clear_children();
     if (mDisplayListData) {
         for (auto&& child : mDisplayListData->children()) {
-            child->mRenderNode->copyTo(pnode->add_children());
+            child->renderNode->copyTo(pnode->add_children());
         }
     }
 }
@@ -332,6 +339,10 @@
     info.damageAccumulator->popTransform();
 }
 
+void RenderNode::syncProperties() {
+    mProperties = mStagingProperties;
+}
+
 void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
     // Push the animators first so that setupStartValueIfNecessary() is called
     // before properties() is trampled by stagingProperties(), as they are
@@ -343,7 +354,7 @@
         mDirtyPropertyFields = 0;
         damageSelf(info);
         info.damageAccumulator->popTransform();
-        mProperties = mStagingProperties;
+        syncProperties();
         applyLayerPropertiesToLayer(info);
         // We could try to be clever and only re-damage if the matrix changed.
         // However, we don't need to worry about that. The cost of over-damaging
@@ -364,35 +375,39 @@
     mLayer->setBlend(props.needsBlending());
 }
 
+void RenderNode::syncDisplayList() {
+    // Make sure we inc first so that we don't fluctuate between 0 and 1,
+    // which would thrash the layer cache
+    if (mStagingDisplayListData) {
+        for (auto&& child : mStagingDisplayListData->children()) {
+            child->renderNode->incParentRefCount();
+        }
+    }
+    deleteDisplayListData();
+    mDisplayListData = mStagingDisplayListData;
+    mStagingDisplayListData = nullptr;
+    if (mDisplayListData) {
+        for (size_t i = 0; i < mDisplayListData->functors.size(); i++) {
+            (*mDisplayListData->functors[i])(DrawGlInfo::kModeSync, nullptr);
+        }
+    }
+}
+
 void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
     if (mNeedsDisplayListDataSync) {
         mNeedsDisplayListDataSync = false;
-        // Make sure we inc first so that we don't fluctuate between 0 and 1,
-        // which would thrash the layer cache
-        if (mStagingDisplayListData) {
-            for (size_t i = 0; i < mStagingDisplayListData->children().size(); i++) {
-                mStagingDisplayListData->children()[i]->mRenderNode->incParentRefCount();
-            }
-        }
         // Damage with the old display list first then the new one to catch any
         // changes in isRenderable or, in the future, bounds
         damageSelf(info);
-        deleteDisplayListData();
-        mDisplayListData = mStagingDisplayListData;
-        mStagingDisplayListData = nullptr;
-        if (mDisplayListData) {
-            for (size_t i = 0; i < mDisplayListData->functors.size(); i++) {
-                (*mDisplayListData->functors[i])(DrawGlInfo::kModeSync, nullptr);
-            }
-        }
+        syncDisplayList();
         damageSelf(info);
     }
 }
 
 void RenderNode::deleteDisplayListData() {
     if (mDisplayListData) {
-        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
-            mDisplayListData->children()[i]->mRenderNode->decParentRefCount();
+        for (auto&& child : mDisplayListData->children()) {
+            child->renderNode->decParentRefCount();
         }
     }
     delete mDisplayListData;
@@ -407,13 +422,17 @@
             info.prepareTextures = cache.prefetchAndMarkInUse(
                     info.canvasContext, subtree->bitmapResources[i]);
         }
-        for (size_t i = 0; i < subtree->children().size(); i++) {
-            DrawRenderNodeOp* op = subtree->children()[i];
-            RenderNode* childNode = op->mRenderNode;
+        for (auto&& op : subtree->children()) {
+            RenderNode* childNode = op->renderNode;
+#if HWUI_NEW_OPS
+            info.damageAccumulator->pushTransform(&op->localMatrix);
+            bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
+#else
             info.damageAccumulator->pushTransform(&op->mTransformFromParent);
             bool childFunctorsNeedLayer = functorsNeedLayer
                     // Recorded with non-rect clip, or canvas-rotated by parent
                     || op->mRecordedWithPotentialStencilClip;
+#endif
             childNode->prepareTreeImpl(info, childFunctorsNeedLayer);
             info.damageAccumulator->popTransform();
         }
@@ -426,8 +445,8 @@
         mLayer = nullptr;
     }
     if (mDisplayListData) {
-        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
-            mDisplayListData->children()[i]->mRenderNode->destroyHardwareResources();
+        for (auto&& child : mDisplayListData->children()) {
+            child->renderNode->destroyHardwareResources();
         }
         if (mNeedsDisplayListDataSync) {
             // Next prepare tree we are going to push a new display list, so we can
@@ -449,6 +468,34 @@
     }
 }
 
+bool RenderNode::applyViewProperties(CanvasState& canvasState) const {
+    const Outline& outline = properties().getOutline();
+    if (properties().getAlpha() <= 0
+            || (outline.getShouldClip() && outline.isEmpty())
+            || properties().getScaleX() == 0
+            || properties().getScaleY() == 0) {
+        return false; // rejected
+    }
+
+    if (properties().getLeft() != 0 || properties().getTop() != 0) {
+        canvasState.translate(properties().getLeft(), properties().getTop());
+    }
+    if (properties().getStaticMatrix()) {
+        canvasState.concatMatrix(*properties().getStaticMatrix());
+    } else if (properties().getAnimationMatrix()) {
+        canvasState.concatMatrix(*properties().getAnimationMatrix());
+    }
+    if (properties().hasTransformMatrix()) {
+        if (properties().isTransformTranslateOnly()) {
+            canvasState.translate(properties().getTranslationX(), properties().getTranslationY());
+        } else {
+            canvasState.concatMatrix(*properties().getTransformMatrix());
+        }
+    }
+    return !canvasState.quickRejectConservative(
+            0, 0, properties().getWidth(), properties().getHeight());
+}
+
 /*
  * For property operations, we pass a savecount of 0, since the operations aren't part of the
  * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
@@ -580,6 +627,7 @@
  * which are flagged to not draw in the standard draw loop.
  */
 void RenderNode::computeOrdering() {
+#if !HWUI_NEW_OPS
     ATRACE_CALL();
     mProjectedNodes.clear();
 
@@ -588,14 +636,16 @@
     if (mDisplayListData == nullptr) return;
     for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
         DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
-        childOp->mRenderNode->computeOrderingImpl(childOp, &mProjectedNodes, &mat4::identity());
+        childOp->renderNode->computeOrderingImpl(childOp, &mProjectedNodes, &mat4::identity());
     }
+#endif
 }
 
 void RenderNode::computeOrderingImpl(
         DrawRenderNodeOp* opState,
         std::vector<DrawRenderNodeOp*>* compositedChildrenOfProjectionSurface,
         const mat4* transformFromProjectionSurface) {
+#if !HWUI_NEW_OPS
     mProjectedNodes.clear();
     if (mDisplayListData == nullptr || mDisplayListData->isEmpty()) return;
 
@@ -619,7 +669,7 @@
         bool haveAppliedPropertiesToProjection = false;
         for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
             DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
-            RenderNode* child = childOp->mRenderNode;
+            RenderNode* child = childOp->renderNode;
 
             std::vector<DrawRenderNodeOp*>* projectionChildren = nullptr;
             const mat4* projectionTransform = nullptr;
@@ -642,6 +692,7 @@
             child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
         }
     }
+#endif
 }
 
 class DeferOperationHandler {
@@ -701,11 +752,12 @@
 
 void RenderNode::buildZSortedChildList(const DisplayListData::Chunk& chunk,
         std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes) {
+#if !HWUI_NEW_OPS
     if (chunk.beginChildIndex == chunk.endChildIndex) return;
 
     for (unsigned int i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
         DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
-        RenderNode* child = childOp->mRenderNode;
+        RenderNode* child = childOp->renderNode;
         float childZ = child->properties().getZ();
 
         if (!MathUtils::isZero(childZ) && chunk.reorderChildren) {
@@ -719,6 +771,7 @@
 
     // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order)
     std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
+#endif
 }
 
 template <class T>
@@ -824,7 +877,7 @@
     while (shadowIndex < endIndex || drawIndex < endIndex) {
         if (shadowIndex < endIndex) {
             DrawRenderNodeOp* casterOp = zTranslatedNodes[shadowIndex].value;
-            RenderNode* caster = casterOp->mRenderNode;
+            RenderNode* caster = casterOp->renderNode;
             const float casterZ = zTranslatedNodes[shadowIndex].key;
             // attempt to render the shadow if the caster about to be drawn is its caster,
             // OR if its caster's Z value is similar to the previous potential caster
@@ -867,9 +920,14 @@
     // Transform renderer to match background we're projecting onto
     // (by offsetting canvas by translationX/Y of background rendernode, since only those are set)
     const DisplayListOp* op =
-            (mDisplayListData->displayListOps[mDisplayListData->projectionReceiveIndex]);
+#if HWUI_NEW_OPS
+            nullptr;
+    LOG_ALWAYS_FATAL("unsupported");
+#else
+            (mDisplayListData->getOps()[mDisplayListData->projectionReceiveIndex]);
+#endif
     const DrawRenderNodeOp* backgroundOp = reinterpret_cast<const DrawRenderNodeOp*>(op);
-    const RenderProperties& backgroundProps = backgroundOp->mRenderNode->properties();
+    const RenderProperties& backgroundProps = backgroundOp->renderNode->properties();
     renderer.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY());
 
     // If the projection reciever has an outline, we mask projected content to it
@@ -948,6 +1006,9 @@
         setViewProperties<T>(renderer, handler);
     }
 
+#if HWUI_NEW_OPS
+    LOG_ALWAYS_FATAL("legacy op traversal not supported");
+#else
     bool quickRejected = properties().getClipToBounds()
             && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
     if (!quickRejected) {
@@ -969,9 +1030,8 @@
                 issueOperationsOf3dChildren(ChildrenSelectMode::NegativeZChildren,
                         initialTransform, zTranslatedNodes, renderer, handler);
 
-
                 for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
-                    DisplayListOp *op = mDisplayListData->displayListOps[opIndex];
+                    DisplayListOp *op = mDisplayListData->getOps()[opIndex];
 #if DEBUG_DISPLAY_LIST
                     op->output(handler.level() + 1);
 #endif
@@ -988,6 +1048,7 @@
             }
         }
     }
+#endif
 
     DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (handler.level() + 1) * 2, "", restoreTo);
     handler(new (alloc) RestoreToCountOp(restoreTo),
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 88fc608..ff673ba 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -29,8 +29,8 @@
 
 #include "AnimatorManager.h"
 #include "Debug.h"
-#include "Matrix.h"
 #include "DisplayList.h"
+#include "Matrix.h"
 #include "RenderProperties.h"
 
 #include <vector>
@@ -43,6 +43,7 @@
 namespace android {
 namespace uirenderer {
 
+class CanvasState;
 class DisplayListOp;
 class DisplayListCanvas;
 class OpenGLRenderer;
@@ -74,6 +75,7 @@
  * attached.
  */
 class RenderNode : public VirtualLightRefBase {
+friend class TestUtils; // allow TestUtils to access syncDisplayList / syncProperties
 public:
     enum DirtyPropertyMask {
         GENERIC         = 1 << 1,
@@ -176,8 +178,25 @@
 
     AnimatorManager& animators() { return mAnimatorManager; }
 
+    // Returns false if the properties dictate the subtree contained in this RenderNode won't render
+    bool applyViewProperties(CanvasState& canvasState) const;
+
     void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false) const;
 
+    bool nothingToDraw() const {
+        const Outline& outline = properties().getOutline();
+        return mDisplayListData == nullptr
+                || properties().getAlpha() <= 0
+                || (outline.getShouldClip() && outline.isEmpty())
+                || properties().getScaleX() == 0
+                || properties().getScaleY() == 0;
+    }
+
+    // Only call if RenderNode has DisplayListData...
+    const DisplayListData& getDisplayListData() const {
+        return *mDisplayListData;
+    }
+
 private:
     typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
 
@@ -235,6 +254,10 @@
         const char* mText;
     };
 
+
+    void syncProperties();
+    void syncDisplayList();
+
     void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
     void pushStagingPropertiesChanges(TreeInfo& info);
     void pushStagingDisplayListChanges(TreeInfo& info);
diff --git a/libs/hwui/microbench/DisplayListCanvasBench.cpp b/libs/hwui/microbench/DisplayListCanvasBench.cpp
index 7b6be7a..fd42adb 100644
--- a/libs/hwui/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/microbench/DisplayListCanvasBench.cpp
@@ -18,12 +18,22 @@
 #include <utils/Singleton.h>
 
 #include "DisplayList.h"
+#if HWUI_NEW_OPS
+#include "RecordingCanvas.h"
+#else
 #include "DisplayListCanvas.h"
+#endif
 #include "microbench/MicroBench.h"
 
 using namespace android;
 using namespace android::uirenderer;
 
+#if HWUI_NEW_OPS
+typedef RecordingCanvas TestCanvas;
+#else
+typedef DisplayListCanvas TestCanvas;
+#endif
+
 BENCHMARK_NO_ARG(BM_DisplayListData_alloc);
 void BM_DisplayListData_alloc::Run(int iters) {
     StartBenchmarkTiming();
@@ -48,7 +58,7 @@
 
 BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_empty);
 void BM_DisplayListCanvas_record_empty::Run(int iters) {
-    DisplayListCanvas canvas(100, 100);
+    TestCanvas canvas(100, 100);
     canvas.finishRecording();
 
     StartBenchmarkTiming();
@@ -62,7 +72,7 @@
 
 BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_saverestore);
 void BM_DisplayListCanvas_record_saverestore::Run(int iters) {
-    DisplayListCanvas canvas(100, 100);
+    TestCanvas canvas(100, 100);
     canvas.finishRecording();
 
     StartBenchmarkTiming();
@@ -80,7 +90,7 @@
 
 BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_translate);
 void BM_DisplayListCanvas_record_translate::Run(int iters) {
-    DisplayListCanvas canvas(100, 100);
+    TestCanvas canvas(100, 100);
     canvas.finishRecording();
 
     StartBenchmarkTiming();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 38f6e53..238cf06 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -28,6 +28,11 @@
 #include "renderstate/Stencil.h"
 #include "protos/hwui.pb.h"
 
+#if HWUI_NEW_OPS
+#include "BakedOpRenderer.h"
+#include "OpReorderer.h"
+#endif
+
 #include <cutils/properties.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <private/hwui/DrawGlInfo.h>
@@ -121,9 +126,11 @@
 
 bool CanvasContext::initialize(ANativeWindow* window) {
     setSurface(window);
+#if !HWUI_NEW_OPS
     if (mCanvas) return false;
     mCanvas = new OpenGLRenderer(mRenderThread.renderState());
     mCanvas->initProperties();
+#endif
     return true;
 }
 
@@ -162,11 +169,13 @@
 }
 
 void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
+#if !HWUI_NEW_OPS
     bool success = layerUpdater->apply();
     LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
     if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
         mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
     }
+#endif
 }
 
 static bool wasSkipped(FrameInfo* info) {
@@ -239,8 +248,10 @@
 }
 
 void CanvasContext::draw() {
+#if !HWUI_NEW_OPS
     LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
             "drawRenderNode called on a context with no canvas or surface!");
+#endif
 
     SkRect dirty;
     mDamageAccumulator.finish(&dirty);
@@ -254,10 +265,12 @@
     mCurrentFrameInfo->markIssueDrawCommandsStart();
 
     Frame frame = mEglManager.beginFrame(mEglSurface);
-    if (frame.width() != mCanvas->getViewportWidth()
-            || frame.height() != mCanvas->getViewportHeight()) {
+
+    if (frame.width() != lastFrameWidth || frame.height() != lastFrameHeight) {
         // can't rely on prior content of window if viewport size changes
         dirty.setEmpty();
+        lastFrameWidth = frame.width();
+        lastFrameHeight = frame.height();
     } else if (mHaveNewSurface || frame.bufferAge() == 0) {
         // New surface needs a full draw
         dirty.setEmpty();
@@ -303,6 +316,18 @@
     mDamageHistory.next() = screenDirty;
 
     mEglManager.damageFrame(frame, dirty);
+
+#if HWUI_NEW_OPS
+    OpReorderer reorderer;
+    reorderer.defer(dirty, frame.width(), frame.height(), mRenderNodes);
+    BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(),
+            frame.width(), frame.height(), mOpaque);
+    // TODO: profiler().draw(mCanvas);
+    reorderer.replayBakedOps<BakedOpRenderer>(&info);
+
+    bool drew = info.didDraw;
+
+#else
     mCanvas->prepareDirty(frame.width(), frame.height(),
             dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque);
 
@@ -413,7 +438,7 @@
     profiler().draw(mCanvas);
 
     bool drew = mCanvas->finish();
-
+#endif
     // Even if we decided to cancel the frame, from the perspective of jank
     // metrics the frame was swapped at this point
     mCurrentFrameInfo->markSwapBuffers();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index e0cbabd..16956e6 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -141,6 +141,9 @@
 
     void freePrefetechedLayers();
 
+    int lastFrameWidth = 0;
+    int lastFrameHeight = 0;
+
     RenderThread& mRenderThread;
     EglManager& mEglManager;
     sp<ANativeWindow> mNativeWindow;
diff --git a/libs/hwui/tests/TreeContentAnimation.cpp b/libs/hwui/tests/TreeContentAnimation.cpp
index a59261c..891af91 100644
--- a/libs/hwui/tests/TreeContentAnimation.cpp
+++ b/libs/hwui/tests/TreeContentAnimation.cpp
@@ -20,6 +20,7 @@
 
 #include <AnimationContext.h>
 #include <DisplayListCanvas.h>
+#include <RecordingCanvas.h>
 #include <RenderNode.h>
 #include <renderthread/RenderProxy.h>
 #include <renderthread/RenderTask.h>
@@ -39,6 +40,13 @@
 using namespace android::uirenderer::renderthread;
 using namespace android::uirenderer::test;
 
+#if HWUI_NEW_OPS
+typedef RecordingCanvas TestCanvas;
+#else
+typedef DisplayListCanvas TestCanvas;
+#endif
+
+
 class ContextFactory : public IContextFactory {
 public:
     virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
@@ -46,13 +54,13 @@
     }
 };
 
-static DisplayListCanvas* startRecording(RenderNode* node) {
-    DisplayListCanvas* renderer = new DisplayListCanvas(
+static TestCanvas* startRecording(RenderNode* node) {
+    TestCanvas* renderer = new TestCanvas(
             node->stagingProperties().getWidth(), node->stagingProperties().getHeight());
     return renderer;
 }
 
-static void endRecording(DisplayListCanvas* renderer, RenderNode* node) {
+static void endRecording(TestCanvas* renderer, RenderNode* node) {
     node->setStagingDisplayList(renderer->finishRecording());
     delete renderer;
 }
@@ -67,7 +75,7 @@
             frameCount = fc;
         }
     }
-    virtual void createContent(int width, int height, DisplayListCanvas* renderer) = 0;
+    virtual void createContent(int width, int height, TestCanvas* renderer) = 0;
     virtual void doFrame(int frameNr) = 0;
 
     template <class T>
@@ -102,7 +110,7 @@
 
         android::uirenderer::Rect DUMMY;
 
-        DisplayListCanvas* renderer = startRecording(rootNode);
+        TestCanvas* renderer = startRecording(rootNode);
         animation.createContent(width, height, renderer);
         endRecording(renderer, rootNode);
 
@@ -132,7 +140,7 @@
 class ShadowGridAnimation : public TreeContentAnimation {
 public:
     std::vector< sp<RenderNode> > cards;
-    void createContent(int width, int height, DisplayListCanvas* renderer) override {
+    void createContent(int width, int height, TestCanvas* renderer) override {
         renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
         renderer->insertReorderBarrier(true);
 
@@ -163,7 +171,7 @@
         node->mutateStagingProperties().mutableOutline().setShouldClip(true);
         node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
 
-        DisplayListCanvas* renderer = startRecording(node.get());
+        TestCanvas* renderer = startRecording(node.get());
         renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
         endRecording(renderer, node.get());
         return node;
@@ -179,7 +187,7 @@
 class ShadowGrid2Animation : public TreeContentAnimation {
 public:
     std::vector< sp<RenderNode> > cards;
-    void createContent(int width, int height, DisplayListCanvas* renderer) override {
+    void createContent(int width, int height, TestCanvas* renderer) override {
         renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
         renderer->insertReorderBarrier(true);
 
@@ -210,7 +218,7 @@
         node->mutateStagingProperties().mutableOutline().setShouldClip(true);
         node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
 
-        DisplayListCanvas* renderer = startRecording(node.get());
+        TestCanvas* renderer = startRecording(node.get());
         renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
         endRecording(renderer, node.get());
         return node;
@@ -226,7 +234,7 @@
 class RectGridAnimation : public TreeContentAnimation {
 public:
     sp<RenderNode> card;
-    void createContent(int width, int height, DisplayListCanvas* renderer) override {
+    void createContent(int width, int height, TestCanvas* renderer) override {
         renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
         renderer->insertReorderBarrier(true);
 
@@ -247,7 +255,7 @@
         node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
         node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
 
-        DisplayListCanvas* renderer = startRecording(node.get());
+        TestCanvas* renderer = startRecording(node.get());
         renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
 
         SkRegion region;
@@ -275,7 +283,7 @@
 class OvalAnimation : public TreeContentAnimation {
 public:
     sp<RenderNode> card;
-    void createContent(int width, int height, DisplayListCanvas* renderer) override {
+    void createContent(int width, int height, TestCanvas* renderer) override {
         renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
         renderer->insertReorderBarrier(true);
 
@@ -297,7 +305,7 @@
         node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
         node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
 
-        DisplayListCanvas* renderer = startRecording(node.get());
+        TestCanvas* renderer = startRecording(node.get());
 
         SkPaint paint;
         paint.setAntiAlias(true);
@@ -317,7 +325,7 @@
 class PartialDamageTest : public TreeContentAnimation {
 public:
     std::vector< sp<RenderNode> > cards;
-    void createContent(int width, int height, DisplayListCanvas* renderer) override {
+    void createContent(int width, int height, TestCanvas* renderer) override {
         static SkColor COLORS[] = {
                 0xFFF44336,
                 0xFF9C27B0,
@@ -342,7 +350,7 @@
         cards[0]->mutateStagingProperties().setTranslationY(curFrame);
         cards[0]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
 
-        DisplayListCanvas* renderer = startRecording(cards[0].get());
+        TestCanvas* renderer = startRecording(cards[0].get());
         renderer->drawColor(interpolateColor(curFrame / 150.0f, 0xFFF44336, 0xFFF8BBD0),
                 SkXfermode::kSrcOver_Mode);
         endRecording(renderer, cards[0].get());
@@ -370,7 +378,7 @@
         node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
         node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
 
-        DisplayListCanvas* renderer = startRecording(node.get());
+        TestCanvas* renderer = startRecording(node.get());
         renderer->drawColor(color, SkXfermode::kSrcOver_Mode);
         endRecording(renderer, node.get());
         return node;
@@ -383,3 +391,43 @@
     "EGL_KHR_partial_update is supported by the device & are enabled in hwui.",
     TreeContentAnimation::run<PartialDamageTest>
 });
+
+
+class SimpleRectGridAnimation : public TreeContentAnimation {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, TestCanvas* renderer) override {
+        SkPaint paint;
+        paint.setColor(0xFF00FFFF);
+        renderer->drawRect(0, 0, width, height, paint);
+
+        card = createCard(40, 40, 200, 200);
+        renderer->drawRenderNode(card.get());
+    }
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 150;
+        card->mutateStagingProperties().setTranslationX(curFrame);
+        card->mutateStagingProperties().setTranslationY(curFrame);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        sp<RenderNode> node = new RenderNode();
+        node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+
+        TestCanvas* renderer = startRecording(node.get());
+        SkPaint paint;
+        paint.setColor(0xFFFF00FF);
+        renderer->drawRect(0, 0, width, height, paint);
+
+        endRecording(renderer, node.get());
+        return node;
+    }
+};
+static Benchmark _SimpleRectGrid(BenchmarkInfo{
+    "simplerectgrid",
+    "A simple collection of rects. "
+    "Low CPU/GPU load.",
+    TreeContentAnimation::run<SimpleRectGridAnimation>
+});
diff --git a/libs/hwui/unit_tests/BakedOpStateTests.cpp b/libs/hwui/unit_tests/BakedOpStateTests.cpp
new file mode 100644
index 0000000..82aebea
--- /dev/null
+++ b/libs/hwui/unit_tests/BakedOpStateTests.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <BakedOpState.h>
+#include <RecordedOp.h>
+#include <unit_tests/TestUtils.h>
+
+namespace android {
+namespace uirenderer {
+
+TEST(ResolvedRenderState, resolution) {
+    Matrix4 identity;
+    identity.loadIdentity();
+
+    Matrix4 translate10x20;
+    translate10x20.loadTranslate(10, 20, 0);
+
+    SkPaint paint;
+    RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, Rect(0, 0, 100, 200), &paint);
+    {
+        // recorded with transform, no parent transform
+        auto parentSnapshot = TestUtils::makeSnapshot(identity, Rect(0, 0, 100, 200));
+        ResolvedRenderState state(*parentSnapshot, recordedOp);
+        EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
+        EXPECT_EQ(state.clipRect, Rect(0, 0, 100, 200));
+        EXPECT_EQ(state.clippedBounds, Rect(40, 60, 100, 200)); // translated and also clipped
+    }
+    {
+        // recorded with transform and parent transform
+        auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(0, 0, 100, 200));
+        ResolvedRenderState state(*parentSnapshot, recordedOp);
+
+        Matrix4 expectedTranslate;
+        expectedTranslate.loadTranslate(20, 40, 0);
+        EXPECT_MATRIX_APPROX_EQ(state.transform, expectedTranslate);
+
+        // intersection of parent & transformed child clip
+        EXPECT_EQ(state.clipRect, Rect(10, 20, 100, 200));
+
+        // translated and also clipped
+        EXPECT_EQ(state.clippedBounds, Rect(50, 80, 100, 200));
+    }
+}
+
+TEST(BakedOpState, constructAndReject) {
+    LinearAllocator allocator;
+
+    Matrix4 identity;
+    identity.loadIdentity();
+
+    Matrix4 translate100x0;
+    translate100x0.loadTranslate(100, 0, 0);
+
+    SkPaint paint;
+    {
+        RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, Rect(0, 0, 100, 200), &paint);
+        auto snapshot = TestUtils::makeSnapshot(identity, Rect(0, 0, 100, 200));
+        BakedOpState* bakedOp = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
+
+        EXPECT_EQ(bakedOp, nullptr); // rejected by clip, so not constructed
+        EXPECT_LE(allocator.usedSize(), 8u); // no significant allocation space used for rejected op
+    }
+    {
+        RectOp successOp(Rect(30, 40, 100, 200), identity, Rect(0, 0, 100, 200), &paint);
+        auto snapshot = TestUtils::makeSnapshot(identity, Rect(0, 0, 100, 200));
+        BakedOpState* bakedOp = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
+
+        EXPECT_NE(bakedOp, nullptr); // NOT rejected by clip, so will be constructed
+        EXPECT_GT(allocator.usedSize(), 64u); // relatively large alloc for non-rejected op
+    }
+}
+
+#define UNSUPPORTED_OP(Info, Type) \
+        static void on##Type(Info*, const Type&, const BakedOpState&) { FAIL(); }
+
+class Info {
+public:
+    int index = 0;
+};
+
+}
+}
diff --git a/libs/hwui/unit_tests/ClipAreaTests.cpp b/libs/hwui/unit_tests/ClipAreaTests.cpp
index 0c5e5e7..d6192df 100644
--- a/libs/hwui/unit_tests/ClipAreaTests.cpp
+++ b/libs/hwui/unit_tests/ClipAreaTests.cpp
@@ -101,10 +101,9 @@
     EXPECT_FALSE(area.isEmpty());
     EXPECT_FALSE(area.isSimple());
     EXPECT_FALSE(area.isRectangleList());
+
     Rect clipRect(area.getClipRect());
-    clipRect.dump("clipRect");
     Rect expected(0, 0, r * 2, r * 2);
-    expected.dump("expected");
     EXPECT_EQ(expected, clipRect);
     SkRegion clipRegion(area.getClipRegion());
     auto skRect(clipRegion.getBounds());
diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp
new file mode 100644
index 0000000..cbfbb23
--- /dev/null
+++ b/libs/hwui/unit_tests/OpReordererTests.cpp
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <BakedOpState.h>
+#include <OpReorderer.h>
+#include <RecordedOp.h>
+#include <RecordingCanvas.h>
+#include <unit_tests/TestUtils.h>
+
+#include <unordered_map>
+
+namespace android {
+namespace uirenderer {
+
+#define UNSUPPORTED_OP(Info, Type) \
+        static void on##Type(Info*, const Type&, const BakedOpState&) { FAIL(); }
+
+class Info {
+public:
+    int index = 0;
+};
+
+class SimpleReceiver {
+public:
+    static void onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) {
+        EXPECT_EQ(1, info->index++);
+    }
+    static void onRectOp(Info* info, const RectOp& op, const BakedOpState& state) {
+        EXPECT_EQ(0, info->index++);
+    }
+    UNSUPPORTED_OP(Info, RenderNodeOp)
+    UNSUPPORTED_OP(Info, SimpleRectsOp)
+    static void startFrame(Info& info) {}
+    static void endFrame(Info& info) {}
+};
+TEST(OpReorderer, simple) {
+    auto dld = TestUtils::createDLD<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
+        SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
+        canvas.drawRect(0, 0, 100, 200, SkPaint());
+        canvas.drawBitmap(bitmap, 10, 10, nullptr);
+    });
+
+    OpReorderer reorderer;
+    reorderer.defer(200, 200, dld->getChunks(), dld->getOps());
+
+    Info info;
+    reorderer.replayBakedOps<SimpleReceiver>(&info);
+}
+
+
+static int SIMPLE_BATCHING_LOOPS = 5;
+class SimpleBatchingReceiver {
+public:
+    static void onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) {
+        EXPECT_TRUE(info->index++ >= SIMPLE_BATCHING_LOOPS);
+    }
+    static void onRectOp(Info* info, const RectOp& op, const BakedOpState& state) {
+        EXPECT_TRUE(info->index++ < SIMPLE_BATCHING_LOOPS);
+    }
+    UNSUPPORTED_OP(Info, RenderNodeOp)
+    UNSUPPORTED_OP(Info, SimpleRectsOp)
+    static void startFrame(Info& info) {}
+    static void endFrame(Info& info) {}
+};
+TEST(OpReorderer, simpleBatching) {
+    auto dld = TestUtils::createDLD<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10);
+
+        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
+        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
+        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+        for (int i = 0; i < SIMPLE_BATCHING_LOOPS; i++) {
+            canvas.translate(0, 10);
+            canvas.drawRect(0, 0, 10, 10, SkPaint());
+            canvas.drawBitmap(bitmap, 5, 0, nullptr);
+        }
+        canvas.restore();
+    });
+
+    OpReorderer reorderer;
+    reorderer.defer(200, 200, dld->getChunks(), dld->getOps());
+
+    Info info;
+    reorderer.replayBakedOps<SimpleBatchingReceiver>(&info);
+    EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, info.index); // 2 x loops ops, because no merging (TODO: force no merging)
+}
+
+class RenderNodeReceiver {
+public:
+    UNSUPPORTED_OP(Info, BitmapOp)
+    static void onRectOp(Info* info, const RectOp& op, const BakedOpState& state) {
+        switch(info->index++) {
+        case 0:
+            EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clippedBounds);
+            EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
+            break;
+        case 1:
+            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
+            EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+            break;
+        default:
+            FAIL();
+        }
+    }
+    UNSUPPORTED_OP(Info, RenderNodeOp)
+    UNSUPPORTED_OP(Info, SimpleRectsOp)
+    static void startFrame(Info& info) {}
+    static void endFrame(Info& info) {}
+};
+TEST(OpReorderer, renderNode) {
+    sp<RenderNode> child = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110, [](RecordingCanvas& canvas) {
+        SkPaint paint;
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(0, 0, 100, 100, paint);
+    });
+
+    RenderNode* childPtr = child.get();
+    sp<RenderNode> parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [childPtr](RecordingCanvas& canvas) {
+        SkPaint paint;
+        paint.setColor(SK_ColorDKGRAY);
+        canvas.drawRect(0, 0, 200, 200, paint);
+
+        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+        canvas.translate(40, 40);
+        canvas.drawRenderNode(childPtr);
+        canvas.restore();
+    });
+
+    TestUtils::syncNodePropertiesAndDisplayList(child);
+    TestUtils::syncNodePropertiesAndDisplayList(parent);
+
+    std::vector< sp<RenderNode> > nodes;
+    nodes.push_back(parent.get());
+
+    OpReorderer reorderer;
+    reorderer.defer(SkRect::MakeWH(200, 200), 200, 200, nodes);
+
+    Info info;
+    reorderer.replayBakedOps<RenderNodeReceiver>(&info);
+}
+
+class ClippedReceiver {
+public:
+    static void onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) {
+        EXPECT_EQ(0, info->index++);
+        EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
+        EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
+        EXPECT_TRUE(state.computedState.transform.isIdentity());
+    }
+    UNSUPPORTED_OP(Info, RectOp)
+    UNSUPPORTED_OP(Info, RenderNodeOp)
+    UNSUPPORTED_OP(Info, SimpleRectsOp)
+    static void startFrame(Info& info) {}
+    static void endFrame(Info& info) {}
+};
+TEST(OpReorderer, clipped) {
+    sp<RenderNode> node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RecordingCanvas& canvas) {
+        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
+        canvas.drawBitmap(bitmap, 0, 0, nullptr);
+    });
+    TestUtils::syncNodePropertiesAndDisplayList(node);
+    std::vector< sp<RenderNode> > nodes;
+    nodes.push_back(node.get());
+
+    OpReorderer reorderer;
+    reorderer.defer(SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
+            200, 200, nodes);
+
+    Info info;
+    reorderer.replayBakedOps<ClippedReceiver>(&info);
+}
+
+}
+}
diff --git a/libs/hwui/unit_tests/RecordingCanvasTests.cpp b/libs/hwui/unit_tests/RecordingCanvasTests.cpp
new file mode 100644
index 0000000..c813833
--- /dev/null
+++ b/libs/hwui/unit_tests/RecordingCanvasTests.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <RecordedOp.h>
+#include <RecordingCanvas.h>
+#include <unit_tests/TestUtils.h>
+
+namespace android {
+namespace uirenderer {
+
+static void playbackOps(const std::vector<DisplayListData::Chunk>& chunks,
+        const std::vector<RecordedOp*>& ops, std::function<void(const RecordedOp&)> opReciever) {
+    for (const DisplayListData::Chunk& chunk : chunks) {
+        for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
+            opReciever(*ops[opIndex]);
+        }
+    }
+}
+
+TEST(RecordingCanvas, emptyPlayback) {
+    auto dld = TestUtils::createDLD<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
+        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+        canvas.restore();
+    });
+    playbackOps(dld->getChunks(), dld->getOps(), [](const RecordedOp& op) { FAIL(); });
+}
+
+TEST(RecordingCanvas, testSimpleRectRecord) {
+    auto dld = TestUtils::createDLD<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
+        canvas.drawRect(10, 20, 90, 180, SkPaint());
+    });
+
+    int count = 0;
+    playbackOps(dld->getChunks(), dld->getOps(), [&count](const RecordedOp& op) {
+        count++;
+        ASSERT_EQ(RecordedOpId::RectOp, op.opId);
+        ASSERT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
+        ASSERT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
+    });
+    ASSERT_EQ(1, count); // only one observed
+}
+
+TEST(RecordingCanvas, backgroundAndImage) {
+    auto dld = TestUtils::createDLD<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
+        SkBitmap bitmap;
+        bitmap.setInfo(SkImageInfo::MakeUnknown(25, 25));
+        SkPaint paint;
+        paint.setColor(SK_ColorBLUE);
+
+        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+        {
+            // a background!
+            canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+            canvas.drawRect(0, 0, 100, 200, paint);
+            canvas.restore();
+        }
+        {
+            // an image!
+            canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+            canvas.translate(25, 25);
+            canvas.scale(2, 2);
+            canvas.drawBitmap(bitmap, 0, 0, nullptr);
+            canvas.restore();
+        }
+        canvas.restore();
+    });
+
+    int count = 0;
+    playbackOps(dld->getChunks(), dld->getOps(), [&count](const RecordedOp& op) {
+        if (count == 0) {
+            ASSERT_EQ(RecordedOpId::RectOp, op.opId);
+            ASSERT_NE(nullptr, op.paint);
+            EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
+            EXPECT_EQ(Rect(0, 0, 100, 200), op.unmappedBounds);
+            EXPECT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
+
+            Matrix4 expectedMatrix;
+            expectedMatrix.loadIdentity();
+            EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
+        } else {
+            ASSERT_EQ(RecordedOpId::BitmapOp, op.opId);
+            EXPECT_EQ(nullptr, op.paint);
+            EXPECT_EQ(Rect(0, 0, 25, 25), op.unmappedBounds);
+            EXPECT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
+
+            Matrix4 expectedMatrix;
+            expectedMatrix.loadTranslate(25, 25, 0);
+            expectedMatrix.scale(2, 2, 1);
+            EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
+        }
+        count++;
+    });
+    ASSERT_EQ(2, count); // two draws observed
+}
+
+}
+}
diff --git a/libs/hwui/unit_tests/TestUtils.h b/libs/hwui/unit_tests/TestUtils.h
new file mode 100644
index 0000000..9b7d1b9
--- /dev/null
+++ b/libs/hwui/unit_tests/TestUtils.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+#ifndef TEST_UTILS_H
+#define TEST_UTILS_H
+
+#include <Matrix.h>
+#include <Snapshot.h>
+#include <RenderNode.h>
+
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+#define EXPECT_MATRIX_APPROX_EQ(a, b) \
+    EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b))
+
+class TestUtils {
+public:
+    static bool matricesAreApproxEqual(const Matrix4& a, const Matrix4& b) {
+        for (int i = 0; i < 16; i++) {
+            if (!MathUtils::areEqual(a[i], b[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    static std::unique_ptr<Snapshot> makeSnapshot(const Matrix4& transform, const Rect& clip) {
+        std::unique_ptr<Snapshot> snapshot(new Snapshot());
+        snapshot->clip(clip.left, clip.top, clip.right, clip.bottom, SkRegion::kReplace_Op);
+        *(snapshot->transform) = transform;
+        return snapshot;
+    }
+
+    static SkBitmap createSkBitmap(int width, int height) {
+        SkBitmap bitmap;
+        bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
+        return bitmap;
+    }
+
+    template<class CanvasType>
+    static std::unique_ptr<DisplayListData> createDLD(int width, int height,
+            std::function<void(CanvasType& canvas)> canvasCallback) {
+        CanvasType canvas(width, height);
+        canvasCallback(canvas);
+        return std::unique_ptr<DisplayListData>(canvas.finishRecording());
+    }
+
+    template<class CanvasType>
+    static sp<RenderNode> createNode(int left, int top, int right, int bottom,
+            std::function<void(CanvasType& canvas)> canvasCallback) {
+        sp<RenderNode> node = new RenderNode();
+        node->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom);
+        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+
+        CanvasType canvas(
+                node->stagingProperties().getWidth(), node->stagingProperties().getHeight());
+        canvasCallback(canvas);
+        node->setStagingDisplayList(canvas.finishRecording());
+        return node;
+    }
+
+    static void syncNodePropertiesAndDisplayList(sp<RenderNode>& node) {
+        node->syncProperties();
+        node->syncDisplayList();
+    }
+}; // class TestUtils
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* TEST_UTILS_H */
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index d00236e..db53713 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -20,6 +20,7 @@
 
 #include <SkColorFilter.h>
 #include <SkDrawLooper.h>
+#include <SkShader.h>
 #include <SkXfermode.h>
 
 namespace android {
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 1152737..0f86bc6 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -78,6 +78,7 @@
     mLocked.pointerAlpha = 0.0f; // pointer is initially faded
     mLocked.pointerSprite = mSpriteController->createSprite();
     mLocked.pointerIconChanged = false;
+    mLocked.requestedPointerShape = 0;
 
     mLocked.buttonState = 0;
 
@@ -231,6 +232,10 @@
 void PointerController::setPresentation(Presentation presentation) {
     AutoMutex _l(mLock);
 
+    if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) {
+        mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources);
+    }
+
     if (mLocked.presentation != presentation) {
         mLocked.presentation = presentation;
         mLocked.presentationChanged = true;
@@ -391,6 +396,15 @@
     updatePointerLocked();
 }
 
+void PointerController::updatePointerShape(int iconId) {
+    AutoMutex _l(mLock);
+    if (mLocked.requestedPointerShape != iconId) {
+        mLocked.requestedPointerShape = iconId;
+        mLocked.presentationChanged = true;
+        updatePointerLocked();
+    }
+}
+
 void PointerController::setPointerIcon(const SpriteIcon& icon) {
     AutoMutex _l(mLock);
 
@@ -497,8 +511,22 @@
     }
 
     if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
-        mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER
-                ? mLocked.pointerIcon : mResources.spotAnchor);
+        if (mLocked.presentation == PRESENTATION_POINTER) {
+            if (mLocked.requestedPointerShape == 0) {
+                mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
+            } else {
+                std::map<int, SpriteIcon>::const_iterator iter =
+                    mLocked.additionalMouseResources.find(mLocked.requestedPointerShape);
+                if (iter != mLocked.additionalMouseResources.end()) {
+                    mLocked.pointerSprite->setIcon(iter->second);
+                } else {
+                    ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerShape);
+                    mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
+                }
+            }
+        } else {
+            mLocked.pointerSprite->setIcon(mResources.spotAnchor);
+        }
         mLocked.pointerIconChanged = false;
         mLocked.presentationChanged = false;
     }
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index b9e4ce7..308ff12 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -19,6 +19,8 @@
 
 #include "SpriteController.h"
 
+#include <map>
+
 #include <ui/DisplayInfo.h>
 #include <input/Input.h>
 #include <inputflinger/PointerControllerInterface.h>
@@ -40,7 +42,6 @@
     SpriteIcon spotAnchor;
 };
 
-
 /*
  * Pointer controller policy interface.
  *
@@ -57,6 +58,7 @@
 
 public:
     virtual void loadPointerResources(PointerResources* outResources) = 0;
+    virtual void loadAdditionalMouseResources(std::map<int, SpriteIcon>* outResources) = 0;
 };
 
 
@@ -93,6 +95,7 @@
             const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
     virtual void clearSpots();
 
+    void updatePointerShape(int iconId);
     void setDisplayViewport(int32_t width, int32_t height, int32_t orientation);
     void setPointerIcon(const SpriteIcon& icon);
     void setInactivityTimeout(InactivityTimeout inactivityTimeout);
@@ -155,6 +158,10 @@
         SpriteIcon pointerIcon;
         bool pointerIconChanged;
 
+        std::map<int, SpriteIcon> additionalMouseResources;
+
+        int32_t requestedPointerShape;
+
         int32_t buttonState;
 
         Vector<Spot*> spots;
diff --git a/media/java/android/mtp/MtpEvent.java b/media/java/android/mtp/MtpEvent.java
index 0fa7d93..4c8a742 100644
--- a/media/java/android/mtp/MtpEvent.java
+++ b/media/java/android/mtp/MtpEvent.java
@@ -18,13 +18,33 @@
 
 /**
  * This class encapsulates information about a MTP event.
+ * Event constants are defined by the USB-IF MTP specification.
  */
 public class MtpEvent {
-    private int mEventCode;
+    public static final int EVENT_UNDEFINED = 0x4000;
+    public static final int EVENT_CANCEL_TRANSACTION = 0x4001;
+    public static final int EVENT_OBJECT_ADDED = 0x4002;
+    public static final int EVENT_OBJECT_REMOVED = 0x4003;
+    public static final int EVENT_STORE_ADDED = 0x4004;
+    public static final int EVENT_STORE_REMOVED = 0x4005;
+    public static final int EVENT_DEVICE_PROP_CHANGED = 0x4006;
+    public static final int EVENT_OBJECT_INFO_CHANGED = 0x4007;
+    public static final int EVENT_DEVICE_INFO_CHANGED = 0x4008;
+    public static final int EVENT_REQUEST_OBJECT_TRANSFER = 0x4009;
+    public static final int EVENT_STORE_FULL = 0x400A;
+    public static final int EVENT_DEVICE_RESET = 0x400B;
+    public static final int EVENT_STORAGE_INFO_CHANGED = 0x400C;
+    public static final int EVENT_CAPTURE_COMPLETE = 0x400D;
+    public static final int EVENT_UNREPORTED_STATUS = 0x400E;
+    public static final int EVENT_OBJECT_PROP_CHANGED = 0xC801;
+    public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 0xC802;
+    public static final int EVENT_OBJECT_REFERENCES_CHANGED = 0xC803;
+
+    private int mEventCode = EVENT_UNDEFINED;
 
     /**
      * Returns event code of MTP event.
-     *
+     * See the USB-IF MTP specification for the details of event constants.
      * @return event code
      */
     public int getEventCode() { return mEventCode; }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 9d2d171..83e3440 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -469,14 +469,18 @@
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         if (DEBUG) Log.d(mTag, "onKeyUp: keycode = " + keyCode);
-        DirectoryFragment dir = DirectoryFragment.get(getFragmentManager());
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_MOVE_HOME:
-                dir.focusFirstFile();
-                return true;
-            case KeyEvent.KEYCODE_MOVE_END:
-                dir.focusLastFile();
-                return true;
+
+        // TODO: Support for RecentsCreateFragment.
+        DirectoryFragment fragment = DirectoryFragment.get(getFragmentManager());
+        if (fragment != null) {
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_MOVE_HOME:
+                    fragment.focusFirstFile();
+                    return true;
+                case KeyEvent.KEYCODE_MOVE_END:
+                    fragment.focusLastFile();
+                    return true;
+            }
         }
         return super.onKeyUp(keyCode, event);
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 94fce59..a3a431f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -205,9 +205,12 @@
         return builder.toString();
     }
 
-    public static DirectoryFragment get(FragmentManager fm) {
+    public static @Nullable DirectoryFragment get(FragmentManager fm) {
         // TODO: deal with multiple directories shown at once
-        return (DirectoryFragment) fm.findFragmentById(R.id.container_directory);
+        Fragment fragment = fm.findFragmentById(R.id.container_directory);
+        return fragment instanceof DirectoryFragment
+                ? (DirectoryFragment) fragment
+                : null;
     }
 
     @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 6b428f5..aae5269 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -337,7 +337,7 @@
 
         if (mState.action == ACTION_CREATE) {
             final FragmentManager fm = getFragmentManager();
-            SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
+            SaveFragment.get(fm).prepareForDirectory(cwd);
         }
 
         Menus.disableHiddenItems(menu);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java
index d4c3ba3..c06ea0a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Events.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java
@@ -38,7 +38,9 @@
      * Returns true if event was triggered by a finger or stylus touch.
      */
     static boolean isTouchEvent(MotionEvent e) {
-        return isTouchType(e.getToolType(0));
+        return isTouchType(e.getToolType(0))
+                // Temporarily work around uiautomator's missing tool type support.
+                || isUnknownType(e.getToolType(0));
     }
 
     /**
@@ -49,7 +51,7 @@
     }
 
     /**
-     * Returns true if event was triggered by a finger or stylus touch.
+     * Returns true if type is finger or stylus.
      */
     static boolean isTouchType(int toolType) {
         return toolType == MotionEvent.TOOL_TYPE_FINGER
@@ -57,6 +59,13 @@
     }
 
     /**
+     * Returns true if type is unknown.
+     */
+    static boolean isUnknownType(int toolType) {
+        return toolType == MotionEvent.TOOL_TYPE_UNKNOWN;
+    }
+
+    /**
      * Returns true if event was triggered by a finger or stylus touch.
      */
     static boolean isActionDown(MotionEvent e) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index de35cef..4fc3788 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -102,6 +102,7 @@
         mRecentsRoot.authority = null;
         mRecentsRoot.rootId = null;
         mRecentsRoot.derivedIcon = R.drawable.ic_root_recent;
+        mRecentsRoot.derivedType = RootInfo.TYPE_RECENTS;
         mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE
                 | Root.FLAG_SUPPORTS_IS_CHILD;
         mRecentsRoot.title = mContext.getString(R.string.root_recent);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index c98da47..0dcd02d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -286,51 +286,34 @@
         public RootsAdapter(Context context, Collection<RootInfo> roots, Intent includeApps) {
             super(context, 0);
 
-            RootItem recents = null;
-            RootItem images = null;
-            RootItem videos = null;
-            RootItem audio = null;
-            RootItem downloads = null;
-
-            final List<RootInfo> clouds = new ArrayList<>();
-            final List<RootInfo> locals = new ArrayList<>();
+            final List<RootItem> libraries = new ArrayList<>();
+            final List<RootItem> clouds = new ArrayList<>();
+            final List<RootItem> locals = new ArrayList<>();
 
             for (RootInfo root : roots) {
-                if (root.isRecents()) {
-                    recents = new RootItem(root);
-                } else if (root.isExternalStorage()) {
-                    locals.add(root);
-                } else if (root.isDownloads()) {
-                    downloads = new RootItem(root);
-                } else if (root.isImages()) {
-                    images = new RootItem(root);
-                } else if (root.isVideos()) {
-                    videos = new RootItem(root);
-                } else if (root.isAudio()) {
-                    audio = new RootItem(root);
-                } else {
-                    clouds.add(root);
+                RootItem item = new RootItem(root);
+                switch (root.derivedType) {
+                    case RootInfo.TYPE_LOCAL:
+                        locals.add(item);
+                        break;
+                    case RootInfo.TYPE_CLOUD:
+                        clouds.add(item);
+                        break;
+                    default:
+                        libraries.add(item);
+                        break;
                 }
             }
 
             final RootComparator comp = new RootComparator();
-            Collections.sort(clouds, comp);
+            Collections.sort(libraries, comp);
             Collections.sort(locals, comp);
+            Collections.sort(clouds, comp);
 
-            if (recents != null) add(recents);
-
-            for (RootInfo cloud : clouds) {
-                add(new RootItem(cloud));
-            }
-
-            if (images != null) add(images);
-            if (videos != null) add(videos);
-            if (audio != null) add(audio);
-            if (downloads != null) add(downloads);
-
-            for (RootInfo local : locals) {
-                add(new RootItem(local));
-            }
+            addAll(libraries);
+            add(new SpacerItem());
+            addAll(locals);
+            addAll(clouds);
 
             if (includeApps != null) {
                 final PackageManager pm = context.getPackageManager();
@@ -348,9 +331,7 @@
 
                 if (apps.size() > 0) {
                     add(new SpacerItem());
-                    for (Item item : apps) {
-                        add(item);
-                    }
+                    addAll(apps);
                 }
             }
         }
@@ -387,15 +368,20 @@
         }
     }
 
-    public static class RootComparator implements Comparator<RootInfo> {
+    public static class RootComparator implements Comparator<RootItem> {
         @Override
-        public int compare(RootInfo lhs, RootInfo rhs) {
-            final int score = DocumentInfo.compareToIgnoreCaseNullable(lhs.title, rhs.title);
+        public int compare(RootItem lhs, RootItem rhs) {
+            // Sort by root type, then title, then summary.
+            int score = lhs.root.derivedType - rhs.root.derivedType;
             if (score != 0) {
                 return score;
-            } else {
-                return DocumentInfo.compareToIgnoreCaseNullable(lhs.summary, rhs.summary);
             }
+            score = DocumentInfo.compareToIgnoreCaseNullable(lhs.root.title, rhs.root.title);
+            if (score != 0) {
+                return score;
+            }
+
+            return DocumentInfo.compareToIgnoreCaseNullable(lhs.root.summary, rhs.root.summary);
         }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index ce98db2..f3b750a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.text.Editable;
 import android.text.TextWatcher;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -79,6 +80,17 @@
         mDisplayName = (EditText) view.findViewById(android.R.id.title);
         mDisplayName.addTextChangedListener(mDisplayNameWatcher);
         mDisplayName.setText(getArguments().getString(EXTRA_DISPLAY_NAME));
+        mDisplayName.setOnKeyListener(
+                new View.OnKeyListener() {
+                    @Override
+                    public boolean onKey(View v, int keyCode, KeyEvent event) {
+                        if (keyCode == KeyEvent.KEYCODE_ENTER && mSave.isEnabled()) {
+                            performSave();
+                            return true;
+                        }
+                        return false;
+                    }
+                });
 
         mSave = (Button) view.findViewById(android.R.id.button1);
         mSave.setOnClickListener(mSaveListener);
@@ -113,17 +125,22 @@
     private View.OnClickListener mSaveListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
-            final DocumentsActivity activity = DocumentsActivity.get(SaveFragment.this);
-            if (mReplaceTarget != null) {
-                activity.onSaveRequested(mReplaceTarget);
-            } else {
-                final String mimeType = getArguments().getString(EXTRA_MIME_TYPE);
-                final String displayName = mDisplayName.getText().toString();
-                activity.onSaveRequested(mimeType, displayName);
-            }
+            performSave();
         }
+
     };
 
+    private void performSave() {
+        final DocumentsActivity activity = DocumentsActivity.get(SaveFragment.this);
+        if (mReplaceTarget != null) {
+            activity.onSaveRequested(mReplaceTarget);
+        } else {
+            final String mimeType = getArguments().getString(EXTRA_MIME_TYPE);
+            final String displayName = mDisplayName.getText().toString();
+            activity.onSaveRequested(mimeType, displayName);
+        }
+    }
+
     /**
      * Set given document as target for in-place writing if user hits save
      * without changing the filename. Can be set to {@code null} if user
@@ -139,7 +156,11 @@
         }
     }
 
-    public void setSaveEnabled(boolean enabled) {
+    public void prepareForDirectory(DocumentInfo cwd) {
+        setSaveEnabled(cwd != null && cwd.isCreateSupported());
+    }
+
+    private void setSaveEnabled(boolean enabled) {
         mSave.setEnabled(enabled);
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index ecf4d6c..17e6a80 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -44,6 +44,15 @@
     private static final int VERSION_INIT = 1;
     private static final int VERSION_DROP_TYPE = 2;
 
+    // The values of these constants determine the sort order of various roots in the RootsFragment.
+    public static final int TYPE_IMAGES = 1;
+    public static final int TYPE_VIDEO = 2;
+    public static final int TYPE_AUDIO = 3;
+    public static final int TYPE_RECENTS = 4;
+    public static final int TYPE_DOWNLOADS = 5;
+    public static final int TYPE_LOCAL = 6;
+    public static final int TYPE_CLOUD = 7;
+
     public String authority;
     public String rootId;
     public int flags;
@@ -57,6 +66,7 @@
     /** Derived fields that aren't persisted */
     public String[] derivedMimeTypes;
     public int derivedIcon;
+    public int derivedType;
 
     public RootInfo() {
         reset();
@@ -76,6 +86,7 @@
 
         derivedMimeTypes = null;
         derivedIcon = 0;
+        derivedType = 0;
     }
 
     @Override
@@ -158,14 +169,23 @@
         // TODO: remove these special case icons
         if (isExternalStorage()) {
             derivedIcon = R.drawable.ic_root_sdcard;
+            derivedType = TYPE_LOCAL;
         } else if (isDownloads()) {
             derivedIcon = R.drawable.ic_root_download;
+            derivedType = TYPE_DOWNLOADS;
         } else if (isImages()) {
             derivedIcon = R.drawable.ic_doc_image;
+            derivedType = TYPE_IMAGES;
         } else if (isVideos()) {
             derivedIcon = R.drawable.ic_doc_video;
+            derivedType = TYPE_VIDEO;
         } else if (isAudio()) {
             derivedIcon = R.drawable.ic_doc_audio;
+            derivedType = TYPE_AUDIO;
+        } else if (isRecents()) {
+            derivedType = TYPE_RECENTS;
+        } else {
+            derivedType = TYPE_CLOUD;
         }
     }
 
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index d778c98..0b8da83 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -23,6 +23,8 @@
     android:layout_width="@dimen/notification_panel_width"
     android:layout_height="@dimen/status_bar_header_height"
     android:layout_gravity="@integer/notification_panel_layout_gravity"
+    android:paddingStart="@dimen/notification_side_padding"
+    android:paddingEnd="@dimen/notification_side_padding"
     android:baselineAligned="false"
     android:elevation="4dp"
     android:background="@drawable/notification_header_bg"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index a64dbbd..bfa13e2 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -102,8 +102,7 @@
         android:id="@+id/status_bar_header"
         android:layout_width="@dimen/notification_panel_width"
         android:layout_height="@dimen/status_bar_header_height"
-        android:layout_marginStart="@dimen/notification_side_padding"
-        android:layout_marginEnd="@dimen/notification_side_padding" />
+        android:layout_gravity="@integer/notification_panel_layout_gravity" />
 
     <com.android.systemui.statusbar.AlphaOptimizedView
         android:id="@+id/qs_navbar_scrim"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index dd75dbf..5eca471 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -23,6 +23,8 @@
     android:layout_width="@dimen/notification_panel_width"
     android:layout_height="@dimen/status_bar_header_height"
     android:layout_gravity="@integer/notification_panel_layout_gravity"
+    android:paddingStart="@dimen/notification_side_padding"
+    android:paddingEnd="@dimen/notification_side_padding"
     android:baselineAligned="false"
     android:elevation="4dp"
     android:background="@drawable/notification_header_bg"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c7c7f1a..4d07cdb 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Wys horlosiesekondes op die statusbalk. Sal batterylewe dalk beïnvloed."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Herrangskik Kitsinstellings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Wys helderheid in Kitsinstellings"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Gebruik verdeling in Kitsinstellings"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimenteel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index f49f5bc..c1180b6 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"የሰዓት ሰከንዶችን በሁኔታ አሞሌ ውስጥ አሳይ። በባትሪ ዕድሜ ላይ ተጽዕኖ ሊኖርው ይችል ይሆናል።"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ፈጣን ቅንብሮችን ዳግም ያደራጁ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"በፈጣን ቅንብሮች ውስጥ ብሩህነትን አሳይ"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"በፈጣን ቅንብሮች ውስጥ ምልክት መጥሪያን ይጠቀሙ"</string>
     <string name="experimental" msgid="6198182315536726162">"የሙከራ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index aaf20cc..fc2941f 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -443,6 +443,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"عرض ثواني الساعة في شريط الحالة. قد يؤثر ذلك في عمر البطارية."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"إعادة ترتيب الإعدادات السريعة"</string>
     <string name="show_brightness" msgid="6613930842805942519">"عرض السطوع في الإعدادات السريعة"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"استخدام ترقيم الصفحات في الإعدادات السريعة"</string>
     <string name="experimental" msgid="6198182315536726162">"إعدادات تجريبية"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 0efc82b..04d680b 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Saatın saniyəsini status panelində göstərin. Batareyaya təsir edə bilər."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Sürətli Ayarları yenidən tənzimləyin"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Sürətli ayarlarda parlaqlılığı göstərin"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Sürətli Ayarlarda səhifə nömrələməsindən istifadə edin"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6805779..ca45d24 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показване на секундите на часовника в лентата на състоянието. Може да се отрази на живота на батерията."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Пренареждане на бързите настройки"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Показване на яркостта от бързите настройки"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Използване на разделянето на страници от бързите настройки"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментални"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index c0ffe2c..7df68ac 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"স্থিতি দন্ডে ঘড়ির সেকেন্ড দেখায়৷ ব্যাটারি লাইফকে প্রভাবিত করতে পারে৷"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"দ্রুত সেটিংসে পুনরায় সাজান"</string>
     <string name="show_brightness" msgid="6613930842805942519">"দ্রুত সেটিংসে উজ্জ্বলতা দেখান"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"দ্রুত সেটিংসে পেজিং ব্যবহার করুন"</string>
     <string name="experimental" msgid="6198182315536726162">"পরীক্ষামূলক"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2a7c326..c85fac6 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Torna a ordenar la Configuració ràpida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a la Configuració ràpida"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Utilitza la paginació a la Configuració ràpida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 18fd994..d58b11b 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -443,6 +443,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Na stavovém řádku se bude zobrazovat sekundová ručička. Může být ovlivněna výdrž baterie."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Změnit uspořádání Rychlého nastavení"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Zobrazit jas v Rychlém nastavení"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Použít v Rychlém nastavení stránkování"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentální"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 5a2dd33..f300b3e 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statuslinjen. Dette kan påvirke batteriets levetid."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Omarranger Hurtige indstillinger"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i Hurtige indstillinger"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Brug sidelayout i Hurtige indstillinger"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index a8143a4..ac513e40 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Uhrsekunden in der Statusleiste anzeigen. Kann sich auf die Akkulaufzeit auswirken."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Schnelleinstellungen neu anordnen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Helligkeit in den Schnelleinstellungen anzeigen"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Seitenlayout in den Schnelleinstellungen verwenden"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentell"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 6031d3b..c8ff7c6 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Εμφάνιση δευτερολέπτων ρολογιού στη γραμμή κατάστασης. Ενδέχεται να επηρεάσει τη διάρκεια ζωής της μπαταρίας."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Αναδιάταξη Γρήγορων ρυθμίσεων"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Εμφάνιση φωτεινότητας στις Γρήγορες ρυθμίσεις"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Χρήση τηλεειδοποίησης στις Γρήγορες ρυθμίσεις"</string>
     <string name="experimental" msgid="6198182315536726162">"Σε πειραματικό στάδιο"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index bef7661..6e66842 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Use paging in Quick Settings"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index bef7661..6e66842 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Use paging in Quick Settings"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index bef7661..6e66842 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Use paging in Quick Settings"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en/donottranslate.xml b/packages/SystemUI/res/values-en/donottranslate.xml
deleted file mode 100644
index 9f04e1f..0000000
--- a/packages/SystemUI/res/values-en/donottranslate.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?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>
-    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
-    <item type="string" name="keyguard_indication_charging_time_fast_if_translated">@string/keyguard_indication_charging_time_fast</item>
-    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
-    <item type="string" name="keyguard_indication_charging_time_slowly_if_translated">@string/keyguard_indication_charging_time_slowly</item>
-</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 1590265..72258fa 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar la duración de la batería."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar la Configuración rápida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar el brillo en la Configuración rápida"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Usar la paginación en la Configuración rápida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 082e762..298a0c6 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Utilizar paginación en Ajustes rápidos"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 4add147..26b3081 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Olekuribal kella sekundite kuvamine. See võib mõjutada aku kasutusaega."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Korralda kiirseaded ümber"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Kuva kiirseadetes heledus"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Kasuta kiirseadetes lehe paigutust"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentaalne"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 4f5c9f2..83aac20 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Erakutsi erlojuko segundoak egoera-barran. Baliteke bateria gehiago erabiltzea."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Berrantolatu ezarpen bizkorrak"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Erakutsi distira Ezarpen bizkorretan"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Erabili orriak pasatzeko diseinu berria Ezarpen bizkorretan"</string>
     <string name="experimental" msgid="6198182315536726162">"Esperimentala"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 6fa7e1c..c8871c4 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -67,12 +67,12 @@
     <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"‏کاربری که درحال‌حاضر در این دستگاه وارد سیستم شده نمی‌تواند اشکال‌زدای USB را روشن کند. برای استفاده از این ویژگی، لطفاً به کاربر «سرپرست» تغییر حالت دهید."</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"بزرگ‌نمایی برای پر کردن صفحه"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"گسترده کردن برای پر کردن صفحه"</string>
-    <string name="screenshot_saving_ticker" msgid="7403652894056693515">"در حال ذخیره تصویر صفحه..."</string>
-    <string name="screenshot_saving_title" msgid="8242282144535555697">"در حال ذخیره تصویر صفحه..."</string>
-    <string name="screenshot_saving_text" msgid="2419718443411738818">"تصویر صفحه ذخیره شد."</string>
-    <string name="screenshot_saved_title" msgid="6461865960961414961">"تصویر صفحه گرفته شد."</string>
+    <string name="screenshot_saving_ticker" msgid="7403652894056693515">"در حال ذخیره عکس صفحه‌نمایش..."</string>
+    <string name="screenshot_saving_title" msgid="8242282144535555697">"در حال ذخیره عکس صفحه‌نمایش..."</string>
+    <string name="screenshot_saving_text" msgid="2419718443411738818">"عکس صفحه‌نمایش ذخیره شد."</string>
+    <string name="screenshot_saved_title" msgid="6461865960961414961">"عکس صفحه‌نمایش گرفته شد."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"برای مشاهده عکس صفحه‌نمایشتان، لمس کنید."</string>
-    <string name="screenshot_failed_title" msgid="705781116746922771">"تصویر صفحه گرفته نشد."</string>
+    <string name="screenshot_failed_title" msgid="705781116746922771">"عکس صفحه‌نمایش گرفته نشد."</string>
     <string name="screenshot_failed_text" msgid="1260203058661337274">"به دلیل فضای ذخیره‌سازی کم یا عدم اجازه برنامه یا سازمانتان، نمی‌توان از صفحه عکس گرفت."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"‏گزینه‌های انتقال فایل USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"‏نصب به‌عنوان دستگاه پخش رسانه (MTP)"</string>
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ثانیه‌های ساعت را در نوار وضعیت نشان می‌دهد. ممکن است بر ماندگاری باتری تأثیر بگذارد."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ترتیب مجدد در تنظیمات سریع"</string>
     <string name="show_brightness" msgid="6613930842805942519">"نمایش روشنایی در تنظیمات سریع"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"استفاده از صفحه‌بندی در تنظیمات سریع"</string>
     <string name="experimental" msgid="6198182315536726162">"آزمایشی"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 655cf31..3154d5c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Näytä sekunnit tilapalkin kellossa. Tämä voi vaikuttaa akun kestoon."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Järjestä pika-asetukset uudelleen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Näytä kirkkaus pika-asetuksissa"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Käytä sivutusta pika-asetuksissa"</string>
     <string name="experimental" msgid="6198182315536726162">"Kokeellinen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 2f2c331..669ca9b 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes sur l\'horloge dans la barre d\'état. Cela peut réduire l\'autonomie de la pile."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser les paramètres rapides"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans les paramètres rapides"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Utiliser la pagination dans les paramètres rapides"</string>
     <string name="experimental" msgid="6198182315536726162">"Fonctions expérimentales"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 9f34431..d42190f 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser la fenêtre de configuration rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Utiliser mise en page dans fenêtre de configuration rapide"</string>
     <string name="experimental" msgid="6198182315536726162">"Paramètres expérimentaux"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index df90ef4..3c53983 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra os segundos do reloxo na barra de estado. Pode influír na duración da batería."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Configuración rápida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Configuración rápida"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Utilizar paxinación en Configuración rápida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 42ee460..0887e75 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"ઝડપી સેટિંગ્સમાં પૃષ્ઠાંકનનો ઉપયોગ કરો"</string>
     <string name="experimental" msgid="6198182315536726162">"પ્રાયોગિક"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 86f536d..11a0d3a 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्थिति बार में घड़ी के सेकंड दिखाएं. इससे बैटरी के जीवनकाल पर प्रभाव पड़ सकता है."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
     <string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"त्वरित सेटिंग में पेजिंग का उपयोग करें"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 043e7ad..eec3a6f 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -440,6 +440,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikazuju se sekunde na satu na traci statusa. Može utjecati na trajanje baterije."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Promijeni raspored Brzih postavki"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaži svjetlinu u Brzim postavkama"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Upotrijebi redni broj stranice u Brzim postavkama"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index e2b0812..2dc9ba0 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Másodpercek megjelenítése az állapotsor óráján. Ez hatással lehet az akkumulátor üzemidejére."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Gyorsbeállítások átrendezése"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Fényerő megjelenítése a gyorsbeállításokban"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Oldalelrendezés használata a gyorsbeállításokban"</string>
     <string name="experimental" msgid="6198182315536726162">"Kísérleti"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index b69fc0f..a7fdb43 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Վերադասավորել Արագ կարգավորումները"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ցույց տալ պայծառությունն Արագ կարգավորումներում"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Օգտագործել էջերի դասավորությունը Արագ կարգավորումներում"</string>
     <string name="experimental" msgid="6198182315536726162">"Փորձնական"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 7dbcda9..a6a68d4 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tampilkan detik jam di bilah status. Dapat memengaruhi masa pakai baterai."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Atur Ulang Setelan Cepat"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tampilkan kecerahan di Setelan Cepat"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Gunakan pembagian laman di Setelan Cepat"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index b28b6fd..83468e5 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Sýna sekúndur á klukku í stöðustikunni. Getur haft áhrif á endingu rafhlöðu."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Endurraða flýtistillingum"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Sýna birtustig í flýtistillingum"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Nota síðuskoðun í flýtistillingum"</string>
     <string name="experimental" msgid="6198182315536726162">"Tilraunastillingar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 54e6f56..4449a0a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra i secondi nell\'orologio nella barra di stato. Ciò potrebbe ridurre la durata della carica della batteria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Riorganizza Impostazioni rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostra luminosità in Impostazioni rapide"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Utilizza nuovo layout in Impostazioni rapide"</string>
     <string name="experimental" msgid="6198182315536726162">"Sperimentali"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c959feb..31c5126 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"הצג שניות בשעון בשורת הסטטוס. פעולה זו עשויה להשפיע על אורך חיי הסוללה."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"סידור מחדש של הגדרות מהירות"</string>
     <string name="show_brightness" msgid="6613930842805942519">"הצג בהירות בהגדרות מהירות"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"השתמש באפשרות הדפדוף בהגדרות המהירות"</string>
     <string name="experimental" msgid="6198182315536726162">"ניסיוניות"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 29476d8..d1603ff 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"クイック設定を並べ替え"</string>
     <string name="show_brightness" msgid="6613930842805942519">"クイック設定に明るさ調整バーを表示する"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"クイック設定でページ設定を使用する"</string>
     <string name="experimental" msgid="6198182315536726162">"試験運用版"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index d83c9e9..e5e9003 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"საათის წამების ჩვენება სტატუსის ზოლში. შეიძლება გავლენა იქონიოს ბატარეაზე."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"სწრაფი პარამეტრების გადაწყობა"</string>
     <string name="show_brightness" msgid="6613930842805942519">"სიკაშკაშის ჩვენება სწრაფ პარამეტრებში"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"გამოიყენეთ გვერდების დანომვრა სწრაფ პარამეტრებში"</string>
     <string name="experimental" msgid="6198182315536726162">"ექსპერიმენტული"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 5c066b3..946d86b 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Күйін көрсету жолағында сағат секундтарын көрсету. Батареяның қызмет көрсету мерзіміне әсер етуі мүмкін."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Жылдам параметрлерді қайта реттеу"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Жылдам параметрлерде жарықтықты көрсету"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Жылдам параметрлерде беттерді нөмірлеуді пайдалану"</string>
     <string name="experimental" msgid="6198182315536726162">"Эксперименттік"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 4c469b0..264438b 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"បង្ហាញវិនាទីនៅលើរបារស្ថានភាពអាចនឹងប៉ះពាល់ដល់ថាមពលថ្ម។"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"រៀបចំការកំណត់រហ័សឡើងវិញ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"បង្ហាញកម្រិតពន្លឺនៅក្នុងការកំណត់រហ័ស"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"ប្រើការចុះទំព័រនៅក្នុងការកំណត់រហ័ស"</string>
     <string name="experimental" msgid="6198182315536726162">"ពិសោធន៍"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 4215a91..1696076 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಗಡಿಯಾರ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು. ಇದಕ್ಕೆ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯು ಪರಿಣಾಮಬೀರಬಹುದು."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪ್ರಖರತೆಯನ್ನು ತೋರಿಸಿ"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪುಟಗಳನ್ನು ಬಳಸಿ"</string>
     <string name="experimental" msgid="6198182315536726162">"ಪ್ರಾಯೋಗಿಕ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 8ee5946..d053b53 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"상태 표시줄에 시계 초 단위를 표시합니다. 배터리 수명에 영향을 줄 수도 있습니다."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"빠른 설정 재정렬"</string>
     <string name="show_brightness" msgid="6613930842805942519">"빠른 설정에서 밝기 표시"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"빠른 설정에서 페이지 레이아웃 사용"</string>
     <string name="experimental" msgid="6198182315536726162">"베타"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index ce0afd4..ec4bec7 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарык деңгээлин көрсөтүү"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Ыкчам жөндөөлөрдөн баракты номерлөөнү колдонуу"</string>
     <string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index b45395e..e5d784f 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ​ຢູ່​ໃນ​ແຖບ​ສະ​ຖາ​ນະ. ອາດ​ຈະ​ມີ​ຜົນ​ກະ​ທົບ​ຕໍ່​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ຈັດ​ວາງ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ​ຄືນ​ໃໝ່"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ສະ​ແດງ​ຄວາມ​ແຈ້ງ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"ໃຊ້​ການ​ໃສ່​ໜ້າ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
     <string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 194668b..ca50956 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Rodyti laikrodžio sekundes būsenos juostoje. Tai gali paveikti akumuliatoriaus naudojimo laiką."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Pertvarkyti sparčiuosius nustatymus"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Rodyti skaistį sparčiuosiuose nustatymuose"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Naudoti puslapių kaitą sparčiuosiuose nustatymuose"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentinė versija"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 2b3be58..a87d918 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -440,6 +440,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Statusa joslā rādīt pulksteņa sekundes. Var ietekmēt akumulatora darbības laiku."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Pārkārtot ātros iestatījumus"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Rādīt spilgtumu ātrajos iestatījumos"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Izmantot lapošanu ātrajos iestatījumos"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentāli"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 912c30f..1015018 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Прикажи ги секундите на часовникот на статусната лента. Може да влијае на траењето на батеријата."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Преуредете ги Брзи поставки"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Прикажете ја осветленоста во Брзи поставки"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Користете прелистување страници во Брзи поставки"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index c85ecc7..45ec29a 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"സ്റ്റാറ്റസ് ബാറിൽ ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുന്നത് ബാറ്ററിയുടെ ലൈഫിനെ ബാധിക്കാം."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ദ്രുത ക്രമീകരണം പുനഃസജ്ജീകരിക്കുക"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ദ്രുത ക്രമീകരണത്തിൽ തെളിച്ചം കാണിക്കുക"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"ദ്രുത്ര ക്രമീകരണത്തിൽ പേജിംഗ് ഉപയോഗിക്കുക"</string>
     <string name="experimental" msgid="6198182315536726162">"പരീക്ഷണാത്മകം!"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 6b29aff..1051e49 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -437,6 +437,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Түргэн тохиргоог дахин засварлах"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Хуудаслалтыг түргэн тохиргоонд ашиглаарай"</string>
     <string name="experimental" msgid="6198182315536726162">"Туршилтын"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 9d518a0..66843fc 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्‍ये घड्‍याळ सेकंद दर्शवा. कदाचित बॅटरी आयुष्‍य प्रभावित होऊ शकते."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिंग्जची पुनर्रचना करा"</string>
     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिंग्जमध्‍ये चमक दर्शवा"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"द्रुत सेटिंग्जमध्ये लिखाण वापरा"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 10dca3e..c50e214 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tunjukkan saat jam dalam bar status. Mungkin menjejaskan hayat bateri."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Susun Semula Tetapan Pantas"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tunjukkan kecerahan dalam Tetapan Pantas"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Gunakan penghalaman dalam Tetapan Pantas"</string>
     <string name="experimental" msgid="6198182315536726162">"Percubaan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index adfd9f8..f4fd3d1 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"အခြေအနေပြနေရာမှာ နာရီ စက္ကန့်များကို ပြပါ။ ဘက်ထရီ သက်တမ်းကို အကျိုးသက်ရောက်နိုင်တယ်။"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
     <string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"အမြန် ဆက်တင်များထဲတွင် စာမျက်နှာ ပုံစံချမှုကို အသုံးပြုပါ"</string>
     <string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index ecfb7f2..cae404d 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statusfeltet på klokken. Det kan påvirke batteritiden."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Omorganiser hurtiginnstillingene"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i hurtiginnstillingene"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Bruk sidetall i hurtiginnstillingene"</string>
     <string name="experimental" msgid="6198182315536726162">"På forsøksstadiet"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index d997aff..563bc87 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"वस्तुस्थिति पट्टीको घडीमा सेकेन्ड देखाउनुहोस्। ब्याट्री आयु प्रभावित हुन सक्छ।"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"द्रुत सेटिङहरूमा पेजिंग प्रयोग गर्नुहोस्"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index c6bab06..bf9f0f2 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Klokseconden op de statusbalk weergeven. Kan van invloed zijn op de accuduur."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Helderheid weergeven in Snelle instellingen"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Paginering gebruiken in Snelle instellingen"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimenteel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 74e5fcb..45d56cc 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮ ਦਿਓ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਮਕ ਦਿਖਾਓ"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਪੇਜਿੰਗ ਵਰਤੋ"</string>
     <string name="experimental" msgid="6198182315536726162">"ਪ੍ਰਯੋਗਾਤਮਿਕ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index e04fd71..2807c5a 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Pokaż sekundy na zegarku na pasku stanu. Może mieć wpływ na czas pracy baterii."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Uporządkuj Szybkie ustawienia"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Pokaż jasność w Szybkich ustawieniach"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Użyj stronicowania w Szybkich ustawieniach"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperymentalne"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 2a8e3ab..c8400c9 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Usar paginação nas \"Configurações rápidas\""</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 8453e5b..43088fe9 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar as Definições rápidas"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar luminosidade nas Definições rápidas"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Utilizar paginação nas Definições rápidas"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 2a8e3ab..c8400c9 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Usar paginação nas \"Configurações rápidas\""</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index de693f5..d64ca7c 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -440,6 +440,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afișează secundele pe ceas în bara de stare. Poate afecta autonomia bateriei."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearanjați Setările rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afișați luminozitatea în Setările rapide"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Folosiți paginarea în Setările rapide"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentale"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 39d8617..480de30 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -443,6 +443,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показывать в строке состояния время с точностью до секунды (заряд батареи может расходоваться быстрее)."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Изменить порядок Быстрых настроек"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Добавить яркость в Быстрые настройки"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Разбить Быстрые настройки на страницы"</string>
     <string name="experimental" msgid="6198182315536726162">"Экспериментальная функция"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 51bb047..e784601 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"තත්ත්ව තීරුවෙහි ඔරලෝසු තත්පර පෙන්වන්න. බැටරි ආයු කාලයට බලපෑමට හැකිය."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ඉක්මන් සැකසීම් යළි පිළිවෙළට සකසන්න"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ඉක්මන් සැකසීම්වල දීප්තිය පෙන්වන්න"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"ඉක්මන් සැකසීම්වල පිටු පිරිසැලසුම් භාවිත කරන්න"</string>
     <string name="experimental" msgid="6198182315536726162">"පරීක්ෂණාත්මක"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 2886e36..15612ee 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -443,6 +443,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Zobrazí sekundy v stavovom riadku. Môže to ovplyvňovať výdrž batérie."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Zmeniť usporiadanie Rýchlych nastavení"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Zobraziť jas v Rýchlych nastaveniach"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Použite stránkovanie v Rýchlych nastaveniach"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentálne"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index e325ef1..23e4233 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Uporaba postavitve strani v hitrih nastavitvah"</string>
     <string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 5bcf941..771ad53 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te jeta e baterisë."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Përdor faqosjen te Cilësimet e shpejta"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 522b2af..f3abc81 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -440,6 +440,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Секунде на сату се приказују на статусној траци. То може да утиче на трајање батерије."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Преуреди Брза подешавања"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Прикажи осветљеност у Брзим подешавањима"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Користи листање страница у Брзим подешавањима"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 7323126..3593b34 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Visa klocksekunder i statusfältet. Detta kan påverka batteritiden."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Ordna snabbinställningarna"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Visa ljusstyrka i snabbinställningarna"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Använd sidindelning i snabbinställningarna"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentella"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 1cf4293..de39e9b 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Panga Upya Mipangilio ya Haraka"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Onyesha unga\'avu katika Mipangilio ya Haraka"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Tumia nambari za ukurasa katika Mipangilio ya Haraka"</string>
     <string name="experimental" msgid="6198182315536726162">"Ya majaribio"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 670bccc..a895df7 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"நிலைப் பட்டியில் கடிகார வினாடிகளைக் காட்டும். பேட்டரியின் ஆயுளைக் குறைக்கலாம்."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"விரைவு அமைப்புகளை மறுவரிசைப்படுத்து"</string>
     <string name="show_brightness" msgid="6613930842805942519">"விரைவு அமைப்புகளில் ஒளிர்வுப் பட்டியைக் காட்டு"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"விரைவு அமைப்புகளில் புதிய பக்கத் தளவமைப்பைப் பயன்படுத்து"</string>
     <string name="experimental" msgid="6198182315536726162">"சோதனை முயற்சி"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index bbd9979..c34a33d 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"స్థితి పట్టీలో గడియారం సెకన్లు చూపుతుంది. బ్యాటరీ శక్తి ప్రభావితం చేయవచ్చు."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"శీఘ్ర సెట్టింగ్‌ల ఏర్పాటు క్రమం మార్చు"</string>
     <string name="show_brightness" msgid="6613930842805942519">"శీఘ్ర సెట్టింగ్‌ల్లో ప్రకాశం చూపు"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"శీఘ్ర సెట్టింగ్‌ల్లో పేజింగ్‌ను ఉపయోగించు"</string>
     <string name="experimental" msgid="6198182315536726162">"ప్రయోగాత్మకం"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 2486519..d777a0a 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
     <string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"ใช้การแบ่งหน้าในการตั้งค่าด่วน"</string>
     <string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3d1243e..292d3a2 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ipakita ang mga segundo ng orasan sa status bar. Maaaring makaapekto sa tagal ng baterya."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Ayusing Muli ang Mga Mabilisang Setting"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ipakita ang liwanag sa Mga Mabilisang Setting"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Gamitin ang paging sa Mga Mabilisang Setting"</string>
     <string name="experimental" msgid="6198182315536726162">"Pang-eksperimento"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4dadfbc..9c42e93 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Durum çubuğunda saatin saniyelerini gösterir. Pil ömrünü etkileyebilir."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Hızlı Ayarlar\'ı Yeniden Düzenle"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Hızlı Ayarlar\'da parlaklığı göster"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Hızlı Ayarlar\'da sayfa ayırmayı kullan"</string>
     <string name="experimental" msgid="6198182315536726162">"Deneysel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index d158dbe..9638e80 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показувати секунди на годиннику в рядку стану. Акумулятор може розряджатися швидше."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Упорядкувати швидкі налаштування"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Показувати панель яскравості у швидких налаштуваннях"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Показувати швидкі налаштування у вигляді сторінок"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментальні налаштування"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index f8d8c71..8c2fb64 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"گھڑی کے سیکنڈز اسٹیٹس بار میں دکھائیں۔ اس کا بیٹری کی زندگی پر اثر پڑ سکتا ہے۔"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"فوری ترتیبات کو دوبارہ ترتیب دیں"</string>
     <string name="show_brightness" msgid="6613930842805942519">"فوری ترتیبات میں چمکیلا پن دکھائیں"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"فوری ترتیبات میں پیجنگ استعمال کریں"</string>
     <string name="experimental" msgid="6198182315536726162">"تجرباتی"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 0186809..0ad5a69 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Holat panelida soat soniyalari ko‘rsatilsin. Bu batareya resursiga ta’sir qilishi mumkin."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Tezkor sozlamalarni qayta tartiblash"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tezkor sozlamalarda yorqinlikni ko‘rsatish"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Tezkor sozlamalarni sahifalarga ajratish"</string>
     <string name="experimental" msgid="6198182315536726162">"Tajribaviy"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 49b5d1d..c1aeeb4 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Hiển thị giây đồng hồ trong thanh trạng thái. Có thể ảnh hưởng đến thời lượng pin."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Sắp xếp lại Cài đặt nhanh"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Hiển thị độ sáng trong Cài đặt nhanh"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Sử dụng đánh số trang trong Cài đặt nhanh"</string>
     <string name="experimental" msgid="6198182315536726162">"Thử nghiệm"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 93ed5ca..fe1c311 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速设置"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快速设置中显示亮度栏"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"在快速设置中使用分页功能"</string>
     <string name="experimental" msgid="6198182315536726162">"实验性"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 2196111..d39adc0 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數,但可能會影響電池壽命。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快速設定顯示亮度"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"在快速設定使用分頁"</string>
     <string name="experimental" msgid="6198182315536726162">"實驗版"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index fe4fe06..6606167 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -441,6 +441,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數。這可能會影響電池續航力。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快速設定中顯示亮度"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"在快速設定中使用分頁功能"</string>
     <string name="experimental" msgid="6198182315536726162">"實驗性"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 2f068af..229c16b 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -439,6 +439,5 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Bonisa amasekhondi wewashi kubha yesimo. Ingathinta impilo yebhethri."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Hlela kabusha izilungiselelo ezisheshayo"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Bonisa ukukhanya kuzilungiselelo ezisheshayo"</string>
-    <string name="qs_paging" msgid="7020133150248666132">"Sebenzisa i-paging kuzilungiselelo ezisheshayo"</string>
     <string name="experimental" msgid="6198182315536726162">"Okokulinga"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/donottranslate.xml b/packages/SystemUI/res/values/donottranslate.xml
index 30ff704..351a1fd 100644
--- a/packages/SystemUI/res/values/donottranslate.xml
+++ b/packages/SystemUI/res/values/donottranslate.xml
@@ -20,10 +20,4 @@
     <!-- Date format for display: should match the lockscreen in /policy.  -->
     <string name="system_ui_date_pattern">@*android:string/system_ui_date_pattern</string>
 
-    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
-    <item type="string" name="keyguard_indication_charging_time_fast_if_translated">@string/keyguard_indication_charging_time</item>
-
-    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
-    <item type="string" name="keyguard_indication_charging_time_slowly_if_translated">@string/keyguard_indication_charging_time</item>
-
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index e562682..8e98f10 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Animatable;
@@ -325,6 +326,7 @@
 
     public interface Host {
         void startActivityDismissingKeyguard(Intent intent);
+        void startActivityDismissingKeyguard(PendingIntent intent);
         void warn(String message, Throwable t);
         void collapsePanels();
         Looper getLooper();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index 3d0dc7b..c7f2284 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -99,7 +99,7 @@
         try {
             if (pi != null) {
                 if (pi.isActivity()) {
-                    getHost().startActivityDismissingKeyguard(pi.getIntent());
+                    getHost().startActivityDismissingKeyguard(pi);
                 } else {
                     pi.send();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index 8827065..d3c65d2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.recents;
 
+import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+
 import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -245,7 +248,7 @@
         // the focus ends on the selected one.
         for (int i = additionalTasks; i >= 0; --i) {
             if (mTasks[i] != null) {
-                mRecentsView.launchTask(mTasks[i], mBounds[i]);
+                mRecentsView.launchTask(mTasks[i], mBounds[i], FREEFORM_WORKSPACE_STACK_ID);
             }
         }
     }
@@ -273,11 +276,11 @@
         // Dismiss the dialog before trying to launch the task
         dismissAllowingStateLoss();
 
-        if (mTasks[0].key.stackId != ActivityManager.DOCKED_STACK_ID) {
+        if (mTasks[0].key.stackId != DOCKED_STACK_ID) {
             int taskId = mTasks[0].key.id;
             mSsp.setTaskResizeable(taskId);
             mSsp.dockTask(taskId, createMode);
-            mRecentsView.launchTask(mTasks[0], null);
+            mRecentsView.launchTask(mTasks[0], null, DOCKED_STACK_ID);
         } else {
             Toast.makeText(getContext(), "Already docked", Toast.LENGTH_SHORT);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 1266120..a5fd3eb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.recents.views;
 
+import static android.app.ActivityManager.INVALID_STACK_ID;
+
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.content.Context;
@@ -185,7 +187,8 @@
                 TaskView tv = taskViews.get(j);
                 Task task = tv.getTask();
                 if (tv.isFocusedTask()) {
-                    onTaskViewClicked(mTaskStackView, tv, stack, task, false, false, null);
+                    onTaskViewClicked(mTaskStackView, tv, stack, task, false, false, null,
+                            INVALID_STACK_ID);
                     return true;
                 }
             }
@@ -194,7 +197,7 @@
     }
 
     /** Launches a given task. */
-    public boolean launchTask(Task task, Rect taskBounds) {
+    public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
         if (mTaskStackView != null) {
             TaskStack stack = mTaskStackView.getStack();
             // Iterate the stack views and try and find the given task.
@@ -204,7 +207,7 @@
                 TaskView tv = taskViews.get(j);
                 if (tv.getTask() == task) {
                     onTaskViewClicked(mTaskStackView, tv, stack, task, false, taskBounds != null,
-                            taskBounds);
+                            taskBounds, destinationStack);
                     return true;
                 }
             }
@@ -226,7 +229,8 @@
                     if (tasks.get(j).isLaunchTarget) {
                         Task task = tasks.get(j);
                         TaskView tv = mTaskStackView.getChildViewForTask(task);
-                        onTaskViewClicked(mTaskStackView, tv, stack, task, false, false, null);
+                        onTaskViewClicked(mTaskStackView, tv, stack, task, false, false, null,
+                                INVALID_STACK_ID);
                         return true;
                     }
                 }
@@ -451,12 +455,13 @@
     private void postDrawHeaderThumbnailTransitionRunnable(final TaskStackView view,
             final TaskView clickedView, final int offsetX, final int offsetY,
             final float stackScroll,
-            final ActivityOptions.OnAnimationStartedListener animStartedListener) {
+            final ActivityOptions.OnAnimationStartedListener animStartedListener,
+            final int destinationStack) {
         Runnable r = new Runnable() {
             @Override
             public void run() {
                 overrideDrawHeaderThumbnailTransition(view, clickedView, offsetX, offsetY,
-                        stackScroll, animStartedListener);
+                        stackScroll, animStartedListener, destinationStack);
 
             }
         };
@@ -466,9 +471,10 @@
 
     private void overrideDrawHeaderThumbnailTransition(TaskStackView stackView,
             TaskView clickedTask, int offsetX, int offsetY, float stackScroll,
-            final ActivityOptions.OnAnimationStartedListener animStartedListener) {
+            final ActivityOptions.OnAnimationStartedListener animStartedListener,
+            int destinationStack) {
         List<AppTransitionAnimationSpec> specs = getAppTransitionAnimationSpecs(stackView,
-                clickedTask, offsetX, offsetY, stackScroll);
+                clickedTask, offsetX, offsetY, stackScroll, destinationStack);
         if (specs == null) {
             return;
         }
@@ -499,8 +505,10 @@
     }
 
     private List<AppTransitionAnimationSpec> getAppTransitionAnimationSpecs(TaskStackView stackView,
-            TaskView clickedTask, int offsetX, int offsetY, float stackScroll) {
-        final int targetStackId = clickedTask.getTask().key.stackId;
+            TaskView clickedTask, int offsetX, int offsetY, float stackScroll,
+            int destinationStack) {
+        final int targetStackId = destinationStack != INVALID_STACK_ID ?
+                destinationStack : clickedTask.getTask().key.stackId;
         if (targetStackId != ActivityManager.FREEFORM_WORKSPACE_STACK_ID
                 && targetStackId != ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID) {
             return null;
@@ -604,9 +612,8 @@
 
     @Override
     public void onTaskViewClicked(final TaskStackView stackView, final TaskView tv,
-                                  final TaskStack stack, final Task task, final boolean lockToTask,
-                                  final boolean boundsValid, final Rect bounds) {
-
+            final TaskStack stack, final Task task, final boolean lockToTask,
+            final boolean boundsValid, final Rect bounds, int destinationStack) {
         // Notify any callbacks of the launching of a new task
         if (mCb != null) {
             mCb.onTaskViewClicked();
@@ -654,7 +661,7 @@
                 };
             }
             postDrawHeaderThumbnailTransitionRunnable(stackView, tv, offsetX, offsetY, stackScroll,
-                    animStartedListener);
+                    animStartedListener, destinationStack);
             opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
                     Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
                     offsetX, offsetY, transform.rect.width(), transform.rect.height(),
@@ -810,7 +817,7 @@
                     SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
                     ssp.setTaskResizeable(event.task.key.id);
                     ssp.dockTask(event.task.key.id, event.dockState.createMode);
-                    launchTask(event.task, null);
+                    launchTask(event.task, null, INVALID_STACK_ID);
                 }
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 08e4e20..f637407 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -16,7 +16,10 @@
 
 package com.android.systemui.recents.views;
 
+import static android.app.ActivityManager.INVALID_STACK_ID;
+
 import android.animation.ValueAnimator;
+import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -59,7 +62,7 @@
     /** The TaskView callbacks */
     interface TaskStackViewCallbacks {
         public void onTaskViewClicked(TaskStackView stackView, TaskView tv, TaskStack stack, Task t,
-                                      boolean lockToTask, boolean boundsValid, Rect bounds);
+                boolean lockToTask, boolean boundsValid, Rect bounds, int destinationStack);
         public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks);
         public void onTaskStackFilterTriggered();
         public void onTaskStackUnfilterTriggered();
@@ -1227,7 +1230,8 @@
         mUIDozeTrigger.stopDozing();
 
         if (mCb != null) {
-            mCb.onTaskViewClicked(this, tv, mStack, task, lockToTask, false, null);
+            mCb.onTaskViewClicked(this, tv, mStack, task, lockToTask, false, null,
+                    INVALID_STACK_ID);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 18e07a3..4322f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -157,6 +157,14 @@
                 mVelocityTracker.addMovement(createMotionEventForStackScroll(ev));
                 break;
             }
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                final int index = ev.getActionIndex();
+                mActivePointerId = ev.getPointerId(index);
+                mLastMotionX = (int) ev.getX(index);
+                mLastMotionY = (int) ev.getY(index);
+                mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
+                break;
+            }
             case MotionEvent.ACTION_MOVE: {
                 if (mActivePointerId == INACTIVE_POINTER_ID) break;
 
@@ -182,6 +190,20 @@
                 mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
                 break;
             }
+            case MotionEvent.ACTION_POINTER_UP: {
+                int pointerIndex = ev.getActionIndex();
+                int pointerId = ev.getPointerId(pointerIndex);
+                if (pointerId == mActivePointerId) {
+                    // Select a new active pointer id and reset the motion state
+                    final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
+                    mActivePointerId = ev.getPointerId(newPointerIndex);
+                    mLastMotionX = (int) ev.getX(newPointerIndex);
+                    mLastMotionY = (int) ev.getY(newPointerIndex);
+                    mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
+                    mVelocityTracker.clear();
+                }
+                break;
+            }
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP: {
                 // Animate the scroll back if we've cancelled
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index d2003bf..d227d55 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -167,7 +167,6 @@
         mContent = findViewById(R.id.task_view_content);
         mHeaderView = (TaskViewHeader) findViewById(R.id.task_view_bar);
         mThumbnailView = (TaskViewThumbnail) findViewById(R.id.task_view_thumbnail);
-        mThumbnailView.updateClipToTaskBar(mHeaderView);
         mActionButtonView = findViewById(R.id.lock_to_app_fab);
         mActionButtonView.setOutlineProvider(new ViewOutlineProvider() {
             @Override
@@ -210,6 +209,7 @@
         mThumbnailView.measure(
                 MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY));
+        mThumbnailView.updateClipToTaskBar(mHeaderView);
         setMeasuredDimension(width, height);
         invalidateOutline();
     }
@@ -786,8 +786,8 @@
             // Start listening for drag events
             setClipViewInStack(false);
 
-            int width = (int) (getScaleX() * getWidth());
-            int height = (int) (getScaleY() * getHeight());
+            final int width = (int) (getScaleX() * getWidth());
+            final int height = (int) (getScaleY() * getHeight());
             Bitmap dragBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
             Canvas c = new Canvas(dragBitmap);
             c.scale(getScaleX(), getScaleY());
@@ -797,7 +797,12 @@
 
             // Initiate the drag
             final DragView dragView = new DragView(getContext(), dragBitmap, mDownTouchPos);
-            dragView.setOutlineProvider(mViewBounds);
+            dragView.setOutlineProvider(new ViewOutlineProvider() {
+                @Override
+                public void getOutline(View view, Outline outline) {
+                    outline.setRect(0, 0, width, height);
+                }
+            });
             dragView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
                 @Override
                 public void onViewAttachedToWindow(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index aaed735..8938669 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1617,6 +1617,59 @@
         return null;
     }
 
+    public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
+        if (!isDeviceProvisioned()) return;
+
+        final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
+        final boolean afterKeyguardGone = intent.isActivity()
+                && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
+                mCurrentUserId);
+        dismissKeyguardThenExecute(new OnDismissAction() {
+            public boolean onDismiss() {
+                new Thread() {
+                    @Override
+                    public void run() {
+                        try {
+                            if (keyguardShowing && !afterKeyguardGone) {
+                                ActivityManagerNative.getDefault()
+                                        .keyguardWaitingForActivityDrawn();
+                            }
+
+                            // The intent we are sending is for the application, which
+                            // won't have permission to immediately start an activity after
+                            // the user switches to home.  We know it is safe to do at this
+                            // point, so make sure new activity switches are now allowed.
+                            ActivityManagerNative.getDefault().resumeAppSwitches();
+                        } catch (RemoteException e) {
+                        }
+
+                        try {
+                            intent.send();
+                        } catch (PendingIntent.CanceledException e) {
+                            // the stack trace isn't very helpful here.
+                            // Just log the exception message.
+                            Log.w(TAG, "Sending intent failed: " + e);
+
+                            // TODO: Dismiss Keyguard.
+                        }
+                        if (intent.isActivity()) {
+                            mAssistManager.hideAssist();
+                            overrideActivityPendingAppTransition(keyguardShowing
+                                    && !afterKeyguardGone);
+                        }
+                    }
+                }.start();
+
+                // close the shade if it was open
+                animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
+                        true /* force */, true /* delayed */);
+                visibilityChanged(false);
+
+                return true;
+            }
+        }, afterKeyguardGone);
+    }
+
     private final class NotificationClicker implements View.OnClickListener {
         public void onClick(final View v) {
             if (!(v instanceof ExpandableNotificationRow)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 5e6fdd0..6d13947 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -200,12 +200,12 @@
         switch (mChargingSpeed) {
             case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
                 chargingId = hasChargingTime
-                        ? R.string.keyguard_indication_charging_time_fast_if_translated
+                        ? R.string.keyguard_indication_charging_time_fast
                         : R.string.keyguard_plugged_in_charging_fast;
                 break;
             case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
                 chargingId = hasChargingTime
-                        ? R.string.keyguard_indication_charging_time_slowly_if_translated
+                        ? R.string.keyguard_indication_charging_time_slowly
                         : R.string.keyguard_plugged_in_charging_slowly;
                 break;
             default:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
index 9ef320bc..8f689c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.PendingIntent;
 import android.content.Intent;
 
 /**
@@ -24,6 +25,7 @@
  * Keyguard.
  */
 public interface ActivityStarter {
+    void startPendingIntentDismissingKeyguard(PendingIntent intent);
     void startActivity(Intent intent, boolean dismissShade);
     void startActivity(Intent intent, boolean dismissShade, Callback callback);
     void preventNextAnimation();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index bd16257..76edafa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -25,6 +25,7 @@
 import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 import android.view.ViewTreeObserver;
@@ -228,8 +229,7 @@
         }
 
         // On expanding, single mouse click expands the panel instead of dragging.
-        if (isFullyCollapsed() && event.getPointerCount() == 1
-                && event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
+        if (isFullyCollapsed() && event.getDevice().getSources() == InputDevice.SOURCE_MOUSE) {
             if (event.getAction() == MotionEvent.ACTION_UP) {
                 expand(true);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1c1a1d7..cfde791 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3261,6 +3261,15 @@
         return !isDeviceProvisioned() || (mDisabled1 & StatusBarManager.DISABLE_SEARCH) != 0;
     }
 
+    public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                startPendingIntentDismissingKeyguard(intent);
+            }
+        });
+    }
+
     public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
         mHandler.postDelayed(new Runnable() {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 6906a52..f8ddc73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -121,6 +122,11 @@
     }
 
     @Override
+    public void startActivityDismissingKeyguard(PendingIntent intent) {
+        mStatusBar.postStartActivityDismissingKeyguard(intent);
+    }
+
+    @Override
     public void warn(String message, Throwable t) {
         // already logged
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 65d84e2..6cda561 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -554,8 +554,8 @@
             startBatteryActivity();
         } else if (v == mAlarmStatus && mNextAlarm != null) {
             PendingIntent showIntent = mNextAlarm.getShowIntent();
-            if (showIntent != null && showIntent.isActivity()) {
-                mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */);
+            if (showIntent != null) {
+                mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index b2df40a..0e91b0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -27,7 +27,6 @@
     void removeCallback(Callback callback);
     void setZen(int zen, Uri conditionId, String reason);
     int getZen();
-    void requestConditions(boolean request);
     ZenRule getManualRule();
     ZenModeConfig getConfig();
     long getNextAlarm();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index c07f1a8..96efea1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -121,15 +121,6 @@
     }
 
     @Override
-    public void requestConditions(boolean request) {
-        mRequesting = request;
-        mNoMan.requestZenModeConditions(mListener, request ? Condition.FLAG_RELEVANT_NOW : 0);
-        if (!mRequesting) {
-            mConditions.clear();
-        }
-    }
-
-    @Override
     public ZenRule getManualRule() {
         return mConfig == null ? null : mConfig.manualRule;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 3c9a7fc..02ee5d4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -58,6 +58,8 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
 import java.util.Locale;
 import java.util.Objects;
 
@@ -76,6 +78,7 @@
     private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
     private static final int FOREVER_CONDITION_INDEX = 0;
     private static final int COUNTDOWN_CONDITION_INDEX = 1;
+    private static final int COUNTDOWN_ALARM_CONDITION_INDEX = 2;
 
     public static final Intent ZEN_SETTINGS
             = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
@@ -104,9 +107,6 @@
     private Callback mCallback;
     private ZenModeController mController;
     private boolean mCountdownConditionSupported;
-    private int mMaxConditions;
-    private int mMaxOptionalConditions;
-    private int mFirstConditionIndex;
     private boolean mRequestingConditions;
     private Condition mExitCondition;
     private int mBucketIndex = -1;
@@ -118,6 +118,7 @@
     private Condition mSessionExitCondition;
     private Condition[] mConditions;
     private Condition mTimeCondition;
+    private Condition mTimeUntilAlarmCondition;
     private boolean mVoiceCapable;
 
     public ZenModePanel(Context context, AttributeSet attrs) {
@@ -135,7 +136,6 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("ZenModePanel state:");
         pw.print("  mCountdownConditionSupported="); pw.println(mCountdownConditionSupported);
-        pw.print("  mMaxConditions="); pw.println(mMaxConditions);
         pw.print("  mRequestingConditions="); pw.println(mRequestingConditions);
         pw.print("  mAttached="); pw.println(mAttached);
         pw.print("  mHidden="); pw.println(mHidden);
@@ -286,14 +286,6 @@
         if (mRequestingConditions == requesting) return;
         if (DEBUG) Log.d(mTag, "setRequestingConditions " + requesting);
         mRequestingConditions = requesting;
-        if (mController != null) {
-            AsyncTask.execute(new Runnable() {
-                @Override
-                public void run() {
-                    mController.requestConditions(requesting);
-                }
-            });
-        }
         if (mRequestingConditions) {
             mTimeCondition = parseExistingTimeCondition(mContext, mExitCondition);
             if (mTimeCondition != null) {
@@ -304,6 +296,11 @@
                         MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
             }
             if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex);
+
+            mTimeUntilAlarmCondition = parseExistingTimeCondition(mContext, mExitCondition);
+            if (mTimeUntilAlarmCondition == null) {
+                mTimeUntilAlarmCondition = getTimeUntilNextAlarmCondition();
+            }
             mConditions = null; // reset conditions
             handleUpdateConditions();
         } else {
@@ -314,13 +311,9 @@
     public void init(ZenModeController controller) {
         mController = controller;
         mCountdownConditionSupported = mController.isCountdownConditionSupported();
-        final int countdownDelta = mCountdownConditionSupported ? 1 : 0;
-        mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta;
+        final int countdownDelta = mCountdownConditionSupported ? 2 : 0;
         final int minConditions = 1 /*forever*/ + countdownDelta;
-        mMaxConditions = MathUtils.constrain(mContext.getResources()
-                .getInteger(R.integer.zen_mode_max_conditions), minConditions, 100);
-        mMaxOptionalConditions = mMaxConditions - minConditions;
-        for (int i = 0; i < mMaxConditions; i++) {
+        for (int i = 0; i < minConditions; i++) {
             mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
         }
         mSessionZen = getSelectedZen(-1);
@@ -357,28 +350,10 @@
         return condition == null ? null : condition.copy();
     }
 
-    public static String getExitConditionText(Context context, Condition exitCondition) {
-        if (exitCondition == null) {
-            return foreverSummary(context);
-        } else if (isCountdown(exitCondition)) {
-            final Condition condition = parseExistingTimeCondition(context, exitCondition);
-            return condition != null ? condition.summary : foreverSummary(context);
-        } else {
-            return exitCondition.summary;
-        }
-    }
-
     public void setCallback(Callback callback) {
         mCallback = callback;
     }
 
-    public void showSilentHint() {
-        if (DEBUG) Log.d(mTag, "showSilentHint");
-        if (mZenButtons == null || mZenButtons.getChildCount() == 0) return;
-        final View noneButton = mZenButtons.getChildAt(0);
-        mIconPulser.start(noneButton);
-    }
-
     private void handleUpdateManualRule(ZenRule rule) {
         final int zen = rule != null ? rule.zenMode : Global.ZEN_MODE_OFF;
         handleUpdateZen(zen);
@@ -410,7 +385,7 @@
             final ConditionTag tag = getConditionTagAt(i);
             if (tag != null) {
                 if (sameConditionId(tag.condition, mExitCondition)) {
-                    bind(exitCondition, mZenConditions.getChildAt(i));
+                    bind(exitCondition, mZenConditions.getChildAt(i), i);
                 }
             }
         }
@@ -495,64 +470,29 @@
         final long span = time - now;
         if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null;
         return ZenModeConfig.toTimeCondition(context,
-                time, Math.round(span / (float) MINUTES_MS), now, ActivityManager.getCurrentUser(),
+                time, Math.round(span / (float) MINUTES_MS), ActivityManager.getCurrentUser(),
                 false /*shortVersion*/);
     }
 
-    private void handleUpdateConditions(Condition[] conditions) {
-        conditions = trimConditions(conditions);
-        if (Arrays.equals(conditions, mConditions)) {
-            final int count = mConditions == null ? 0 : mConditions.length;
-            if (DEBUG) Log.d(mTag, "handleUpdateConditions unchanged conditionCount=" + count);
-            return;
-        }
-        mConditions = conditions;
-        handleUpdateConditions();
-    }
-
-    private Condition[] trimConditions(Condition[] conditions) {
-        if (conditions == null || conditions.length <= mMaxOptionalConditions) {
-            // no need to trim
-            return conditions;
-        }
-        // look for current exit condition, ensure it is included if found
-        int found = -1;
-        for (int i = 0; i < conditions.length; i++) {
-            final Condition c = conditions[i];
-            if (mSessionExitCondition != null && sameConditionId(mSessionExitCondition, c)) {
-                found = i;
-                break;
-            }
-        }
-        final Condition[] rt = Arrays.copyOf(conditions, mMaxOptionalConditions);
-        if (found >= mMaxOptionalConditions) {
-            // found after the first N, promote to the end of the first N
-            rt[mMaxOptionalConditions - 1] = conditions[found];
-        }
-        return rt;
-    }
-
     private void handleUpdateConditions() {
         if (mTransitionHelper.isTransitioning()) {
-            mTransitionHelper.pendingUpdateConditions();
             return;
         }
         final int conditionCount = mConditions == null ? 0 : mConditions.length;
         if (DEBUG) Log.d(mTag, "handleUpdateConditions conditionCount=" + conditionCount);
         // forever
-        bind(forever(), mZenConditions.getChildAt(FOREVER_CONDITION_INDEX));
+        bind(forever(), mZenConditions.getChildAt(FOREVER_CONDITION_INDEX),
+                FOREVER_CONDITION_INDEX);
         // countdown
         if (mCountdownConditionSupported && mTimeCondition != null) {
-            bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX));
+            bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX),
+                    COUNTDOWN_CONDITION_INDEX);
         }
-        // provider conditions
-        for (int i = 0; i < conditionCount; i++) {
-            bind(mConditions[i], mZenConditions.getChildAt(mFirstConditionIndex + i));
-        }
-        // hide the rest
-        for (int i = mZenConditions.getChildCount() - 1; i > mFirstConditionIndex + conditionCount;
-                i--) {
-            mZenConditions.getChildAt(i).setVisibility(GONE);
+        // countdown until alarm
+        if (mCountdownConditionSupported && mTimeUntilAlarmCondition != null) {
+            bind(mTimeUntilAlarmCondition,
+                    mZenConditions.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX),
+                    COUNTDOWN_ALARM_CONDITION_INDEX);
         }
         // ensure something is selected
         if (mExpanded && isShown()) {
@@ -569,6 +509,33 @@
         return context.getString(com.android.internal.R.string.zen_mode_forever);
     }
 
+    // Returns a time condition if the next alarm is within the next week.
+    private Condition getTimeUntilNextAlarmCondition() {
+        GregorianCalendar weekRange = new GregorianCalendar();
+        final long now = weekRange.getTimeInMillis();
+        setToMidnight(weekRange);
+        weekRange.roll(Calendar.DATE, 6);
+        final long nextAlarmMs = mController.getNextAlarm();
+        if (nextAlarmMs > 0) {
+            GregorianCalendar nextAlarm = new GregorianCalendar();
+            nextAlarm.setTimeInMillis(nextAlarmMs);
+            setToMidnight(nextAlarm);
+
+            if (weekRange.compareTo(nextAlarm) >= 0) {
+                return ZenModeConfig.toNextAlarmCondition(mContext, now, nextAlarmMs,
+                        ActivityManager.getCurrentUser());
+            }
+        }
+        return null;
+    }
+
+    private void setToMidnight(Calendar calendar) {
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+    }
+
     private ConditionTag getConditionTagAt(int index) {
         return (ConditionTag) mZenConditions.getChildAt(index).getTag();
     }
@@ -610,7 +577,8 @@
             mTimeCondition = ZenModeConfig.toTimeCondition(mContext,
                     MINUTE_BUCKETS[favoriteIndex], ActivityManager.getCurrentUser());
             mBucketIndex = favoriteIndex;
-            bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX));
+            bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX),
+                    COUNTDOWN_CONDITION_INDEX);
             getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
         }
     }
@@ -623,7 +591,7 @@
         return c != null && mForeverId.equals(c.id);
     }
 
-    private void bind(final Condition condition, final View row) {
+    private void bind(final Condition condition, final View row, final int rowId) {
         if (condition == null) throw new IllegalArgumentException("condition must not be null");
         final boolean enabled = condition.state == Condition.STATE_TRUE;
         final ConditionTag tag =
@@ -640,8 +608,7 @@
         tag.rb.setEnabled(enabled);
         final boolean checked = (mSessionExitCondition != null
                     || mAttachedZen != Global.ZEN_MODE_OFF)
-                && (sameConditionId(mSessionExitCondition, tag.condition)
-                    || isCountdown(mSessionExitCondition) && isCountdown(tag.condition));
+                && (sameConditionId(mSessionExitCondition, tag.condition));
         if (checked != tag.rb.isChecked()) {
             if (DEBUG) Log.d(mTag, "bind checked=" + checked + " condition=" + conditionId);
             tag.rb.setChecked(checked);
@@ -692,7 +659,7 @@
         button1.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
-                onClickTimeButton(row, tag, false /*down*/);
+                onClickTimeButton(row, tag, false /*down*/, rowId);
             }
         });
 
@@ -700,7 +667,7 @@
         button2.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
-                onClickTimeButton(row, tag, true /*up*/);
+                onClickTimeButton(row, tag, true /*up*/, rowId);
             }
         });
         tag.lines.setOnClickListener(new OnClickListener() {
@@ -711,7 +678,7 @@
         });
 
         final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
-        if (time > 0) {
+        if (rowId != COUNTDOWN_ALARM_CONDITION_INDEX && time > 0) {
             button1.setVisibility(VISIBLE);
             button2.setVisibility(VISIBLE);
             if (mBucketIndex > -1) {
@@ -761,7 +728,7 @@
                 tag.line1.getText()));
     }
 
-    private void onClickTimeButton(View row, ConditionTag tag, boolean up) {
+    private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
         MetricsLogger.action(mContext, MetricsLogger.QS_DND_TIME, up);
         Condition newCondition = null;
         final int N = MINUTE_BUCKETS.length;
@@ -777,7 +744,7 @@
                 if (up && bucketTime > time || !up && bucketTime < time) {
                     mBucketIndex = j;
                     newCondition = ZenModeConfig.toTimeCondition(mContext,
-                            bucketTime, bucketMinutes, now, ActivityManager.getCurrentUser(),
+                            bucketTime, bucketMinutes, ActivityManager.getCurrentUser(),
                             false /*shortVersion*/);
                     break;
                 }
@@ -794,7 +761,7 @@
                     MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
         }
         mTimeCondition = newCondition;
-        bind(mTimeCondition, row);
+        bind(mTimeCondition, row, rowId);
         tag.rb.setChecked(true);
         select(mTimeCondition);
         announceConditionSelection(tag);
@@ -838,18 +805,12 @@
 
     private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
         @Override
-        public void onConditionsChanged(Condition[] conditions) {
-            mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
-        }
-
-        @Override
         public void onManualRuleChanged(ZenRule rule) {
             mHandler.obtainMessage(H.MANUAL_RULE_CHANGED, rule).sendToTarget();
         }
     };
 
     private final class H extends Handler {
-        private static final int UPDATE_CONDITIONS = 1;
         private static final int MANUAL_RULE_CHANGED = 2;
         private static final int UPDATE_WIDGETS = 3;
 
@@ -860,7 +821,6 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case UPDATE_CONDITIONS: handleUpdateConditions((Condition[]) msg.obj); break;
                 case MANUAL_RULE_CHANGED: handleUpdateManualRule((ZenRule) msg.obj); break;
                 case UPDATE_WIDGETS: updateWidgets(); break;
             }
@@ -1005,26 +965,20 @@
         private final ArraySet<View> mTransitioningViews = new ArraySet<View>();
 
         private boolean mTransitioning;
-        private boolean mPendingUpdateConditions;
         private boolean mPendingUpdateWidgets;
 
         public void clear() {
             mTransitioningViews.clear();
-            mPendingUpdateConditions = mPendingUpdateWidgets = false;
+            mPendingUpdateWidgets = false;
         }
 
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             pw.println("  TransitionHelper state:");
-            pw.print("    mPendingUpdateConditions="); pw.println(mPendingUpdateConditions);
             pw.print("    mPendingUpdateWidgets="); pw.println(mPendingUpdateWidgets);
             pw.print("    mTransitioning="); pw.println(mTransitioning);
             pw.print("    mTransitioningViews="); pw.println(mTransitioningViews);
         }
 
-        public void pendingUpdateConditions() {
-            mPendingUpdateConditions = true;
-        }
-
         public void pendingUpdateWidgets() {
             mPendingUpdateWidgets = true;
         }
@@ -1050,15 +1004,11 @@
         @Override
         public void run() {
             if (DEBUG) Log.d(mTag, "TransitionHelper run"
-                    + " mPendingUpdateWidgets=" + mPendingUpdateWidgets
-                    + " mPendingUpdateConditions=" + mPendingUpdateConditions);
+                    + " mPendingUpdateWidgets=" + mPendingUpdateWidgets);
             if (mPendingUpdateWidgets) {
                 updateWidgets();
             }
-            if (mPendingUpdateConditions) {
-                handleUpdateConditions();
-            }
-            mPendingUpdateWidgets = mPendingUpdateConditions = false;
+            mPendingUpdateWidgets = false;
         }
 
         private void updateTransitioning() {
@@ -1067,10 +1017,10 @@
             mTransitioning = transitioning;
             if (DEBUG) Log.d(mTag, "TransitionHelper mTransitioning=" + mTransitioning);
             if (!mTransitioning) {
-                if (mPendingUpdateConditions || mPendingUpdateWidgets) {
+                if (mPendingUpdateWidgets) {
                     mHandler.post(this);
                 } else {
-                    mPendingUpdateConditions = mPendingUpdateWidgets = false;
+                    mPendingUpdateWidgets = false;
                 }
             }
         }
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 882899e..08f0952e 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -971,8 +971,8 @@
             // This is a special alarm that will put the system into idle until it goes off.
             // The caller has given the time they want this to happen at, however we need
             // to pull that earlier if there are existing alarms that have requested to
-            // bring us out of idle.
-            if (mNextWakeFromIdle != null) {
+            // bring us out of idle at an earlier time.
+            if (mNextWakeFromIdle != null && a.whenElapsed > mNextWakeFromIdle.whenElapsed) {
                 a.when = a.whenElapsed = a.maxWhenElapsed = mNextWakeFromIdle.whenElapsed;
             }
             // Add fuzz to make the alarm go off some time before the actual desired time.
@@ -1256,7 +1256,7 @@
                 pw.print("      Idling until: ");
                 if (mPendingIdleUntil != null) {
                     pw.println(mPendingIdleUntil);
-                    mPendingIdleUntil.dump(pw, "    ", nowRTC, nowELAPSED, sdf);
+                    mPendingIdleUntil.dump(pw, "        ", nowRTC, nowELAPSED, sdf);
                 } else {
                     pw.println("null");
                 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 75dda9c..d031165 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -948,13 +948,13 @@
             uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
         }
 
-        if ((uidRules & RULE_REJECT_ALL) != 0
-                || (networkCostly && (uidRules & RULE_REJECT_METERED) != 0)) {
+        if (uidRules == RULE_REJECT_ALL) {
             return true;
+        } else if ((uidRules == RULE_REJECT_METERED) && networkCostly) {
+            return true;
+        } else {
+            return false;
         }
-
-        // no restrictive rules; network is visible
-        return false;
     }
 
     /**
@@ -3215,6 +3215,11 @@
             final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
             final VpnProfile profile = VpnProfile.decode(
                     profileName, mKeyStore.get(Credentials.VPN + profileName));
+            if (profile == null) {
+                Slog.e(TAG, "Lockdown VPN configured invalid profile " + profileName);
+                setLockdownTracker(null);
+                return true;
+            }
             int user = UserHandle.getUserId(Binder.getCallingUid());
             synchronized(mVpns) {
                 setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpns.get(user),
@@ -3751,7 +3756,7 @@
             synchronized(mRulesLock) {
                 uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
             }
-            if ((uidRules & (RULE_REJECT_METERED | RULE_REJECT_ALL)) != 0) {
+            if (uidRules != RULE_ALLOW_ALL) {
                 // we could silently fail or we can filter the available nets to only give
                 // them those they have access to.  Chose the more useful
                 networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 223519d..87b490d 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -246,6 +246,14 @@
             if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
                 int plugged = intent.getIntExtra("plugged", 0);
                 updateChargingLocked(plugged != 0);
+            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                    Uri data = intent.getData();
+                    String ssp;
+                    if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
+                        removePowerSaveWhitelistAppInternal(ssp);
+                    }
+                }
             } else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
                 synchronized (DeviceIdleController.this) {
                     stepIdleStateLocked();
@@ -972,6 +980,10 @@
                 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
                 filter.addAction(ACTION_STEP_IDLE_STATE);
                 getContext().registerReceiver(mReceiver, filter);
+                filter = new IntentFilter();
+                filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+                filter.addDataScheme("package");
+                getContext().registerReceiver(mReceiver, filter);
 
                 mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
 
@@ -984,7 +996,10 @@
     public boolean addPowerSaveWhitelistAppInternal(String name) {
         synchronized (this) {
             try {
-                ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name, 0);
+                ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name,
+                        PackageManager.GET_UNINSTALLED_PACKAGES
+                                | PackageManager.GET_DISABLED_COMPONENTS
+                                | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
                 if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid)) == null) {
                     reportPowerSaveWhitelistChangedLocked();
                     updateWhitelistAppIdsLocked();
@@ -1610,7 +1625,6 @@
             } catch (IOException e) {
             }
         }
-
     }
 
     private void readConfigFileLocked(XmlPullParser parser) {
@@ -1639,7 +1653,10 @@
                     String name = parser.getAttributeValue(null, "n");
                     if (name != null) {
                         try {
-                            ApplicationInfo ai = pm.getApplicationInfo(name, 0);
+                            ApplicationInfo ai = pm.getApplicationInfo(name,
+                                    PackageManager.GET_UNINSTALLED_PACKAGES
+                                            | PackageManager.GET_DISABLED_COMPONENTS
+                                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
                             mPowerSaveWhitelistUserApps.put(ai.packageName,
                                     UserHandle.getAppId(ai.uid));
                         } catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 087ddd6..9405d8e0 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -341,8 +341,10 @@
             gpsProvider.disable();
         }
 
-        FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
-        if (FlpHardwareProvider.isSupported() && flpHardwareProvider != null) {
+        // it is needed to check if FLP HW provider is supported before accessing the instance, this
+        // avoids an exception to be thrown by the singleton factory method
+        if (FlpHardwareProvider.isSupported()) {
+            FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
             flpHardwareProvider.cleanup();
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 759a4f3..e7601c2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9161,13 +9161,14 @@
     }
 
     @Override
-    public void resizeStack(int stackId, Rect bounds) {
+    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
                 "resizeStack()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                mStackSupervisor.resizeStackLocked(stackId, bounds, !PRESERVE_WINDOWS);
+                mStackSupervisor.resizeStackLocked(
+                        stackId, bounds, !PRESERVE_WINDOWS, allowResizeInDockedMode);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index cdb00ef..00664b4 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4572,7 +4572,7 @@
         // add the task to stack first, mTaskPositioner might need the stack association
         addTask(task, toTop, false);
         if (mTaskPositioner != null) {
-            mTaskPositioner.updateDefaultBounds(task, mTaskHistory, info.initialLayout);
+            mTaskPositioner.updateDefaultBounds(task, mTaskHistory, info.layout);
         } else if (mBounds != null && task.mResizeable) {
             task.updateOverrideConfiguration(mBounds);
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e465009..2a36230 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -97,6 +97,7 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -352,6 +353,10 @@
     private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
     private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
 
+    // The default minimal size that will be used if the activity doesn't specify its minimal size.
+    // It will be calculated when the default display gets added.
+    private int mDefaultMinimalSizeOfResizeableTask = -1;
+
     /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
@@ -432,6 +437,7 @@
                     throw new IllegalStateException("Default Display does not exist");
                 }
                 mActivityDisplays.put(displayId, activityDisplay);
+                calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
             }
 
             createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY, true);
@@ -2973,13 +2979,21 @@
         }
     }
 
-    void resizeStackLocked(int stackId, Rect bounds, boolean preserveWindows) {
+    void resizeStackLocked(int stackId, Rect bounds, boolean preserveWindows,
+            boolean allowResizeInDockedMode) {
         final ActivityStack stack = getStack(stackId);
         if (stack == null) {
             Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
             return;
         }
 
+        if (!allowResizeInDockedMode
+                && stackId != DOCKED_STACK_ID && getStack(DOCKED_STACK_ID) != null) {
+            // If the docked stack exist we don't allow resizes of stacks not caused by the docked
+            // stack size changing so things don't get out of sync.
+            return;
+        }
+
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
 
         ActivityRecord r = stack.topRunningActivityLocked();
@@ -3014,7 +3028,7 @@
                 // docked stack tasks to the fullscreen stack.
                 for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
                     if (i != DOCKED_STACK_ID && getStack(i) != null) {
-                        resizeStackLocked(i, null, preserveWindows);
+                        resizeStackLocked(i, null, preserveWindows, true);
                     }
                 }
 
@@ -3029,23 +3043,15 @@
             } else {
                 // Docked stacks occupy a dedicated region on screen so the size of all other
                 // static stacks need to be adjusted so they don't overlap with the docked stack.
-                final int leftChange = stack.mBounds.left - bounds.left;
-                final int rightChange = stack.mBounds.right - bounds.right;
-                final int topChange = stack.mBounds.top - bounds.top;
-                final int bottomChange = stack.mBounds.bottom - bounds.bottom;
+                // We get the bounds to use from window manager which has been adjusted for any
+                // screen controls and is also the same for all stacks.
+                mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
 
                 for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
                     if (i != DOCKED_STACK_ID) {
                         ActivityStack otherStack = getStack(i);
                         if (otherStack != null) {
-                            tempRect.set(otherStack.mBounds);
-                            // We adjust the opposing sides of the other stacks to
-                            // the side in the dock stack that changed.
-                            tempRect.left -= rightChange;
-                            tempRect.right -= leftChange;
-                            tempRect.top -= bottomChange;
-                            tempRect.bottom -= topChange;
-                            resizeStackLocked(i, tempRect, PRESERVE_WINDOWS);
+                            resizeStackLocked(i, tempRect, PRESERVE_WINDOWS, true);
                         }
                     }
                 }
@@ -3075,6 +3081,8 @@
             return;
         }
 
+        adjustForMinimalTaskDimensions(task, bounds);
+
         // If this is a forced resize, let it go through even if the bounds is not changing,
         // as we might need a relayout due to surface size change (to/from fullscreen).
         final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
@@ -3123,6 +3131,38 @@
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
+    private void adjustForMinimalTaskDimensions(TaskRecord task, Rect bounds) {
+        if (bounds == null) {
+            return;
+        }
+        int minimalSize = task.mMinimalSize == -1 ? mDefaultMinimalSizeOfResizeableTask
+                : task.mMinimalSize;
+        final boolean adjustWidth = minimalSize > bounds.width();
+        final boolean adjustHeight = minimalSize > bounds.height();
+        if (!(adjustWidth || adjustHeight)) {
+            return;
+        }
+        Rect taskBounds = task.mBounds;
+        if (adjustWidth) {
+            if (taskBounds != null && bounds.right == taskBounds.right) {
+                bounds.left = bounds.right - minimalSize;
+            } else {
+                // Either left bounds match, or neither match, or the previous bounds were
+                // fullscreen and we default to keeping left.
+                bounds.right = bounds.left + minimalSize;
+            }
+        }
+        if (adjustHeight) {
+            if (taskBounds != null && bounds.bottom == taskBounds.bottom) {
+                bounds.top = bounds.bottom - minimalSize;
+            } else {
+                // Either top bounds match, or neither match, or the previous bounds were
+                // fullscreen and we default to keeping top.
+                bounds.bottom = bounds.top + minimalSize;
+            }
+        }
+    }
+
     ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
         ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
         if (activityDisplay == null) {
@@ -3228,9 +3268,16 @@
             // Apps may depend on onResume()/onPause() being called in pairs.
             if (wasResumed) {
                 stack.mResumedActivity = r;
+                // Move the stack in which we are placing the task to the front. We don't use
+                // ActivityManagerService.setFocusedActivityLocked, because if the activity is
+                // already focused, the call will short-circuit and do nothing.
+                stack.moveToFront(reason);
+            } else {
+                // We need to not only move the stack to the front, but also have the activity
+                // focused. This will achieve both goals.
+                mService.setFocusedActivityLocked(r, reason);
             }
-            // move the stack in which we are placing the task to the front.
-            stack.moveToFront(reason);
+
         }
 
         return stack;
@@ -4026,6 +4073,7 @@
                     return;
                 }
                 mActivityDisplays.put(displayId, activityDisplay);
+                calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
             }
         }
         if (newDisplay) {
@@ -4033,6 +4081,16 @@
         }
     }
 
+    private void calculateDefaultMinimalSizeOfResizeableTasks(ActivityDisplay display) {
+        if (display.mDisplayId != Display.DEFAULT_DISPLAY) {
+            return;
+        }
+        final float fraction = mService.mContext.getResources().getFraction(com.android.internal.R.
+                fraction.config_displayFractionForDefaultMinimalSizeOfResizeableTask, 1, 1);
+        mDefaultMinimalSizeOfResizeableTask = (int) (fraction * Math.min(
+                display.mDisplayInfo.logicalWidth, display.mDisplayInfo.logicalHeight));
+    }
+
     private void handleDisplayRemoved(int displayId) {
         synchronized (mService) {
             ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
@@ -4193,7 +4251,7 @@
         mLockTaskModeTasks.add(task);
 
         if (task.mLockTaskUid == -1) {
-            task.mLockTaskUid = task.mCallingUid;
+            task.mLockTaskUid = task.effectiveUid;
         }
 
         if (andResume) {
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
index 3d45915..4ba1d0d 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -109,22 +109,22 @@
      *
      * @param task Task for which we want to find bounds that won't collide with other.
      * @param tasks Existing tasks with which we don't want to collide.
-     * @param initialLayout Optional information from the client about how it would like to be sized
+     * @param layout Optional information from the client about how it would like to be sized
      *                      and positioned.
      */
     void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks,
-            @Nullable ActivityInfo.InitialLayout initialLayout) {
+            @Nullable ActivityInfo.Layout layout) {
         if (!mDefaultStartBoundsConfigurationSet) {
             return;
         }
-        if (initialLayout == null) {
+        if (layout == null) {
             positionCenter(task, tasks, mDefaultFreeformWidth, mDefaultFreeformHeight);
             return;
         }
-        int width = getFinalWidth(initialLayout);
-        int height = getFinalHeight(initialLayout);
-        int verticalGravity = initialLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
-        int horizontalGravity = initialLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+        int width = getFinalWidth(layout);
+        int height = getFinalHeight(layout);
+        int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+        int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
         if (verticalGravity == Gravity.TOP) {
             if (horizontalGravity == Gravity.RIGHT) {
                 positionTopRight(task, tasks, width, height);
@@ -140,30 +140,30 @@
         } else {
             // Some fancy gravity setting that we don't support yet. We just put the activity in the
             // center.
-            Slog.w(TAG, "Received unsupported gravity: " + initialLayout.gravity
+            Slog.w(TAG, "Received unsupported gravity: " + layout.gravity
                     + ", positioning in the center instead.");
             positionCenter(task, tasks, width, height);
         }
     }
 
-    private int getFinalWidth(ActivityInfo.InitialLayout initialLayout) {
+    private int getFinalWidth(ActivityInfo.Layout layout) {
         int width = mDefaultFreeformWidth;
-        if (initialLayout.width > 0) {
-            width = initialLayout.width;
+        if (layout.width > 0) {
+            width = layout.width;
         }
-        if (initialLayout.widthFraction > 0) {
-            width = (int) (mAvailableRect.width() * initialLayout.widthFraction);
+        if (layout.widthFraction > 0) {
+            width = (int) (mAvailableRect.width() * layout.widthFraction);
         }
         return width;
     }
 
-    private int getFinalHeight(ActivityInfo.InitialLayout initialLayout) {
+    private int getFinalHeight(ActivityInfo.Layout layout) {
         int height = mDefaultFreeformHeight;
-        if (initialLayout.height > 0) {
-            height = initialLayout.height;
+        if (layout.height > 0) {
+            height = layout.height;
         }
-        if (initialLayout.heightFraction > 0) {
-            height = (int) (mAvailableRect.height() * initialLayout.heightFraction);
+        if (layout.heightFraction > 0) {
+            height = (int) (mAvailableRect.height() * layout.heightFraction);
         }
         return height;
     }
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index b216114..edd16ef 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -465,7 +465,7 @@
                     if (!sameActivity) {
                         continue;
                     }
-                    if (maxRecents > 0) {
+                    if (maxRecents > 0 && !doTrim) {
                         --maxRecents;
                         continue;
                     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 77dbad4..5d5b5fe 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -217,6 +217,9 @@
     // The information is persisted and used to determine the appropriate stack to launch the
     // task into on restore.
     Rect mLastNonFullscreenBounds = null;
+    // Minimal size for width/height of this task when it's resizeable. -1 means it should use the
+    // default minimal size.
+    final int mMinimalSize;
 
     Configuration mOverrideConfig = Configuration.EMPTY;
 
@@ -235,6 +238,7 @@
         mCallingUid = info.applicationInfo.uid;
         mCallingPackage = info.packageName;
         setIntent(_intent, info);
+        mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
     }
 
     TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
@@ -263,6 +267,7 @@
         mTaskToReturnTo = HOME_ACTIVITY_TYPE;
         userId = UserHandle.getUserId(info.applicationInfo.uid);
         lastTaskDescription = _taskDescription;
+        mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
     }
 
     private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
@@ -310,6 +315,8 @@
         mCallingPackage = callingPackage;
         mResizeable = resizeable;
         mPrivileged = privileged;
+        ActivityInfo info = mActivities.get(0).info;
+        mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
     }
 
     void touchActiveTime() {
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index bb4dbc3..835ba17 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -74,6 +74,7 @@
 
     // Set to true when the animation context has been fully prepared.
     private boolean mPrepared;
+    private boolean mCreatedResources;
     private int mMode;
 
     private final DisplayManagerInternal mDisplayManagerInternal;
@@ -169,6 +170,7 @@
         }
 
         // Done.
+        mCreatedResources = true;
         mPrepared = true;
 
         // Dejanking optimization.
@@ -313,6 +315,34 @@
     }
 
     /**
+     * Dismisses the color fade animation resources.
+     *
+     * This function destroys the resources that are created for the color fade
+     * animation but does not clean up the surface.
+     */
+    public void dismissResources() {
+        if (DEBUG) {
+            Slog.d(TAG, "dismissResources");
+        }
+
+        if (mCreatedResources) {
+            attachEglContext();
+            try {
+                destroyScreenshotTexture();
+                destroyGLShaders();
+                destroyGLBuffers();
+                destroyEglSurface();
+            } finally {
+                detachEglContext();
+            }
+            // This is being called with no active context so shouldn't be
+            // needed but is safer to not change for now.
+            GLES20.glFlush();
+            mCreatedResources = false;
+        }
+    }
+
+    /**
      * Dismisses the color fade animation surface and cleans up.
      *
      * To prevent stray photons from leaking out after the color fade has been
@@ -325,17 +355,8 @@
         }
 
         if (mPrepared) {
-            attachEglContext();
-            try {
-                destroyScreenshotTexture();
-                destroyGLShaders();
-                destroyGLBuffers();
-                destroyEglSurface();
-            } finally {
-                detachEglContext();
-            }
+            dismissResources();
             destroySurface();
-            GLES20.glFlush();
             mPrepared = false;
         }
     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 452378f..7b49530 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -837,6 +837,7 @@
         if (mPendingScreenOff && target != Display.STATE_OFF) {
             setScreenState(Display.STATE_OFF);
             mPendingScreenOff = false;
+            mPowerState.dismissColorFadeResources();
         }
 
         if (target == Display.STATE_ON) {
@@ -910,6 +911,7 @@
                 // A black surface is already hiding the contents of the screen.
                 setScreenState(Display.STATE_OFF);
                 mPendingScreenOff = false;
+                mPowerState.dismissColorFadeResources();
             } else if (performScreenOffTransition
                     && mPowerState.prepareColorFade(mContext,
                             mColorFadeFadesConfig ?
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 2eabd32..9862516 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -187,7 +187,7 @@
     }
 
     /**
-     * Dismisses the electron beam surface.
+     * Dismisses the color fade surface.
      */
     public void dismissColorFade() {
         mColorFade.dismiss();
@@ -195,6 +195,13 @@
         mColorFadeReady = true;
     }
 
+   /**
+     * Dismisses the color fade resources.
+     */
+    public void dismissColorFadeResources() {
+        mColorFade.dismissResources();
+    }
+
     /**
      * Sets the level of the electron beam steering current.
      *
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 5a13672..5b40375 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -206,6 +206,7 @@
     private static native void nativeReloadDeviceAliases(long ptr);
     private static native String nativeDump(long ptr);
     private static native void nativeMonitor(long ptr);
+    private static native void nativeSetPointerIconShape(long ptr, int iconId);
 
     // Input event injection constants defined in InputDispatcher.h.
     private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
@@ -1407,6 +1408,12 @@
         }
     }
 
+  // Binder call
+  @Override
+  public void setPointerIconShape(int iconId) {
+      nativeSetPointerIconShape(mPtr, iconId);
+  }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 06bd583..3c50102 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -73,7 +73,7 @@
  */
 public class JobSchedulerService extends com.android.server.SystemService
         implements StateChangedListener, JobCompletedListener {
-    static final boolean DEBUG = false;
+    public static final boolean DEBUG = false;
     /** The number of concurrent jobs we run at one time. */
     private static final int MAX_JOB_CONTEXTS_COUNT
             = ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
@@ -99,7 +99,7 @@
      * Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule
      * things early.
      */
-    static final int MIN_CONNECTIVITY_COUNT = 2;
+    static final int MIN_CONNECTIVITY_COUNT = 1;  // Run connectivity jobs as soon as ready.
     /**
      * Minimum # of jobs (with no particular constraints) for which the JMS will be happy running
      * some work early.
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 3991489..17ae6dc 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -39,17 +39,17 @@
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
 import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_UNKNOWN;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
-import static android.net.NetworkPolicyManager.dumpPolicy;
-import static android.net.NetworkPolicyManager.dumpRules;
 import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
 import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
 import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
@@ -108,6 +108,7 @@
 import android.net.NetworkIdentity;
 import android.net.NetworkInfo;
 import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkState;
 import android.net.NetworkTemplate;
@@ -138,6 +139,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.DebugUtils;
 import android.util.Log;
 import android.util.NtpTrustedTime;
 import android.util.Pair;
@@ -147,8 +149,6 @@
 import android.util.TrustedTime;
 import android.util.Xml;
 
-import com.android.server.DeviceIdleController;
-import com.android.server.EventLogTags;
 import libcore.io.IoUtils;
 
 import com.android.internal.R;
@@ -156,6 +156,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.DeviceIdleController;
+import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.google.android.collect.Lists;
 
@@ -280,6 +282,12 @@
     /** Currently derived rules for each UID. */
     final SparseIntArray mUidRules = new SparseIntArray();
 
+    final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
+    final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
+
+    /** Set of states for the child firewall chains. True if the chain is active. */
+    final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
+
     /**
      * UIDs that have been white-listed to always be able to have network access
      * in power save mode, except device idle (doze) still applies.
@@ -444,14 +452,8 @@
             // read policy from disk
             readPolicyLocked();
 
-            if (mRestrictBackground || mRestrictPower || mDeviceIdleMode) {
-                updateRulesForGlobalChangeLocked(false);
-                updateNotificationsLocked();
-            } else {
-                // If we are not in any special mode, we just need to make sure the current
-                // app idle state is updated.
-                updateRulesForAppIdleLocked();
-            }
+            updateRulesForGlobalChangeLocked(false);
+            updateNotificationsLocked();
         }
 
         updateScreenOn();
@@ -1796,7 +1798,9 @@
             if (mDeviceIdleMode != enabled) {
                 mDeviceIdleMode = enabled;
                 if (mSystemReady) {
-                    updateRulesForDeviceIdleLocked();
+                    // Device idle change means we need to rebuild rules for all
+                    // known apps, so do a global refresh.
+                    updateRulesForGlobalChangeLocked(false);
                 }
                 if (enabled) {
                     EventLogTags.writeDeviceIdleOnPhase("net");
@@ -1934,7 +1938,7 @@
                 fout.print("UID=");
                 fout.print(uid);
                 fout.print(" policy=");
-                dumpPolicy(fout, policy);
+                fout.print(DebugUtils.flagsToString(NetworkPolicyManager.class, "POLICY_", policy));
                 fout.println();
             }
             fout.decreaseIndent();
@@ -1979,18 +1983,14 @@
                 fout.print("UID=");
                 fout.print(uid);
 
-                int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+                final int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
                 fout.print(" state=");
                 fout.print(state);
                 fout.print(state <= ActivityManager.PROCESS_STATE_TOP ? " (fg)" : " (bg)");
 
-                fout.print(" rules=");
-                final int rulesIndex = mUidRules.indexOfKey(uid);
-                if (rulesIndex < 0) {
-                    fout.print("UNKNOWN");
-                } else {
-                    dumpRules(fout, mUidRules.valueAt(rulesIndex));
-                }
+                final int rule = mUidRules.get(uid, RULE_UNKNOWN);
+                fout.print(" rule=");
+                fout.print(DebugUtils.valueToString(NetworkPolicyManager.class, "RULE_", rule));
 
                 fout.println();
             }
@@ -2025,7 +2025,7 @@
             updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
             if (mDeviceIdleMode && isProcStateAllowedWhileIdle(oldUidState)
                     != isProcStateAllowedWhileIdle(uidState)) {
-                updateRulesForDeviceIdleLocked();
+                updateRuleForDeviceIdleLocked(uid);
             }
         }
     }
@@ -2039,7 +2039,7 @@
                 updateRulesForUidStateChangeLocked(uid, oldUidState,
                         ActivityManager.PROCESS_STATE_CACHED_EMPTY);
                 if (mDeviceIdleMode) {
-                    updateRulesForDeviceIdleLocked();
+                    updateRuleForDeviceIdleLocked(uid);
                 }
             }
         }
@@ -2086,7 +2086,8 @@
         if (mDeviceIdleMode) {
             // sync the whitelists before enable dozable chain.  We don't care about the rules if
             // we are disabling the chain.
-            SparseIntArray uidRules = new SparseIntArray();
+            final SparseIntArray uidRules = mUidFirewallDozableRules;
+            uidRules.clear();
             final List<UserInfo> users = mUserManager.getUsers();
             for (int ui = users.size() - 1; ui >= 0; ui--) {
                 UserInfo user = users.get(ui);
@@ -2110,6 +2111,7 @@
             }
             setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
         }
+
         enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
     }
 
@@ -2123,11 +2125,15 @@
                 setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
             }
         }
+
+        updateRulesForUidLocked(uid);
     }
 
     void updateRulesForAppIdleLocked() {
+        final SparseIntArray uidRules = mUidFirewallStandbyRules;
+        uidRules.clear();
+
         // Fully update the app idle firewall chain.
-        SparseIntArray uidRules = new SparseIntArray();
         final List<UserInfo> users = mUserManager.getUsers();
         for (int ui = users.size() - 1; ui >= 0; ui--) {
             UserInfo user = users.get(ui);
@@ -2138,6 +2144,7 @@
                 }
             }
         }
+
         setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules);
     }
 
@@ -2150,11 +2157,14 @@
         } else {
             setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
         }
+
+        updateRulesForUidLocked(uid);
     }
 
     void updateRulesForAppIdleParoleLocked() {
         boolean enableChain = !mUsageStats.isAppIdleParoleOn();
         enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain);
+        updateRulesForUidsLocked(mUidFirewallStandbyRules);
     }
 
     /**
@@ -2224,6 +2234,12 @@
         return true;
     }
 
+    void updateRulesForUidsLocked(SparseIntArray uids) {
+        for (int i = 0; i < uids.size(); i++) {
+            updateRulesForUidLocked(uids.keyAt(i));
+        }
+    }
+
     /**
      * Applies network rules to bandwidth and firewall controllers based on uid policy.
      * @param uid The uid for which to apply the latest policy
@@ -2245,8 +2261,7 @@
         final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
         final boolean uidForeground = isUidForegroundLocked(uid);
 
-        // derive active rules based on policy and active state
-
+        // Derive active rules based on policy and active state
         int appId = UserHandle.getAppId(uid);
         int uidRules = RULE_ALLOW_ALL;
         if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
@@ -2269,20 +2284,27 @@
             }
         }
 
-        final int oldRules = mUidRules.get(uid);
+        // Check dozable state, which is whitelist
+        if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)
+                && mUidFirewallDozableRules.get(uid, FIREWALL_RULE_DEFAULT) != FIREWALL_RULE_ALLOW) {
+            uidRules = RULE_REJECT_ALL;
+        }
 
+        // Check standby state, which is blacklist
+        if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)
+                && mUidFirewallStandbyRules.get(uid, FIREWALL_RULE_DEFAULT) == FIREWALL_RULE_DENY) {
+            uidRules = RULE_REJECT_ALL;
+        }
+
+        final int oldRules = mUidRules.get(uid);
         if (uidRules == RULE_ALLOW_ALL) {
             mUidRules.delete(uid);
         } else {
             mUidRules.put(uid, uidRules);
         }
 
-        // Update bandwidth rules if necessary
-        final boolean oldRejectMetered = (oldRules & RULE_REJECT_METERED) != 0;
-        final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
-        if (oldRejectMetered != rejectMetered) {
-            setUidNetworkRules(uid, rejectMetered);
-        }
+        final boolean rejectMetered = (uidRules == RULE_REJECT_METERED);
+        setUidNetworkRules(uid, rejectMetered);
 
         // dispatch changed rule to existing listeners
         if (oldRules != uidRules) {
@@ -2468,6 +2490,12 @@
      * Add or remove a uid to the firewall blacklist for all network ifaces.
      */
     private void setUidFirewallRule(int chain, int uid, int rule) {
+        if (chain == FIREWALL_CHAIN_DOZABLE) {
+            mUidFirewallDozableRules.put(uid, rule);
+        } else if (chain == FIREWALL_CHAIN_STANDBY) {
+            mUidFirewallStandbyRules.put(uid, rule);
+        }
+
         try {
             mNetworkManager.setFirewallUidRule(chain, uid, rule);
         } catch (IllegalStateException e) {
@@ -2481,6 +2509,12 @@
      * Add or remove a uid to the firewall blacklist for all network ifaces.
      */
     private void enableFirewallChainLocked(int chain, boolean enable) {
+        if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
+                mFirewallChainStates.get(chain) == enable) {
+            // All is the same, nothing to do.
+            return;
+        }
+        mFirewallChainStates.put(chain, enable);
         try {
             mNetworkManager.setFirewallChainEnabled(chain, enable);
         } catch (IllegalStateException e) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3e27c95..f7f38db 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8471,6 +8471,7 @@
 
         final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
 
+        boolean runtimePermissionsRevoked = false;
         int[] changedRuntimePermissionUserIds = EMPTY_INT_ARRAY;
 
         boolean changedInstallPermission = false;
@@ -8480,6 +8481,17 @@
             if (!ps.isSharedUser()) {
                 origPermissions = new PermissionsState(permissionsState);
                 permissionsState.reset();
+            } else {
+                // We need to know only about runtime permission changes since the
+                // calling code always writes the install permissions state but
+                // the runtime ones are written only if changed. The only cases of
+                // changed runtime permissions here are promotion of an install to
+                // runtime and revocation of a runtime from a shared user.
+                changedRuntimePermissionUserIds = revokeUnusedSharedUserPermissionsLPw(
+                        ps.sharedUser, UserManagerService.getInstance().getUserIds());
+                if (!ArrayUtils.isEmpty(changedRuntimePermissionUserIds)) {
+                    runtimePermissionsRevoked = true;
+                }
             }
         }
 
@@ -8695,9 +8707,11 @@
             ps.installPermissionsFixed = true;
         }
 
-        // Persist the runtime permissions state for users with changes.
+        // Persist the runtime permissions state for users with changes. If permissions
+        // were revoked because no app in the shared user declares them we have to
+        // write synchronously to avoid losing runtime permissions state.
         for (int userId : changedRuntimePermissionUserIds) {
-            mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+            mSettings.writeRuntimePermissionsForUserLPr(userId, runtimePermissionsRevoked);
         }
 
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -12248,6 +12262,66 @@
         }
     }
 
+    private int[] revokeUnusedSharedUserPermissionsLPw(SharedUserSetting su, int[] allUserIds) {
+        // Collect all used permissions in the UID
+        ArraySet<String> usedPermissions = new ArraySet<>();
+        final int packageCount = su.packages.size();
+        for (int i = 0; i < packageCount; i++) {
+            PackageSetting ps = su.packages.valueAt(i);
+            if (ps.pkg == null) {
+                continue;
+            }
+            final int requestedPermCount = ps.pkg.requestedPermissions.size();
+            for (int j = 0; j < requestedPermCount; j++) {
+                String permission = ps.pkg.requestedPermissions.get(j);
+                BasePermission bp = mSettings.mPermissions.get(permission);
+                if (bp != null) {
+                    usedPermissions.add(permission);
+                }
+            }
+        }
+
+        PermissionsState permissionsState = su.getPermissionsState();
+        // Prune install permissions
+        List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates();
+        final int installPermCount = installPermStates.size();
+        for (int i = installPermCount - 1; i >= 0;  i--) {
+            PermissionState permissionState = installPermStates.get(i);
+            if (!usedPermissions.contains(permissionState.getName())) {
+                BasePermission bp = mSettings.mPermissions.get(permissionState.getName());
+                if (bp != null) {
+                    permissionsState.revokeInstallPermission(bp);
+                    permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+                            PackageManager.MASK_PERMISSION_FLAGS, 0);
+                }
+            }
+        }
+
+        int[] runtimePermissionChangedUserIds = EmptyArray.INT;
+
+        // Prune runtime permissions
+        for (int userId : allUserIds) {
+            List<PermissionState> runtimePermStates = permissionsState
+                    .getRuntimePermissionStates(userId);
+            final int runtimePermCount = runtimePermStates.size();
+            for (int i = runtimePermCount - 1; i >= 0; i--) {
+                PermissionState permissionState = runtimePermStates.get(i);
+                if (!usedPermissions.contains(permissionState.getName())) {
+                    BasePermission bp = mSettings.mPermissions.get(permissionState.getName());
+                    if (bp != null) {
+                        permissionsState.revokeRuntimePermission(bp, userId);
+                        permissionsState.updatePermissionFlags(bp, userId,
+                                PackageManager.MASK_PERMISSION_FLAGS, 0);
+                        runtimePermissionChangedUserIds = ArrayUtils.appendInt(
+                                runtimePermissionChangedUserIds, userId);
+                    }
+                }
+            }
+        }
+
+        return runtimePermissionChangedUserIds;
+    }
+
     private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
             String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res,
             UserHandle user) {
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 66170d4..5d8b1d2 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -100,6 +100,9 @@
     private static final String SEAPP_HASH_FILE =
             Environment.getDataDirectory().toString() + "/system/seapp_hash";
 
+    // Append privapp to existing seinfo label
+    private static final String PRIVILEGED_APP_STR = ":privapp";
+
     /**
      * Load the mac_permissions.xml file containing all seinfo assignments used to
      * label apps. The loaded mac_permissions.xml file is determined by the
@@ -313,6 +316,9 @@
             }
         }
 
+        if (pkg.applicationInfo.isPrivilegedApp())
+            pkg.applicationInfo.seinfo += PRIVILEGED_APP_STR;
+
         if (DEBUG_POLICY_INSTALL) {
             Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
                     "seinfo=" + pkg.applicationInfo.seinfo);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 341410d..80697ed 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -356,6 +356,27 @@
     }
 
     @Override
+    public boolean isSameProfileGroup(int userId, int otherUserId) {
+        if (userId == otherUserId) return true;
+        checkManageUsersPermission("check if in the same profile group");
+        synchronized (mPackagesLock) {
+            return isSameProfileGroupLocked(userId, otherUserId);
+        }
+    }
+
+    private boolean isSameProfileGroupLocked(int userId, int otherUserId) {
+        UserInfo userInfo = getUserInfoLocked(userId);
+        if (userInfo == null || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+            return false;
+        }
+        UserInfo otherUserInfo = getUserInfoLocked(otherUserId);
+        if (otherUserInfo == null || otherUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+            return false;
+        }
+        return userInfo.profileGroupId == otherUserInfo.profileGroupId;
+    }
+
+    @Override
     public UserInfo getProfileParent(int userHandle) {
         checkManageUsersPermission("get the profile parent");
         synchronized (mPackagesLock) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 16add37..e354029 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4614,7 +4614,8 @@
                 final int fl = PolicyControl.getWindowFlags(null, lp);
                 if (localLOGV) {
                     Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
-                            + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
+                            + " shown position: "
+                            + mTopFullscreenOpaqueWindowState.getShownPositionLw());
                     Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
                             + " lp.flags=0x" + Integer.toHexString(fl));
                 }
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index 4ae3154..db2b941 100644
--- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -22,6 +22,7 @@
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.GestureDetector;
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.WindowManagerPolicy.PointerEventListener;
 import android.widget.OverScroller;
@@ -130,8 +131,7 @@
                 }
                 break;
             case MotionEvent.ACTION_HOVER_MOVE:
-                if (event.getPointerCount() == 1
-                        && event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
+                if (event.getDevice().getSources() == InputDevice.SOURCE_MOUSE) {
                     if (!mMouseHoveringAtEdge && event.getY() == 0) {
                         mCallbacks.onMouseHoverAtTop();
                         mMouseHoveringAtEdge = true;
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 66ae9ef..d713751 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -206,8 +206,8 @@
         sTempFloats[Matrix.MSKEW_Y] = windowState.mWinAnimator.mDtDx;
         sTempFloats[Matrix.MSKEW_X] = windowState.mWinAnimator.mDsDy;
         sTempFloats[Matrix.MSCALE_Y] = windowState.mWinAnimator.mDtDy;
-        sTempFloats[Matrix.MTRANS_X] = windowState.mShownFrame.left;
-        sTempFloats[Matrix.MTRANS_Y] = windowState.mShownFrame.top;
+        sTempFloats[Matrix.MTRANS_X] = windowState.mShownPosition.x;
+        sTempFloats[Matrix.MTRANS_Y] = windowState.mShownPosition.y;
         sTempFloats[Matrix.MPERSP_0] = 0;
         sTempFloats[Matrix.MPERSP_1] = 0;
         sTempFloats[Matrix.MPERSP_2] = 1;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index cc51d20..9f44fea 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -760,26 +760,24 @@
                     a = createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
                             containingFrame, surfaceInsets, taskId);
                 } else {
+                    mTmpFromClipRect.set(containingFrame);
+                    // exclude top screen decor (status bar) region from the source clip.
+                    mTmpFromClipRect.top = contentInsets.top;
                     // App window scaling up to become full screen
+                    mTmpToClipRect.set(containingFrame);
                     if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                         // In portrait, we scale the width and clip to the top/left square
                         scale = thumbWidth / appWidth;
                         scaledTopDecor = (int) (scale * contentInsets.top);
                         int unscaledThumbHeight = (int) (thumbHeight / scale);
-                        mTmpFromClipRect.set(containingFrame);
-                        mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
-                        mTmpToClipRect.set(containingFrame);
+                        mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
                     } else {
                         // In landscape, we scale the height and clip to the top/left square
                         scale = thumbHeight / (appHeight - contentInsets.top);
                         scaledTopDecor = (int) (scale * contentInsets.top);
                         int unscaledThumbWidth = (int) (thumbWidth / scale);
-                        mTmpFromClipRect.set(containingFrame);
-                        mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth);
-                        mTmpToClipRect.set(containingFrame);
+                        mTmpFromClipRect.right = mTmpFromClipRect.left + unscaledThumbWidth;
                     }
-                    // exclude top screen decor (status bar) region from the source clip.
-                    mTmpFromClipRect.top = contentInsets.top;
 
                     mNextAppTransitionInsets.set(contentInsets);
 
@@ -821,25 +819,23 @@
             }
             case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
                 // App window scaling down from full screen
+                mTmpFromClipRect.set(containingFrame);
+                mTmpToClipRect.set(containingFrame);
+                // exclude top screen decor (status bar) region from the destination clip.
+                mTmpToClipRect.top = contentInsets.top;
                 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                     // In portrait, we scale the width and clip to the top/left square
                     scale = thumbWidth / appWidth;
                     scaledTopDecor = (int) (scale * contentInsets.top);
                     int unscaledThumbHeight = (int) (thumbHeight / scale);
-                    mTmpFromClipRect.set(containingFrame);
-                    mTmpToClipRect.set(containingFrame);
-                    mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight);
+                    mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
                 } else {
                     // In landscape, we scale the height and clip to the top/left square
                     scale = thumbHeight / (appHeight - contentInsets.top);
                     scaledTopDecor = (int) (scale * contentInsets.top);
                     int unscaledThumbWidth = (int) (thumbWidth / scale);
-                    mTmpFromClipRect.set(containingFrame);
-                    mTmpToClipRect.set(containingFrame);
-                    mTmpToClipRect.right = (mTmpToClipRect.left + unscaledThumbWidth);
+                    mTmpToClipRect.right = mTmpToClipRect.left + unscaledThumbWidth;
                 }
-                // exclude top screen decor (status bar) region from the destination clip.
-                mTmpToClipRect.top = contentInsets.top;
 
                 mNextAppTransitionInsets.set(contentInsets);
 
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 3c28648..2d87123 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -206,7 +206,8 @@
         }
         if (distance <= mSideMargin) {
             try {
-                mDisplayContent.mService.mActivityManager.resizeStack(mTaskStack.mStackId, null);
+                mDisplayContent.mService.mActivityManager.resizeStack(
+                        mTaskStack.mStackId, null, true);
             } catch (RemoteException e) {
                 // This can't happen because we are in the same process.
             }
@@ -364,7 +365,7 @@
         }
         mLastResizeRect.set(mTmpRect);
         try {
-            mDisplayContent.mService.mActivityManager.resizeStack(DOCKED_STACK_ID, mTmpRect);
+            mDisplayContent.mService.mActivityManager.resizeStack(DOCKED_STACK_ID, mTmpRect, true);
         } catch (RemoteException e) {
             // This can't happen because we are in the same process.
         }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ca358b1..b409cea 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -238,8 +238,8 @@
                     // Post message to inform activity manager of the bounds change simulating
                     // a one-way call. We do this to prevent a deadlock between window manager
                     // lock and activity manager lock been held.
-                    mService.mH.sendMessage(
-                            mService.mH.obtainMessage(RESIZE_STACK, mStackId, UNUSED, mBounds));
+                    mService.mH.sendMessage(mService.mH.obtainMessage(
+                            RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mBounds));
                 }
             }
         }
@@ -399,8 +399,11 @@
             if (dockedStack != null) {
                 dockedStack.getRawBounds(mTmpRect2);
             }
-            getInitialDockedStackBounds(mTmpRect, bounds, mStackId, mTmpRect2,
-                    mDisplayContent.mDividerControllerLocked.getWidthAdjustment());
+            final boolean dockedOnTopOrLeft = WindowManagerService.sDockedStackCreateMode
+                    == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+            getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
+                    mDisplayContent.mDividerControllerLocked.getWidthAdjustment(),
+                    dockedOnTopOrLeft);
         }
 
         updateDisplayInfo(bounds);
@@ -413,28 +416,60 @@
         }
     }
 
+    void getStackDockedModeBoundsLocked(Rect outBounds) {
+        if (mStackId == DOCKED_STACK_ID
+                || mStackId > LAST_STATIC_STACK_ID
+                || mDisplayContent == null) {
+            outBounds.set(mBounds);
+            return;
+        }
+
+        final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
+        if (dockedStack == null) {
+            // Not sure why you are calling this method when there is no docked stack...
+            throw new IllegalStateException(
+                    "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
+        }
+
+        @DockSide
+        final int dockedSide = dockedStack.getDockSide();
+        if (dockedSide == DOCKED_INVALID) {
+            // Not sure how you got here...Only thing we can do is return current bounds.
+            Slog.e(TAG, "Failed to get valid docked side for docked stack=" + dockedStack);
+            outBounds.set(mBounds);
+            return;
+        }
+
+        mDisplayContent.getLogicalDisplayRect(mTmpRect);
+        dockedStack.getRawBounds(mTmpRect2);
+        final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
+        getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2,
+                mDisplayContent.mDividerControllerLocked.getWidthAdjustment(), dockedOnTopOrLeft);
+
+    }
+
     /**
-     * Outputs the initial bounds a stack should be given the presence of a docked stack on the
-     * display.
+     * Outputs the bounds a stack should be given the presence of a docked stack on the display.
      * @param displayRect The bounds of the display the docked stack is on.
      * @param outBounds Output bounds that should be used for the stack.
      * @param stackId Id of stack we are calculating the bounds for.
      * @param dockedBounds Bounds of the docked stack.
-     * @param adjustment
+     * @param adjustment Additional adjustment to make to the output bounds close to the side of the
+     *                   dock.
+     * @param dockOntopOrLeft If the docked stack is on the top or left side of the screen.
      */
-    private static void getInitialDockedStackBounds(
-            Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int adjustment) {
+    private static void getStackDockedModeBounds(
+            Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int adjustment,
+            boolean dockOntopOrLeft) {
         final boolean dockedStack = stackId == DOCKED_STACK_ID;
         final boolean splitHorizontally = displayRect.width() > displayRect.height();
-        final boolean topOrLeftCreateMode =
-                WindowManagerService.sDockedStackCreateMode == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 
         outBounds.set(displayRect);
         if (dockedStack) {
             // The initial bounds of the docked stack when it is created half the screen space and
             // its bounds can be adjusted after that. The bounds of all other stacks are adjusted
             // to occupy whatever screen space the docked stack isn't occupying.
-            if (topOrLeftCreateMode) {
+            if (dockOntopOrLeft) {
                 if (splitHorizontally) {
                     outBounds.right = displayRect.centerX() - adjustment;
                 } else {
@@ -451,7 +486,7 @@
         }
 
         // Other stacks occupy whatever space is left by the docked stack.
-        if (!topOrLeftCreateMode) {
+        if (!dockOntopOrLeft) {
             if (splitHorizontally) {
                 outBounds.right = dockedBounds.left - adjustment;
             } else {
@@ -477,8 +512,10 @@
         final Rect bounds = new Rect();
         mDisplayContent.getLogicalDisplayRect(bounds);
         if (!fullscreen) {
-            getInitialDockedStackBounds(bounds, bounds, FULLSCREEN_WORKSPACE_STACK_ID, dockedBounds,
-                    mDisplayContent.mDividerControllerLocked.getWidth());
+            final boolean dockedOnTopOrLeft = WindowManagerService.sDockedStackCreateMode
+                    == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+            getStackDockedModeBounds(bounds, bounds, FULLSCREEN_WORKSPACE_STACK_ID, dockedBounds,
+                    mDisplayContent.mDividerControllerLocked.getWidth(), dockedOnTopOrLeft);
         }
 
         final int count = mService.mStackIdToStack.size();
@@ -489,7 +526,8 @@
                     && otherStackId >= FIRST_STATIC_STACK_ID
                     && otherStackId <= LAST_STATIC_STACK_ID) {
                 mService.mH.sendMessage(
-                        mService.mH.obtainMessage(RESIZE_STACK, otherStackId, UNUSED, bounds));
+                        mService.mH.obtainMessage(RESIZE_STACK, otherStackId,
+                                1 /*allowResizeInDockedMode*/, bounds));
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 1a946b2..7f2f2cd 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -419,7 +419,7 @@
                     winAnimator.computeShownFrameLocked();
                     // No need to lay out the windows - we can just set the wallpaper position
                     // directly.
-                    winAnimator.setWallpaperOffset(wallpaper.mShownFrame);
+                    winAnimator.setWallpaperOffset(wallpaper.mShownPosition);
                     // We only want to be synchronous with one wallpaper.
                     sync = false;
                 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0932f15..f571d9c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4617,6 +4617,17 @@
         }
     }
 
+    public void getStackDockedModeBounds(int stackId, Rect bounds) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack != null) {
+                stack.getStackDockedModeBoundsLocked(bounds);
+                return;
+            }
+            bounds.setEmpty();
+        }
+    }
+
     public void getStackBounds(int stackId, Rect bounds) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
@@ -7779,7 +7790,7 @@
                 break;
                 case RESIZE_STACK: {
                     try {
-                        mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj);
+                        mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1);
                     } catch (RemoteException e) {
                         // This will not happen since we are in the same process.
                     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 383ad8c..e72d35c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -29,15 +29,14 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION;
-import static com.android.server.wm.WindowManagerService.DEBUG_DIM_LAYER;
 import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerService.DEBUG_POWER;
 import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 
-import android.app.ActivityManager;
 import android.app.AppOpsManager;
+import android.graphics.Point;
 import android.os.PowerManager;
 import android.os.RemoteCallbackList;
 import android.os.SystemClock;
@@ -159,11 +158,10 @@
     private boolean mConfigHasChanged;
 
     /**
-     * Actual frame shown on-screen (may be modified by animation).  These
-     * are in the screen's coordinate space (WITH the compatibility scale
-     * applied).
+     * Actual position of the surface shown on-screen (may be modified by animation). These are
+     * in the screen's coordinate space (WITH the compatibility scale applied).
      */
-    final RectF mShownFrame = new RectF();
+    final Point mShownPosition = new Point();
 
     /**
      * Insets that determine the actually visible area.  These are in the application's
@@ -787,8 +785,8 @@
     }
 
     @Override
-    public RectF getShownFrameLw() {
-        return mShownFrame;
+    public Point getShownPositionLw() {
+        return mShownPosition;
     }
 
     @Override
@@ -1822,7 +1820,7 @@
             }
         }
         pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
-                pw.print(" mShownFrame="); mShownFrame.printShortString(pw);
+                pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
                 pw.print(" isReadyForDisplay()="); pw.println(isReadyForDisplay());
         if (dumpAll) {
             pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 2733933..1913604 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1190,9 +1190,7 @@
             mDtDy = tmpFloats[Matrix.MSCALE_Y];
             float x = tmpFloats[Matrix.MTRANS_X];
             float y = tmpFloats[Matrix.MTRANS_Y];
-            int w = frame.width();
-            int h = frame.height();
-            mWin.mShownFrame.set(x, y, x+w, y+h);
+            mWin.mShownPosition.set((int) x, (int) y);
 
             // Now set the alpha...  but because our current hardware
             // can't do alpha transformation on a non-opaque surface,
@@ -1287,13 +1285,13 @@
             float y = tmpFloats[Matrix.MTRANS_Y];
             int w = frame.width();
             int h = frame.height();
-            mWin.mShownFrame.set(x, y, x + w, y + h);
+            mWin.mShownPosition.set((int) x, (int) y);
 
             mShownAlpha = mAlpha;
         } else {
-            mWin.mShownFrame.set(mWin.mFrame);
+            mWin.mShownPosition.set(mWin.mFrame.left, mWin.mFrame.top);
             if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
-                mWin.mShownFrame.offset(mWin.mXOffset, mWin.mYOffset);
+                mWin.mShownPosition.offset(mWin.mXOffset, mWin.mYOffset);
             }
             mShownAlpha = mAlpha;
             mHaveMatrix = false;
@@ -1458,8 +1456,8 @@
     void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
         final WindowState w = mWin;
 
-        float left = w.mShownFrame.left;
-        float top = w.mShownFrame.top;
+        float left = w.mShownPosition.x;
+        float top = w.mShownPosition.y;
 
         int width;
         int height;
@@ -1701,10 +1699,10 @@
         }
     }
 
-    void setWallpaperOffset(RectF shownFrame) {
+    void setWallpaperOffset(Point shownPosition) {
         final LayoutParams attrs = mWin.getAttrs();
-        final int left = ((int) shownFrame.left) - attrs.surfaceInsets.left;
-        final int top = ((int) shownFrame.top) - attrs.surfaceInsets.top;
+        final int left = shownPosition.x - attrs.surfaceInsets.left;
+        final int top = shownPosition.y - attrs.surfaceInsets.top;
         if (mSurfaceX != left || mSurfaceY != top) {
             if (mAnimating) {
                 // If this window (or its app token) is animating, then the position
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 112646a..247562f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -717,7 +717,8 @@
                     /*
                      * Updates the shown frame before we set up the surface. This is needed because
                      * the resizing could change the top-left position (in addition to size) of the
-                     * window. setSurfaceBoundariesLocked uses mShownFrame to position the surface.
+                     * window. setSurfaceBoundariesLocked uses mShownPosition to position the
+                      * surface.
                      */
                     winAnimator.computeShownFrameLocked();
                     winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 1d4f047..8cb0a13 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -199,6 +199,7 @@
     void setShowTouches(bool enabled);
     void setInteractive(bool interactive);
     void reloadCalibration();
+    void setPointerIconShape(int32_t iconId);
 
     /* --- InputReaderPolicyInterface implementation --- */
 
@@ -237,6 +238,7 @@
     /* --- PointerControllerPolicyInterface implementation --- */
 
     virtual void loadPointerResources(PointerResources* outResources);
+    virtual void loadAdditionalMouseResources(std::map<int, SpriteIcon>* outResources);
 
 private:
     sp<InputManager> mInputManager;
@@ -779,6 +781,15 @@
             InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION);
 }
 
+void NativeInputManager::setPointerIconShape(int32_t iconId) {
+  AutoMutex _l(mLock);
+  sp<PointerController> controller = mLocked.pointerController.promote();
+  if (controller != NULL) {
+        // Use 0 (the default icon) for ARROW.
+        controller->updatePointerShape((iconId == POINTER_ICON_STYLE_ARROW) ? 0 : iconId);
+  }
+}
+
 TouchAffineTransformation NativeInputManager::getTouchAffineTransformation(
         JNIEnv *env, jfloatArray matrixArr) {
     ScopedFloatArrayRO matrix(env, matrixArr);
@@ -1029,6 +1040,15 @@
             &outResources->spotAnchor);
 }
 
+void NativeInputManager::loadAdditionalMouseResources(std::map<int, SpriteIcon>* outResources) {
+    JNIEnv* env = jniEnv();
+
+    for (int iconId = POINTER_ICON_STYLE_CONTEXT_MENU; iconId <= POINTER_ICON_STYLE_GRABBING;
+             ++iconId) {
+        loadSystemIconAsSprite(env, mContextObj, iconId, &((*outResources)[iconId]));
+    }
+}
+
 
 // ----------------------------------------------------------------------------
 
@@ -1367,6 +1387,11 @@
     im->getInputManager()->getDispatcher()->monitor();
 }
 
+static void nativeSetPointerIconShape(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, jint iconId) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+    im->setPointerIconShape(iconId);
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gInputManagerMethods[] = {
@@ -1425,6 +1450,8 @@
             (void*) nativeDump },
     { "nativeMonitor", "(J)V",
             (void*) nativeMonitor },
+    { "nativeSetPointerIconShape", "(JI)V",
+            (void*) nativeSetPointerIconShape },
 };
 
 #define FIND_CLASS(var, className) \
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 8b37ec4..13e600e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -314,6 +314,8 @@
                 mAppIdleParoled = paroled;
                 if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleParoled);
                 if (paroled) {
+                    postParoleEndTimeout();
+                } else {
                     mLastAppIdleParoledTime = checkAndGetTimeLocked();
                     postNextParoleTimeout();
                 }
@@ -404,8 +406,6 @@
                 if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
                     if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
                     setAppIdleParoled(true);
-                    // Make sure it ends at some point
-                    postParoleEndTimeout();
                 } else {
                     if (DEBUG) Slog.d(TAG, "Not long enough to go to parole");
                     postNextParoleTimeout();
@@ -492,7 +492,6 @@
             if (!deviceIdle
                     && timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
                 if (DEBUG) Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
-                postNextParoleTimeout();
                 setAppIdleParoled(true);
             } else if (deviceIdle) {
                 if (DEBUG) Slog.i(TAG, "Device idle, back to prison");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
index 3ca0c84..31d859f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
@@ -87,6 +87,7 @@
     // This is an indirect indication of the microphone being open in some other application.
     private boolean mServiceDisabled = false;
     private boolean mStarted = false;
+    private boolean mRecognitionAborted = false;
     private PowerSaveModeListener mPowerSaveModeListener;
 
     SoundTriggerHelper(Context context) {
@@ -386,8 +387,9 @@
 
     private void onRecognitionAbortLocked() {
         Slog.w(TAG, "Recognition aborted");
-        // No-op
-        // This is handled via service state changes instead.
+        // If abort has been called, the hardware has already stopped recognition, so we shouldn't
+        // call it again when we process the state change.
+        mRecognitionAborted = true;
     }
 
     private void onRecognitionFailureLocked() {
@@ -490,8 +492,13 @@
             }
             return status;
         } else {
-            // Stop recognition.
-            int status = mModule.stopRecognition(mCurrentSoundModelHandle);
+            // Stop recognition (only if we haven't been aborted).
+            int status = STATUS_OK;
+            if (!mRecognitionAborted) {
+                status = mModule.stopRecognition(mCurrentSoundModelHandle);
+            } else {
+                mRecognitionAborted = false;
+            }
             if (status != SoundTrigger.STATUS_OK) {
                 Slog.w(TAG, "stopRecognition call failed with " + status);
                 if (notify) {
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 5c64168..abb8803 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -584,9 +584,8 @@
             out.writeInt(1);
             mIcon.writeToParcel(out, flags);
         }
-
-        out.writeBundle(mExtras);
         out.writeByte((byte) (mIsEnabled ? 1 : 0));
+        out.writeBundle(mExtras);
     }
 
     public static final Creator<PhoneAccount> CREATOR
@@ -628,8 +627,8 @@
         } else {
             mIcon = null;
         }
-        mExtras = in.readBundle();
         mIsEnabled = in.readByte() == 1;
+        mExtras = in.readBundle();
     }
 
     @Override
@@ -645,7 +644,7 @@
             sb.append(scheme)
                     .append(" ");
         }
-        sb.append(" Extras : ");
+        sb.append(" Extras: ");
         sb.append(mExtras);
         sb.append("]");
         return sb.toString();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ba91254..7cf5f73 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -191,7 +191,7 @@
     public static final String
             KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
 
-   /**
+    /**
      * Override the platform's notion of a network operator being considered roaming.
      * Value is string array of MCCMNCs to be considered roaming for 3GPP RATs.
      */
@@ -468,6 +468,12 @@
      */
     public static final String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
 
+    /**
+     * Allow user to add APNs
+     * @hide
+     */
+    public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
+
     // These variables are used by the MMS service and exposed through another API, {@link
     // SmsManager}. The variable names and string values are copied from there.
     public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
@@ -567,6 +573,7 @@
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING, "");
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING, "");
         sDefaults.putBoolean(KEY_CSP_ENABLED_BOOL, false);
+        sDefaults.putBoolean(KEY_ALLOW_ADDING_APNS_BOOL, true);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
 
         sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null);
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index f535e5d..fced667 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -911,7 +911,7 @@
         else if (tdScdmaDbm >= -49) level = SIGNAL_STRENGTH_GREAT;
         else if (tdScdmaDbm >= -73) level = SIGNAL_STRENGTH_GOOD;
         else if (tdScdmaDbm >= -97) level = SIGNAL_STRENGTH_MODERATE;
-        else if (tdScdmaDbm >= -120) level = SIGNAL_STRENGTH_POOR;
+        else if (tdScdmaDbm >= -110) level = SIGNAL_STRENGTH_POOR;
         else level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
 
         if (DBG) log("getTdScdmaLevel = " + level);
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 37ffa06..e11c8d3 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -334,7 +334,8 @@
 
     @Override
     public String toString() {
-        return "{id=" + mId + ", iccId=" + mIccId + " simSlotIndex=" + mSimSlotIndex
+        String iccIdToPrint = mIccId != null ? mIccId.substring(0, 9) + "XXXXXXXXXXX" : null;
+        return "{id=" + mId + ", iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex
                 + " displayName=" + mDisplayName + " carrierName=" + mCarrierName
                 + " nameSource=" + mNameSource + " iconTint=" + mIconTint
                 + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index b2dc29a..93b3f4f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -73,6 +73,7 @@
 import android.os.Parcel;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -1130,6 +1131,11 @@
                 public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
                     return false;
                 }
+
+                @Override
+                public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+                  String[] args, ResultReceiver resultReceiver) {
+                }
             };
         }
         return mBinder;