Merge "Implement system bar color runtime API"
diff --git a/api/current.txt b/api/current.txt
index d3996e4..b03c079 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29,9 +29,8 @@
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
     field public static final java.lang.String BIND_ROUTE_PROVIDER = "android.permission.BIND_ROUTE_PROVIDER";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
-    field public static final java.lang.String BIND_TRUST_AGENT_SERVICE = "android.permission.BIND_TRUST_AGENT_SERVICE";
+    field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
-    field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
     field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
@@ -1017,7 +1016,6 @@
     field public static final int selectableItemBackground = 16843534; // 0x101030e
     field public static final int selectedDateVerticalBar = 16843591; // 0x1010347
     field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
-    field public static final int sessionService = 16843841; // 0x1010441
     field public static final int settingsActivity = 16843301; // 0x1010225
     field public static final int shadowColor = 16843105; // 0x1010161
     field public static final int shadowDx = 16843106; // 0x1010162
@@ -3238,7 +3236,6 @@
     method public int getTaskId();
     method public final java.lang.CharSequence getTitle();
     method public final int getTitleColor();
-    method public android.app.VoiceInteractor getVoiceInteractor();
     method public final int getVolumeControlStream();
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
@@ -3250,7 +3247,6 @@
     method public boolean isFinishing();
     method public boolean isImmersive();
     method public boolean isTaskRoot();
-    method public boolean isVoiceInteraction();
     method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
     method public boolean moveTaskToBack(boolean);
     method public boolean navigateUpTo(android.content.Intent);
@@ -3352,12 +3348,12 @@
     method public final void setProgressBarIndeterminate(boolean);
     method public final void setProgressBarIndeterminateVisibility(boolean);
     method public final void setProgressBarVisibility(boolean);
-    method public void setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
     method public void setRequestedOrientation(int);
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
     method public final void setSecondaryProgress(int);
     method public void setSharedElementListener(android.app.SharedElementListener);
+    method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
     method public void setTitle(java.lang.CharSequence);
     method public void setTitle(int);
     method public deprecated void setTitleColor(int);
@@ -3482,7 +3478,6 @@
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
-    field public android.app.ActivityManager.RecentsActivityValues activityValues;
     field public android.content.Intent baseIntent;
     field public java.lang.CharSequence description;
     field public int id;
@@ -3490,21 +3485,6 @@
     field public int persistentId;
   }
 
-  public static class ActivityManager.RecentsActivityValues implements android.os.Parcelable {
-    ctor public ActivityManager.RecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
-    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap, int);
-    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap);
-    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence);
-    ctor public ActivityManager.RecentsActivityValues();
-    method public int describeContents();
-    method public void readFromParcel(android.os.Parcel);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public int colorPrimary;
-    field public android.graphics.Bitmap icon;
-    field public java.lang.CharSequence label;
-  }
-
   public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
     ctor public ActivityManager.RunningAppProcessInfo();
     ctor public ActivityManager.RunningAppProcessInfo(java.lang.String, int, java.lang.String[]);
@@ -3574,6 +3554,21 @@
     field public android.content.ComponentName topActivity;
   }
 
+  public static class ActivityManager.TaskDescription implements android.os.Parcelable {
+    ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
+    ctor public ActivityManager.TaskDescription(java.lang.CharSequence, android.graphics.Bitmap, int);
+    ctor public ActivityManager.TaskDescription(java.lang.CharSequence, android.graphics.Bitmap);
+    ctor public ActivityManager.TaskDescription(java.lang.CharSequence);
+    ctor public ActivityManager.TaskDescription();
+    method public int describeContents();
+    method public android.graphics.Bitmap getIcon();
+    method public java.lang.CharSequence getLabel();
+    method public int getPrimaryColor();
+    method public void readFromParcel(android.os.Parcel);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public class ActivityOptions {
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
     method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
@@ -4515,6 +4510,7 @@
     ctor public Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.Notification.Action clone();
     method public int describeContents();
+    method public android.os.Bundle getExtras();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public android.app.PendingIntent actionIntent;
@@ -4522,6 +4518,14 @@
     field public java.lang.CharSequence title;
   }
 
+  public static class Notification.Action.Builder {
+    ctor public Notification.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+    ctor public Notification.Action.Builder(android.app.Notification.Action);
+    method public android.app.Notification.Action.Builder addExtras(android.os.Bundle);
+    method public android.app.Notification.Action build();
+    method public android.os.Bundle getExtras();
+  }
+
   public static class Notification.BigPictureStyle extends android.app.Notification.Style {
     ctor public Notification.BigPictureStyle();
     ctor public Notification.BigPictureStyle(android.app.Notification.Builder);
@@ -4542,6 +4546,7 @@
   public static class Notification.Builder {
     ctor public Notification.Builder(android.content.Context);
     method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.app.Notification.Builder addAction(android.app.Notification.Action);
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
@@ -4902,29 +4907,6 @@
     field public static final int MODE_NIGHT_YES = 2; // 0x2
   }
 
-  public class VoiceInteractor {
-    method public boolean submitRequest(android.app.VoiceInteractor.Request);
-    method public boolean[] supportsCommands(java.lang.String[]);
-  }
-
-  public static class VoiceInteractor.CommandRequest extends android.app.VoiceInteractor.Request {
-    ctor public VoiceInteractor.CommandRequest(java.lang.String, android.os.Bundle);
-    method public void onCommandResult(android.os.Bundle);
-  }
-
-  public static class VoiceInteractor.ConfirmationRequest extends android.app.VoiceInteractor.Request {
-    ctor public VoiceInteractor.ConfirmationRequest(java.lang.CharSequence, android.os.Bundle);
-    method public void onConfirmationResult(boolean, android.os.Bundle);
-  }
-
-  public static abstract class VoiceInteractor.Request {
-    ctor public VoiceInteractor.Request();
-    method public void cancel();
-    method public android.app.Activity getActivity();
-    method public android.content.Context getContext();
-    method public void onCancel();
-  }
-
   public final class WallpaperInfo implements android.os.Parcelable {
     ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
@@ -5235,7 +5217,7 @@
   public abstract class TaskService extends android.app.Service {
     ctor public TaskService();
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onStartTask(android.app.task.TaskParams);
+    method public abstract boolean onStartTask(android.app.task.TaskParams);
     method public abstract boolean onStopTask(android.app.task.TaskParams);
     method public final void taskFinished(android.app.task.TaskParams, boolean);
     field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_TASK_SERVICE";
@@ -7122,7 +7104,6 @@
     field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
     field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
     field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
-    field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
     field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
@@ -12298,12 +12279,16 @@
     field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
   }
 
+}
+
+package android.hardware.camera2.params {
+
   public final class ColorSpaceTransform {
-    ctor public ColorSpaceTransform(android.hardware.camera2.Rational[]);
+    ctor public ColorSpaceTransform(android.util.Rational[]);
     ctor public ColorSpaceTransform(int[]);
-    method public void copyElements(android.hardware.camera2.Rational[], int);
+    method public void copyElements(android.util.Rational[], int);
     method public void copyElements(int[], int);
-    method public android.hardware.camera2.Rational getElement(int, int);
+    method public android.util.Rational getElement(int, int);
   }
 
   public final class Face {
@@ -12323,7 +12308,7 @@
     method public int getColumnCount();
     method public float getGainFactor(int, int, int);
     method public int getGainFactorCount();
-    method public android.hardware.camera2.RggbChannelVector getGainFactorVector(int, int);
+    method public android.hardware.camera2.params.RggbChannelVector getGainFactorVector(int, int);
     method public int getRowCount();
     field public static final float MINIMUM_GAIN_FACTOR = 1.0f;
   }
@@ -12332,7 +12317,7 @@
     ctor public MeteringRectangle(int, int, int, int, int);
     ctor public MeteringRectangle(android.graphics.Point, android.util.Size, int);
     ctor public MeteringRectangle(android.graphics.Rect, int);
-    method public boolean equals(android.hardware.camera2.MeteringRectangle);
+    method public boolean equals(android.hardware.camera2.params.MeteringRectangle);
     method public int getHeight();
     method public int getMeteringWeight();
     method public android.graphics.Rect getRect();
@@ -12343,12 +12328,6 @@
     method public int getY();
   }
 
-  public final class Rational {
-    ctor public Rational(int, int);
-    method public int getDenominator();
-    method public int getNumerator();
-  }
-
   public final class RggbChannelVector {
     ctor public RggbChannelVector(float, float, float, float);
     method public void copyTo(float[], int);
@@ -12364,10 +12343,17 @@
     field public static final int RED = 0; // 0x0
   }
 
-  public final class Size {
-    ctor public Size(int, int);
-    method public final int getHeight();
-    method public final int getWidth();
+  public final class StreamConfigurationMap {
+    method public final int[] getOutputFormats();
+    method public long getOutputMinFrameDuration(int, android.util.Size);
+    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
+    method public android.util.Size[] getOutputSizes(int);
+    method public long getOutputStallDuration(int, android.util.Size);
+    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public boolean isOutputSupportedFor(int);
+    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
+    method public boolean isOutputSupportedFor(android.view.Surface);
   }
 
   public final class TonemapCurve {
@@ -12384,23 +12370,6 @@
 
 }
 
-package android.hardware.camera2.params {
-
-  public final class StreamConfigurationMap {
-    method public final int[] getOutputFormats();
-    method public long getOutputMinFrameDuration(int, android.util.Size);
-    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
-    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
-    method public android.util.Size[] getOutputSizes(int);
-    method public long getOutputStallDuration(int, android.util.Size);
-    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
-    method public boolean isOutputSupportedFor(int);
-    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
-    method public boolean isOutputSupportedFor(android.view.Surface);
-  }
-
-}
-
 package android.hardware.display {
 
   public final class DisplayManager {
@@ -25327,82 +25296,16 @@
 
   public class TrustAgentService extends android.app.Service {
     ctor public TrustAgentService();
-    method protected final void enableTrust(java.lang.String, long, boolean);
+    method public final void grantTrust(java.lang.CharSequence, long, boolean);
     method public final android.os.IBinder onBind(android.content.Intent);
-    method protected void onUnlockAttempt(boolean);
-    method protected final void revokeTrust();
+    method public void onUnlockAttempt(boolean);
+    method public final void revokeTrust();
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
     field public static final java.lang.String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
   }
 
 }
 
-package android.service.voice {
-
-  public class VoiceInteractionService extends android.app.Service {
-    ctor public VoiceInteractionService();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public void startSession(android.os.Bundle);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
-    field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
-  }
-
-  public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback {
-    ctor public VoiceInteractionSession(android.content.Context);
-    ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
-    method public void finish();
-    method public android.view.LayoutInflater getLayoutInflater();
-    method public android.app.Dialog getWindow();
-    method public void hideWindow();
-    method public void onBackPressed();
-    method public abstract void onCancel(android.service.voice.VoiceInteractionSession.Request);
-    method public void onCloseSystemDialogs();
-    method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
-    method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets);
-    method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
-    method public void onCreate(android.os.Bundle);
-    method public android.view.View onCreateContentView();
-    method public void onDestroy();
-    method public abstract boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
-    method public boolean onKeyDown(int, android.view.KeyEvent);
-    method public boolean onKeyLongPress(int, android.view.KeyEvent);
-    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
-    method public boolean onKeyUp(int, android.view.KeyEvent);
-    method public void onTaskFinished(android.content.Intent, int);
-    method public void onTaskStarted(android.content.Intent, int);
-    method public void setContentView(android.view.View);
-    method public void setTheme(int);
-    method public void showWindow();
-    method public void startVoiceActivity(android.content.Intent);
-  }
-
-  public static class VoiceInteractionSession.Caller {
-  }
-
-  public static final class VoiceInteractionSession.Insets {
-    ctor public VoiceInteractionSession.Insets();
-    field public static final int TOUCHABLE_INSETS_CONTENT = 1; // 0x1
-    field public static final int TOUCHABLE_INSETS_FRAME = 0; // 0x0
-    field public static final int TOUCHABLE_INSETS_REGION = 3; // 0x3
-    field public int contentTopInsets;
-    field public int touchableInsets;
-    field public final android.graphics.Region touchableRegion;
-  }
-
-  public static class VoiceInteractionSession.Request {
-    method public void sendCancelResult();
-    method public void sendCommandResult(boolean, android.os.Bundle);
-    method public void sendConfirmResult(boolean, android.os.Bundle);
-  }
-
-  public abstract class VoiceInteractionSessionService extends android.app.Service {
-    ctor public VoiceInteractionSessionService();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.service.voice.VoiceInteractionSession onNewSession(android.os.Bundle);
-  }
-
-}
-
 package android.service.wallpaper {
 
   public abstract class WallpaperService extends android.app.Service {
@@ -27114,6 +27017,7 @@
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
     method public boolean isNetworkRoaming();
     method public void listen(android.telephony.PhoneStateListener, int);
+    method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
     field public static final int CALL_STATE_IDLE = 0; // 0x0
@@ -29986,6 +29890,12 @@
     method public T getUpper();
   }
 
+  public final class Rational {
+    ctor public Rational(int, int);
+    method public int getDenominator();
+    method public int getNumerator();
+  }
+
   public final class Size {
     ctor public Size(int, int);
     method public int getHeight();
@@ -30824,6 +30734,7 @@
     field public static final int KEYCODE_P = 44; // 0x2c
     field public static final int KEYCODE_PAGE_DOWN = 93; // 0x5d
     field public static final int KEYCODE_PAGE_UP = 92; // 0x5c
+    field public static final int KEYCODE_PAIRING = 225; // 0xe1
     field public static final int KEYCODE_PERIOD = 56; // 0x38
     field public static final int KEYCODE_PICTSYMBOLS = 94; // 0x5e
     field public static final int KEYCODE_PLUS = 81; // 0x51
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 36c36a8..e1a94d7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1222,6 +1222,7 @@
      * Check whether this activity is running as part of a voice interaction with the user.
      * If true, it should perform its interaction with the user through the
      * {@link VoiceInteractor} returned by {@link #getVoiceInteractor}.
+     * @hide
      */
     public boolean isVoiceInteraction() {
         return mVoiceInteractor != null;
@@ -1230,6 +1231,7 @@
     /**
      * Retrieve the active {@link VoiceInteractor} that the user is going through to
      * interact with this activity.
+     * @hide
      */
     public VoiceInteractor getVoiceInteractor() {
         return mVoiceInteractor;
@@ -3611,15 +3613,15 @@
             theme.applyStyle(resid, false);
         }
 
-        // Get the primary color and update the RecentsActivityValues for this activity
+        // Get the primary color and update the TaskDescription for this activity
         if (theme != null) {
             TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
             int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
             a.recycle();
             if (colorPrimary != 0) {
-                ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues();
-                v.colorPrimary = colorPrimary;
-                setRecentsActivityValues(v);
+                ActivityManager.TaskDescription v = new ActivityManager.TaskDescription(null, null,
+                        colorPrimary);
+                setTaskDescription(v);
             }
         }
     }
@@ -4924,27 +4926,30 @@
     }
 
     /**
-     * Sets information describing this Activity for presentation inside the Recents System UI. When
-     * {@link ActivityManager#getRecentTasks} is called, the activities of each task are
-     * traversed in order from the topmost activity to the bottommost. The traversal continues for
-     * each property until a suitable value is found. For each task those values will be returned in
-     * {@link android.app.ActivityManager.RecentsActivityValues}.
+     * Sets information describing the task with this activity for presentation inside the Recents
+     * System UI. When {@link ActivityManager#getRecentTasks} is called, the activities of each task
+     * are traversed in order from the topmost activity to the bottommost. The traversal continues
+     * for each property until a suitable value is found. For each task the taskDescription will be
+     * returned in {@link android.app.ActivityManager.TaskDescription}.
      *
      * @see ActivityManager#getRecentTasks
-     * @see android.app.ActivityManager.RecentsActivityValues
+     * @see android.app.ActivityManager.TaskDescription
      *
-     * @param values The Recents values that describe this activity.
+     * @param taskDescription The TaskDescription properties that describe the task with this activity
      */
-    public void setRecentsActivityValues(ActivityManager.RecentsActivityValues values) {
-        ActivityManager.RecentsActivityValues activityValues =
-                new ActivityManager.RecentsActivityValues(values);
-        // Scale the icon down to something reasonable
-        if (values.icon != null) {
+    public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
+        ActivityManager.TaskDescription td;
+        // Scale the icon down to something reasonable if it is provided
+        if (taskDescription.getIcon() != null) {
             final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
-            activityValues.icon = Bitmap.createScaledBitmap(values.icon, size, size, true);
+            final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size, true);
+            td = new ActivityManager.TaskDescription(taskDescription.getLabel(), icon,
+                    taskDescription.getPrimaryColor());
+        } else {
+            td = taskDescription;
         }
         try {
-            ActivityManagerNative.getDefault().setRecentsActivityValues(mToken, activityValues);
+            ActivityManagerNative.getDefault().setTaskDescription(mToken, td);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1d05320..abcb0d0 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -33,6 +33,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Debug;
@@ -477,65 +478,84 @@
     /**
      * Information you can set and retrieve about the current activity within the recent task list.
      */
-    public static class RecentsActivityValues implements Parcelable {
-        public CharSequence label;
-        public Bitmap icon;
-        public int colorPrimary;
-
-        public RecentsActivityValues(RecentsActivityValues values) {
-            copyFrom(values);
-        }
+    public static class TaskDescription implements Parcelable {
+        private String mLabel;
+        private Bitmap mIcon;
+        private int mColorPrimary;
 
         /**
-         * Creates the RecentsActivityValues to the specified values.
+         * Creates the TaskDescription to the specified values.
          *
-         * @param label A label and description of the current state of this activity.
-         * @param icon An icon that represents the current state of this activity.
-         * @param color A color to override the theme's primary color.
+         * @param label A label and description of the current state of this task.
+         * @param icon An icon that represents the current state of this task.
+         * @param colorPrimary A color to override the theme's primary color.  This color must be opaque.
          */
-        public RecentsActivityValues(CharSequence label, Bitmap icon, int color) {
-            this.label = label;
-            this.icon = icon;
-            this.colorPrimary = color;
+        public TaskDescription(String label, Bitmap icon, int colorPrimary) {
+            if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
+                throw new RuntimeException("A TaskDescription's primary color should be opaque");
+            }
+
+            mLabel = label;
+            mIcon = icon;
+            mColorPrimary = colorPrimary;
         }
 
         /**
-         * Creates the RecentsActivityValues to the specified values.
+         * Creates the TaskDescription to the specified values.
          *
          * @param label A label and description of the current state of this activity.
          * @param icon An icon that represents the current state of this activity.
          */
-        public RecentsActivityValues(CharSequence label, Bitmap icon) {
+        public TaskDescription(String label, Bitmap icon) {
             this(label, icon, 0);
         }
 
         /**
-         * Creates the RecentsActivityValues to the specified values.
+         * Creates the TaskDescription to the specified values.
          *
          * @param label A label and description of the current state of this activity.
          */
-        public RecentsActivityValues(CharSequence label) {
+        public TaskDescription(String label) {
             this(label, null, 0);
         }
 
-        public RecentsActivityValues() {
+        /**
+         * Creates an empty TaskDescription.
+         */
+        public TaskDescription() {
             this(null, null, 0);
         }
 
-        private RecentsActivityValues(Parcel source) {
+        /**
+         * Creates a copy of another TaskDescription.
+         */
+        public TaskDescription(TaskDescription td) {
+            this(td.getLabel(), td.getIcon(), td.getPrimaryColor());
+        }
+
+        private TaskDescription(Parcel source) {
             readFromParcel(source);
         }
 
         /**
-         * Do a shallow copy of another set of activity values.
-         * @hide
+         * @return The label and description of the current state of this task.
          */
-        public void copyFrom(RecentsActivityValues v) {
-            if (v != null) {
-                label = v.label;
-                icon = v.icon;
-                colorPrimary = v.colorPrimary;
-            }
+        public String getLabel() {
+            return mLabel;
+        }
+
+        /**
+         * @return The icon that represents the current state of this task.
+         */
+        public Bitmap getIcon() {
+            return mIcon;
+        }
+
+        /**
+         * @return The color override on the theme's primary color.
+         */
+        public int getPrimaryColor() {
+            return mColorPrimary;
         }
 
         @Override
@@ -545,37 +565,41 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            TextUtils.writeToParcel(label, dest,
-                    Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            if (icon == null) {
+            if (mLabel == null) {
                 dest.writeInt(0);
             } else {
                 dest.writeInt(1);
-                icon.writeToParcel(dest, 0);
+                dest.writeString(mLabel);
             }
-            dest.writeInt(colorPrimary);
+            if (mIcon == null) {
+                dest.writeInt(0);
+            } else {
+                dest.writeInt(1);
+                mIcon.writeToParcel(dest, 0);
+            }
+            dest.writeInt(mColorPrimary);
         }
 
         public void readFromParcel(Parcel source) {
-            label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            icon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
-            colorPrimary = source.readInt();
+            mLabel = source.readInt() > 0 ? source.readString() : null;
+            mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+            mColorPrimary = source.readInt();
         }
 
-        public static final Creator<RecentsActivityValues> CREATOR
-                = new Creator<RecentsActivityValues>() {
-            public RecentsActivityValues createFromParcel(Parcel source) {
-                return new RecentsActivityValues(source);
+        public static final Creator<TaskDescription> CREATOR
+                = new Creator<TaskDescription>() {
+            public TaskDescription createFromParcel(Parcel source) {
+                return new TaskDescription(source);
             }
-            public RecentsActivityValues[] newArray(int size) {
-                return new RecentsActivityValues[size];
+            public TaskDescription[] newArray(int size) {
+                return new TaskDescription[size];
             }
         };
 
         @Override
         public String toString() {
-            return "RecentsActivityValues Label: " + label + " Icon: " + icon +
-                    " colorPrimary: " + colorPrimary;
+            return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
+                    " colorPrimary: " + mColorPrimary;
         }
     }
 
@@ -629,9 +653,11 @@
 
         /**
          * The recent activity values for the highest activity in the stack to have set the values.
-         * {@link Activity#setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues)}.
+         * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}.
+         *
+         * @hide
          */
-        public RecentsActivityValues activityValues;
+        public TaskDescription taskDescription;
 
         public RecentTaskInfo() {
         }
@@ -654,9 +680,9 @@
             ComponentName.writeToParcel(origActivity, dest);
             TextUtils.writeToParcel(description, dest,
                     Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            if (activityValues != null) {
+            if (taskDescription != null) {
                 dest.writeInt(1);
-                activityValues.writeToParcel(dest, 0);
+                taskDescription.writeToParcel(dest, 0);
             } else {
                 dest.writeInt(0);
             }
@@ -670,8 +696,8 @@
             baseIntent = source.readInt() > 0 ? Intent.CREATOR.createFromParcel(source) : null;
             origActivity = ComponentName.readFromParcel(source);
             description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            activityValues = source.readInt() > 0 ?
-                    RecentsActivityValues.CREATOR.createFromParcel(source) : null;
+            taskDescription = source.readInt() > 0 ?
+                    TaskDescription.CREATOR.createFromParcel(source) : null;
             stackId = source.readInt();
             userId = source.readInt();
         }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index e704a1c..0f65454 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2158,12 +2158,12 @@
             return true;
         }
 
-        case SET_RECENTS_ACTIVITY_VALUES_TRANSACTION: {
+        case SET_TASK_DESCRIPTION_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            ActivityManager.RecentsActivityValues values =
-                    ActivityManager.RecentsActivityValues.CREATOR.createFromParcel(data);
-            setRecentsActivityValues(token, values);
+            ActivityManager.TaskDescription values =
+                    ActivityManager.TaskDescription.CREATOR.createFromParcel(data);
+            setTaskDescription(token, values);
             reply.writeNoException();
             return true;
         }
@@ -4967,14 +4967,14 @@
     }
 
     @Override
-    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+    public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
         values.writeToParcel(data, 0);
-        mRemote.transact(SET_RECENTS_ACTIVITY_VALUES_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(SET_TASK_DESCRIPTION_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
         reply.readException();
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d813dab..62c4f0f 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.UserManager;
 import android.util.ArrayMap;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IAppOpsCallback;
@@ -412,6 +413,58 @@
     };
 
     /**
+     * Specifies whether an Op should be restricted by a user restriction.
+     * Each Op should be filled with a restriction string from UserManager or
+     * null to specify it is not affected by any user restriction.
+     */
+    private static String[] sOpRestrictions = new String[] {
+            null, //COARSE_LOCATION
+            null, //FINE_LOCATION
+            null, //GPS
+            null, //VIBRATE
+            null, //READ_CONTACTS
+            null, //WRITE_CONTACTS
+            null, //READ_CALL_LOG
+            null, //WRITE_CALL_LOG
+            null, //READ_CALENDAR
+            null, //WRITE_CALENDAR
+            null, //WIFI_SCAN
+            null, //POST_NOTIFICATION
+            null, //NEIGHBORING_CELLS
+            null, //CALL_PHONE
+            null, //READ_SMS
+            null, //WRITE_SMS
+            null, //RECEIVE_SMS
+            null, //RECEIVE_EMERGECY_SMS
+            null, //RECEIVE_MMS
+            null, //RECEIVE_WAP_PUSH
+            null, //SEND_SMS
+            null, //READ_ICC_SMS
+            null, //WRITE_ICC_SMS
+            null, //WRITE_SETTINGS
+            null, //SYSTEM_ALERT_WINDOW
+            null, //ACCESS_NOTIFICATIONS
+            null, //CAMERA
+            null, //RECORD_AUDIO
+            null, //PLAY_AUDIO
+            null, //READ_CLIPBOARD
+            null, //WRITE_CLIPBOARD
+            null, //TAKE_MEDIA_BUTTONS
+            null, //TAKE_AUDIO_FOCUS
+            null, //AUDIO_MASTER_VOLUME
+            null, //AUDIO_VOICE_VOLUME
+            null, //AUDIO_RING_VOLUME
+            null, //AUDIO_MEDIA_VOLUME
+            null, //AUDIO_ALARM_VOLUME
+            null, //AUDIO_NOTIFICATION_VOLUME
+            null, //AUDIO_BLUETOOTH_VOLUME
+            null, //WAKE_LOCK
+            null, //MONITOR_LOCATION
+            null, //MONITOR_HIGH_POWER_LOCATION
+            null, //GET_USAGE_STATS
+    };
+
+    /**
      * This specifies the default mode for each operation.
      */
     private static int[] sOpDefaultMode = new int[] {
@@ -542,6 +595,10 @@
             throw new IllegalStateException("sOpDisableReset length " + sOpDisableReset.length
                     + " should be " + _NUM_OP);
         }
+        if (sOpRestrictions.length != _NUM_OP) {
+            throw new IllegalStateException("sOpRestrictions length " + sOpRestrictions.length
+                    + " should be " + _NUM_OP);
+        }
         for (int i=0; i<_NUM_OP; i++) {
             if (sOpToString[i] != null) {
                 sOpStrToOp.put(sOpToString[i], i);
@@ -575,6 +632,14 @@
     }
 
     /**
+     * Retrieve the user restriction associated with an operation, or null if there is not one.
+     * @hide
+     */
+    public static String opToRestriction(int op) {
+        return sOpRestrictions[op];
+    }
+
+    /**
      * Retrieve the default mode for the operation.
      * @hide
      */
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b4d8942..eeb5283 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1345,6 +1345,15 @@
     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
             int initialCode, String initialData, Bundle initialExtras) {
+        sendOrderedBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE,
+                resultReceiver, scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
         IIntentReceiver rd = null;
         if (resultReceiver != null) {
             if (mPackageInfo != null) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 8753312..8434c2a 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -440,7 +440,7 @@
     public boolean isInLockTaskMode() throws RemoteException;
 
     /** @hide */
-    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+    public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException;
 
     /*
@@ -739,7 +739,7 @@
     int START_LOCK_TASK_BY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+214;
     int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215;
     int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
-    int SET_RECENTS_ACTIVITY_VALUES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
+    int SET_TASK_DESCRIPTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
     int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
     int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219;
     int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 76a6a8e..fd76b9c4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,9 +16,6 @@
 
 package android.app;
 
-import com.android.internal.R;
-import com.android.internal.util.NotificationColorUtil;
-
 import android.annotation.IntDef;
 import android.content.Context;
 import android.content.Intent;
@@ -41,6 +38,9 @@
 import android.widget.ProgressBar;
 import android.widget.RemoteViews;
 
+import com.android.internal.R;
+import com.android.internal.util.NotificationColorUtil;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.text.NumberFormat;
@@ -134,7 +134,7 @@
      * leave it at its default value of 0.
      *
      * @see android.widget.ImageView#setImageLevel
-     * @see android.graphics.drawable#setLevel
+     * @see android.graphics.drawable.Drawable#setLevel
      */
     public int iconLevel;
 
@@ -700,10 +700,13 @@
      * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
      * selected by the user.
      * <p>
-     * Apps should use {@link Builder#addAction(int, CharSequence, PendingIntent)} to create and
-     * attach actions.
+     * Apps should use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}
+     * or {@link Notification.Builder#addAction(Notification.Action)}
+     * to attach actions.
      */
     public static class Action implements Parcelable {
+        private final Bundle mExtras;
+
         /**
          * Small icon representing the action.
          */
@@ -717,22 +720,102 @@
          * may be rendered in a disabled presentation by the system UI.
          */
         public PendingIntent actionIntent;
- 
-        private Action() { }
+
         private Action(Parcel in) {
             icon = in.readInt();
             title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             if (in.readInt() == 1) {
                 actionIntent = PendingIntent.CREATOR.createFromParcel(in);
             }
+            mExtras = in.readBundle();
         }
         /**
-         * Use {@link Builder#addAction(int, CharSequence, PendingIntent)}.
+         * Use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}.
          */
         public Action(int icon, CharSequence title, PendingIntent intent) {
+            this(icon, title, intent, new Bundle());
+        }
+
+        private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
             this.icon = icon;
             this.title = title;
             this.actionIntent = intent;
+            this.mExtras = extras != null ? extras : new Bundle();
+        }
+
+        /**
+         * Get additional metadata carried around with this Action.
+         */
+        public Bundle getExtras() {
+            return mExtras;
+        }
+
+        /**
+         * Builder class for {@link Action} objects.
+         */
+        public static class Builder {
+            private final int mIcon;
+            private final CharSequence mTitle;
+            private final PendingIntent mIntent;
+            private final Bundle mExtras;
+
+            /**
+             * Construct a new builder for {@link Action} object.
+             * @param icon icon to show for this action
+             * @param title the title of the action
+             * @param intent the {@link PendingIntent} to fire when users trigger this action
+             */
+            public Builder(int icon, CharSequence title, PendingIntent intent) {
+                this(icon, title, intent, new Bundle());
+            }
+
+            /**
+             * Construct a new builder for {@link Action} object using the fields from an
+             * {@link Action}.
+             * @param action the action to read fields from.
+             */
+            public Builder(Action action) {
+                this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras));
+            }
+
+            private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
+                mIcon = icon;
+                mTitle = title;
+                mIntent = intent;
+                mExtras = extras;
+            }
+
+            /**
+             * Merge additional metadata into this builder.
+             *
+             * <p>Values within the Bundle will replace existing extras values in this Builder.
+             *
+             * @see Notification.Action#extras
+             */
+            public Builder addExtras(Bundle extras) {
+                if (extras != null) {
+                    mExtras.putAll(extras);
+                }
+                return this;
+            }
+
+            /**
+             * Get the metadata Bundle used by this Builder.
+             *
+             * <p>The returned Bundle is shared with this Builder.
+             */
+            public Bundle getExtras() {
+                return mExtras;
+            }
+
+            /**
+             * Combine all of the options that have been set and return a new {@link Action}
+             * object.
+             * @return the built action
+             */
+            public Action build() {
+                return new Action(mIcon, mTitle, mIntent, mExtras);
+            }
         }
 
         @Override
@@ -740,8 +823,8 @@
             return new Action(
                 this.icon,
                 this.title,
-                this.actionIntent // safe to alias
-            );
+                this.actionIntent, // safe to alias
+                new Bundle(this.mExtras));
         }
         @Override
         public int describeContents() {
@@ -757,9 +840,10 @@
             } else {
                 out.writeInt(0);
             }
+            out.writeBundle(mExtras);
         }
-        public static final Parcelable.Creator<Action> CREATOR
-        = new Parcelable.Creator<Action>() {
+        public static final Parcelable.Creator<Action> CREATOR =
+                new Parcelable.Creator<Action>() {
             public Action createFromParcel(Parcel in) {
                 return new Action(in);
             }
@@ -1372,7 +1456,7 @@
         /**
          * Add a timestamp pertaining to the notification (usually the time the event occurred).
          * It will be shown in the notification content view by default; use
-         * {@link Builder#setShowWhen(boolean) setShowWhen} to control this.
+         * {@link #setShowWhen(boolean) setShowWhen} to control this.
          *
          * @see Notification#when
          */
@@ -1382,7 +1466,7 @@
         }
 
         /**
-         * Control whether the timestamp set with {@link Builder#setWhen(long) setWhen} is shown
+         * Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown
          * in the content view.
          */
         public Builder setShowWhen(boolean show) {
@@ -1761,11 +1845,13 @@
          *
          * @see Notification#extras
          */
-        public Builder addExtras(Bundle bag) {
-            if (mExtras == null) {
-                mExtras = new Bundle(bag);
-            } else {
-                mExtras.putAll(bag);
+        public Builder addExtras(Bundle extras) {
+            if (extras != null) {
+                if (mExtras == null) {
+                    mExtras = new Bundle(extras);
+                } else {
+                    mExtras.putAll(extras);
+                }
             }
             return this;
         }
@@ -1782,8 +1868,8 @@
          *
          * @see Notification#extras
          */
-        public Builder setExtras(Bundle bag) {
-            mExtras = bag;
+        public Builder setExtras(Bundle extras) {
+            mExtras = extras;
             return this;
         }
 
@@ -1827,6 +1913,26 @@
         }
 
         /**
+         * Add an action to this notification. Actions are typically displayed by
+         * the system as a button adjacent to the notification content.
+         * <p>
+         * Every action must have an icon (32dp square and matching the
+         * <a href="{@docRoot}design/style/iconography.html#action-bar">Holo
+         * Dark action bar</a> visual style), a textual label, and a {@link PendingIntent}.
+         * <p>
+         * A notification in its expanded form can display up to 3 actions, from left to right in
+         * the order they were added. Actions will not be displayed when the notification is
+         * collapsed, however, so be sure that any essential functions may be accessed by the user
+         * in some other way (for example, in the Activity pointed to by {@link #contentIntent}).
+         *
+         * @param action The action to add.
+         */
+        public Builder addAction(Action action) {
+            mActions.add(action);
+            return this;
+        }
+
+        /**
          * Add a rich notification style to be applied at build time.
          *
          * @param style Object responsible for modifying the notification style.
@@ -1889,26 +1995,20 @@
             RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
             boolean showLine3 = false;
             boolean showLine2 = false;
-            int smallIconImageViewId = R.id.icon;
+
             if (mPriority < PRIORITY_LOW) {
                 // TODO: Low priority presentation
             }
             if (mLargeIcon != null) {
                 contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
                 processLargeIcon(mLargeIcon, contentView);
-                smallIconImageViewId = R.id.right_icon;
-            }
-            if (mSmallIcon != 0) {
-                contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
-                contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
-                if (mLargeIcon != null) {
-                    processSmallRightIcon(mSmallIcon, smallIconImageViewId, contentView);
-                } else {
-                    processSmallIconAsLarge(mSmallIcon, contentView);
-                }
-
-            } else {
-                contentView.setViewVisibility(smallIconImageViewId, View.GONE);
+                contentView.setImageViewResource(R.id.right_icon, mSmallIcon);
+                contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
+                processSmallRightIcon(mSmallIcon, contentView);
+            } else { // small icon at left
+                contentView.setImageViewResource(R.id.icon, mSmallIcon);
+                contentView.setViewVisibility(R.id.icon, View.VISIBLE);
+                processSmallIconAsLarge(mSmallIcon, contentView);
             }
             if (mContentTitle != null) {
                 contentView.setTextViewText(R.id.title, processLegacyText(mContentTitle));
@@ -2103,6 +2203,8 @@
         private void processLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
             if (!isLegacy() || mColorUtil.isGrayscale(largeIcon)) {
                 applyLargeIconBackground(contentView);
+            } else {
+                removeLargeIconBackground(contentView);
             }
         }
 
@@ -2122,16 +2224,31 @@
                     -1);
         }
 
+        private void removeLargeIconBackground(RemoteViews contentView) {
+            contentView.setInt(R.id.icon, "setBackgroundResource", 0);
+        }
+
         /**
          * Recolor small icons when used in the R.id.right_icon slot.
          */
-        private void processSmallRightIcon(int smallIconDrawableId, int smallIconImageViewId,
+        private void processSmallRightIcon(int smallIconDrawableId,
                 RemoteViews contentView) {
             if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) {
-                contentView.setDrawableParameters(smallIconImageViewId, false, -1,
-                        mContext.getResources().getColor(
-                                R.color.notification_action_legacy_color_filter),
-                        PorterDuff.Mode.MULTIPLY, -1);
+                contentView.setDrawableParameters(R.id.right_icon, false, -1,
+                        0xFFFFFFFF,
+                        PorterDuff.Mode.SRC_ATOP, -1);
+
+                contentView.setInt(R.id.right_icon,
+                        "setBackgroundResource",
+                        R.drawable.notification_icon_legacy_bg);
+
+                contentView.setDrawableParameters(
+                        R.id.right_icon,
+                        true,
+                        -1,
+                        mColor,
+                        PorterDuff.Mode.SRC_ATOP,
+                        -1);
             }
         }
 
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 6dc48b0..4fcf7cd 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -34,6 +34,7 @@
 
 /**
  * Interface for an {@link Activity} to interact with the user through voice.
+ * @hide
  */
 public class VoiceInteractor {
     static final String TAG = "VoiceInteractor";
diff --git a/core/java/android/app/task/ITaskCallback.aidl b/core/java/android/app/task/ITaskCallback.aidl
index ffa57d1..d8a32fd 100644
--- a/core/java/android/app/task/ITaskCallback.aidl
+++ b/core/java/android/app/task/ITaskCallback.aidl
@@ -34,14 +34,17 @@
      * Immediate callback to the system after sending a start signal, used to quickly detect ANR.
      *
      * @param taskId Unique integer used to identify this task.
+     * @param ongoing True to indicate that the client is processing the task. False if the task is
+     * complete
      */
-    void acknowledgeStartMessage(int taskId);
+    void acknowledgeStartMessage(int taskId, boolean ongoing);
     /**
      * Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
      *
      * @param taskId Unique integer used to identify this task.
+     * @param rescheulde Whether or not to reschedule this task.
      */
-    void acknowledgeStopMessage(int taskId);
+    void acknowledgeStopMessage(int taskId, boolean reschedule);
     /*
      * Tell the task manager that the client is done with its execution, so that it can go on to
      * the next one and stop attributing wakelock time to us etc.
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/task/TaskService.java
index 81333be..ab1a565 100644
--- a/core/java/android/app/task/TaskService.java
+++ b/core/java/android/app/task/TaskService.java
@@ -18,7 +18,6 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -124,22 +123,20 @@
             switch (msg.what) {
                 case MSG_EXECUTE_TASK:
                     try {
-                        TaskService.this.onStartTask(params);
+                        boolean workOngoing = TaskService.this.onStartTask(params);
+                        ackStartMessage(params, workOngoing);
                     } catch (Exception e) {
                         Log.e(TAG, "Error while executing task: " + params.getTaskId());
                         throw new RuntimeException(e);
-                    } finally {
-                        maybeAckMessageReceived(params, MSG_EXECUTE_TASK);
                     }
                     break;
                 case MSG_STOP_TASK:
                     try {
-                        TaskService.this.onStopTask(params);
+                        boolean ret = TaskService.this.onStopTask(params);
+                        ackStopMessage(params, ret);
                     } catch (Exception e) {
                         Log.e(TAG, "Application unable to handle onStopTask.", e);
                         throw new RuntimeException(e);
-                    } finally {
-                        maybeAckMessageReceived(params, MSG_STOP_TASK);
                     }
                     break;
                 case MSG_TASK_FINISHED:
@@ -162,30 +159,34 @@
             }
         }
 
-        /**
-         * Messages come in on the application's main thread, so rather than run the risk of
-         * waiting for an app that may be doing something foolhardy, we ack to the system after
-         * processing a message. This allows us to throw up an ANR dialogue as quickly as possible.
-         * @param params id of the task we're acking.
-         * @param state Information about what message we're acking.
-         */
-        private void maybeAckMessageReceived(TaskParams params, int state) {
+        private void ackStartMessage(TaskParams params, boolean workOngoing) {
             final ITaskCallback callback = params.getCallback();
             final int taskId = params.getTaskId();
             if (callback != null) {
                 try {
-                    if (state == MSG_EXECUTE_TASK) {
-                        callback.acknowledgeStartMessage(taskId);
-                    } else if (state == MSG_STOP_TASK) {
-                        callback.acknowledgeStopMessage(taskId);
-                    }
+                     callback.acknowledgeStartMessage(taskId, workOngoing);
                 } catch(RemoteException e) {
                     Log.e(TAG, "System unreachable for starting task.");
                 }
             } else {
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, state + ": Attempting to ack a task that has already been" +
-                            "processed.");
+                    Log.d(TAG, "Attempting to ack a task that has already been processed.");
+                }
+            }
+        }
+
+        private void ackStopMessage(TaskParams params, boolean reschedule) {
+            final ITaskCallback callback = params.getCallback();
+            final int taskId = params.getTaskId();
+            if (callback != null) {
+                try {
+                    callback.acknowledgeStopMessage(taskId, reschedule);
+                } catch(RemoteException e) {
+                    Log.e(TAG, "System unreachable for stopping task.");
+                }
+            } else {
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Attempting to ack a task that has already been processed.");
                 }
             }
         }
@@ -203,12 +204,14 @@
      *
      * @param params Parameters specifying info about this task, including the extras bundle you
      *               optionally provided at task-creation time.
+     * @return True if your service needs to process the work (on a separate thread). False if
+     * there's no more work to be done for this task.
      */
-    public abstract void onStartTask(TaskParams params);
+    public abstract boolean onStartTask(TaskParams params);
 
     /**
-     * This method is called if your task should be stopped even before you've called
-     * {@link #taskFinished(TaskParams, boolean)}.
+     * This method is called if the system has determined that you must stop execution of your task
+     * even before you've had a chance to call {@link #taskFinished(TaskParams, boolean)}.
      *
      * <p>This will happen if the requirements specified at schedule time are no longer met. For
      * example you may have requested WiFi with
@@ -217,33 +220,27 @@
      * {@link android.content.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
      * idle maintenance window. You are solely responsible for the behaviour of your application
      * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
-     * repercussion is that the system will cease to hold a wakelock for you.</p>
-     *
-     * <p>After you've done your clean-up you are still expected to call
-     * {@link #taskFinished(TaskParams, boolean)} this will inform the TaskManager that all is well, and
-     * allow you to reschedule your task as it is probably uncompleted. Until you call
-     * taskFinished() you will not receive any newly scheduled tasks with the given task id as the
-     * TaskManager will consider the task to be in an error state.</p>
+     * immediate repercussion is that the system will cease holding a wakelock for you.</p>
      *
      * @param params Parameters specifying info about this task.
      * @return True to indicate to the TaskManager whether you'd like to reschedule this task based
-     * on the criteria provided at task creation-time. False to drop the task. Regardless of the
-     * value returned, your task must stop executing.
+     * on the retry criteria provided at task creation-time. False to drop the task. Regardless of
+     * the value returned, your task must stop executing.
      */
     public abstract boolean onStopTask(TaskParams params);
 
     /**
-     * Callback to inform the TaskManager you have completed execution. This can be called from any
+     * Callback to inform the TaskManager you've finished executing. This can be called from any
      * thread, as it will ultimately be run on your application's main thread. When the system
      * receives this message it will release the wakelock being held.
      * <p>
-     *     You can specify post-execution behaviour to the scheduler here with <code>needsReschedule
-     *     </code>. This will apply a back-off timer to your task based on the default, or what was
-     *     set with {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The
-     *     original requirements are always honoured even for a backed-off task.
-     *     Note that a task running in idle mode will not be backed-off. Instead what will happen
-     *     is the task will be re-added to the queue and re-executed within a future idle
-     *     maintenance window.
+     *     You can specify post-execution behaviour to the scheduler here with
+     *     <code>needsReschedule </code>. This will apply a back-off timer to your task based on
+     *     the default, or what was set with
+     *     {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The original
+     *     requirements are always honoured even for a backed-off task. Note that a task running in
+     *     idle mode will not be backed-off. Instead what will happen is the task will be re-added
+     *     to the queue and re-executed within a future idle maintenance window.
      * </p>
      *
      * @param params Parameters specifying system-provided info about this task, this was given to
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a059e48..a364e68 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1499,6 +1499,17 @@
             @Nullable  Bundle initialExtras);
 
     /**
+     * Similar to above but takes an appOp as well, to enforce restrictions.
+     * @see #sendOrderedBroadcastAsUser(Intent, UserHandle, String,
+     *       BroadcastReceiver, Handler, int, String, Bundle)
+     * @hide
+     */
+    public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            @Nullable String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+            @Nullable  Bundle initialExtras);
+
+    /**
      * Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
      * Intent you are sending stays around after the broadcast is complete,
      * so that others can quickly retrieve that data through the return
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 93f6cdf..c66355b 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -418,6 +418,16 @@
                 scheduler, initialCode, initialData, initialExtras);
     }
 
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, resultReceiver,
+                scheduler, initialCode, initialData, initialExtras);
+    }
+
     @Override
     public void sendStickyBroadcast(Intent intent) {
         mBase.sendStickyBroadcast(intent);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 076f657..fed63d2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2809,6 +2809,7 @@
      * An activity that supports this category must be prepared to run with
      * no UI shown at all (though in some case it may have a UI shown), and
      * rely on {@link android.app.VoiceInteractor} to interact with the user.
+     * @hide
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_VOICE = "android.intent.category.VOICE";
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 197e3ff..a75372f 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -42,12 +42,8 @@
 public class CursorWindow extends SQLiteClosable implements Parcelable {
     private static final String STATS_TAG = "CursorWindowStats";
 
-    /** The cursor window size. resource xml file specifies the value in kB.
-     * convert it to bytes here by multiplying with 1024.
-     */
-    private static final int sCursorWindowSize =
-        Resources.getSystem().getInteger(
-                com.android.internal.R.integer.config_cursorWindowSize) * 1024;
+    // This static member will be evaluated when first used.
+    private static int sCursorWindowSize = -1;
 
     /**
      * The native CursorWindow object pointer.  (FOR INTERNAL USE ONLY)
@@ -100,6 +96,13 @@
     public CursorWindow(String name) {
         mStartPos = 0;
         mName = name != null && name.length() != 0 ? name : "<unnamed>";
+        if (sCursorWindowSize < 0) {
+            /** The cursor window size. resource xml file specifies the value in kB.
+             * convert it to bytes here by multiplying with 1024.
+             */
+            sCursorWindowSize = Resources.getSystem().getInteger(
+                com.android.internal.R.integer.config_cursorWindowSize) * 1024;
+        }
         mWindowPtr = nativeCreate(mName, sCursorWindowSize);
         if (mWindowPtr == 0) {
             throw new CursorWindowAllocationException("Cursor window allocation of " +
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index b1c1005..1127fe5 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -17,6 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.util.Rational;
 
 import java.util.Collections;
 import java.util.List;
@@ -316,8 +317,8 @@
      * <li>All non (0, 0) sizes will have non-zero widths and heights.</li>
      * </ul>
      */
-    public static final Key<android.hardware.camera2.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
-            new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class);
+    public static final Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
+            new Key<android.util.Size[]>("android.jpeg.availableThumbnailSizes", android.util.Size[].class);
 
     /**
      * <p>List of supported aperture
@@ -393,8 +394,8 @@
      * <p>The map should be on the order of 30-40 rows and columns, and
      * must be smaller than 64x64.</p>
      */
-    public static final Key<android.hardware.camera2.Size> LENS_INFO_SHADING_MAP_SIZE =
-            new Key<android.hardware.camera2.Size>("android.lens.info.shadingMapSize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> LENS_INFO_SHADING_MAP_SIZE =
+            new Key<android.util.Size>("android.lens.info.shadingMapSize", android.util.Size.class);
 
     /**
      * <p>The lens focus distance calibration quality.</p>
@@ -658,8 +659,8 @@
      * @hide
      */
     @Deprecated
-    public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
-            new Key<android.hardware.camera2.Size[]>("android.scaler.availableJpegSizes", android.hardware.camera2.Size[].class);
+    public static final Key<android.util.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
+            new Key<android.util.Size[]>("android.scaler.availableJpegSizes", android.util.Size[].class);
 
     /**
      * <p>The maximum ratio between active area width
@@ -704,8 +705,8 @@
      * @hide
      */
     @Deprecated
-    public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
-            new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
+    public static final Key<android.util.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
+            new Key<android.util.Size[]>("android.scaler.availableProcessedSizes", android.util.Size[].class);
 
     /**
      * <p>The mapping of image formats that are supported by this
@@ -961,9 +962,6 @@
      * can provide.</p>
      * <p>Please reference the documentation for the image data destination to
      * check if it limits the maximum size for image data.</p>
-     * <p>Not all output formats may be supported in a configuration with
-     * an input stream of a particular format. For more details, see
-     * android.scaler.availableInputOutputFormatsMap.</p>
      * <p>The following table describes the minimum required output stream
      * configurations based on the hardware level
      * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p>
@@ -1106,8 +1104,8 @@
      * match this in
      * android.scaler.availableStreamConfigurations.</p>
      */
-    public static final Key<android.hardware.camera2.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
-            new Key<android.hardware.camera2.Size>("android.sensor.info.pixelArraySize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
+            new Key<android.util.Size>("android.sensor.info.pixelArraySize", android.util.Size.class);
 
     /**
      * <p>Maximum raw value output by sensor.</p>
@@ -1515,13 +1513,4 @@
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
-
 }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 8ae21f3..a70aa3b 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -19,6 +19,7 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Rational;
 import android.view.Surface;
 
 import java.util.HashSet;
@@ -169,7 +170,7 @@
      * @param in The parcel from which the object should be read
      * @hide
      */
-    public void readFromParcel(Parcel in) {
+    private void readFromParcel(Parcel in) {
         mSettings.readFromParcel(in);
 
         mSurfaceSet.clear();
@@ -965,8 +966,8 @@
      * <p>When a jpeg image capture is issued, the thumbnail size selected should have
      * the same aspect ratio as the jpeg image.</p>
      */
-    public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
-            new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
+            new Key<android.util.Size>("android.jpeg.thumbnailSize", android.util.Size.class);
 
     /**
      * <p>The ratio of lens focal length to the effective
@@ -1518,12 +1519,4 @@
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
 }
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 0160622..d79f4b0 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -17,6 +17,8 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.params.Face;
+import android.util.Rational;
 
 /**
  * <p>The results of a single image capture from the image sensor.</p>
@@ -1512,8 +1514,8 @@
      * <p>When a jpeg image capture is issued, the thumbnail size selected should have
      * the same aspect ratio as the jpeg image.</p>
      */
-    public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
-            new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
+            new Key<android.util.Size>("android.jpeg.thumbnailSize", android.util.Size.class);
 
     /**
      * <p>The ratio of lens focal length to the effective
@@ -2060,6 +2062,16 @@
             new Key<byte[]>("android.statistics.faceScores", byte[].class);
 
     /**
+     * <p>List of the faces detected through camera face detection
+     * in this result.</p>
+     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} <code>!=</code> OFF.</p>
+     *
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
+     */
+    public static final Key<android.hardware.camera2.params.Face[]> STATISTICS_FACES =
+            new Key<android.hardware.camera2.params.Face[]>("android.statistics.faces", android.hardware.camera2.params.Face[].class);
+
+    /**
      * <p>The shading map is a low-resolution floating-point map
      * that lists the coefficients used to correct for vignetting, for each
      * Bayer color channel.</p>
@@ -2425,27 +2437,4 @@
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
-
-    /**
-     * <p>
-     * List of the {@link Face Faces} detected through camera face detection
-     * in this result.
-     * </p>
-     * <p>
-     * Only available if {@link #STATISTICS_FACE_DETECT_MODE} {@code !=}
-     * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_OFF OFF}.
-     * </p>
-     *
-     * @see Face
-     */
-    public static final Key<Face[]> STATISTICS_FACES =
-            new Key<Face[]>("android.statistics.faces", Face[].class);
 }
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index a14d38b..caabed3 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -17,7 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.CaptureResultExtras;
+import android.hardware.camera2.impl.CaptureResultExtras;
 
 /** @hide */
 interface ICameraDeviceCallbacks
diff --git a/core/java/android/hardware/camera2/Size.java b/core/java/android/hardware/camera2/Size.java
deleted file mode 100644
index 9328a003..0000000
--- a/core/java/android/hardware/camera2/Size.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-// TODO: Delete this class, since it was moved to android.util as public API
-
-/**
- * Immutable class for describing width and height dimensions in pixels.
- *
- * @hide
- */
-public final class Size {
-    /**
-     * Create a new immutable Size instance.
-     *
-     * @param width The width of the size, in pixels
-     * @param height The height of the size, in pixels
-     */
-    public Size(final int width, final int height) {
-        mWidth = width;
-        mHeight = height;
-    }
-
-    /**
-     * Get the width of the size (in pixels).
-     * @return width
-     */
-    public final int getWidth() {
-        return mWidth;
-    }
-
-    /**
-     * Get the height of the size (in pixels).
-     * @return height
-     */
-    public final int getHeight() {
-        return mHeight;
-    }
-
-    /**
-     * Check if this size is equal to another size.
-     * <p>
-     * Two sizes are equal if and only if both their widths and heights are
-     * equal.
-     * </p>
-     * <p>
-     * A size object is never equal to any other type of object.
-     * </p>
-     *
-     * @return {@code true} if the objects were equal, {@code false} otherwise
-     */
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof Size) {
-            final Size other = (Size) obj;
-            return mWidth == other.mWidth && mHeight == other.mHeight;
-        }
-        return false;
-    }
-
-    /**
-     * Return the size represented as a string with the format {@code "WxH"}
-     *
-     * @return string representation of the size
-     */
-    @Override
-    public String toString() {
-        return mWidth + "x" + mHeight;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-        // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
-        return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
-    }
-
-    private final int mWidth;
-    private final int mHeight;
-};
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 628d1c3..dba24a1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -21,7 +21,6 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.utils.CameraBinderDecorator;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index d28f7bd..db7486d 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -22,7 +22,6 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Face;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
 import android.hardware.camera2.marshal.MarshalRegistry;
@@ -43,6 +42,7 @@
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableString;
+import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
similarity index 94%
rename from core/java/android/hardware/camera2/CaptureResultExtras.aidl
rename to core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
index 6587f02..ebc812a 100644
--- a/core/java/android/hardware/camera2/CaptureResultExtras.aidl
+++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.impl;
 
 /** @hide */
 parcelable CaptureResultExtras;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.java b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
similarity index 98%
rename from core/java/android/hardware/camera2/CaptureResultExtras.java
rename to core/java/android/hardware/camera2/impl/CaptureResultExtras.java
index e5c2c1c..b3a9559 100644
--- a/core/java/android/hardware/camera2/CaptureResultExtras.java
+++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.camera2;
+package android.hardware.camera2.impl;
 
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/hardware/camera2/marshal/MarshalHelpers.java b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
index fd72ee2..35ecc2a 100644
--- a/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
+++ b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
@@ -18,8 +18,8 @@
 import static android.hardware.camera2.impl.CameraMetadataNative.*;
 import static com.android.internal.util.Preconditions.*;
 
-import android.hardware.camera2.Rational;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.util.Rational;
 
 /**
  * Static functions in order to help implementing various marshaler functionality.
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
index d3796db..47f79bf 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
@@ -15,9 +15,9 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.ColorSpaceTransform;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.ColorSpaceTransform;
 import android.hardware.camera2.utils.TypeReference;
 
 import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
index c8b9bd8..01780db 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
@@ -15,9 +15,9 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.MeteringRectangle;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.utils.TypeReference;
 
 import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
index 708da70..189b597 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
@@ -15,11 +15,11 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.Rational;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
 import android.hardware.camera2.utils.TypeReference;
+import android.util.Rational;
 
 import static android.hardware.camera2.impl.CameraMetadataNative.*;
 import static android.hardware.camera2.marshal.MarshalHelpers.*;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
index 93c0e92..4253a0a 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
@@ -15,9 +15,9 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.RggbChannelVector;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.RggbChannelVector;
 import android.hardware.camera2.utils.TypeReference;
 
 import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
index 6a73bee..721644e 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
@@ -15,7 +15,7 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
 import android.hardware.camera2.utils.TypeReference;
diff --git a/core/java/android/hardware/camera2/ColorSpaceTransform.java b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
similarity index 98%
rename from core/java/android/hardware/camera2/ColorSpaceTransform.java
rename to core/java/android/hardware/camera2/params/ColorSpaceTransform.java
index 5e4c0a2..fa8c8ea 100644
--- a/core/java/android/hardware/camera2/ColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
 
+import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.utils.HashCodeHelpers;
+import android.util.Rational;
 
 import java.util.Arrays;
 
diff --git a/core/java/android/hardware/camera2/Face.java b/core/java/android/hardware/camera2/params/Face.java
similarity index 97%
rename from core/java/android/hardware/camera2/Face.java
rename to core/java/android/hardware/camera2/params/Face.java
index ded8839d..2cd83a3 100644
--- a/core/java/android/hardware/camera2/Face.java
+++ b/core/java/android/hardware/camera2/params/Face.java
@@ -15,10 +15,13 @@
  */
 
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureResult;
 
 /**
  * Describes a face detected in an image.
diff --git a/core/java/android/hardware/camera2/LensShadingMap.java b/core/java/android/hardware/camera2/params/LensShadingMap.java
similarity index 97%
rename from core/java/android/hardware/camera2/LensShadingMap.java
rename to core/java/android/hardware/camera2/params/LensShadingMap.java
index 2b0108c..b328f57 100644
--- a/core/java/android/hardware/camera2/LensShadingMap.java
+++ b/core/java/android/hardware/camera2/params/LensShadingMap.java
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
-import static android.hardware.camera2.RggbChannelVector.*;
+import static android.hardware.camera2.params.RggbChannelVector.*;
 
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 import java.util.Arrays;
diff --git a/core/java/android/hardware/camera2/MeteringRectangle.java b/core/java/android/hardware/camera2/params/MeteringRectangle.java
similarity index 97%
rename from core/java/android/hardware/camera2/MeteringRectangle.java
rename to core/java/android/hardware/camera2/params/MeteringRectangle.java
index bb8e5b1..a26c57d 100644
--- a/core/java/android/hardware/camera2/MeteringRectangle.java
+++ b/core/java/android/hardware/camera2/params/MeteringRectangle.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import android.util.Size;
 import static com.android.internal.util.Preconditions.*;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 /**
diff --git a/core/java/android/hardware/camera2/RggbChannelVector.java b/core/java/android/hardware/camera2/params/RggbChannelVector.java
similarity index 99%
rename from core/java/android/hardware/camera2/RggbChannelVector.java
rename to core/java/android/hardware/camera2/params/RggbChannelVector.java
index 80167c6..30591f6 100644
--- a/core/java/android/hardware/camera2/RggbChannelVector.java
+++ b/core/java/android/hardware/camera2/params/RggbChannelVector.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
 
diff --git a/core/java/android/hardware/camera2/TonemapCurve.java b/core/java/android/hardware/camera2/params/TonemapCurve.java
similarity index 97%
rename from core/java/android/hardware/camera2/TonemapCurve.java
rename to core/java/android/hardware/camera2/params/TonemapCurve.java
index 2958ebf..0fcffac 100644
--- a/core/java/android/hardware/camera2/TonemapCurve.java
+++ b/core/java/android/hardware/camera2/params/TonemapCurve.java
@@ -14,11 +14,15 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
 
 import android.graphics.PointF;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 import java.util.Arrays;
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 4b85398..c2b06a2 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -66,6 +66,7 @@
     private AsyncChannel mAsyncChannel;
     private final String LOG_TAG;
     private static final boolean DBG = true;
+    private static final boolean VDBG = true;
     // TODO - this class shouldn't cache data or it runs the risk of getting out of sync
     // Make the API require each of these when any is updated so we have the data we need,
     // without caching.
@@ -266,11 +267,14 @@
      */
     private void evalScores() {
         if (mConnectionRequested) {
+            if (VDBG) log("evalScores - already trying - size=" + mNetworkRequests.size());
             // already trying
             return;
         }
+        if (VDBG) log("evalScores!");
         for (int i=0; i < mNetworkRequests.size(); i++) {
             int score = mNetworkRequests.valueAt(i).score;
+            if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore);
             if (score < mNetworkScore) {
                 // have a request that has a lower scored network servicing it
                 // (or no network) than we could provide, so lets connect!
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index cf0caed..af45fa0 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -531,7 +531,8 @@
 
     public final static class HistoryItem implements Parcelable {
         public HistoryItem next;
-        
+
+        // The time of this event in milliseconds, as per SystemClock.elapsedRealtime().
         public long time;
 
         public static final byte CMD_UPDATE = 0;        // These can be written as deltas
@@ -645,7 +646,7 @@
         public int eventCode;
         public HistoryTag eventTag;
 
-        // Only set for CMD_CURRENT_TIME.
+        // Only set for CMD_CURRENT_TIME or CMD_RESET, as per System.currentTimeMillis().
         public long currentTime;
 
         // Meta-data when reading.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d09bb88..cd28085 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -773,13 +773,24 @@
      * Activity Action: Show Device Name Settings.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you safeguard
-     * against ithis.
+     * against this.
      *
      * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String DEVICE_NAME_SETTINGS = "android.settings.DEVICE_NAME";
 
+    /**
+     * Activity Action: Show pairing settings.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard
+     * against this.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_PAIRING_SETTINGS = "android.settings.PAIRING_SETTINGS";
+
     // End of Intent actions for Settings
 
     /**
@@ -2900,6 +2911,7 @@
             MOVED_TO_GLOBAL.add(Settings.Global.SET_GLOBAL_HTTP_PROXY);
             MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_DNS_SERVER);
             MOVED_TO_GLOBAL.add(Settings.Global.PREFERRED_NETWORK_MODE);
+            MOVED_TO_GLOBAL.add(Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY);
         }
 
         /** @hide */
@@ -5330,6 +5342,13 @@
         */
        public static final String USE_GOOGLE_MAIL = "use_google_mail";
 
+        /**
+         * Webview Data reduction proxy key.
+         * @hide
+         */
+        public static final String WEBVIEW_DATA_REDUCTION_PROXY_KEY =
+                "webview_data_reduction_proxy_key";
+
        /**
         * Whether Wifi display is enabled/disabled
         * 0=disabled. 1=enabled.
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a94f45a..e2e9ff4 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -16,9 +16,11 @@
 
 package android.service.notification;
 
+import android.annotation.PrivateApi;
 import android.annotation.SdkConstant;
 import android.app.INotificationManager;
 import android.app.Service;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
@@ -26,9 +28,6 @@
 import android.os.ServiceManager;
 import android.util.Log;
 
-import java.util.Comparator;
-import java.util.HashMap;
-
 /**
  * A service that receives calls from the system when new notifications are posted or removed.
  * <p>To extend this class, you must declare the service in your manifest file with
@@ -53,6 +52,9 @@
 
     private INotificationManager mNoMan;
 
+    /** Only valid after a successful call to (@link registerAsService}. */
+    private int mCurrentUser;
+
     /**
      * The {@link Intent} that must be declared as handled by the service.
      */
@@ -267,6 +269,42 @@
         return true;
     }
 
+    /**
+     * Directly register this service with the Notification Manager.
+     *
+     * <p>Only system services may use this call. It will fail for non-system callers.
+     * Apps should ask the user to add their listener in Settings.
+     *
+     * @param componentName the component that will consume the notification information
+     * @param currentUser the user to use as the stream filter
+     * @hide
+     */
+    @PrivateApi
+    public void registerAsSystemService(ComponentName componentName, int currentUser)
+            throws RemoteException {
+        if (mWrapper == null) {
+            mWrapper = new INotificationListenerWrapper();
+        }
+        INotificationManager noMan = getNotificationInterface();
+        noMan.registerListener(mWrapper, componentName, currentUser);
+        mCurrentUser = currentUser;
+    }
+
+    /**
+     * Directly unregister this service from the Notification Manager.
+     *
+     * <P>This method will fail for listeners that were not registered
+     * with (@link registerAsService).
+     * @hide
+     */
+    @PrivateApi
+    public void unregisterAsSystemService() throws RemoteException {
+        if (mWrapper != null) {
+            INotificationManager noMan = getNotificationInterface();
+            noMan.unregisterListener(mWrapper, mCurrentUser);
+        }
+    }
+
     private class INotificationListenerWrapper extends INotificationListener.Stub {
         @Override
         public void onNotificationPosted(StatusBarNotification sbn,
diff --git a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index c346771..9e4c2bf 100644
--- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -23,6 +23,6 @@
  * @hide
  */
 oneway interface ITrustAgentServiceCallback {
-    void enableTrust(String message, long durationMs, boolean initiatedByUser);
+    void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser);
     void revokeTrust();
 }
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index d5ce429..bb40eec 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -29,12 +29,12 @@
  * to be trusted.
  *
  * <p>To extend this class, you must declare the service in your manifest file with
- * the {@link android.Manifest.permission#BIND_TRUST_AGENT_SERVICE} permission
+ * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
  * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
  * <pre>
  * &lt;service android:name=".TrustAgent"
  *          android:label="&#64;string/service_name"
- *          android:permission="android.permission.BIND_TRUST_AGENT_SERVICE">
+ *          android:permission="android.permission.BIND_TRUST_AGENT">
  *     &lt;intent-filter>
  *         &lt;action android:name="android.service.trust.TrustAgentService" />
  *     &lt;/intent-filter>
@@ -47,7 +47,7 @@
  * {@link android.R.styleable#TrustAgent}. For example:</p>
  *
  * <pre>
- * &lt;trust_agent xmlns:android="http://schemas.android.com/apk/res/android"
+ * &lt;trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
  *          android:settingsActivity=".TrustAgentSettings" /></pre>
  */
 public class TrustAgentService extends Service {
@@ -88,7 +88,7 @@
      *
      * @param successful true if the attempt succeeded
      */
-    protected void onUnlockAttempt(boolean successful) {
+    public void onUnlockAttempt(boolean successful) {
     }
 
     private void onError(String msg) {
@@ -96,7 +96,7 @@
     }
 
     /**
-     * Call to enable trust on the device.
+     * Call to grant trust on the device.
      *
      * @param message describes why the device is trusted, e.g. "Trusted by location".
      * @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust
@@ -104,10 +104,10 @@
      * @param initiatedByUser indicates that the user has explicitly initiated an action that proves
      *                        the user is about to use the device.
      */
-    protected final void enableTrust(String message, long durationMs, boolean initiatedByUser) {
+    public final void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser) {
         if (mCallback != null) {
             try {
-                mCallback.enableTrust(message, durationMs, initiatedByUser);
+                mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
             } catch (RemoteException e) {
                 onError("calling enableTrust()");
             }
@@ -117,7 +117,7 @@
     /**
      * Call to revoke trust on the device.
      */
-    protected final void revokeTrust() {
+    public final void revokeTrust() {
         if (mCallback != null) {
             try {
                 mCallback.revokeTrust();
diff --git a/core/java/android/service/voice/package.html b/core/java/android/service/voice/package.html
new file mode 100644
index 0000000..1c9bf9d
--- /dev/null
+++ b/core/java/android/service/voice/package.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+    {@hide}
+</body>
+</html>
diff --git a/core/java/android/hardware/camera2/Rational.java b/core/java/android/util/Rational.java
similarity index 92%
rename from core/java/android/hardware/camera2/Rational.java
rename to core/java/android/util/Rational.java
index 693ee2b..8d4c67f 100644
--- a/core/java/android/hardware/camera2/Rational.java
+++ b/core/java/android/util/Rational.java
@@ -13,11 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.camera2;
+package android.util;
 
 /**
- * The rational data type used by CameraMetadata keys. Contains a pair of ints representing the
- * numerator and denominator of a Rational number. This type is immutable.
+ * <p>An immutable data type representation a rational number.</p>
+ *
+ * <p>Contains a pair of {@code int}s representing the numerator and denominator of a
+ * Rational number. </p>
  */
 public final class Rational {
     private final int mNumerator;
@@ -30,7 +32,9 @@
      * is always positive.</p>
      *
      * <p>A rational value with a 0-denominator may be constructed, but will have similar semantics
-     * as float NaN and INF values. The int getter functions return 0 in this case.</p>
+     * as float {@code NaN} and {@code INF} values. For {@code NaN},
+     * both {@link #getNumerator} and {@link #getDenominator} functions will return 0. For
+     * positive or negative {@code INF}, only the {@link #getDenominator} will return 0.</p>
      *
      * @param numerator the numerator of the rational
      * @param denominator the denominator of the rational
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 7b49006..9601a8d 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -1220,10 +1220,6 @@
     }
 
     private RenderNode buildDisplayList(View view, HardwareCanvas canvas) {
-        if (mDrawDelta <= 0) {
-            return view.mRenderNode;
-        }
-
         view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
                 == View.PFLAG_INVALIDATED;
         view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 852fce5..b8e1b89 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -639,8 +639,13 @@
      * Wakes up the device.  Behaves somewhat like {@link #KEYCODE_POWER} but it
      * has no effect if the device is already awake. */
     public static final int KEYCODE_WAKEUP          = 224;
+    /** Key code constant: Pairing key.
+     * Initiates peripheral pairing mode. Useful for pairing remote control
+     * devices or game controllers, especially if no other input mode is
+     * available. */
+    public static final int KEYCODE_PAIRING         = 225;
 
-    private static final int LAST_KEYCODE = KEYCODE_WAKEUP;
+    private static final int LAST_KEYCODE = KEYCODE_PAIRING;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index f14e73f..c1a4fee 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.animation.Animator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
@@ -28,12 +29,12 @@
 import com.android.internal.view.animation.NativeInterpolatorFactory;
 
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 /**
  * @hide
  */
-public final class RenderNodeAnimator {
-
+public final class RenderNodeAnimator extends Animator {
     // Keep in sync with enum RenderProperty in Animator.h
     public static final int TRANSLATION_X = 0;
     public static final int TRANSLATION_Y = 1;
@@ -50,6 +51,11 @@
 
     // Keep in sync with enum PaintFields in Animator.h
     public static final int PAINT_STROKE_WIDTH = 0;
+
+    /**
+     * Field for the Paint alpha channel, which should be specified as a value
+     * between 0 and 255.
+     */
     public static final int PAINT_ALPHA = 1;
 
     // ViewPropertyAnimator uses a mask for its values, we need to remap them
@@ -74,8 +80,11 @@
     private VirtualRefBasePtr mNativePtr;
 
     private RenderNode mTarget;
+    private View mViewTarget;
     private TimeInterpolator mInterpolator;
+
     private boolean mStarted = false;
+    private boolean mFinished = false;
 
     public int mapViewPropertyToRenderProperty(int viewProperty) {
         return sViewPropertyAnimatorMap.get(viewProperty);
@@ -92,6 +101,14 @@
                 property.getNativeContainer(), finalValue));
     }
 
+    /**
+     * Creates a new render node animator for a field on a Paint property.
+     *
+     * @param property The paint property to target
+     * @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
+     *            {@link #PAINT_STROKE_WIDTH}
+     * @param finalValue The target value for the property
+     */
     public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
         init(nCreateCanvasPropertyPaintAnimator(
                 new WeakReference<RenderNodeAnimator>(this),
@@ -115,56 +132,139 @@
         if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) {
             ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
         } else {
-            int duration = nGetDuration(mNativePtr.get());
+            long duration = nGetDuration(mNativePtr.get());
             ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
         }
         nSetInterpolator(mNativePtr.get(), ni);
     }
 
-    private void start(RenderNode node) {
+    @Override
+    public void start() {
+        if (mTarget == null) {
+            throw new IllegalStateException("Missing target!");
+        }
+
         if (mStarted) {
             throw new IllegalStateException("Already started!");
         }
+
         mStarted = true;
         applyInterpolator();
-        mTarget = node;
         mTarget.addAnimator(this);
+
+        final ArrayList<AnimatorListener> listeners = getListeners();
+        final int numListeners = listeners == null ? 0 : listeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            listeners.get(i).onAnimationStart(this);
+        }
+
+        if (mViewTarget != null) {
+            // Kick off a frame to start the process
+            mViewTarget.invalidateViewProperty(true, false);
+        }
     }
 
-    public void start(View target) {
-        start(target.mRenderNode);
-        // Kick off a frame to start the process
-        target.invalidateViewProperty(true, false);
+    @Override
+    public void cancel() {
+        mTarget.removeAnimator(this);
+
+        final ArrayList<AnimatorListener> listeners = getListeners();
+        final int numListeners = listeners == null ? 0 : listeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            listeners.get(i).onAnimationCancel(this);
+        }
     }
 
-    public void start(Canvas canvas) {
+    @Override
+    public void end() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void pause() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void resume() {
+        throw new UnsupportedOperationException();
+    }
+
+    public void setTarget(View view) {
+        mViewTarget = view;
+        mTarget = view.mRenderNode;
+    }
+
+    public void setTarget(Canvas canvas) {
         if (!(canvas instanceof GLES20RecordingCanvas)) {
             throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
         }
-        GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
-        start(recordingCanvas.mNode);
+
+        final GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
+        setTarget(recordingCanvas.mNode);
     }
 
-    public void cancel() {
-        mTarget.removeAnimator(this);
+    public void setTarget(RenderNode node) {
+        mViewTarget = null;
+        mTarget = node;
     }
 
-    public void setDuration(int duration) {
+    public RenderNode getTarget() {
+        return mTarget;
+    }
+
+    @Override
+    public void setStartDelay(long startDelay) {
+        checkMutable();
+        nSetStartDelay(mNativePtr.get(), startDelay);
+    }
+
+    @Override
+    public long getStartDelay() {
+        return nGetStartDelay(mNativePtr.get());
+    }
+
+    @Override
+    public RenderNodeAnimator setDuration(long duration) {
         checkMutable();
         nSetDuration(mNativePtr.get(), duration);
+        return this;
     }
 
+    @Override
+    public long getDuration() {
+        return nGetDuration(mNativePtr.get());
+    }
+
+    @Override
+    public boolean isRunning() {
+        return mStarted && !mFinished;
+    }
+
+    @Override
     public void setInterpolator(TimeInterpolator interpolator) {
         checkMutable();
         mInterpolator = interpolator;
     }
 
-    long getNativeAnimator() {
-        return mNativePtr.get();
+    @Override
+    public TimeInterpolator getInterpolator() {
+        return mInterpolator;
     }
 
     private void onFinished() {
+        mFinished = true;
         mTarget.removeAnimator(this);
+
+        final ArrayList<AnimatorListener> listeners = getListeners();
+        final int numListeners = listeners == null ? 0 : listeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            listeners.get(i).onAnimationEnd(this);
+        }
+    }
+
+    long getNativeAnimator() {
+        return mNativePtr.get();
     }
 
     // Called by native
@@ -181,7 +281,9 @@
             long canvasProperty, float deltaValue);
     private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
             long canvasProperty, int paintField, float deltaValue);
-    private static native void nSetDuration(long nativePtr, int duration);
-    private static native int nGetDuration(long nativePtr);
+    private static native void nSetDuration(long nativePtr, long duration);
+    private static native long nGetDuration(long nativePtr);
+    private static native void nSetStartDelay(long nativePtr, long startDelay);
+    private static native long nGetStartDelay(long nativePtr);
     private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5141877..fb7d57d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4774,8 +4774,8 @@
                 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this);
             }
 
-            manageFocusHotspot(true, oldFocus);
             onFocusChanged(true, direction, previouslyFocusedRect);
+            manageFocusHotspot(true, oldFocus);
             refreshDrawableState();
         }
     }
@@ -6752,6 +6752,24 @@
     }
 
     /**
+     * Sets the pressed state for this view and provides a touch coordinate for
+     * animation hinting.
+     *
+     * @param pressed Pass true to set the View's internal state to "pressed",
+     *            or false to reverts the View's internal state from a
+     *            previously set "pressed" state.
+     * @param x The x coordinate of the touch that caused the press
+     * @param y The y coordinate of the touch that caused the press
+     */
+    private void setPressed(boolean pressed, float x, float y) {
+        if (pressed) {
+            setHotspot(R.attr.state_pressed, x, y);
+        }
+
+        setPressed(pressed);
+    }
+
+    /**
      * Sets the pressed state for this view.
      *
      * @see #isClickable()
@@ -6769,6 +6787,10 @@
             mPrivateFlags &= ~PFLAG_PRESSED;
         }
 
+        if (!pressed) {
+            clearHotspot(R.attr.state_pressed);
+        }
+
         if (needsRefresh) {
             refreshDrawableState();
         }
@@ -8993,7 +9015,6 @@
 
         if ((viewFlags & ENABLED_MASK) == DISABLED) {
             if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
-                clearHotspot(R.attr.state_pressed);
                 setPressed(false);
             }
             // A disabled view that is clickable still consumes the touch
@@ -9026,8 +9047,7 @@
                             // showed it as pressed.  Make it show the pressed
                             // state now (before scheduling the click) to ensure
                             // the user sees it.
-                            setHotspot(R.attr.state_pressed, x, y);
-                            setPressed(true);
+                            setPressed(true, x, y);
                        }
 
                         if (!mHasPerformedLongPress) {
@@ -9061,8 +9081,6 @@
                         }
 
                         removeTapCallback();
-                    } else {
-                        clearHotspot(R.attr.state_pressed);
                     }
                     break;
 
@@ -9175,7 +9193,6 @@
      */
     private void removeUnsetPressCallback() {
         if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) {
-            clearHotspot(R.attr.state_pressed);
             setPressed(false);
             removeCallbacks(mUnsetPressedState);
         }
@@ -19234,8 +19251,7 @@
         @Override
         public void run() {
             mPrivateFlags &= ~PFLAG_PREPRESSED;
-            setHotspot(R.attr.state_pressed, x, y);
-            setPressed(true);
+            setPressed(true, x, y);
             checkForLongClick(ViewConfiguration.getTapTimeout());
         }
     }
@@ -19516,7 +19532,6 @@
     private final class UnsetPressedState implements Runnable {
         @Override
         public void run() {
-            clearHotspot(R.attr.state_pressed);
             setPressed(false);
         }
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9b09d85..eed6412 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -111,6 +111,7 @@
     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
     private static final boolean DEBUG_FPS = false;
+    private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
 
     /**
      * Set this system property to true to force the view hierarchy to render
@@ -668,6 +669,11 @@
     public void detachFunctor(long functor) {
         // TODO: Make the resize buffer some other way to not need this block
         mBlockResizeBuffer = true;
+        if (mAttachInfo.mHardwareRenderer != null) {
+            // Fence so that any pending invokeFunctor() messages will be processed
+            // before we return from detachFunctor.
+            mAttachInfo.mHardwareRenderer.fence();
+        }
     }
 
     public boolean invokeFunctor(long functor, boolean waitForCompletion) {
@@ -3481,6 +3487,9 @@
          * Called when an event is being delivered to the next stage.
          */
         protected void onDeliverToNext(QueuedInputEvent q) {
+            if (DEBUG_INPUT_STAGES) {
+                Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);
+            }
             if (mNext != null) {
                 mNext.deliver(q);
             } else {
@@ -5515,6 +5524,37 @@
 
             return false;
         }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
+            boolean hasPrevious = false;
+            hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
+            hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
+            hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
+            hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
+            hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
+            hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
+            if (!hasPrevious) {
+                sb.append("0");
+            }
+            sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
+            sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
+            sb.append(", mEvent=" + mEvent + "}");
+            return sb.toString();
+        }
+
+        private boolean flagToString(String name, int flag,
+                boolean hasPrevious, StringBuilder sb) {
+            if ((mFlags & flag) != 0) {
+                if (hasPrevious) {
+                    sb.append("|");
+                }
+                sb.append(name);
+                return true;
+            }
+            return hasPrevious;
+        }
     }
 
     private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 438e164..74a3eec 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -666,6 +666,8 @@
             case MotionEvent.ACTION_CANCEL: {
                 if (mTouchMode == TOUCH_MODE_DRAGGING) {
                     stopDrag(ev);
+                    // Allow super class to handle pressed state, etc.
+                    super.onTouchEvent(ev);
                     return true;
                 }
                 mTouchMode = TOUCH_MODE_IDLE;
@@ -801,7 +803,7 @@
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    public void draw(Canvas c) {
         final Rect tempRect = mTempRect;
         final Drawable trackDrawable = mTrackDrawable;
         final Drawable thumbDrawable = mThumbDrawable;
@@ -815,9 +817,6 @@
         trackDrawable.getPadding(tempRect);
 
         final int switchInnerLeft = switchLeft + tempRect.left;
-        final int switchInnerTop = switchTop + tempRect.top;
-        final int switchInnerRight = switchRight - tempRect.right;
-        final int switchInnerBottom = switchBottom - tempRect.bottom;
 
         // Relies on mTempRect, MUST be called first!
         final int thumbPos = getThumbOffset();
@@ -833,8 +832,26 @@
             background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
         }
 
+        // Draw the background.
+        super.draw(c);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
+        final Rect tempRect = mTempRect;
+        final Drawable trackDrawable = mTrackDrawable;
+        final Drawable thumbDrawable = mThumbDrawable;
+        trackDrawable.getPadding(tempRect);
+
+        final int switchTop = mSwitchTop;
+        final int switchBottom = mSwitchBottom;
+        final int switchInnerLeft = mSwitchLeft + tempRect.left;
+        final int switchInnerTop = switchTop + tempRect.top;
+        final int switchInnerRight = mSwitchRight - tempRect.right;
+        final int switchInnerBottom = switchBottom - tempRect.bottom;
+
         if (mSplitTrack) {
             final Insets insets = thumbDrawable.getOpticalInsets();
             thumbDrawable.copyBounds(tempRect);
@@ -861,7 +878,8 @@
             }
             mTextPaint.drawableState = drawableState;
 
-            final int left = (thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2;
+            final Rect thumbBounds = thumbDrawable.getBounds();
+            final int left = (thumbBounds.left + thumbBounds.right) / 2 - switchText.getWidth() / 2;
             final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
             canvas.translate(left, top);
             switchText.draw(canvas);
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index cd75010..8e6fa58 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.app;
 
 import android.app.AppOpsManager;
+import android.os.Bundle;
 import com.android.internal.app.IAppOpsCallback;
 
 interface IAppOpsService {
@@ -38,4 +39,10 @@
     void resetAllModes();
     int checkAudioOperation(int code, int stream, int uid, String packageName);
     void setAudioRestriction(int code, int stream, int uid, int mode, in String[] exceptionPackages);
+
+    void setDeviceOwner(String packageName);
+    void setProfileOwner(String packageName, int userHandle);
+    void setUserRestrictions(in Bundle restrictions, int userHandle);
+    void removeUser(int userHandle);
+
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 956c86d..8428f66 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -235,7 +235,8 @@
 
     int mWakeLockNesting;
     boolean mWakeLockImportant;
-    public boolean mRecordAllWakeLocks;
+    boolean mRecordAllWakeLocks;
+    boolean mNoAutoReset;
 
     int mScreenState = Display.STATE_UNKNOWN;
     StopwatchTimer mScreenOnTimer;
@@ -2314,9 +2315,6 @@
         }
     }
 
-    private String mInitialAcquireWakeName;
-    private int mInitialAcquireWakeUid = -1;
-
     public void setRecordAllWakeLocksLocked(boolean enabled) {
         mRecordAllWakeLocks = enabled;
         if (!enabled) {
@@ -2325,6 +2323,13 @@
         }
     }
 
+    public void setNoAutoReset(boolean enabled) {
+        mNoAutoReset = enabled;
+    }
+
+    private String mInitialAcquireWakeName;
+    private int mInitialAcquireWakeUid = -1;
+
     public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
             boolean unimportantForLogging, long elapsedRealtime, long uptime) {
         uid = mapUid(uid);
@@ -2355,6 +2360,7 @@
             } else if (mRecordAllWakeLocks) {
                 if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
                         uid, 0)) {
+                    mWakeLockNesting++;
                     return;
                 }
                 addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_START,
@@ -5942,9 +5948,9 @@
             // we have gone through a significant charge (from a very low
             // level to a now very high level).
             boolean reset = false;
-            if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
+            if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
                     || level >= 90
-                    || (mDischargeCurrentLevel < 20 && level >= 80)) {
+                    || (mDischargeCurrentLevel < 20 && level >= 80))) {
                 doWrite = true;
                 resetAllStatsLocked();
                 mDischargeStartLevel = level;
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
index aec2b7e..1feb943 100644
--- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -34,11 +34,11 @@
      * Used to cache the float[] LUT for use across multiple native
      * interpolator creation
      */
-    public FallbackLUTInterpolator(TimeInterpolator interpolator, int duration) {
+    public FallbackLUTInterpolator(TimeInterpolator interpolator, long duration) {
         mLut = createLUT(interpolator, duration);
     }
 
-    private static float[] createLUT(TimeInterpolator interpolator, int duration) {
+    private static float[] createLUT(TimeInterpolator interpolator, long duration) {
         long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
         int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
         int numAnimFrames = (int) Math.ceil(duration / animIntervalMs);
@@ -59,7 +59,7 @@
     /**
      * Used to create a one-shot float[] LUT & native interpolator
      */
-    public static long createNativeInterpolator(TimeInterpolator interpolator, int duration) {
+    public static long createNativeInterpolator(TimeInterpolator interpolator, long duration) {
         float[] lut = createLUT(interpolator, duration);
         return NativeInterpolatorFactoryHelper.createLutInterpolator(lut);
     }
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index bf58918..9279758 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -367,7 +367,6 @@
         bool forceLTR = false;
         bool forceRTL = false;
 
-        ALOGD("computeValues dirFlags=%d", dirFlags);
         switch (dirFlags & kBidi_Mask) {
             case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
             case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
diff --git a/core/jni/android_media_AudioErrors.h b/core/jni/android_media_AudioErrors.h
new file mode 100644
index 0000000..4907830
--- /dev/null
+++ b/core/jni/android_media_AudioErrors.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_AUDIOERRORS_H
+#define ANDROID_MEDIA_AUDIOERRORS_H
+
+#include <utils/Errors.h>
+
+namespace android {
+// status codes used by JAVA APIs. Translation from native error codes is done by
+// nativeToJavaStatus()
+// must be kept in sync with values in
+// frameworks/base/media/java/android/media/AudioSystem.java.
+enum {
+    AUDIO_JAVA_SUCCESS            = 0,
+    AUDIO_JAVA_ERROR              = -1,
+    AUDIO_JAVA_BAD_VALUE          = -2,
+    AUDIO_JAVA_INVALID_OPERATION  = -3,
+    AUDIO_JAVA_PERMISSION_DENIED  = -4,
+    AUDIO_JAVA_NO_INIT            = -5,
+    AUDIO_JAVA_DEAD_OBJECT        = -6,
+};
+
+static inline jint nativeToJavaStatus(status_t status) {
+    switch (status) {
+    case NO_ERROR:
+        return AUDIO_JAVA_SUCCESS;
+    case BAD_VALUE:
+        return AUDIO_JAVA_BAD_VALUE;
+    case INVALID_OPERATION:
+        return AUDIO_JAVA_INVALID_OPERATION;
+    case PERMISSION_DENIED:
+        return AUDIO_JAVA_PERMISSION_DENIED;
+    case NO_INIT:
+        return AUDIO_JAVA_NO_INIT;
+    case DEAD_OBJECT:
+        return AUDIO_JAVA_DEAD_OBJECT;
+    default:
+        return AUDIO_JAVA_ERROR;
+    }
+}
+}; // namespace android
+#endif // ANDROID_MEDIA_AUDIOERRORS_H
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 09bdc61..a54eba1 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -27,6 +27,7 @@
 #include <media/AudioRecord.h>
 
 #include "android_media_AudioFormat.h"
+#include "android_media_AudioErrors.h"
 
 // ----------------------------------------------------------------------------
 
@@ -55,29 +56,12 @@
 
 // ----------------------------------------------------------------------------
 
-#define AUDIORECORD_SUCCESS                         0
-#define AUDIORECORD_ERROR                           -1
-#define AUDIORECORD_ERROR_BAD_VALUE                 -2
-#define AUDIORECORD_ERROR_INVALID_OPERATION         -3
 #define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      -16
 #define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
 #define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       -18
 #define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       -19
 #define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    -20
 
-jint android_media_translateRecorderErrorCode(int code) {
-    switch (code) {
-    case NO_ERROR:
-        return AUDIORECORD_SUCCESS;
-    case BAD_VALUE:
-        return AUDIORECORD_ERROR_BAD_VALUE;
-    case INVALID_OPERATION:
-        return AUDIORECORD_ERROR_INVALID_OPERATION;
-    default:
-        return AUDIORECORD_ERROR;
-    }
-}
-
 // ----------------------------------------------------------------------------
 static void recorderCallback(int event, void* user, void *info) {
 
@@ -197,13 +181,13 @@
 
     if (jSession == NULL) {
         ALOGE("Error creating AudioRecord: invalid session ID pointer");
-        return (jint) AUDIORECORD_ERROR;
+        return (jint) AUDIO_JAVA_ERROR;
     }
 
     jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
     if (nSession == NULL) {
         ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
-        return (jint) AUDIORECORD_ERROR;
+        return (jint) AUDIO_JAVA_ERROR;
     }
     int sessionId = nSession[0];
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
@@ -259,7 +243,7 @@
     // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
     env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
 
-    return (jint) AUDIORECORD_SUCCESS;
+    return (jint) AUDIO_JAVA_SUCCESS;
 
     // failure:
 native_init_failure:
@@ -280,10 +264,10 @@
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
     if (lpRecorder == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return (jint) AUDIORECORD_ERROR;
+        return (jint) AUDIO_JAVA_ERROR;
     }
 
-    return (jint) android_media_translateRecorderErrorCode(
+    return nativeToJavaStatus(
             lpRecorder->start((AudioSystem::sync_event_t)event, triggerSession));
 }
 
@@ -383,7 +367,7 @@
     env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
 
     if (readSize < 0) {
-        readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+        readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
     }
     return (jint) readSize;
 }
@@ -428,7 +412,7 @@
     env->ReleaseShortArrayElements(javaAudioData, recordBuff, 0);
 
     if (readSize < 0) {
-        readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+        readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
     } else {
         readSize /= sizeof(short);
     }
@@ -461,7 +445,7 @@
     ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
                                    capacity < sizeInBytes ? capacity : sizeInBytes);
     if (readSize < 0) {
-        readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+        readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
     }
     return (jint)readSize;
 }
@@ -475,9 +459,9 @@
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioRecord pointer for setMarkerPosition()");
-        return AUDIORECORD_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateRecorderErrorCode( lpRecorder->setMarkerPosition(markerPos) );
+    return nativeToJavaStatus( lpRecorder->setMarkerPosition(markerPos) );
 }
 
 
@@ -490,7 +474,7 @@
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioRecord pointer for getMarkerPosition()");
-        return AUDIORECORD_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     lpRecorder->getMarkerPosition(&markerPos);
     return (jint)markerPos;
@@ -506,9 +490,9 @@
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
-        return AUDIORECORD_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateRecorderErrorCode( lpRecorder->setPositionUpdatePeriod(period) );
+    return nativeToJavaStatus( lpRecorder->setPositionUpdatePeriod(period) );
 }
 
 
@@ -521,7 +505,7 @@
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
-        return AUDIORECORD_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     lpRecorder->getPositionUpdatePeriod(&period);
     return (jint)period;
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 463a0a8..e548e91 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -32,6 +32,7 @@
 #include <binder/MemoryBase.h>
 
 #include "android_media_AudioFormat.h"
+#include "android_media_AudioErrors.h"
 
 // ----------------------------------------------------------------------------
 
@@ -94,31 +95,12 @@
 // ----------------------------------------------------------------------------
 #define DEFAULT_OUTPUT_SAMPLE_RATE   44100
 
-#define AUDIOTRACK_SUCCESS                         0
-#define AUDIOTRACK_ERROR                           -1
-#define AUDIOTRACK_ERROR_BAD_VALUE                 -2
-#define AUDIOTRACK_ERROR_INVALID_OPERATION         -3
 #define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM         -16
 #define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK  -17
 #define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT       -18
 #define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE   -19
 #define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED    -20
 
-
-jint android_media_translateErrorCode(int code) {
-    switch (code) {
-    case NO_ERROR:
-        return AUDIOTRACK_SUCCESS;
-    case BAD_VALUE:
-        return AUDIOTRACK_ERROR_BAD_VALUE;
-    case INVALID_OPERATION:
-        return AUDIOTRACK_ERROR_INVALID_OPERATION;
-    default:
-        return AUDIOTRACK_ERROR;
-    }
-}
-
-
 // ----------------------------------------------------------------------------
 static void audioCallback(int event, void* user, void *info) {
 
@@ -201,22 +183,6 @@
 {
     ALOGV("sampleRate=%d, audioFormat(from Java)=%d, channel mask=%x, buffSize=%d",
         sampleRateInHertz, audioFormat, javaChannelMask, buffSizeInBytes);
-    uint32_t afSampleRate;
-    size_t afFrameCount;
-
-    status_t status = AudioSystem::getOutputFrameCount(&afFrameCount,
-            (audio_stream_type_t) streamType);
-    if (status != NO_ERROR) {
-        ALOGE("Error %d creating AudioTrack: Could not get AudioSystem frame count "
-              "for stream type %d.", status, streamType);
-        return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
-    }
-    status = AudioSystem::getOutputSamplingRate(&afSampleRate, (audio_stream_type_t) streamType);
-    if (status != NO_ERROR) {
-        ALOGE("Error %d creating AudioTrack: Could not get AudioSystem sampling rate "
-              "for stream type %d.", status, streamType);
-        return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
-    }
 
     // Java channel masks don't map directly to the native definition, but it's a simple shift
     // to skip the two deprecated channel configurations "default" and "mono".
@@ -229,23 +195,8 @@
 
     uint32_t channelCount = popcount(nativeChannelMask);
 
-    // check the stream type
-    audio_stream_type_t atStreamType;
-    switch (streamType) {
-    case AUDIO_STREAM_VOICE_CALL:
-    case AUDIO_STREAM_SYSTEM:
-    case AUDIO_STREAM_RING:
-    case AUDIO_STREAM_MUSIC:
-    case AUDIO_STREAM_ALARM:
-    case AUDIO_STREAM_NOTIFICATION:
-    case AUDIO_STREAM_BLUETOOTH_SCO:
-    case AUDIO_STREAM_DTMF:
-        atStreamType = (audio_stream_type_t) streamType;
-        break;
-    default:
-        ALOGE("Error creating AudioTrack: unknown stream type %d.", streamType);
-        return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
-    }
+    // stream type already checked in Java
+    audio_stream_type_t atStreamType = (audio_stream_type_t) streamType;
 
     // check the format.
     // This function was called from Java, so we compare the format against the Java constants
@@ -280,13 +231,13 @@
 
     if (jSession == NULL) {
         ALOGE("Error creating AudioTrack: invalid session ID pointer");
-        return (jint) AUDIOTRACK_ERROR;
+        return (jint) AUDIO_JAVA_ERROR;
     }
 
     jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
     if (nSession == NULL) {
         ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
-        return (jint) AUDIOTRACK_ERROR;
+        return (jint) AUDIO_JAVA_ERROR;
     }
     int sessionId = nSession[0];
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
@@ -305,6 +256,7 @@
     lpJniStorage->mCallbackData.busy = false;
 
     // initialize the native AudioTrack object
+    status_t status = NO_ERROR;
     switch (memoryMode) {
     case MODE_STREAM:
 
@@ -376,7 +328,7 @@
     //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
     env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
 
-    return (jint) AUDIOTRACK_SUCCESS;
+    return (jint) AUDIO_JAVA_SUCCESS;
 
     // failures:
 native_init_failure:
@@ -626,7 +578,7 @@
     ScopedBytesRO bytes(env, javaBytes);
     if (bytes.get() == NULL) {
         ALOGE("Error retrieving source of audio data to play, can't play");
-        return AUDIOTRACK_ERROR_BAD_VALUE;
+        return (jint)AUDIO_JAVA_BAD_VALUE;
     }
 
     jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get(), byteOffset,
@@ -725,7 +677,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for frameCount()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
 
     return lpTrack->frameCount();
@@ -739,9 +691,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setSampleRate()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
+    return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
 }
 
 
@@ -751,7 +703,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for getSampleRate()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     return (jint) lpTrack->getSampleRate();
 }
@@ -764,9 +716,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );
+    return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
 }
 
 
@@ -778,7 +730,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     lpTrack->getMarkerPosition(&markerPos);
     return (jint)markerPos;
@@ -792,9 +744,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );
+    return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
 }
 
 
@@ -806,7 +758,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     lpTrack->getPositionUpdatePeriod(&period);
     return (jint)period;
@@ -820,9 +772,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setPosition()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->setPosition(position) );
+    return nativeToJavaStatus( lpTrack->setPosition(position) );
 }
 
 
@@ -834,7 +786,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for getPosition()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     lpTrack->getPosition(&position);
     return (jint)position;
@@ -848,7 +800,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for latency()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     return (jint)lpTrack->latency();
 }
@@ -860,7 +812,7 @@
 
     if (lpTrack == NULL) {
         ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     AudioTimestamp timestamp;
     status_t status = lpTrack->getTimestamp(timestamp);
@@ -868,13 +820,13 @@
         jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
         if (nTimestamp == NULL) {
             ALOGE("Unable to get array for getTimestamp()");
-            return AUDIOTRACK_ERROR;
+            return (jint)AUDIO_JAVA_ERROR;
         }
         nTimestamp[0] = (jlong) timestamp.mPosition;
         nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
         env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
     }
-    return (jint) android_media_translateErrorCode(status);
+    return (jint) nativeToJavaStatus(status);
 }
 
 
@@ -885,9 +837,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setLoop()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
+    return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
 }
 
 
@@ -897,9 +849,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for reload()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->reload() );
+    return nativeToJavaStatus( lpTrack->reload() );
 }
 
 
@@ -982,9 +934,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
+    return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
 }
 
 // ----------------------------------------------------------------------------
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index ea2f96e..e19ce36 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -116,15 +116,26 @@
     return reinterpret_cast<jlong>( animator );
 }
 
-static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jint duration) {
+static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong duration) {
     LOG_ALWAYS_FATAL_IF(duration < 0, "Duration cannot be negative");
     BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
     animator->setDuration(duration);
 }
 
-static jint getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+static jlong getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
     BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
-    return static_cast<jint>(animator->duration());
+    return static_cast<jlong>(animator->duration());
+}
+
+static void setStartDelay(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong startDelay) {
+    LOG_ALWAYS_FATAL_IF(startDelay < 0, "Start delay cannot be negative");
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+    animator->setStartDelay(startDelay);
+}
+
+static jlong getStartDelay(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+    return static_cast<jlong>(animator->startDelay());
 }
 
 static void setInterpolator(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong interpolatorPtr) {
@@ -146,8 +157,10 @@
     { "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IF)J", (void*) createAnimator },
     { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JF)J", (void*) createCanvasPropertyFloatAnimator },
     { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyPaintAnimator },
-    { "nSetDuration", "(JI)V", (void*) setDuration },
-    { "nGetDuration", "(J)I", (void*) getDuration },
+    { "nSetDuration", "(JJ)V", (void*) setDuration },
+    { "nGetDuration", "(J)J", (void*) getDuration },
+    { "nSetStartDelay", "(JJ)V", (void*) setStartDelay },
+    { "nGetStartDelay", "(J)J", (void*) getStartDelay },
     { "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
 #endif
 };
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cdb77f1..f262a93 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2056,7 +2056,7 @@
         android:protectionLevel="signature|system" />
 
     <!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it. @hide -->
     <permission android:name="android.permission.BIND_VOICE_INTERACTION"
         android:label="@string/permlab_bindVoiceInteraction"
         android:description="@string/permdesc_bindVoiceInteraction"
@@ -2613,7 +2613,7 @@
     <!-- Must be required by an {@link
          android.service.trust.TrustAgentService},
          to ensure that only the system can bind to it. -->
-    <permission android:name="android.permission.BIND_TRUST_AGENT_SERVICE"
+    <permission android:name="android.permission.BIND_TRUST_AGENT"
                 android:protectionLevel="signature"
                 android:label="@string/permlab_bind_trust_agent_service"
                 android:description="@string/permdesc_bind_trust_agent_service" />
diff --git a/core/res/res/layout/notification_action.xml b/core/res/res/layout/notification_action.xml
deleted file mode 100644
index 4e7c74c..0000000
--- a/core/res/res/layout/notification_action.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
-    style="?android:attr/borderlessButtonStyle" 
-    android:id="@+id/action0"
-    android:layout_width="0dp"
-    android:layout_height="48dp"
-    android:layout_weight="1"
-    android:gravity="start|center_vertical"
-    android:drawablePadding="8dp"
-    android:paddingStart="8dp"
-    android:textColor="#ccc"
-    android:textSize="14dp"
-    android:singleLine="true"
-    android:ellipsize="end"
-    />
diff --git a/core/res/res/layout/notification_action_tombstone.xml b/core/res/res/layout/notification_action_tombstone.xml
deleted file mode 100644
index 9977cfe..0000000
--- a/core/res/res/layout/notification_action_tombstone.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
-    style="?android:attr/borderlessButtonStyle" 
-    android:id="@+id/action0"
-    android:layout_width="0dp"
-    android:layout_height="48dp"
-    android:layout_weight="1"
-    android:gravity="start|center_vertical"
-    android:drawablePadding="8dp"
-    android:paddingStart="8dp"
-    android:textColor="#ccc"
-    android:textSize="14dp"
-    android:singleLine="true"
-    android:ellipsize="end"
-    android:alpha="0.5"
-    android:enabled="false"
-    />
diff --git a/core/res/res/layout/notification_template_base.xml b/core/res/res/layout/notification_template_base.xml
deleted file mode 100644
index d2e25c1..0000000
--- a/core/res/res/layout/notification_template_base.xml
+++ /dev/null
@@ -1,136 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_bg"
-    android:id="@+id/status_bar_latest_event_content"
-    android:layout_width="match_parent"
-    android:layout_height="64dp"
-    internal:layout_minHeight="64dp"
-    internal:layout_maxHeight="64dp"
-    >
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@dimen/notification_large_icon_width"
-        android:layout_height="@dimen/notification_large_icon_height"
-        android:background="@android:drawable/notification_template_icon_bg"
-        android:scaleType="center"
-        />
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="fill_vertical"
-        android:layout_marginStart="@dimen/notification_large_icon_width"
-        android:minHeight="@dimen/notification_large_icon_height"
-        android:orientation="vertical"
-        android:paddingEnd="8dp"
-        android:paddingTop="2dp"
-        android:paddingBottom="2dp"
-        android:gravity="top"
-        >
-        <LinearLayout
-            android:id="@+id/line1"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="6dp"
-            android:layout_marginStart="8dp"
-            android:orientation="horizontal"
-            >
-            <TextView android:id="@+id/title"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                android:layout_weight="1"
-                />
-            <ViewStub android:id="@+id/time"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="0"
-                android:visibility="gone"
-                android:layout="@layout/notification_template_part_time"
-                />
-            <ViewStub android:id="@+id/chronometer"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="0"
-                android:visibility="gone"
-                android:layout="@layout/notification_template_part_chronometer"
-                />
-        </LinearLayout>
-        <TextView android:id="@+id/text2"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="-2dp"
-            android:layout_marginBottom="-2dp"
-            android:layout_marginStart="8dp"
-            android:singleLine="true"
-            android:fadingEdge="horizontal"
-            android:ellipsize="marquee"
-            android:visibility="gone"
-            />
-        <ProgressBar
-            android:id="@android:id/progress"
-            android:layout_width="match_parent"
-            android:layout_height="12dp"
-            android:layout_marginStart="8dp"
-            android:visibility="gone"
-            style="?android:attr/progressBarStyleHorizontal"
-            />
-        <LinearLayout
-            android:id="@+id/line3"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:gravity="center_vertical"
-            android:layout_marginStart="8dp"
-            >
-            <TextView android:id="@+id/text"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:layout_gravity="center"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                />
-            <TextView android:id="@+id/info"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:singleLine="true"
-                android:gravity="center"
-                android:paddingStart="8dp"
-                />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
-        </LinearLayout>
-    </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_base.xml b/core/res/res/layout/notification_template_big_base.xml
deleted file mode 100644
index 7cc6650..0000000
--- a/core/res/res/layout/notification_template_big_base.xml
+++ /dev/null
@@ -1,167 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_bg"
-    android:id="@+id/status_bar_latest_event_content"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
-    >
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@dimen/notification_large_icon_width"
-        android:layout_height="@dimen/notification_large_icon_height"
-        android:background="@android:drawable/notification_template_icon_bg"
-        android:scaleType="center"
-        />
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="fill_vertical"
-        android:minHeight="@dimen/notification_large_icon_height"
-        android:orientation="vertical"
-        android:gravity="top"
-        >
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="@dimen/notification_large_icon_width"
-            android:minHeight="@dimen/notification_large_icon_height"
-            android:paddingTop="2dp"
-            android:orientation="vertical"
-            >
-            <LinearLayout
-                android:id="@+id/line1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingTop="6dp"
-                android:layout_marginEnd="8dp"
-                android:layout_marginStart="8dp"
-                android:orientation="horizontal"
-                >
-                <TextView android:id="@+id/title"
-                    android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:fadingEdge="horizontal"
-                    android:layout_weight="1"
-                    />
-                <ViewStub android:id="@+id/time"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_time"
-                    />
-                <ViewStub android:id="@+id/chronometer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_chronometer"
-                    />
-            </LinearLayout>
-            <TextView android:id="@+id/text2"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="-2dp"
-                android:layout_marginBottom="-2dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:fadingEdge="horizontal"
-                android:ellipsize="marquee"
-                android:visibility="gone"
-                />
-            <TextView android:id="@+id/big_text"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="false"
-                android:visibility="gone"
-                />
-            <LinearLayout
-                android:id="@+id/line3"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:orientation="horizontal"
-                android:gravity="center_vertical"
-                >
-                <TextView android:id="@+id/text"
-                    android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                    android:layout_width="0dp"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1"
-                    android:layout_gravity="center"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:fadingEdge="horizontal"
-                    />
-                <TextView android:id="@+id/info"
-                    android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:layout_weight="0"
-                    android:singleLine="true"
-                    android:gravity="center"
-                    android:paddingStart="8dp"
-                    />
-                <ImageView android:id="@+id/right_icon"
-                    android:layout_width="16dp"
-                    android:layout_height="16dp"
-                    android:layout_gravity="center"
-                    android:layout_weight="0"
-                    android:layout_marginStart="8dp"
-                    android:scaleType="centerInside"
-                    android:visibility="gone"
-                    android:drawableAlpha="153"
-                    />
-            </LinearLayout>
-            <ProgressBar
-                android:id="@android:id/progress"
-                android:layout_width="match_parent"
-                android:layout_height="12dp"
-                android:layout_marginBottom="8dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:visibility="gone"
-                style="?android:attr/progressBarStyleHorizontal"
-                />
-        </LinearLayout>
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:id="@+id/action_divider"
-            android:visibility="gone"
-            android:background="?android:attr/dividerHorizontal" />
-        <include
-            layout="@layout/notification_action_list"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="@dimen/notification_large_icon_width"
-            />
-    </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_picture.xml b/core/res/res/layout/notification_template_big_picture.xml
deleted file mode 100644
index f3f3951..0000000
--- a/core/res/res/layout/notification_template_big_picture.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_bg"
-    android:id="@+id/status_bar_latest_event_content"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
-    >
-    <ImageView
-        android:id="@+id/big_picture"
-        android:layout_width="match_parent"
-        android:layout_height="192dp"
-        android:layout_marginTop="64dp"
-        android:layout_gravity="bottom"
-        android:scaleType="centerCrop"
-        />
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="6dp"
-        android:layout_marginTop="64dp"
-        android:scaleType="fitXY"
-        android:src="@drawable/title_bar_shadow"
-        />
-    <include layout="@layout/notification_template_base"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        />
-  <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="208dp"
-        android:paddingStart="64dp"
-        android:layout_gravity="bottom"
-        android:background="#CC111111"
-        >
-        <include
-            layout="@layout/notification_action_list"
-            android:id="@+id/actions"
-            android:layout_gravity="bottom"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
-    </FrameLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_text.xml b/core/res/res/layout/notification_template_big_text.xml
deleted file mode 100644
index 7e6da22..0000000
--- a/core/res/res/layout/notification_template_big_text.xml
+++ /dev/null
@@ -1,183 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_bg"
-    android:id="@+id/status_bar_latest_event_content"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
-    >
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@dimen/notification_large_icon_width"
-        android:layout_height="@dimen/notification_large_icon_height"
-        android:background="@android:drawable/notification_template_icon_bg"
-        android:scaleType="center"
-        />
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="fill_vertical"
-        android:layout_marginStart="@dimen/notification_large_icon_width"
-        android:orientation="vertical"
-        android:paddingTop="0dp"
-        android:paddingBottom="2dp"
-        android:gravity="top"
-        >
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:minHeight="@dimen/notification_large_icon_height"
-            android:orientation="vertical"
-            android:layout_marginStart="8dp"
-            android:layout_marginEnd="8dp"
-            android:layout_weight="1"
-            >
-            <LinearLayout
-                android:id="@+id/line1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingTop="8dp"
-                android:orientation="horizontal"
-                android:layout_gravity="top"
-                android:layout_weight="0"
-                >
-                <TextView android:id="@+id/title"
-                    android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:fadingEdge="horizontal"
-                    android:layout_weight="1"
-                    />
-                <ViewStub android:id="@+id/time"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_time"
-                    />
-                <ViewStub android:id="@+id/chronometer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_chronometer"
-                    />
-            </LinearLayout>
-            <TextView android:id="@+id/text2"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="-2dp"
-                android:layout_marginBottom="-2dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:fadingEdge="horizontal"
-                android:ellipsize="marquee"
-                android:layout_weight="0"
-                android:visibility="gone"
-                />
-            <ProgressBar
-                android:id="@android:id/progress"
-                android:layout_width="match_parent"
-                android:layout_height="12dp"
-                android:layout_marginBottom="8dp"
-                android:layout_marginEnd="8dp"
-                android:visibility="gone"
-                android:layout_weight="0"
-                style="?android:attr/progressBarStyleHorizontal"
-                />
-            <TextView android:id="@+id/big_text"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginBottom="10dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="false"
-                android:visibility="gone"
-                android:maxLines="8"
-                android:ellipsize="end"
-                android:layout_weight="1"
-                />
-        </LinearLayout>
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="1dip"
-            android:layout_marginTop="-1px"
-            android:id="@+id/action_divider"
-            android:visibility="gone"
-            android:background="?android:attr/dividerHorizontal" />
-        <include
-            layout="@layout/notification_action_list"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:visibility="gone"
-            android:layout_weight="1"
-            />
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:id="@+id/overflow_divider"
-            android:layout_marginBottom="8dp"
-            android:visibility="visible"
-            android:background="?android:attr/dividerHorizontal" />
-        <LinearLayout
-            android:id="@+id/line3"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="8dp"
-            android:layout_marginBottom="8dp"
-            android:layout_marginEnd="8dp"
-            android:orientation="horizontal"
-            android:layout_weight="0"
-            android:gravity="center_vertical"
-            >
-            <TextView android:id="@+id/text"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:layout_gravity="center"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                />
-            <TextView android:id="@+id/info"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:singleLine="true"
-                android:gravity="center"
-                android:paddingStart="8dp"
-                />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
-        </LinearLayout>
-    </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_icon_group.xml b/core/res/res/layout/notification_template_icon_group.xml
new file mode 100644
index 0000000..2ad6f9e
--- /dev/null
+++ b/core/res/res/layout/notification_template_icon_group.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:layout_width="@dimen/notification_large_icon_width"
+    android:layout_height="@dimen/notification_large_icon_height"
+    android:id="@+id/icon_group"
+    >
+    <ImageView android:id="@+id/icon"
+        android:layout_width="@dimen/notification_large_icon_width"
+        android:layout_height="@dimen/notification_large_icon_height"
+        android:padding="8dp"
+        android:scaleType="centerInside"
+        />
+    <ImageView android:id="@+id/right_icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:padding="4dp"
+        android:layout_gravity="end|bottom"
+        android:scaleType="centerInside"
+        android:visibility="gone"
+        android:layout_marginEnd="3dp"
+        android:layout_marginBottom="3dp"
+        />
+</FrameLayout>
+
diff --git a/core/res/res/layout/notification_template_inbox.xml b/core/res/res/layout/notification_template_inbox.xml
deleted file mode 100644
index 1eec871..0000000
--- a/core/res/res/layout/notification_template_inbox.xml
+++ /dev/null
@@ -1,267 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:id="@+id/status_bar_latest_event_content"
-    android:background="@android:drawable/notification_bg"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
-    >
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@dimen/notification_large_icon_width"
-        android:layout_height="@dimen/notification_large_icon_height"
-        android:background="@android:drawable/notification_template_icon_bg"
-        android:scaleType="center"
-        />
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="fill_vertical"
-        android:layout_marginStart="@dimen/notification_large_icon_width"
-        android:minHeight="@dimen/notification_large_icon_height"
-        android:orientation="vertical"
-        android:paddingTop="0dp"
-        android:paddingBottom="2dp"
-        android:gravity="top"
-        >
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:minHeight="@dimen/notification_large_icon_height"
-            android:paddingTop="2dp"
-            android:orientation="vertical"
-            >
-            <LinearLayout
-                android:id="@+id/line1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:paddingTop="6dp"
-                android:orientation="horizontal"
-                android:layout_weight="0"
-                >
-                <TextView android:id="@+id/title"
-                    android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:fadingEdge="horizontal"
-                    android:layout_weight="1"
-                    />
-                <ViewStub android:id="@+id/time"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_time"
-                    />
-                <ViewStub android:id="@+id/chronometer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_chronometer"
-                    />
-            </LinearLayout>
-            <TextView android:id="@+id/text2"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="-2dp"
-                android:layout_marginBottom="-2dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:fadingEdge="horizontal"
-                android:ellipsize="marquee"
-                android:visibility="gone"
-                android:layout_weight="0"
-                />
-            <ProgressBar
-                android:id="@android:id/progress"
-                android:layout_width="match_parent"
-                android:layout_height="12dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:visibility="gone"
-                android:layout_weight="0"
-                style="?android:attr/progressBarStyleHorizontal"
-                />
-            <TextView android:id="@+id/inbox_text0"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text1"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text2"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text3"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text4"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text5"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text6"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_more"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                android:text="@android:string/ellipsis"
-                />
-            <FrameLayout 
-                android:id="@+id/inbox_end_pad"
-                android:layout_width="match_parent"
-                android:layout_height="8dip"
-                android:visibility="gone"
-                android:layout_weight="0"
-            />
-        </LinearLayout>
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="1dip"
-            android:layout_marginTop="-1px"
-            android:id="@+id/action_divider"
-            android:background="?android:attr/dividerHorizontal" />
-        <include
-            layout="@layout/notification_action_list"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_weight="0"
-            />
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="1dip"
-            android:layout_marginTop="-1px"
-            android:id="@+id/overflow_divider"
-            android:visibility="visible"
-            android:background="?android:attr/dividerHorizontal" />
-        <LinearLayout
-            android:id="@+id/line3"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="8dp"
-            android:layout_marginStart="8dp"
-            android:layout_marginBottom="8dp"
-            android:layout_marginEnd="8dp"
-            android:orientation="horizontal"
-            android:layout_weight="0"
-            android:gravity="center_vertical"
-            >
-            <TextView android:id="@+id/text"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:layout_gravity="center"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                />
-            <TextView android:id="@+id/info"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:singleLine="true"
-                android:gravity="center"
-                android:paddingStart="8dp"
-                />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
-        </LinearLayout>
-    </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_quantum_base.xml b/core/res/res/layout/notification_template_quantum_base.xml
index 8f3019d..789bf32 100644
--- a/core/res/res/layout/notification_template_quantum_base.xml
+++ b/core/res/res/layout/notification_template_quantum_base.xml
@@ -23,10 +23,9 @@
     internal:layout_minHeight="64dp"
     internal:layout_maxHeight="64dp"
     >
-    <ImageView android:id="@+id/icon"
+    <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
         android:layout_height="@dimen/notification_large_icon_height"
-        android:scaleType="center"
         />
     <LinearLayout
         android:layout_width="match_parent"
@@ -91,7 +90,7 @@
             android:layout_height="12dp"
             android:layout_marginStart="8dp"
             android:visibility="gone"
-            style="@style/Widget.Quantum.Light.ProgressBar.Horizontal"
+            style="@style/Widget.StatusBar.Quantum.ProgressBar"
             />
         <LinearLayout
             android:id="@+id/line3"
@@ -121,16 +120,6 @@
                 android:gravity="center"
                 android:paddingStart="8dp"
                 />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
         </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_quantum_big_base.xml b/core/res/res/layout/notification_template_quantum_big_base.xml
index 45e69b1..8cb5549 100644
--- a/core/res/res/layout/notification_template_quantum_big_base.xml
+++ b/core/res/res/layout/notification_template_quantum_big_base.xml
@@ -23,10 +23,9 @@
     internal:layout_minHeight="65dp"
     internal:layout_maxHeight="unbounded"
     >
-    <ImageView android:id="@+id/icon"
+    <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
         android:layout_height="@dimen/notification_large_icon_height"
-        android:scaleType="center"
         />
     <LinearLayout
         android:layout_width="match_parent"
@@ -128,16 +127,6 @@
                     android:gravity="center"
                     android:paddingStart="8dp"
                     />
-                <ImageView android:id="@+id/right_icon"
-                    android:layout_width="16dp"
-                    android:layout_height="16dp"
-                    android:layout_gravity="center"
-                    android:layout_weight="0"
-                    android:layout_marginStart="8dp"
-                    android:scaleType="centerInside"
-                    android:visibility="gone"
-                    android:drawableAlpha="153"
-                    />
             </LinearLayout>
             <ProgressBar
                 android:id="@android:id/progress"
diff --git a/core/res/res/layout/notification_template_quantum_big_text.xml b/core/res/res/layout/notification_template_quantum_big_text.xml
index f7769d7..bbd1071 100644
--- a/core/res/res/layout/notification_template_quantum_big_text.xml
+++ b/core/res/res/layout/notification_template_quantum_big_text.xml
@@ -22,10 +22,9 @@
     internal:layout_minHeight="65dp"
     internal:layout_maxHeight="unbounded"
     >
-    <ImageView android:id="@+id/icon"
+    <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
         android:layout_height="@dimen/notification_large_icon_height"
-        android:scaleType="center"
         />
     <LinearLayout
         android:layout_width="match_parent"
@@ -166,16 +165,6 @@
                 android:gravity="center"
                 android:paddingStart="8dp"
                 />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
         </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_quantum_inbox.xml b/core/res/res/layout/notification_template_quantum_inbox.xml
index 04974c4..a071d59 100644
--- a/core/res/res/layout/notification_template_quantum_inbox.xml
+++ b/core/res/res/layout/notification_template_quantum_inbox.xml
@@ -23,10 +23,9 @@
     internal:layout_minHeight="65dp"
     internal:layout_maxHeight="unbounded"
     >
-    <ImageView android:id="@+id/icon"
+    <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
         android:layout_height="@dimen/notification_large_icon_height"
-        android:scaleType="center"
         />
     <LinearLayout
         android:layout_width="match_parent"
@@ -250,16 +249,6 @@
                 android:gravity="center"
                 android:paddingStart="8dp"
                 />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
         </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index b3db01a..dc78174 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -22,7 +22,7 @@
     android:layout_height="wrap_content"
     android:background="#FFFF00FF"
     >
-    <include layout="@layout/notification_template_base"
+    <include layout="@layout/notification_template_quantum_base"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index ac75b38..3746780 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1672,6 +1672,7 @@
         <enum name="KEYCODE_MEDIA_AUDIO_TRACK" value="222" />
         <enum name="KEYCODE_MEDIA_SLEEP" value="223" />
         <enum name="KEYCODE_MEDIA_WAKEUP" value="224" />
+        <enum name="KEYCODE_PAIRING" value="225" />
     </attr>
 
     <!-- ***************************************************************** -->
@@ -6115,13 +6116,13 @@
         <attr name="settingsActivity" />
     </declare-styleable>
 
-    <!-- Use <code>trust_agent</code> as the root tag of the XML resource that
+    <!-- Use <code>trust-agent</code> as the root tag of the XML resource that
          describes an {@link android.service.trust.TrustAgentService}, which is
          referenced from its {@link android.service.trust.TrustAgentService#TRUST_AGENT_META_DATA}
          meta-data entry.  Described here are the attributes that can be included in that tag. -->
     <declare-styleable name="TrustAgent">
         <!-- Component name of an activity that allows the user to modify
-             the settings for this TrustAgent. -->
+             the settings for this trust agent. -->
         <attr name="settingsActivity" />
     </declare-styleable>
 
@@ -6343,8 +6344,9 @@
     <!-- Use <code>voice-interaction-service</code> as the root tag of the XML resource that
          describes a {@link android.service.voice.VoiceInteractionService}, which is referenced from
          its {@link android.service.voice.VoiceInteractionService#SERVICE_META_DATA} meta-data entry.
-         Described here are the attributes that can be included in that tag. -->
+         Described here are the attributes that can be included in that tag. @hide -->
     <declare-styleable name="VoiceInteractionService">
+        <!-- @hide -->
         <attr name="sessionService" format="string" />
         <attr name="settingsActivity" />
     </declare-styleable>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 69b11cd..52b021f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -227,9 +227,9 @@
     <dimen name="action_bar_stacked_tab_max_width">180dp</dimen>
 
     <!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
-    <dimen name="notification_text_size">14dp</dimen>
+    <dimen name="notification_text_size">13dp</dimen>
     <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
-    <dimen name="notification_title_text_size">18dp</dimen>
+    <dimen name="notification_title_text_size">16dp</dimen>
     <!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
     <dimen name="notification_subtext_size">12dp</dimen>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 891265f..fd57c5e 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -280,28 +280,28 @@
     <style name="TextAppearance.StatusBar.Quantum">
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent">
-        <item name="android:textColor">#888888</item>
+        <item name="android:textColor">#90000000</item>
         <item name="android:textSize">@dimen/notification_text_size</item>
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent.Title">
-        <item name="android:textColor">#000000</item>
-        <item name="android:fontFamily">sans-serif-light</item>
+        <item name="android:textColor">#DD000000</item>
         <item name="android:textSize">@dimen/notification_title_text_size</item>
-        <item name="android:textStyle">bold</item>
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent.Line2">
         <item name="android:textSize">@dimen/notification_subtext_size</item>
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent.Info">
         <item name="android:textSize">@dimen/notification_subtext_size</item>
-        <item name="android:textColor">#888888</item>
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent.Time">
         <item name="android:textSize">@dimen/notification_subtext_size</item>
-        <item name="android:textColor">#888888</item>
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent.Emphasis">
-        <item name="android:textColor">#555555</item>
+        <item name="android:textColor">#66000000</item>
+    </style>
+
+    <style name="Widget.StatusBar.Quantum.ProgressBar"
+           parent="Widget.Quantum.Light.ProgressBar.Horizontal">
     </style>
 
     <style name="TextAppearance.Small.CalendarViewWeekDayView">
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index a49b89a..d04bddf 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -427,7 +427,10 @@
         <item name="paddingEnd">8dp</item>
     </style>
 
-    <style name="Widget.Quantum.CheckedTextView" parent="Widget.CheckedTextView"/>
+    <style name="Widget.Quantum.CheckedTextView" parent="Widget.CheckedTextView">
+        <item name="drawablePadding">4dip</item>
+    </style>
+
     <style name="Widget.Quantum.TextSelectHandle" parent="Widget.TextSelectHandle"/>
     <style name="Widget.Quantum.TextSuggestionsPopupWindow" parent="Widget.TextSuggestionsPopupWindow"/>
     <style name="Widget.Quantum.AbsListView" parent="Widget.AbsListView"/>
@@ -441,10 +444,12 @@
 
     <style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
         <item name="background">?attr/selectableItemBackground</item>
+        <item name="drawablePadding">4dip</item>
     </style>
 
     <style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
         <item name="background">?attr/selectableItemBackground</item>
+        <item name="drawablePadding">4dip</item>
     </style>
 
     <style name="Widget.Quantum.CompoundButton.Star" parent="Widget.CompoundButton.Star">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 84c9023..2f0ac49 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1209,16 +1209,7 @@
   <java-symbol type="layout" name="zoom_container" />
   <java-symbol type="layout" name="zoom_controls" />
   <java-symbol type="layout" name="zoom_magnify" />
-  <java-symbol type="layout" name="notification_action" />
-  <java-symbol type="layout" name="notification_action_tombstone" />
   <java-symbol type="layout" name="notification_intruder_content" />
-  <java-symbol type="layout" name="notification_template_base" />
-  <java-symbol type="layout" name="notification_template_big_base" />
-  <java-symbol type="layout" name="notification_template_big_picture" />
-  <java-symbol type="layout" name="notification_template_big_text" />
-  <java-symbol type="layout" name="notification_template_part_time" />
-  <java-symbol type="layout" name="notification_template_part_chronometer" />
-  <java-symbol type="layout" name="notification_template_inbox" />
   <java-symbol type="layout" name="sms_short_code_confirmation_dialog" />
   <java-symbol type="layout" name="action_bar_up_container" />
   <java-symbol type="layout" name="app_not_authorized" />
@@ -1667,8 +1658,10 @@
   <java-symbol type="layout" name="notification_template_quantum_big_picture" />
   <java-symbol type="layout" name="notification_template_quantum_big_text" />
   <java-symbol type="layout" name="notification_template_quantum_inbox" />
+  <java-symbol type="layout" name="notification_template_icon_group" />
   <java-symbol type="color" name="notification_action_legacy_color_filter" />
   <java-symbol type="color" name="notification_icon_bg_color" />
+  <java-symbol type="drawable" name="notification_icon_legacy_bg" />
   <java-symbol type="drawable" name="notification_icon_legacy_bg_inset" />
   <java-symbol type="drawable" name="notification_quantum_bg_dim" />
   <java-symbol type="drawable" name="notification_quantum_bg" />
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 218a057..24e8de6 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -17,227 +17,220 @@
 package android.graphics.drawable;
 
 import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
-import android.view.animation.DecelerateInterpolator;
+import android.view.HardwareCanvas;
+import android.view.RenderNodeAnimator;
+import android.view.animation.AccelerateInterpolator;
+
+import java.util.ArrayList;
 
 /**
  * Draws a Quantum Paper ripple.
  */
 class Ripple {
-    private static final TimeInterpolator INTERPOLATOR = new DecelerateInterpolator();
+    private static final TimeInterpolator INTERPOLATOR = new AccelerateInterpolator();
 
-    /** Starting radius for a ripple. */
-    private static final int STARTING_RADIUS_DP = 16;
+    private static final float GLOBAL_SPEED = 1.0f;
+    private static final float WAVE_TOUCH_DOWN_ACCELERATION = 512.0f * GLOBAL_SPEED;
+    private static final float WAVE_TOUCH_UP_ACCELERATION = 1024.0f * GLOBAL_SPEED;
+    private static final float WAVE_OPACITY_DECAY_VELOCITY = 1.6f / GLOBAL_SPEED;
+    private static final float WAVE_OUTER_OPACITY_VELOCITY = 1.2f * GLOBAL_SPEED;
 
-    /** Radius when finger is outside view bounds. */
-    private static final int OUTSIDE_RADIUS_DP = 16;
-
-    /** Radius when finger is inside view bounds. */
-    private static final int INSIDE_RADIUS_DP = 96;
-
-    /** Margin when constraining outside touches (fraction of outer radius). */
-    private static final float OUTSIDE_MARGIN = 0.8f;
-
-    /** Resistance factor when constraining outside touches. */
-    private static final float OUTSIDE_RESISTANCE = 0.7f;
-
-    /** Minimum alpha value during a pulse animation. */
-    private static final float PULSE_MIN_ALPHA = 0.5f;
-
-    /** Duration for animating the trailing edge of the ripple. */
-    private static final int EXIT_DURATION = 600;
-
-    /** Duration for animating the leading edge of the ripple. */
-    private static final int ENTER_DURATION = 400;
-
-    /** Duration for animating the ripple alpha in and out. */
-    private static final int FADE_DURATION = 50;
-
-    /** Minimum elapsed time between start of enter and exit animations. */
-    private static final int EXIT_MIN_DELAY = 200;
-
-    /** Duration for animating between inside and outside touch. */
-    private static final int OUTSIDE_DURATION = 300;
-
-    /** Duration for animating pulses. */
-    private static final int PULSE_DURATION = 400;
-
-    /** Interval between pulses while inside and fully entered. */
-    private static final int PULSE_INTERVAL = 400;
-
-    /** Delay before pulses start. */
-    private static final int PULSE_DELAY = 500;
+    // Hardware animators.
+    private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>();
+    private final ArrayList<RenderNodeAnimator> mPendingAnimations = new ArrayList<>();
 
     private final Drawable mOwner;
 
-    /** Bounds used for computing max radius and containment. */
+    /** Bounds used for computing max radius. */
     private final Rect mBounds;
 
-    /** Configured maximum ripple radius when the center is outside the bounds. */
-    private final int mMaxOutsideRadius;
-
-    /** Configured maximum ripple radius. */
-    private final int mMaxInsideRadius;
-
-    private ObjectAnimator mOuter;
-    private ObjectAnimator mInner;
-    private ObjectAnimator mAlpha;
+    /** Full-opacity color for drawing this ripple. */
+    private final int mColor;
 
     /** Maximum ripple radius. */
-    private int mMaxRadius;
-
     private float mOuterRadius;
-    private float mInnerRadius;
-    private float mAlphaMultiplier;
 
-    /** Center x-coordinate. */
+    // Hardware rendering properties.
+    private CanvasProperty<Paint> mPropPaint;
+    private CanvasProperty<Float> mPropRadius;
+    private CanvasProperty<Float> mPropX;
+    private CanvasProperty<Float> mPropY;
+    private CanvasProperty<Paint> mPropOuterPaint;
+    private CanvasProperty<Float> mPropOuterRadius;
+    private CanvasProperty<Float> mPropOuterX;
+    private CanvasProperty<Float> mPropOuterY;
+
+    // Software animators.
+    private ObjectAnimator mAnimRadius;
+    private ObjectAnimator mAnimOpacity;
+    private ObjectAnimator mAnimOuterOpacity;
+    private ObjectAnimator mAnimX;
+    private ObjectAnimator mAnimY;
+
+    // Software rendering properties.
+    private float mOuterOpacity = 0;
+    private float mOpacity = 1;
+    private float mRadius = 0;
+    private float mOuterX;
+    private float mOuterY;
     private float mX;
-
-    /** Center y-coordinate. */
     private float mY;
 
-    /** Whether the center is within the parent bounds. */
-    private boolean mInsideBounds;
+    private boolean mFinished;
 
-    /** Whether to pulse this ripple. */
-    private boolean mPulseEnabled;
+    /** Whether we should be drawing hardware animations. */
+    private boolean mHardwareAnimating;
 
-    /** Temporary hack since we can't check finished state of animator. */
-    private boolean mExitFinished;
-
-    /** Whether this ripple has ever moved. */
-    private boolean mHasMoved;
+    /** Whether we can use hardware acceleration for the exit animation. */
+    private boolean mCanUseHardware;
 
     /**
      * Creates a new ripple.
      */
-    public Ripple(Drawable owner, Rect bounds, float density, boolean pulseEnabled) {
+    public Ripple(Drawable owner, Rect bounds, int color) {
         mOwner = owner;
         mBounds = bounds;
-        mPulseEnabled = pulseEnabled;
+        mColor = color | 0xFF000000;
 
-        mOuterRadius = (int) (density * STARTING_RADIUS_DP + 0.5f);
-        mMaxOutsideRadius = (int) (density * OUTSIDE_RADIUS_DP + 0.5f);
-        mMaxInsideRadius = (int) (density * INSIDE_RADIUS_DP + 0.5f);
-        mMaxRadius = Math.min(mMaxInsideRadius, Math.max(bounds.width(), bounds.height()));
+        final float halfWidth = bounds.width() / 2.0f;
+        final float halfHeight = bounds.height() / 2.0f;
+        mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
+        mOuterX = 0;
+        mOuterY = 0;
     }
 
-    public void setOuterRadius(float r) {
-        mOuterRadius = r;
+    public void setRadius(float r) {
+        mRadius = r;
         invalidateSelf();
     }
 
-    public float getOuterRadius() {
-        return mOuterRadius;
+    public float getRadius() {
+        return mRadius;
     }
 
-    public void setInnerRadius(float r) {
-        mInnerRadius = r;
+    public void setOpacity(float a) {
+        mOpacity = a;
         invalidateSelf();
     }
 
-    public float getInnerRadius() {
-        return mInnerRadius;
+    public float getOpacity() {
+        return mOpacity;
     }
 
-    public void setAlphaMultiplier(float a) {
-        mAlphaMultiplier = a;
+    public void setOuterOpacity(float a) {
+        mOuterOpacity = a;
         invalidateSelf();
     }
 
-    public float getAlphaMultiplier() {
-        return mAlphaMultiplier;
+    public float getOuterOpacity() {
+        return mOuterOpacity;
+    }
+
+    public void setX(float x) {
+        mX = x;
+        invalidateSelf();
+    }
+
+    public float getX() {
+        return mX;
+    }
+
+    public void setY(float y) {
+        mY = y;
+        invalidateSelf();
+    }
+
+    public float getY() {
+        return mY;
     }
 
     /**
      * Returns whether this ripple has finished exiting.
      */
     public boolean isFinished() {
-        return mExitFinished;
+        return mFinished;
     }
 
     /**
-     * Called when the bounds change.
-     */
-    public void onBoundsChanged() {
-        mMaxRadius = Math.min(mMaxInsideRadius, Math.max(mBounds.width(), mBounds.height()));
-
-        updateInsideBounds();
-    }
-
-    private void updateInsideBounds() {
-        final boolean insideBounds = mBounds.contains((int) (mX + 0.5f), (int) (mY + 0.5f));
-        if (mInsideBounds != insideBounds || !mHasMoved) {
-            mInsideBounds = insideBounds;
-            mHasMoved = true;
-
-            if (insideBounds) {
-                enter();
-            } else {
-                outside();
-            }
-        }
-    }
-
-    /**
-     * Draws the ripple using the specified paint.
+     * Draws the ripple centered at (0,0) using the specified paint.
      */
     public boolean draw(Canvas c, Paint p) {
-        final Rect bounds = mBounds;
-        final float outerRadius = mOuterRadius;
-        final float innerRadius = mInnerRadius;
-        final float alphaMultiplier = mAlphaMultiplier;
+        final boolean canUseHardware = c.isHardwareAccelerated();
+        if (mCanUseHardware != canUseHardware && mCanUseHardware) {
+            // We've switched from hardware to non-hardware mode. Panic.
+            cancelHardwareAnimations();
+        }
+        mCanUseHardware = canUseHardware;
+
+        final boolean hasContent;
+        if (canUseHardware && mHardwareAnimating) {
+            hasContent = drawHardware((HardwareCanvas) c);
+        } else {
+            hasContent = drawSoftware(c, p);
+        }
+
+        return hasContent;
+    }
+
+    private boolean drawHardware(HardwareCanvas c) {
+        // If we have any pending hardware animations, cancel any running
+        // animations and start those now.
+        final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
+        final int N = pendingAnimations == null ? 0 : pendingAnimations.size();
+        if (N > 0) {
+            cancelHardwareAnimations();
+
+            for (int i = 0; i < N; i++) {
+                pendingAnimations.get(i).setTarget(c);
+                pendingAnimations.get(i).start();
+            }
+
+            mRunningAnimations.addAll(pendingAnimations);
+            pendingAnimations.clear();
+        }
+
+        c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint);
+        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
+
+        return true;
+    }
+
+    private boolean drawSoftware(Canvas c, Paint p) {
+        final float radius = mRadius;
+        final float opacity = mOpacity;
+        final float outerOpacity = mOuterOpacity;
 
         // Cache the paint alpha so we can restore it later.
         final int paintAlpha = p.getAlpha();
-        final int alpha = (int) (paintAlpha * alphaMultiplier + 0.5f);
+        final int alpha = (int) (255 * opacity + 0.5f);
+        final int outerAlpha = (int) (255 * outerOpacity + 0.5f);
 
-        // Apply resistance effect when outside bounds.
-        final float x;
-        final float y;
-        if (mInsideBounds) {
-            x = mX;
-            y = mY;
-        } else {
-            // TODO: We need to do this outside of draw() so that our dirty
-            // bounds accurately reflect resistance.
-            x = looseConstrain(mX, bounds.left, bounds.right,
-                    mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
-            y = looseConstrain(mY, bounds.top, bounds.bottom,
-                    mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
+        boolean hasContent = false;
+
+        if (outerAlpha > 0 && alpha > 0) {
+            p.setAlpha(Math.min(alpha, outerAlpha));
+            p.setStyle(Style.FILL);
+            c.drawCircle(mOuterX, mOuterY, mOuterRadius, p);
+            hasContent = true;
         }
 
-        final boolean hasContent;
-        if (alphaMultiplier <= 0 || innerRadius >= outerRadius) {
-            // Nothing to draw.
-            hasContent = false;
-        } else if (innerRadius > 0) {
-            // Draw a ring.
-            final float strokeWidth = outerRadius - innerRadius;
-            final float strokeRadius = innerRadius + strokeWidth / 2.0f;
-            p.setAlpha(alpha);
-            p.setStyle(Style.STROKE);
-            p.setStrokeWidth(strokeWidth);
-            c.drawCircle(x, y, strokeRadius, p);
-            hasContent = true;
-        } else if (outerRadius > 0) {
-            // Draw a circle.
+        if (opacity > 0 && radius > 0) {
             p.setAlpha(alpha);
             p.setStyle(Style.FILL);
-            c.drawCircle(x, y, outerRadius, p);
+            c.drawCircle(mX, mY, radius, p);
             hasContent = true;
-        } else {
-            hasContent = false;
         }
 
         p.setAlpha(paintAlpha);
+
         return hasContent;
     }
 
@@ -245,156 +238,279 @@
      * Returns the maximum bounds for this ripple.
      */
     public void getBounds(Rect bounds) {
+        final int outerX = (int) mOuterX;
+        final int outerY = (int) mOuterY;
+        final int r = (int) mOuterRadius;
+        bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
+
         final int x = (int) mX;
         final int y = (int) mY;
-        final int maxRadius = mMaxRadius;
-        bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius);
+        bounds.union(x - r, y - r, x + r, y + r);
     }
 
     /**
-     * Updates the center coordinates.
+     * Starts the enter animation at the specified absolute coordinates.
      */
-    public void move(float x, float y) {
-        mX = x;
-        mY = y;
+    public void enter(float x, float y) {
+        mX = x - mBounds.exactCenterX();
+        mY = y - mBounds.exactCenterY();
 
-        updateInsideBounds();
+        final int radiusDuration = (int)
+                (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION) + 0.5);
+        final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY);
+
+        final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radius", 0, mOuterRadius);
+        radius.setAutoCancel(true);
+        radius.setDuration(radiusDuration);
+
+        final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "x", mOuterX);
+        cX.setAutoCancel(true);
+        cX.setDuration(radiusDuration);
+
+        final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "y", mOuterY);
+        cY.setAutoCancel(true);
+        cY.setDuration(radiusDuration);
+
+        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
+        outer.setAutoCancel(true);
+        outer.setDuration(outerDuration);
+
+        mAnimRadius = radius;
+        mAnimOuterOpacity = outer;
+        mAnimX = cX;
+        mAnimY = cY;
+
+        // Enter animations always run on the UI thread, since it's unlikely
+        // that anything interesting is happening until the user lifts their
+        // finger.
+        radius.start();
+        outer.start();
+        cX.start();
+        cY.start();
+    }
+
+    /**
+     * Starts the exit animation.
+     */
+    public void exit() {
+        cancelSoftwareAnimations();
+
+        final float remaining;
+        if (mAnimRadius != null && mAnimRadius.isRunning()) {
+            remaining = mOuterRadius - mRadius;
+        } else {
+            remaining = mOuterRadius;
+        }
+
+        final int radiusDuration = (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION
+                + WAVE_TOUCH_DOWN_ACCELERATION)) + 0.5);
+        final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
+
+        // Determine at what time the inner and outer opacity intersect.
+        // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
+        // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000
+        final int outerInflection = Math.max(0, (int) (1000 * (mOpacity - mOuterOpacity)
+                / (WAVE_OPACITY_DECAY_VELOCITY + WAVE_OUTER_OPACITY_VELOCITY) + 0.5f));
+        final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection
+                * WAVE_OUTER_OPACITY_VELOCITY / 1000) + 0.5f);
+
+        if (mCanUseHardware) {
+            exitHardware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
+        } else {
+            exitSoftware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
+        }
+    }
+
+    private void exitHardware(int radiusDuration, int opacityDuration, int outerInflection,
+            int inflectionOpacity) {
+        mPendingAnimations.clear();
+
+        final Paint outerPaint = new Paint();
+        outerPaint.setAntiAlias(true);
+        outerPaint.setColor(mColor);
+        outerPaint.setAlpha((int) (255 * mOuterOpacity + 0.5f));
+        outerPaint.setStyle(Style.FILL);
+        mPropOuterPaint = CanvasProperty.createPaint(outerPaint);
+        mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius);
+        mPropOuterX = CanvasProperty.createFloat(mOuterX);
+        mPropOuterY = CanvasProperty.createFloat(mOuterY);
+
+        final Paint paint = new Paint();
+        paint.setAntiAlias(true);
+        paint.setColor(mColor);
+        paint.setAlpha((int) (255 * mOpacity + 0.5f));
+        paint.setStyle(Style.FILL);
+        mPropPaint = CanvasProperty.createPaint(paint);
+        mPropRadius = CanvasProperty.createFloat(mRadius);
+        mPropX = CanvasProperty.createFloat(mX);
+        mPropY = CanvasProperty.createFloat(mY);
+
+        final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mOuterRadius);
+        radius.setDuration(radiusDuration);
+
+        final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mOuterX);
+        x.setDuration(radiusDuration);
+
+        final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mOuterY);
+        y.setDuration(radiusDuration);
+
+        final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,
+                RenderNodeAnimator.PAINT_ALPHA, 0);
+        opacity.setDuration(opacityDuration);
+        opacity.addListener(mAnimationListener);
+
+        final RenderNodeAnimator outerOpacity;
+        if (outerInflection > 0) {
+            // Outer opacity continues to increase for a bit.
+            outerOpacity = new RenderNodeAnimator(
+                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
+            outerOpacity.setDuration(outerInflection);
+
+            // Chain the outer opacity exit animation.
+            final int outerDuration = opacityDuration - outerInflection;
+            if (outerDuration > 0) {
+                final RenderNodeAnimator outerFadeOut = new RenderNodeAnimator(
+                        mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+                outerFadeOut.setDuration(outerDuration);
+                outerFadeOut.setStartDelay(outerInflection);
+
+                mPendingAnimations.add(outerFadeOut);
+            }
+        } else {
+            outerOpacity = new RenderNodeAnimator(
+                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+            outerOpacity.setDuration(opacityDuration);
+        }
+
+        mPendingAnimations.add(radius);
+        mPendingAnimations.add(opacity);
+        mPendingAnimations.add(outerOpacity);
+        mPendingAnimations.add(x);
+        mPendingAnimations.add(y);
+
+        mHardwareAnimating = true;
+
         invalidateSelf();
     }
 
-    /**
-     * Starts the exit animation. If {@link #enter()} was called recently, the
-     * animation may be postponed.
-     */
-    public void exit() {
-        mExitFinished = false;
+    private void exitSoftware(int radiusDuration, int opacityDuration, int outerInflection,
+            float inflectionOpacity) {
+        final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radius", mOuterRadius);
+        radius.setAutoCancel(true);
+        radius.setDuration(radiusDuration);
 
-        final ObjectAnimator inner = ObjectAnimator.ofFloat(this, "innerRadius", 0, mMaxRadius);
-        inner.setAutoCancel(true);
-        inner.setDuration(EXIT_DURATION);
-        inner.setInterpolator(INTERPOLATOR);
-        inner.addListener(mAnimationListener);
+        final ObjectAnimator x = ObjectAnimator.ofFloat(this, "x", mOuterX);
+        x.setAutoCancel(true);
+        x.setDuration(radiusDuration);
 
-        if (mOuter != null && mOuter.isStarted()) {
-            // If we haven't been running the enter animation for long enough,
-            // delay the exit animator.
-            final int elapsed = (int) (mOuter.getAnimatedFraction() * mOuter.getDuration());
-            final int delay = Math.max(0, EXIT_MIN_DELAY - elapsed);
-            inner.setStartDelay(delay);
+        final ObjectAnimator y = ObjectAnimator.ofFloat(this, "y", mOuterY);
+        y.setAutoCancel(true);
+        y.setDuration(radiusDuration);
+
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "opacity", 0);
+        opacity.setAutoCancel(true);
+        opacity.setDuration(opacityDuration);
+        opacity.addListener(mAnimationListener);
+
+        final ObjectAnimator outerOpacity;
+        if (outerInflection > 0) {
+            // Outer opacity continues to increase for a bit.
+            outerOpacity = ObjectAnimator.ofFloat(this, "outerOpacity", inflectionOpacity);
+            outerOpacity.setDuration(outerInflection);
+
+            // Chain the outer opacity exit animation.
+            final int outerDuration = opacityDuration - outerInflection;
+            outerOpacity.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    final ObjectAnimator outerFadeOut = ObjectAnimator.ofFloat(Ripple.this,
+                            "outerOpacity", 0);
+                    outerFadeOut.setDuration(outerDuration);
+
+                    mAnimOuterOpacity = outerFadeOut;
+
+                    outerFadeOut.start();
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    animation.removeListener(this);
+                }
+            });
+        } else {
+            outerOpacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0);
+            outerOpacity.setDuration(opacityDuration);
         }
 
-        inner.start();
+        mAnimRadius = radius;
+        mAnimOpacity = opacity;
+        mAnimOuterOpacity = outerOpacity;
+        mAnimX = opacity;
+        mAnimY = opacity;
 
-        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 0);
-        alpha.setAutoCancel(true);
-        alpha.setDuration(EXIT_DURATION);
-        alpha.start();
-
-        mInner = inner;
-        mAlpha = alpha;
+        radius.start();
+        opacity.start();
+        outerOpacity.start();
+        x.start();
+        y.start();
     }
 
     /**
      * Cancel all animations.
      */
     public void cancel() {
-        if (mInner != null) {
-            mInner.cancel();
+        cancelSoftwareAnimations();
+        cancelHardwareAnimations();
+    }
+
+    private void cancelSoftwareAnimations() {
+        if (mAnimRadius != null) {
+            mAnimRadius.cancel();
         }
 
-        if (mOuter != null) {
-            mOuter.cancel();
+        if (mAnimOpacity != null) {
+            mAnimOpacity.cancel();
         }
 
-        if (mAlpha != null) {
-            mAlpha.cancel();
+        if (mAnimOuterOpacity != null) {
+            mAnimOuterOpacity.cancel();
         }
+
+        if (mAnimX != null) {
+            mAnimX.cancel();
+        }
+
+        if (mAnimY != null) {
+            mAnimY.cancel();
+        }
+    }
+
+    /**
+     * Cancels any running hardware animations.
+     */
+    private void cancelHardwareAnimations() {
+        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+        final int N = runningAnimations == null ? 0 : runningAnimations.size();
+        for (int i = 0; i < N; i++) {
+            runningAnimations.get(i).cancel();
+        }
+
+        runningAnimations.clear();
     }
 
     private void invalidateSelf() {
         mOwner.invalidateSelf();
     }
 
-    /**
-     * Starts the enter animation.
-     */
-    private void enter() {
-        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxRadius);
-        outer.setAutoCancel(true);
-        outer.setDuration(ENTER_DURATION);
-        outer.setInterpolator(INTERPOLATOR);
-        outer.start();
-
-        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
-        if (mPulseEnabled) {
-            alpha.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    final ObjectAnimator pulse = ObjectAnimator.ofFloat(
-                            this, "alphaMultiplier", 1, PULSE_MIN_ALPHA);
-                    pulse.setAutoCancel(true);
-                    pulse.setDuration(PULSE_DURATION + PULSE_INTERVAL);
-                    pulse.setRepeatCount(ObjectAnimator.INFINITE);
-                    pulse.setRepeatMode(ObjectAnimator.REVERSE);
-                    pulse.setStartDelay(PULSE_DELAY);
-                    pulse.start();
-
-                    mAlpha = pulse;
-                }
-            });
-        }
-        alpha.setAutoCancel(true);
-        alpha.setDuration(FADE_DURATION);
-        alpha.start();
-
-        mOuter = outer;
-        mAlpha = alpha;
-    }
-
-    /**
-     * Starts the outside transition animation.
-     */
-    private void outside() {
-        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxOutsideRadius);
-        outer.setAutoCancel(true);
-        outer.setDuration(OUTSIDE_DURATION);
-        outer.setInterpolator(INTERPOLATOR);
-        outer.start();
-
-        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
-        alpha.setAutoCancel(true);
-        alpha.setDuration(FADE_DURATION);
-        alpha.start();
-
-        mOuter = outer;
-        mAlpha = alpha;
-    }
-
-    /**
-     * Constrains a value within a specified asymptotic margin outside a minimum
-     * and maximum.
-     */
-    private static float looseConstrain(float value, float min, float max, float margin,
-            float factor) {
-        // TODO: Can we use actual spring physics here?
-        if (value < min) {
-            return min - Math.min(margin, (float) Math.pow(min - value, factor));
-        } else if (value > max) {
-            return max + Math.min(margin, (float) Math.pow(value - max, factor));
-        } else {
-            return value;
-        }
-    }
-
-    private final AnimatorListener mAnimationListener = new AnimatorListenerAdapter() {
+    private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            if (animation == mInner) {
-                mExitFinished = true;
-                mOuterRadius = 0;
-                mInnerRadius = 0;
-                mAlphaMultiplier = 1;
-            }
+            mFinished = true;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mFinished = true;
         }
     };
 }
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 8128b5f..a55a4b2 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -24,6 +24,7 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PointF;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
@@ -33,6 +34,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.R;
+import com.android.org.bouncycastle.util.Arrays;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -40,11 +42,36 @@
 import java.io.IOException;
 
 /**
- * Documentation pending.
+ * Drawable that shows a ripple effect in response to state changes. The
+ * anchoring position of the ripple for a given state may be specified by
+ * calling {@link #setHotspot(int, float, float)} with the corresponding state
+ * attribute identifier.
+ * <p>
+ * A touch feedback drawable may contain multiple child layers, including a
+ * special mask layer that is not drawn to the screen. A single layer may be set
+ * as the mask by specifying its android:id value as {@link android.R.id#mask}.
+ * <p>
+ * If a mask layer is set, the ripple effect will be masked against that layer
+ * before it is blended onto the composite of the remaining child layers.
+ * <p>
+ * If no mask layer is set, the ripple effect is simply blended onto the
+ * composite of the child layers using the specified
+ * {@link android.R.styleable#TouchFeedbackDrawable_tintMode}.
+ * <p>
+ * If no child layers or mask is specified and the ripple is set as a View
+ * background, the ripple will be blended onto the first available parent
+ * background within the View's hierarchy using the specified
+ * {@link android.R.styleable#TouchFeedbackDrawable_tintMode}. In this case, the
+ * drawing region may extend outside of the Drawable bounds.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
  */
 public class TouchFeedbackDrawable extends LayerDrawable {
     private static final String LOG_TAG = TouchFeedbackDrawable.class.getSimpleName();
     private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
+    private static final PorterDuffXfermode DST_ATOP = new PorterDuffXfermode(Mode.DST_ATOP);
+    private static final PorterDuffXfermode SRC_ATOP = new PorterDuffXfermode(Mode.SRC_ATOP);
     private static final PorterDuffXfermode SRC_OVER = new PorterDuffXfermode(Mode.SRC_OVER);
 
     /** The maximum number of ripples supported. */
@@ -63,10 +90,22 @@
 
     private final TouchFeedbackState mState;
 
-    /** Lazily-created map of touch hotspot IDs to ripples. */
-    private SparseArray<Ripple> mRipples;
+    /**
+     * Lazily-created map of pending hotspot locations. These may be modified by
+     * calls to {@link #setHotspot(int, float, float)}.
+     */
+    private SparseArray<PointF> mPendingHotspots;
 
-    /** Lazily-created array of actively animating ripples. */
+    /**
+     * Lazily-created map of active hotspot locations. These may be modified by
+     * calls to {@link #setHotspot(int, float, float)}.
+     */
+    private SparseArray<Ripple> mActiveHotspots;
+
+    /**
+     * Lazily-created array of actively animating ripples. Inactive ripples are
+     * pruned during draw(). The locations of these will not change.
+     */
     private Ripple[] mAnimatingRipples;
     private int mAnimatingRipplesCount = 0;
 
@@ -96,24 +135,18 @@
     protected boolean onStateChange(int[] stateSet) {
         super.onStateChange(stateSet);
 
-        // TODO: Implicitly tie states to ripple IDs. For now, just clear
-        // focused and pressed if they aren't in the state set.
-        boolean hasFocused = false;
-        boolean hasPressed = false;
-        for (int i = 0; i < stateSet.length; i++) {
-            if (stateSet[i] == R.attr.state_pressed) {
-                hasPressed = true;
-            } else if (stateSet[i] == R.attr.state_focused) {
-                hasFocused = true;
-            }
-        }
-
-        if (!hasPressed) {
+        final boolean pressed = Arrays.contains(stateSet, R.attr.state_pressed);
+        if (!pressed) {
             removeHotspot(R.attr.state_pressed);
+        } else {
+            activateHotspot(R.attr.state_pressed);
         }
 
-        if (!hasFocused) {
+        final boolean focused = Arrays.contains(stateSet, R.attr.state_focused);
+        if (!focused) {
             removeHotspot(R.attr.state_focused);
+        } else {
+            activateHotspot(R.attr.state_focused);
         }
 
         if (mRipplePaint != null && mState.mTint != null) {
@@ -138,19 +171,7 @@
             mHotspotBounds.set(bounds);
         }
 
-        onHotspotBoundsChange();
-    }
-
-    private void onHotspotBoundsChange() {
-        final int x = mHotspotBounds.centerX();
-        final int y = mHotspotBounds.centerY();
-        final int N = mAnimatingRipplesCount;
-        for (int i = 0; i < N; i++) {
-            if (mState.mPinned) {
-                mAnimatingRipples[i].move(x, y);
-            }
-            mAnimatingRipples[i].onBoundsChanged();
-        }
+        invalidateSelf();
     }
 
     @Override
@@ -172,7 +193,7 @@
 
     @Override
     public boolean isStateful() {
-        return super.isStateful() || mState.mTint != null && mState.mTint.isStateful();
+        return true;
     }
 
     /**
@@ -213,7 +234,7 @@
             throws XmlPullParserException, IOException {
         final TypedArray a = obtainAttributes(
                 r, theme, attrs, R.styleable.TouchFeedbackDrawable);
-        inflateStateFromTypedArray(a);
+        updateStateFromTypedArray(a);
         a.recycle();
 
         super.inflate(r, parser, attrs, theme);
@@ -245,25 +266,23 @@
     /**
      * Initializes the constant state from the values in the typed array.
      */
-    private void inflateStateFromTypedArray(TypedArray a) {
+    private void updateStateFromTypedArray(TypedArray a) {
         final TouchFeedbackState state = mState;
 
         // Extract the theme attributes, if any.
-        final int[] themeAttrs = a.extractThemeAttrs();
-        state.mTouchThemeAttrs = themeAttrs;
+        state.mTouchThemeAttrs = a.extractThemeAttrs();
 
-        if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tint] == 0) {
-            mState.mTint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
+        final ColorStateList tint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
+        if (tint != null) {
+            mState.mTint = tint;
         }
 
-        if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tintMode] == 0) {
-            mState.setTintMode(Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
+        final int tintMode = a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1);
+        if (tintMode != -1) {
+            mState.setTintMode(Drawable.parseTintMode(tintMode, Mode.SRC_ATOP));
         }
 
-        if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_pinned] == 0) {
-            mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, false);
-        }
+        mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, mState.mPinned);
     }
 
     /**
@@ -283,38 +302,14 @@
         super.applyTheme(t);
 
         final TouchFeedbackState state = mState;
-        if (state == null) {
-            throw new RuntimeException(
-                    "Can't apply theme to <touch-feedback> with no constant state");
+        if (state == null || state.mTouchThemeAttrs == null) {
+            return;
         }
 
-        final int[] themeAttrs = state.mTouchThemeAttrs;
-        if (themeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(
-                    themeAttrs, R.styleable.TouchFeedbackDrawable);
-            updateStateFromTypedArray(a);
-            a.recycle();
-        }
-    }
-
-    /**
-     * Updates the constant state from the values in the typed array.
-     */
-    private void updateStateFromTypedArray(TypedArray a) {
-        final TouchFeedbackState state = mState;
-
-        if (a.hasValue(R.styleable.TouchFeedbackDrawable_tint)) {
-            state.mTint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
-        }
-
-        if (a.hasValue(R.styleable.TouchFeedbackDrawable_tintMode)) {
-            mState.setTintMode(Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
-        }
-
-        if (a.hasValue(R.styleable.TouchFeedbackDrawable_pinned)) {
-            mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, false);
-        }
+        final TypedArray a = t.resolveAttributes(state.mTouchThemeAttrs,
+                R.styleable.TouchFeedbackDrawable);
+        updateStateFromTypedArray(a);
+        a.recycle();
     }
 
     @Override
@@ -329,59 +324,123 @@
 
     @Override
     public void setHotspot(int id, float x, float y) {
-        if (mRipples == null) {
-            mRipples = new SparseArray<Ripple>();
-            mAnimatingRipples = new Ripple[MAX_RIPPLES];
+        if (mState.mPinned && !circleContains(mHotspotBounds, x, y)) {
+            x = mHotspotBounds.exactCenterX();
+            y = mHotspotBounds.exactCenterY();
         }
 
-        if (mAnimatingRipplesCount >= MAX_RIPPLES) {
-            Log.e(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
+        final int[] stateSet = getState();
+        if (!Arrays.contains(stateSet, id)) {
+            // The hotspot is not active, so just modify the pending location.
+            getOrCreatePendingHotspot(id).set(x, y);
             return;
         }
 
-        final Ripple ripple = mRipples.get(id);
-        if (ripple == null) {
-            final Rect bounds = mHotspotBounds;
-            if (mState.mPinned) {
-                x = bounds.exactCenterX();
-                y = bounds.exactCenterY();
-            }
-
-            // TODO: Clean this up in the API.
-            final boolean pulse = (id != R.attr.state_focused);
-            final Ripple newRipple = new Ripple(this, bounds, mDensity, pulse);
-            newRipple.move(x, y);
-
-            mAnimatingRipples[mAnimatingRipplesCount++] = newRipple;
-            mRipples.put(id, newRipple);
-        } else if (mState.mPinned) {
-            final Rect bounds = mHotspotBounds;
-            x = bounds.exactCenterX();
-            y = bounds.exactCenterY();
-            ripple.move(x, y);
-        } else {
-            ripple.move(x, y);
+        if (mAnimatingRipplesCount >= MAX_RIPPLES) {
+            // This should never happen unless the user is tapping like a maniac
+            // or there is a bug that's preventing ripples from being removed.
+            Log.d(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
+            return;
         }
+
+        if (mActiveHotspots == null) {
+            mActiveHotspots = new SparseArray<Ripple>();
+            mAnimatingRipples = new Ripple[MAX_RIPPLES];
+        }
+
+        final Ripple ripple = mActiveHotspots.get(id);
+        if (ripple != null) {
+            // The hotspot is active, but we can't move it because it's probably
+            // busy animating the center position.
+            return;
+        }
+
+        // The hotspot needs to be made active.
+        createActiveHotspot(id, x, y);
+    }
+
+    private boolean circleContains(Rect bounds, float x, float y) {
+        final float pX = bounds.exactCenterX() - x;
+        final float pY = bounds.exactCenterY() - y;
+        final double pointRadius = Math.sqrt(pX * pX + pY * pY);
+
+        final float bX = bounds.width() / 2.0f;
+        final float bY = bounds.height() / 2.0f;
+        final double boundsRadius = Math.sqrt(bX * bX + bY * bY);
+
+        return pointRadius < boundsRadius;
+    }
+
+    private PointF getOrCreatePendingHotspot(int id) {
+        final PointF p;
+        if (mPendingHotspots == null) {
+            mPendingHotspots = new SparseArray<>(2);
+            p = null;
+        } else {
+            p = mPendingHotspots.get(id);
+        }
+
+        if (p == null) {
+            final PointF newPoint = new PointF();
+            mPendingHotspots.put(id, newPoint);
+            return newPoint;
+        } else {
+            return p;
+        }
+    }
+
+    /**
+     * Moves a hotspot from pending to active.
+     */
+    private void activateHotspot(int id) {
+        final SparseArray<PointF> pendingHotspots = mPendingHotspots;
+        if (pendingHotspots != null) {
+            final int index = pendingHotspots.indexOfKey(id);
+            if (index >= 0) {
+                final PointF hotspot = pendingHotspots.valueAt(index);
+                pendingHotspots.removeAt(index);
+                createActiveHotspot(id, hotspot.x, hotspot.y);
+            }
+        }
+    }
+
+    /**
+     * Creates an active hotspot at the specified location.
+     */
+    private void createActiveHotspot(int id, float x, float y) {
+        final int color = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
+        final Ripple newRipple = new Ripple(this, mHotspotBounds, color);
+        newRipple.enter(x, y);
+
+        if (mAnimatingRipples == null) {
+            mAnimatingRipples = new Ripple[MAX_RIPPLES];
+        }
+        mAnimatingRipples[mAnimatingRipplesCount++] = newRipple;
+
+        if (mActiveHotspots == null) {
+            mActiveHotspots = new SparseArray<Ripple>();
+        }
+        mActiveHotspots.put(id, newRipple);
     }
 
     @Override
     public void removeHotspot(int id) {
-        if (mRipples == null) {
+        if (mActiveHotspots == null) {
             return;
         }
 
-        final Ripple ripple = mRipples.get(id);
+        final Ripple ripple = mActiveHotspots.get(id);
         if (ripple != null) {
             ripple.exit();
 
-            mRipples.remove(id);
+            mActiveHotspots.remove(id);
         }
     }
 
     @Override
     public void clearHotspots() {
-        if (mRipples != null) {
-            mRipples.clear();
+        if (mActiveHotspots != null) {
+            mActiveHotspots.clear();
         }
 
         final int count = mAnimatingRipplesCount;
@@ -402,7 +461,6 @@
     public void setHotspotBounds(int left, int top, int right, int bottom) {
         mOverrideBounds = true;
         mHotspotBounds.set(left, top, right, bottom);
-        onHotspotBoundsChange();
     }
 
     @Override
@@ -412,9 +470,9 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final boolean maskOnly = mState.mMask != null && N == 1;
 
-        int restoreToCount = drawRippleLayer(canvas, bounds, maskOnly);
+        int restoreToCount = drawRippleLayer(canvas, maskOnly);
 
-        if (restoreToCount >= 0) { 
+        if (restoreToCount >= 0) {
             // We have a ripple layer that contains ripples. If we also have an
             // explicit mask drawable, apply it now using DST_IN blending.
             if (mState.mMask != null) {
@@ -450,7 +508,7 @@
         }
     }
 
-    private int drawRippleLayer(Canvas canvas, Rect bounds, boolean maskOnly) {
+    private int drawRippleLayer(Canvas canvas, boolean maskOnly) {
         final int count = mAnimatingRipplesCount;
         if (count == 0) {
             return -1;
@@ -458,7 +516,7 @@
 
         final Ripple[] ripples = mAnimatingRipples;
         final boolean projected = isProjected();
-        final Rect layerBounds = projected ? getDirtyBounds() : bounds;
+        final Rect layerBounds = projected ? getDirtyBounds() : getBounds();
 
         // Separate the ripple color and alpha channel. The alpha will be
         // applied when we merge the ripples down to the canvas.
@@ -479,6 +537,7 @@
 
         boolean drewRipples = false;
         int restoreToCount = -1;
+        int restoreTranslate = -1;
         int animatingCount = 0;
 
         // Draw ripples and update the animating ripples array.
@@ -509,6 +568,10 @@
                 restoreToCount = canvas.saveLayer(layerBounds.left, layerBounds.top,
                         layerBounds.right, layerBounds.bottom, layerPaint);
                 layerPaint.setAlpha(255);
+
+                restoreTranslate = canvas.save();
+                // Translate the canvas to the current hotspot bounds.
+                canvas.translate(mHotspotBounds.exactCenterX(), mHotspotBounds.exactCenterY());
             }
 
             drewRipples |= ripple.draw(canvas, ripplePaint);
@@ -519,6 +582,11 @@
 
         mAnimatingRipplesCount = animatingCount;
 
+        // Always restore the translation.
+        if (restoreTranslate >= 0) {
+            canvas.restoreToCount(restoreTranslate);
+        }
+
         // If we created a layer with no content, merge it immediately.
         if (restoreToCount >= 0 && !drewRipples) {
             canvas.restoreToCount(restoreToCount);
@@ -543,11 +611,14 @@
         dirtyBounds.set(drawingBounds);
         drawingBounds.setEmpty();
 
+        final int cX = (int) mHotspotBounds.exactCenterX();
+        final int cY = (int) mHotspotBounds.exactCenterY();
         final Rect rippleBounds = mTempRect;
         final Ripple[] activeRipples = mAnimatingRipples;
         final int N = mAnimatingRipplesCount;
         for (int i = 0; i < N; i++) {
             activeRipples[i].getBounds(rippleBounds);
+            rippleBounds.offset(cX, cY);
             drawingBounds.union(rippleBounds);
         }
 
@@ -563,11 +634,11 @@
 
     static class TouchFeedbackState extends LayerState {
         int[] mTouchThemeAttrs;
-        ColorStateList mTint;
-        PorterDuffXfermode mTintXfermode;
-        PorterDuffXfermode mTintXfermodeInverse;
+        ColorStateList mTint = null;
+        PorterDuffXfermode mTintXfermode = SRC_ATOP;
+        PorterDuffXfermode mTintXfermodeInverse = DST_ATOP;
         Drawable mMask;
-        boolean mPinned;
+        boolean mPinned = false;
 
         public TouchFeedbackState(
                 TouchFeedbackState orig, TouchFeedbackDrawable owner, Resources res) {
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 83eedfb..b80f7e9 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -37,7 +37,10 @@
         , mInterpolator(0)
         , mPlayState(NEEDS_START)
         , mStartTime(0)
-        , mDuration(300){
+        , mDelayUntil(0)
+        , mDuration(300)
+        , mStartDelay(0) {
+
 }
 
 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
@@ -49,10 +52,6 @@
     mInterpolator = interpolator;
 }
 
-void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
-    mDuration = duration;
-}
-
 void BaseRenderNodeAnimator::setStartValue(float value) {
     LOG_ALWAYS_FATAL_IF(mPlayState != NEEDS_START,
             "Cannot set the start value after the animator has started!");
@@ -68,7 +67,24 @@
     }
 }
 
+void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
+    mDuration = duration;
+}
+
+void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
+    mStartDelay = startDelay;
+}
+
 bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
+    if (mPlayState == PENDING && mStartDelay > 0 && mDelayUntil == 0) {
+        mDelayUntil = info.frameTimeMs + mStartDelay;
+        return false;
+    }
+
+    if (mDelayUntil > info.frameTimeMs) {
+        return false;
+    }
+
     if (mPlayState == PENDING) {
         mPlayState = RUNNING;
         mStartTime = info.frameTimeMs;
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index fe88cbf..7741617 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -44,6 +44,8 @@
     ANDROID_API void setInterpolator(Interpolator* interpolator);
     ANDROID_API void setDuration(nsecs_t durationInMs);
     ANDROID_API nsecs_t duration() { return mDuration; }
+    ANDROID_API void setStartDelay(nsecs_t startDelayInMs);
+    ANDROID_API nsecs_t startDelay() { return mStartDelay; }
     ANDROID_API void setListener(AnimationListener* listener) {
         mListener = listener;
     }
@@ -82,10 +84,12 @@
 
     Interpolator* mInterpolator;
     PlayState mPlayState;
-    long mStartTime;
-    long mDuration;
+    nsecs_t mStartTime;
+    nsecs_t mDelayUntil;
+    nsecs_t mDuration;
+    nsecs_t mStartDelay;
 
-   sp<AnimationListener> mListener;
+    sp<AnimationListener> mListener;
 };
 
 class RenderPropertyAnimator : public BaseRenderNodeAnimator {
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 384e120..d4e85c8 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -61,25 +61,25 @@
      */
     public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
 
-    // Error codes:
-    // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
     /**
      * Denotes a successful operation.
      */
-    public static final int SUCCESS                 = 0;
+    public  static final int SUCCESS                               = AudioSystem.SUCCESS;
     /**
      * Denotes a generic operation failure.
      */
-    public static final int ERROR                   = -1;
+    public  static final int ERROR                                 = AudioSystem.ERROR;
     /**
      * Denotes a failure due to the use of an invalid value.
      */
-    public static final int ERROR_BAD_VALUE         = -2;
+    public  static final int ERROR_BAD_VALUE                       = AudioSystem.BAD_VALUE;
     /**
      * Denotes a failure due to the improper use of a method.
      */
-    public static final int ERROR_INVALID_OPERATION = -3;
+    public  static final int ERROR_INVALID_OPERATION               = AudioSystem.INVALID_OPERATION;
 
+    // Error codes:
+    // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
     private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      = -16;
     private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK  = -17;
     private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       = -18;
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 327c10c..5ddb198 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -199,6 +199,17 @@
         }
     }
 
+    /*
+     * Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...)
+     * Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h
+     */
+    public static final int SUCCESS            = 0;
+    public static final int ERROR              = -1;
+    public static final int BAD_VALUE          = -2;
+    public static final int INVALID_OPERATION  = -3;
+    public static final int PERMISSION_DENIED  = -4;
+    public static final int NO_INIT            = -5;
+    public static final int DEAD_OBJECT        = -6;
 
     /*
      * AudioPolicyService methods
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1a64cff..1baaaa4 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -125,25 +125,25 @@
      */
     public static final int STATE_NO_STATIC_DATA = 2;
 
-    // Error codes:
-    // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
     /**
      * Denotes a successful operation.
      */
-    public  static final int SUCCESS                               = 0;
+    public  static final int SUCCESS                               = AudioSystem.SUCCESS;
     /**
      * Denotes a generic operation failure.
      */
-    public  static final int ERROR                                 = -1;
+    public  static final int ERROR                                 = AudioSystem.ERROR;
     /**
      * Denotes a failure due to the use of an invalid value.
      */
-    public  static final int ERROR_BAD_VALUE                       = -2;
+    public  static final int ERROR_BAD_VALUE                       = AudioSystem.BAD_VALUE;
     /**
      * Denotes a failure due to the improper use of a method.
      */
-    public  static final int ERROR_INVALID_OPERATION               = -3;
+    public  static final int ERROR_INVALID_OPERATION               = AudioSystem.INVALID_OPERATION;
 
+    // Error codes:
+    // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
     private static final int ERROR_NATIVESETUP_AUDIOSYSTEM         = -16;
     private static final int ERROR_NATIVESETUP_INVALIDCHANNELMASK  = -17;
     private static final int ERROR_NATIVESETUP_INVALIDFORMAT       = -18;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 89886ef..8a7e642 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -23,10 +23,10 @@
 import android.hardware.IProCameraCallbacks;
 import android.hardware.IProCameraUser;
 import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.utils.BinderHolder;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.os.Binder;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 74ce997..7b2e7dd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -21,10 +21,10 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.utils.BinderHolder;
 import android.media.Image;
 import android.media.ImageReader;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 5ab586f..a77b647 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -18,6 +18,7 @@
 
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Range;
+import android.util.Rational;
 import android.util.SizeF;
 import android.graphics.ImageFormat;
 import android.graphics.Point;
@@ -26,15 +27,14 @@
 import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.ColorSpaceTransform;
-import android.hardware.camera2.Face;
-import android.hardware.camera2.MeteringRectangle;
-import android.hardware.camera2.Rational;
-import android.hardware.camera2.RggbChannelVector;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
+import android.hardware.camera2.params.ColorSpaceTransform;
+import android.hardware.camera2.params.Face;
+import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.RggbChannelVector;
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
index 9621f92..18c0d3e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
@@ -17,7 +17,7 @@
 package com.android.mediaframeworktest.unit;
 
 import android.test.suitebuilder.annotation.SmallTest;
-import android.hardware.camera2.Rational;
+import android.util.Rational;
 
 /**
  * <pre>
diff --git a/packages/InputDevices/res/raw/keyboard_layout_latvian_qwerty.kcm b/packages/InputDevices/res/raw/keyboard_layout_latvian_qwerty.kcm
new file mode 100644
index 0000000..d4bc0c0
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_latvian_qwerty.kcm
@@ -0,0 +1,362 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Latvian (QWERTY-US-intl based) keyboard layout.
+#
+
+type OVERLAY
+
+map key 86 BACKSLASH
+map key 43 POUND
+
+### ROW 1
+
+key GRAVE {
+    label:                              '\u0300'
+    base:                               '\u0300'
+    shift:                              '\u0303'
+    ralt:                               '-'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+    ralt:                               '\u00a0'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '@'
+    ralt:                               '\u00ab'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '#'
+    ralt:                               '\u00bb'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+    ralt:                               '\u20ac'
+    ralt+shift:                         '\u00a7'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+    ralt+shift:                         '\u00b0'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '\u0302'
+    ralt:                               '\u2019'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '&'
+    ralt+shift:                         '\u00b1'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '*'
+    ralt+shift:                         '\u00d7'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+    ralt:                               '\u2013'
+    ralt+shift:                         '\u2014'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    ralt:                               '\u0113'
+    shift+ralt, ralt+capslock:          '\u0112'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+    ralt:                               '\u0157'
+    shift+ralt, ralt+capslock:          '\u0156'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+    ralt:                               '\u016b'
+    shift+ralt, ralt+capslock:          '\u016a'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+    ralt:                               '\u012b'
+    shift+ralt, ralt+capslock:          '\u012a'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+    ralt:                               '\u00f5'
+    shift+ralt, ralt+capslock:          '\u00d5'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '['
+    base:                               '['
+    shift:                              '{'
+}
+
+key RIGHT_BRACKET {
+    label:                              ']'
+    base:                               ']'
+    shift:                              '}'
+}
+
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+    ralt:                               '\u0101'
+    shift+ralt, ralt+capslock:          '\u0100'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+    ralt:                               '\u0161'
+    shift+ralt, ralt+capslock:          '\u0160'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+    ralt:                               '\u0123'
+    shift+ralt, ralt+capslock:          '\u0122'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+    ralt:                               '\u0137'
+    shift+ralt, ralt+capslock:          '\u0136'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+    ralt:                               '\u013c'
+    shift+ralt, ralt+capslock:          '\u013b'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               ';'
+    shift:                              ':'
+}
+
+key APOSTROPHE {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '"'
+    ralt:                               '\u0301'
+    shift+ralt:                         '\u0308'
+}
+
+key POUND {
+    label:                              '\u00b0'
+    base:                               '\u00b0'
+    shift:                              '|'
+}
+
+### ROW 4
+
+key BACKSLASH {
+    label:                              '\\'
+    base:                               '\\'
+    shift:                              '|'
+    ralt:                               '\u00ac'
+    shift+ralt:                         '\u00a6'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+    ralt:                               '\u017e'
+    shift+ralt, ralt+capslock:          '\u017d'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+    ralt:                               '\u010d'
+    shift+ralt, ralt+capslock:          '\u010c'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+    ralt:                               '\u0146'
+    shift+ralt, ralt+capslock:          '\u0145'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              '<'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              '>'
+}
+
+key SLASH {
+    label:                              '/'
+    base:                               '/'
+    shift:                              '?'
+    ralt:                               '\u00bf'
+}
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 6239336..968961a 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -113,4 +113,7 @@
 
     <!-- Spanish (Latin) keyboard layout label. [CHAR LIMIT=35] -->
     <string name="keyboard_layout_spanish_latin">Spanish (Latin)</string>
+
+    <!-- Latvian keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_latvian">Latvian</string>
 </resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index dc1db0b..6f7253c 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -143,4 +143,8 @@
     <keyboard-layout android:name="keyboard_layout_spanish_latin"
             android:label="@string/keyboard_layout_spanish_latin"
             android:keyboardLayout="@raw/keyboard_layout_spanish_latin" />
+
+    <keyboard-layout android:name="keyboard_layout_latvian"
+            android:label="@string/keyboard_layout_latvian"
+            android:keyboardLayout="@raw/keyboard_layout_latvian_qwerty" />
 </keyboard-layouts>
diff --git a/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml b/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
index b48e011..b363ab4 100644
--- a/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
@@ -14,5 +14,5 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<trust_agent xmlns:android="http://schemas.android.com/apk/res/android"
+<trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
         android:settingsActivity=".SampleTrustAgentSettings" />
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
index 25406d6..a51ea75 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
@@ -31,7 +31,7 @@
 
     LocalBroadcastManager mLocalBroadcastManager;
 
-    private static final String ACTION_ENABLE_TRUST = "action.sample_trust_agent.enable_trust";
+    private static final String ACTION_GRANT_TRUST = "action.sample_trust_agent.grant_trust";
     private static final String ACTION_REVOKE_TRUST = "action.sample_trust_agent.revoke_trust";
 
     private static final String EXTRA_MESSAGE = "extra.message";
@@ -45,14 +45,14 @@
     public void onCreate() {
         super.onCreate();
         IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_ENABLE_TRUST);
+        filter.addAction(ACTION_GRANT_TRUST);
         filter.addAction(ACTION_REVOKE_TRUST);
         mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
         mLocalBroadcastManager.registerReceiver(mReceiver, filter);
     }
 
     @Override
-    protected void onUnlockAttempt(boolean successful) {
+    public void onUnlockAttempt(boolean successful) {
         if (getReportUnlockAttempts(this)) {
             Toast.makeText(this, "onUnlockAttempt(successful=" + successful + ")",
                     Toast.LENGTH_SHORT).show();
@@ -69,8 +69,8 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (ACTION_ENABLE_TRUST.equals(action)) {
-                enableTrust(intent.getStringExtra(EXTRA_MESSAGE),
+            if (ACTION_GRANT_TRUST.equals(action)) {
+                grantTrust(intent.getStringExtra(EXTRA_MESSAGE),
                         intent.getLongExtra(EXTRA_DURATION, 0),
                         false /* initiatedByUser */);
             } else if (ACTION_REVOKE_TRUST.equals(action)) {
@@ -79,9 +79,9 @@
         }
     };
 
-    public static void sendEnableTrust(Context context,
+    public static void sendGrantTrust(Context context,
             String message, long durationMs, Bundle extra) {
-        Intent intent = new Intent(ACTION_ENABLE_TRUST);
+        Intent intent = new Intent(ACTION_GRANT_TRUST);
         intent.putExtra(EXTRA_MESSAGE, message);
         intent.putExtra(EXTRA_DURATION, durationMs);
         intent.putExtra(EXTRA_EXTRA, extra);
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
index 0a6f675..8e293fb 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
@@ -19,7 +19,6 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.os.Bundle;
-import android.preference.CheckBoxPreference;
 import android.view.View;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
@@ -53,7 +52,7 @@
     public void onClick(View v) {
         int id = v.getId();
         if (id == R.id.enable_trust) {
-            SampleTrustAgent.sendEnableTrust(this, "SampleTrustAgent", TRUST_DURATION_MS,
+            SampleTrustAgent.sendGrantTrust(this, "SampleTrustAgent", TRUST_DURATION_MS,
                     null /* extra */);
         } else if (id == R.id.revoke_trust) {
             SampleTrustAgent.sendRevokeTrust(this);
diff --git a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
new file mode 100644
index 0000000..ff8800c
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
@@ -0,0 +1,65 @@
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!-- Extends FrameLayout -->
+<com.android.systemui.statusbar.SpeedBumpView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusable="true"
+    android:clickable="true"
+    android:visibility="gone"
+    >
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/speed_bump_height_collapsed"
+            android:layout_gravity="top"
+            android:orientation="horizontal">
+        <View
+            android:id="@+id/speedbump_line_left"
+            android:layout_width="0dp"
+            android:layout_height="1dp"
+            android:layout_weight="1"
+            android:background="#6fdddddd"
+            android:layout_gravity="center_vertical"/>
+        <com.android.systemui.statusbar.SpeedBumpDotsLayout
+                android:id="@+id/speed_bump_dots_layout"
+                android:layout_width="34dp"
+                android:layout_marginStart="8dp"
+                android:layout_marginEnd="8dp"
+                android:layout_height="match_parent"
+                android:layout_weight="0"/>
+        <View
+            android:id="@+id/speedbump_line_right"
+            android:layout_width="0dp"
+            android:layout_height="1dp"
+            android:layout_weight="1"
+            android:background="#6fdddddd"
+            android:layout_gravity="center_vertical"/>
+    </LinearLayout>
+    <TextView
+            android:id="@+id/speed_bump_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal"
+            android:fontFamily="sans-serif-condensed"
+            android:textSize="15sp"
+            android:singleLine="true"
+            android:textColor="#eeeeee"
+            android:visibility="invisible"
+            android:text="@string/speed_bump_explanation"
+            android:paddingTop="4dp" />
+</com.android.systemui.statusbar.SpeedBumpView>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 9582b21..cba13004 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -58,6 +58,18 @@
     <!-- Tint color for the content on the notification overflow card. -->
     <color name="keyguard_overflow_content_color">#ff666666</color>
 
+    <!-- The color of the red speed bump dot -->
+    <color name="speed_bump_dot_red">#ffd50000</color>
+
+    <!-- The color of the blue speed bump dot -->
+    <color name="speed_bump_dot_blue">#ff2962ff</color>
+
+    <!-- The color of the yellow speed bump dot -->
+    <color name="speed_bump_dot_yellow">#ffffd600</color>
+
+    <!-- The color of the green speed bump dot -->
+    <color name="speed_bump_dot_green">#ff00c853</color>
+
     <!-- The default recents task bar background color. -->
     <color name="recents_task_bar_default_background_color">#e6444444</color>
     <!-- The default recents task bar text color. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 79612e0..d403bf3 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -260,6 +260,15 @@
     <!-- The padding between the individual notification cards. -->
     <dimen name="notification_padding">4dp</dimen>
 
+    <!-- The height of the collapsed speed bump view. -->
+    <dimen name="speed_bump_height_collapsed">24dp</dimen>
+
+    <!-- The padding inset the explanation text needs compared to the collapsed height -->
+    <dimen name="speed_bump_text_padding_inset">10dp</dimen>
+
+    <!-- The height of the speed bump dots. -->
+    <dimen name="speed_bump_dots_height">5dp</dimen>
+
     <!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) -->
     <dimen name="collapsed_stack_height">94dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a50a0ac..b3829a3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -553,6 +553,9 @@
         <item quantity="other">%d more</item>
     </plurals>
 
+    <!-- An explanation for the visual speed bump in the notifications, which will appear when you click on it. [CHAR LIMIT=50] -->
+    <string name="speed_bump_explanation">Less urgent notifications below</string>
+
     <!-- Shows to explain the double tap interaction with notifications: After tapping a notification on Keyguard, this will explain users to tap again to launch a notification. [CHAR LIMIT=60] -->
     <string name="notification_tap_again">Tap again to open</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 1ca0476..1c12ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -400,15 +400,14 @@
             ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
             if (info == null) continue;
 
-            ActivityManager.RecentsActivityValues av = t.activityValues;
+            ActivityManager.TaskDescription av = t.taskDescription;
             String activityLabel = null;
             BitmapDrawable activityIcon = null;
             int activityColor = 0;
             if (av != null) {
-                activityLabel = (av.label != null ? av.label.toString() :
-                        ssp.getActivityLabel(info));
-                activityIcon = (av.icon != null) ? new BitmapDrawable(res, av.icon) : null;
-                activityColor = av.colorPrimary;
+                activityLabel = (av.getLabel() != null ? av.getLabel() : ssp.getActivityLabel(info));
+                activityIcon = (av.getIcon() != null) ? new BitmapDrawable(res, av.getIcon()) : null;
+                activityColor = av.getPrimaryColor();
             } else {
                 activityLabel = ssp.getActivityLabel(info);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 8d82883..59d0ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -96,18 +96,19 @@
                 int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount;
                 ComponentName cn = new ComponentName("com.android.test" + packageIndex,
                         "com.android.test" + i + ".Activity");
+                String description = "" + i + " - " +
+                        Long.toString(Math.abs(new Random().nextLong()), 36);
                 // Create the recent task info
                 ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
                 rti.id = rti.persistentId = i;
                 rti.baseIntent = new Intent();
                 rti.baseIntent.setComponent(cn);
-                rti.activityValues = new ActivityManager.RecentsActivityValues();
-                rti.description = "" + i + " - " +
-                        Long.toString(Math.abs(new Random().nextLong()), 36);
+                rti.description = description;
                 if (i % 2 == 0) {
-                    rti.activityValues.label = rti.description;
-                    rti.activityValues.icon = Bitmap.createBitmap(mDummyIcon);
-                    rti.activityValues.colorPrimary = new Random().nextInt();
+                    rti.taskDescription = new ActivityManager.TaskDescription(description,
+                        Bitmap.createBitmap(mDummyIcon), new Random().nextInt());
+                } else {
+                    rti.taskDescription = new ActivityManager.TaskDescription();
                 }
                 tasks.add(rti);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 91df9ef..5e8c769 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -21,6 +21,7 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -45,6 +46,9 @@
     private int mBgResId = R.drawable.notification_quantum_bg;
     private int mDimmedBgResId = R.drawable.notification_quantum_bg_dim;
 
+    private int mBgTint = 0;
+    private int mDimmedBgTint = 0;
+
     /**
      * Flag to indicate that the notification has been touched once and the second touch will
      * click it.
@@ -209,17 +213,23 @@
      * @param bgResId The background resource to use in normal state.
      * @param dimmedBgResId The background resource to use in dimmed state.
      */
-    public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) {
+    public void setBackgroundResourceIds(int bgResId, int bgTint, int dimmedBgResId, int dimmedTint) {
         mBgResId = bgResId;
+        mBgTint = bgTint;
         mDimmedBgResId = dimmedBgResId;
+        mDimmedBgTint = dimmedTint;
         updateBackgroundResource();
     }
 
+    public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) {
+        setBackgroundResourceIds(bgResId, 0, dimmedBgResId, 0);
+    }
+
     private void fadeBackgroundResource() {
         if (mDimmed) {
-            setBackgroundDimmed(mDimmedBgResId);
+            setBackgroundDimmed(mDimmedBgResId, mDimmedBgTint);
         } else {
-            setBackgroundNormal(mBgResId);
+            setBackgroundNormal(mBgResId, mBgTint);
         }
         int startAlpha = mDimmed ? 255 : 0;
         int endAlpha = mDimmed ? 0 : 255;
@@ -256,12 +266,12 @@
 
     private void updateBackgroundResource() {
         if (mDimmed) {
-            setBackgroundDimmed(mDimmedBgResId);
+            setBackgroundDimmed(mDimmedBgResId, mDimmedBgTint);
             mBackgroundDimmed.setAlpha(255);
             setBackgroundNormal(null);
         } else {
             setBackgroundDimmed(null);
-            setBackgroundNormal(mBgResId);
+            setBackgroundNormal(mBgResId, mBgTint);
             mBackgroundNormal.setAlpha(255);
         }
     }
@@ -295,12 +305,20 @@
         invalidate();
     }
 
-    private void setBackgroundNormal(int drawableResId) {
-        setBackgroundNormal(getResources().getDrawable(drawableResId));
+    private void setBackgroundNormal(int drawableResId, int tintColor) {
+        final Drawable d = getResources().getDrawable(drawableResId);
+        if (tintColor != 0) {
+            d.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
+        }
+        setBackgroundNormal(d);
     }
 
-    private void setBackgroundDimmed(int drawableResId) {
-        setBackgroundDimmed(getResources().getDrawable(drawableResId));
+    private void setBackgroundDimmed(int drawableResId, int tintColor) {
+        final Drawable d = getResources().getDrawable(drawableResId);
+        if (tintColor != 0) {
+            d.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
+        }
+        setBackgroundDimmed(d);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 898f06e..c1228d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -428,14 +428,16 @@
 
     protected void applyLegacyRowBackground(StatusBarNotification sbn,
             NotificationData.Entry entry) {
+        int version = 0;
+        try {
+            ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.getPackageName(), 0);
+            version = info.targetSdkVersion;
+        } catch (NameNotFoundException ex) {
+            Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
+        }
+
         if (entry.expanded.getId() != com.android.internal.R.id.status_bar_latest_event_content) {
-            int version = 0;
-            try {
-                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.getPackageName(), 0);
-                version = info.targetSdkVersion;
-            } catch (NameNotFoundException ex) {
-                Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
-            }
+            // Using custom RemoteViews
             if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
                 entry.row.setBackgroundResource(R.drawable.notification_row_legacy_bg);
             } else if (version < Build.VERSION_CODES.L) {
@@ -875,6 +877,7 @@
         entry.row = row;
         entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
         entry.row.setOnActivatedListener(this);
+        entry.row.setIsBelowSpeedBump(isBelowSpeedBump(entry.notification));
         entry.expanded = contentViewLocal;
         entry.expandedPublic = publicViewLocal;
         entry.setBigContentView(bigContentViewLocal);
@@ -1037,8 +1040,8 @@
         if (DEBUG) {
             Log.d(TAG, "addNotificationViews: added at " + pos);
         }
-        updateRowStates();
         updateNotificationIcons();
+        updateRowStates();
     }
 
     private void addNotificationViews(IBinder key, StatusBarNotification notification) {
@@ -1058,6 +1061,7 @@
         mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
         int n = mNotificationData.size();
         int visibleNotifications = 0;
+        int speedBumpIndex = -1;
         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
         for (int i = n-1; i >= 0; i--) {
             NotificationData.Entry entry = mNotificationData.get(i);
@@ -1085,6 +1089,10 @@
                 entry.row.setVisibility(View.VISIBLE);
                 visibleNotifications++;
             }
+            if (entry.row.getVisibility() != View.GONE && speedBumpIndex == -1
+                    && entry.row.isBelowSpeedBump() ) {
+                speedBumpIndex = n - 1 - i;
+            }
         }
 
         if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
@@ -1092,6 +1100,8 @@
         } else {
             mKeyguardIconOverflowContainer.setVisibility(View.GONE);
         }
+
+        mStackScroller.updateSpeedBumpIndex(speedBumpIndex);
     }
 
     private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
@@ -1307,9 +1317,19 @@
         } else {
             entry.row.setOnClickListener(null);
         }
+        boolean wasBelow = entry.row.isBelowSpeedBump();
+        boolean nowBelow = isBelowSpeedBump(notification);
+        if (wasBelow != nowBelow) {
+            entry.row.setIsBelowSpeedBump(nowBelow);
+        }
         entry.row.notifyContentUpdated();
     }
 
+    private boolean isBelowSpeedBump(StatusBarNotification notification) {
+        return notification.getNotification().priority ==
+                Notification.PRIORITY_MIN;
+    }
+
     protected void notifyHeadsUpScreenOn(boolean screenOn) {
         if (!screenOn && mInterruptingNotificationEntry != null) {
             mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 39f2bb9..f6c80fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -52,6 +52,7 @@
     private NotificationContentView mPublicLayout;
     private NotificationContentView mPrivateLayout;
     private int mMaxExpandHeight;
+    private boolean mIsBelowSpeedBump;
 
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -244,6 +245,14 @@
         mPrivateLayout.setClipTopAmount(clipTopAmount);
     }
 
+    public boolean isBelowSpeedBump() {
+        return mIsBelowSpeedBump;
+    }
+
+    public void setIsBelowSpeedBump(boolean isBelow) {
+        this.mIsBelowSpeedBump = isBelow;
+    }
+
     public void notifyContentUpdated() {
         mPrivateLayout.notifyContentUpdated();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 4bd0e1c..061396d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -40,11 +40,15 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         if (!mActualHeightInitialized && mActualHeight == 0) {
-            mActualHeight = getHeight();
+            mActualHeight = getInitialHeight();
         }
         mActualHeightInitialized = true;
     }
 
+    protected int getInitialHeight() {
+        return getHeight();
+    }
+
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         if (filterMotionEvent(ev)) {
@@ -146,6 +150,10 @@
         }
     }
 
+    public boolean isTransparent() {
+        return false;
+    }
+
     /**
      * A listener notifying when {@link #getActualHeight} changes.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
new file mode 100644
index 0000000..3ca021a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * An single dot of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
+ */
+public class SpeedBumpDotView extends View {
+
+    private final Paint mPaint = new Paint();
+
+    public SpeedBumpDotView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mPaint.setAntiAlias(true);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        float radius = getWidth() / 2.0f;
+        canvas.drawCircle(radius, radius, radius, mPaint);
+    }
+
+    public void setColor(int color) {
+        mPaint.setColor(color);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
new file mode 100644
index 0000000..cac6327
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.view.View;
+import com.android.systemui.R;
+
+/**
+ * The Algorithm of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout} which can be
+ * queried for {@link * com.android.systemui.statusbar.SpeedBumpDotsState}
+ */
+public class SpeedBumpDotsAlgorithm {
+
+    private final float mDotRadius;
+
+    public SpeedBumpDotsAlgorithm(Context context) {
+        mDotRadius = context.getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height)
+                / 2.0f;
+    }
+
+    public void getState(SpeedBumpDotsState resultState) {
+
+        // First reset the current state and ensure that every View has a ViewState
+        resultState.resetViewStates();
+
+        SpeedBumpDotsLayout hostView = resultState.getHostView();
+        boolean currentlyVisible = hostView.isCurrentlyVisible();
+        resultState.setActiveState(currentlyVisible
+                ? SpeedBumpDotsState.SHOWN
+                : SpeedBumpDotsState.HIDDEN);
+        int hostWidth = hostView.getWidth();
+        float layoutWidth = hostWidth - 2 * mDotRadius;
+        int childCount = hostView.getChildCount();
+        float paddingBetween = layoutWidth / (childCount - 1);
+        float centerY = hostView.getHeight() / 2.0f;
+        for (int i = 0; i < childCount; i++) {
+            View child = hostView.getChildAt(i);
+            SpeedBumpDotsState.ViewState viewState = resultState.getViewStateForView(child);
+            if (currentlyVisible) {
+                float xTranslation = i * paddingBetween;
+                viewState.xTranslation = xTranslation;
+                viewState.yTranslation = calculateYTranslation(hostView, centerY, xTranslation,
+                        layoutWidth);
+            } else {
+                viewState.xTranslation = layoutWidth / 2;
+                viewState.yTranslation = centerY - mDotRadius;
+            }
+            viewState.alpha = currentlyVisible ? 1.0f : 0.0f;
+            viewState.scale = currentlyVisible ? 1.0f : 0.5f;
+        }
+    }
+
+    private float calculateYTranslation(SpeedBumpDotsLayout hostView, float centerY,
+            float xTranslation, float layoutWidth) {
+        float t = hostView.getAnimationProgress();
+        if (t == 0.0f || t == 1.0f) {
+            return centerY - mDotRadius;
+        }
+        float damping = (0.5f -Math.abs(0.5f - t)) * 1.3f;
+        float partialOffset = xTranslation / layoutWidth;
+        float indentFactor = (float) (Math.sin((t + partialOffset * 1.5f) * - Math.PI) * damping);
+        return (1.0f - indentFactor) * centerY - mDotRadius;
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
new file mode 100644
index 0000000..ddf5215
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.TimeAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import com.android.systemui.R;
+
+/**
+ * A layout with a certain number of dots which are integrated in the
+ * {@link com.android.systemui.statusbar.SpeedBumpView}
+ */
+public class SpeedBumpDotsLayout extends ViewGroup {
+
+    private static final float DOT_CLICK_ANIMATION_LENGTH = 300;
+    private final int mDotSize;
+    private final SpeedBumpDotsAlgorithm mAlgorithm = new SpeedBumpDotsAlgorithm(getContext());
+    private final SpeedBumpDotsState mCurrentState = new SpeedBumpDotsState(this);
+    private boolean mIsCurrentlyVisible = true;
+    private final ValueAnimator mClickAnimator;
+    private float mAnimationProgress;
+    private ValueAnimator.AnimatorUpdateListener mClickUpdateListener
+            = new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            mAnimationProgress = animation.getAnimatedFraction();
+            updateChildren();
+        }
+    };
+
+    public SpeedBumpDotsLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mDotSize = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
+        createDots(context, attrs);
+        mClickAnimator = TimeAnimator.ofFloat(0, DOT_CLICK_ANIMATION_LENGTH);
+        mClickAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
+        mClickAnimator.addUpdateListener(mClickUpdateListener);
+    }
+
+    private void createDots(Context context, AttributeSet attrs) {
+        SpeedBumpDotView blueDot = new SpeedBumpDotView(context, attrs);
+        blueDot.setColor(getResources().getColor(R.color.speed_bump_dot_blue));
+        addView(blueDot);
+
+        SpeedBumpDotView redDot = new SpeedBumpDotView(context, attrs);
+        redDot.setColor(getResources().getColor(R.color.speed_bump_dot_red));
+        addView(redDot);
+
+        SpeedBumpDotView yellowDot = new SpeedBumpDotView(context, attrs);
+        yellowDot.setColor(getResources().getColor(R.color.speed_bump_dot_yellow));
+        addView(yellowDot);
+
+        SpeedBumpDotView greenDot = new SpeedBumpDotView(context, attrs);
+        greenDot.setColor(getResources().getColor(R.color.speed_bump_dot_green));
+        addView(greenDot);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int childWidthSpec = MeasureSpec.makeMeasureSpec(mDotSize,
+                MeasureSpec.getMode(widthMeasureSpec));
+        int childHeightSpec = MeasureSpec.makeMeasureSpec(mDotSize,
+                MeasureSpec.getMode(heightMeasureSpec));
+        measureChildren(childWidthSpec, childHeightSpec);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            child.layout(0, 0, mDotSize, mDotSize);
+        }
+        if (changed) {
+            updateChildren();
+        }
+    }
+
+    private void updateChildren() {
+        mAlgorithm.getState(mCurrentState);
+        mCurrentState.apply();
+    }
+
+    public void performVisibilityAnimation(boolean visible) {
+        if (mClickAnimator.isRunning()) {
+            mClickAnimator.cancel();
+        }
+        mIsCurrentlyVisible = visible;
+        mAlgorithm.getState(mCurrentState);
+        mCurrentState.animateToState();
+    }
+
+    public void setInvisible() {
+        mIsCurrentlyVisible = false;
+        mAlgorithm.getState(mCurrentState);
+        mCurrentState.apply();
+    }
+
+    public boolean isCurrentlyVisible() {
+        return mIsCurrentlyVisible;
+    }
+
+    public void performDotClickAnimation() {
+        if (mClickAnimator.isRunning()) {
+            // don't perform an animation if it's running already
+            return;
+        }
+        mClickAnimator.start();
+    }
+
+
+    public float getAnimationProgress() {
+        return mAnimationProgress;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
new file mode 100644
index 0000000..06a7f95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A state of a {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
+ */
+public class SpeedBumpDotsState {
+
+    public static final int HIDDEN = 1;
+    public static final int SHOWN = 2;
+    private static final int VISIBILITY_ANIMATION_DELAY_PER_ELEMENT = 80;
+
+    private final SpeedBumpDotsLayout mHostView;
+    private final HashMap<View, ViewState> mStateMap = new HashMap<View, ViewState>();
+    private final Interpolator mFastOutSlowInInterpolator;
+    private int mActiveState = 0;
+
+    public SpeedBumpDotsState(SpeedBumpDotsLayout hostLayout) {
+        mHostView = hostLayout;
+        mFastOutSlowInInterpolator = AnimationUtils
+                .loadInterpolator(hostLayout.getContext(),
+                        android.R.interpolator.fast_out_slow_in);
+    }
+
+    public SpeedBumpDotsLayout getHostView() {
+        return mHostView;
+    }
+
+    public void resetViewStates() {
+        int numChildren = mHostView.getChildCount();
+        for (int i = 0; i < numChildren; i++) {
+            View child = mHostView.getChildAt(i);
+            ViewState viewState = mStateMap.get(child);
+            if (viewState == null) {
+                viewState = new ViewState();
+                mStateMap.put(child, viewState);
+            }
+        }
+    }
+
+    public ViewState getViewStateForView(View requestedView) {
+        return mStateMap.get(requestedView);
+    }
+
+    public void apply() {
+        int childCount = mHostView.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = mHostView.getChildAt(i);
+            ViewState viewState = mStateMap.get(child);
+            float translationX = child.getTranslationX();
+            float translationY = child.getTranslationY();
+            float scale = child.getScaleX();
+            float alpha = child.getAlpha();
+            if (translationX != viewState.xTranslation) {
+                child.setTranslationX(viewState.xTranslation);
+            }
+            if (translationY != viewState.yTranslation) {
+                child.setTranslationY(viewState.yTranslation);
+            }
+            if (scale != viewState.scale) {
+                child.setScaleX(viewState.scale);
+                child.setScaleY(viewState.scale);
+            }
+            if (alpha != viewState.alpha) {
+                child.setAlpha(viewState.alpha);
+            }
+        }
+    }
+
+    public void animateToState() {
+        int childCount = mHostView.getChildCount();
+        int middleIndex = (childCount - 1) / 2;
+        long delayPerElement = VISIBILITY_ANIMATION_DELAY_PER_ELEMENT;
+        boolean isAppearing = getActiveState() == SHOWN;
+        boolean isDisappearing = getActiveState() == HIDDEN;
+        for (int i = 0; i < childCount; i++) {
+            int delayIndex;
+            if (i <= middleIndex) {
+                delayIndex = i * 2;
+            } else {
+                int distToMiddle = i - middleIndex;
+                delayIndex = (childCount - 1) - (distToMiddle - 1) * 2;
+            }
+            long startDelay = 0;
+            if (isAppearing || isDisappearing) {
+                if (isDisappearing) {
+                    delayIndex = childCount - 1 - delayIndex;
+                }
+                startDelay = delayIndex * delayPerElement;
+            }
+            View child = mHostView.getChildAt(i);
+            ViewState viewState = mStateMap.get(child);
+            child.animate().setInterpolator(mFastOutSlowInInterpolator)
+                    .setStartDelay(startDelay)
+                    .alpha(viewState.alpha).withLayer()
+                    .translationX(viewState.xTranslation)
+                    .translationY(viewState.yTranslation)
+                    .scaleX(viewState.scale).scaleY(viewState.scale);
+        }
+    }
+
+    public int getActiveState() {
+        return mActiveState;
+    }
+
+    public void setActiveState(int mActiveState) {
+        this.mActiveState = mActiveState;
+    }
+
+    public static class ViewState {
+        float xTranslation;
+        float yTranslation;
+        float alpha;
+        float scale;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
new file mode 100644
index 0000000..8ae503a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Outline;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.TextView;
+import com.android.systemui.R;
+
+/**
+ * The view representing the separation between important and less important notifications
+ */
+public class SpeedBumpView extends ExpandableView implements View.OnClickListener {
+
+    private final int mCollapsedHeight;
+    private final int mDotsHeight;
+    private final int mTextPaddingInset;
+    private SpeedBumpDotsLayout mDots;
+    private View mLineLeft;
+    private View mLineRight;
+    private boolean mIsExpanded;
+    private boolean mDividerVisible = true;
+    private ValueAnimator mCurrentAnimator;
+    private final Interpolator mFastOutSlowInInterpolator;
+    private float mCenterX;
+    private TextView mExplanationText;
+    private boolean mExplanationTextVisible = false;
+    private AnimatorListenerAdapter mHideExplanationListener = new AnimatorListenerAdapter() {
+        private boolean mCancelled;
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (!mCancelled) {
+                mExplanationText.setVisibility(View.INVISIBLE);
+            }
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCancelled = true;
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            mCancelled = false;
+        }
+    };
+    private Animator.AnimatorListener mAnimationFinishedListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mCurrentAnimator = null;
+        }
+    };
+
+    public SpeedBumpView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mCollapsedHeight = getResources()
+                .getDimensionPixelSize(R.dimen.speed_bump_height_collapsed);
+        mTextPaddingInset = getResources().getDimensionPixelSize(
+                R.dimen.speed_bump_text_padding_inset);
+        mDotsHeight = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
+        setOnClickListener(this);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+                android.R.interpolator.fast_out_slow_in);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mDots = (SpeedBumpDotsLayout) findViewById(R.id.speed_bump_dots_layout);
+        mLineLeft = findViewById(R.id.speedbump_line_left);
+        mLineRight = findViewById(R.id.speedbump_line_right);
+        mExplanationText = (TextView) findViewById(R.id.speed_bump_text);
+        resetExplanationText();
+
+    }
+
+    @Override
+    protected int getInitialHeight() {
+        return mCollapsedHeight;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return getActualHeight();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        Outline outline = new Outline();
+        mCenterX = getWidth() / 2;
+        float centerY = getHeight() / 2;
+        // TODO: hide outline better
+        // Temporary workaround to hide outline on a transparent view
+        int outlineLeft = (int) (mCenterX - getResources().getDisplayMetrics().densityDpi * 8);
+        int outlineTop = (int) (centerY - mDotsHeight / 2);
+        outline.setOval(outlineLeft, outlineTop, outlineLeft + mDotsHeight,
+                outlineTop + mDotsHeight);
+        setOutline(outline);
+        mLineLeft.setPivotX(mLineLeft.getWidth());
+        mLineLeft.setPivotY(mLineLeft.getHeight() / 2);
+        mLineRight.setPivotX(0);
+        mLineRight.setPivotY(mLineRight.getHeight() / 2);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        measureChildren(widthMeasureSpec, heightMeasureSpec);
+        int height = mCollapsedHeight + mExplanationText.getMeasuredHeight() - mTextPaddingInset;
+        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (mCurrentAnimator != null) {
+            return;
+        }
+        int startValue = mIsExpanded ? getMaxHeight() : mCollapsedHeight;
+        int endValue = mIsExpanded ? mCollapsedHeight : getMaxHeight();
+        mCurrentAnimator = ValueAnimator.ofInt(startValue, endValue);
+        mCurrentAnimator.setInterpolator(mFastOutSlowInInterpolator);
+        mCurrentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                setActualHeight((int) animation.getAnimatedValue());
+            }
+        });
+        mCurrentAnimator.addListener(mAnimationFinishedListener);
+        mCurrentAnimator.start();
+        mIsExpanded = !mIsExpanded;
+        mDots.performDotClickAnimation();
+        animateExplanationTextInternal(mIsExpanded);
+    }
+
+    private void animateExplanationTextInternal(boolean visible) {
+        if (mExplanationTextVisible != visible) {
+            float translationY = 0.0f;
+            float scale = 0.5f;
+            float alpha = 0.0f;
+            boolean needsHideListener = true;
+            if (visible) {
+                mExplanationText.setVisibility(VISIBLE);
+                translationY = mDots.getBottom() - mTextPaddingInset;
+                scale = 1.0f;
+                alpha = 1.0f;
+                needsHideListener = false;
+            }
+            mExplanationText.animate().setInterpolator(mFastOutSlowInInterpolator)
+                    .alpha(alpha)
+                    .scaleX(scale)
+                    .scaleY(scale)
+                    .translationY(translationY)
+                    .setListener(needsHideListener ? mHideExplanationListener : null)
+                    .withLayer();
+            mExplanationTextVisible = visible;
+        }
+    }
+
+    @Override
+    public boolean isTransparent() {
+        return true;
+    }
+
+    public void performVisibilityAnimation(boolean nowVisible) {
+        animateDivider(nowVisible);
+
+        // Animate explanation Text
+        if (mIsExpanded) {
+            animateExplanationTextInternal(nowVisible);
+        }
+    }
+
+    public void animateDivider(boolean nowVisible) {
+        if (nowVisible != mDividerVisible) {
+            // Animate dividers
+            float endValue = nowVisible ? 1.0f : 0.0f;
+            float endTranslationXLeft = nowVisible ? 0.0f : mCenterX - mLineLeft.getRight();
+            float endTranslationXRight = nowVisible ? 0.0f : mCenterX - mLineRight.getLeft();
+            mLineLeft.animate()
+                    .alpha(endValue)
+                    .withLayer()
+                    .scaleX(endValue)
+                    .scaleY(endValue)
+                    .translationX(endTranslationXLeft)
+                    .setInterpolator(mFastOutSlowInInterpolator);
+            mLineRight.animate()
+                    .alpha(endValue)
+                    .withLayer()
+                    .scaleX(endValue)
+                    .scaleY(endValue)
+                    .translationX(endTranslationXRight)
+                    .setInterpolator(mFastOutSlowInInterpolator);
+
+            // Animate dots
+            mDots.performVisibilityAnimation(nowVisible);
+            mDividerVisible = nowVisible;
+        }
+    }
+
+    public void setInvisible() {
+        float endTranslationXLeft = mCenterX - mLineLeft.getRight();
+        float endTranslationXRight = mCenterX - mLineRight.getLeft();
+        mLineLeft.setAlpha(0.0f);
+        mLineLeft.setScaleX(0.0f);
+        mLineLeft.setScaleY(0.0f);
+        mLineLeft.setTranslationX(endTranslationXLeft);
+        mLineRight.setAlpha(0.0f);
+        mLineRight.setScaleX(0.0f);
+        mLineRight.setScaleY(0.0f);
+        mLineRight.setTranslationX(endTranslationXRight);
+        mDots.setInvisible();
+        resetExplanationText();
+
+        mDividerVisible = false;
+    }
+
+    public void collapse() {
+        if (mIsExpanded) {
+            setActualHeight(mCollapsedHeight);
+            mIsExpanded = false;
+        }
+        resetExplanationText();
+    }
+
+    public void animateExplanationText(boolean nowVisible) {
+        if (mIsExpanded) {
+            animateExplanationTextInternal(nowVisible);
+        }
+    }
+
+    private void resetExplanationText() {
+        mExplanationText.setTranslationY(0);
+        mExplanationText.setVisibility(INVISIBLE);
+        mExplanationText.setAlpha(0.0f);
+        mExplanationText.setScaleX(0.5f);
+        mExplanationText.setScaleY(0.5f);
+        mExplanationTextVisible = false;
+    }
+
+    public boolean isExpanded() {
+        return mIsExpanded;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b9f5ab2..cd985f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -143,8 +143,9 @@
         }
     }
 
-    public void animateNextTopPaddingChange() {
+    public void animateToFullShade() {
         mAnimateNextTopPaddingChange = true;
+        mNotificationStackScroller.goToFullShade();
         requestLayout();
     }
 
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 8c70517..dde2ebb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -20,6 +20,7 @@
 import android.animation.TimeAnimator;
 import android.animation.TimeAnimator.TimeListener;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -218,7 +219,7 @@
     };
 
     private float mVel, mAccel;
-    protected int mMaxPanelHeight = 0;
+    protected int mMaxPanelHeight = -1;
     private String mViewName;
     private float mInitialTouchY;
     private float mInitialTouchX;
@@ -617,7 +618,8 @@
 
         // Did one of our children change size?
         int newHeight = getMeasuredHeight();
-        if (newHeight != mMaxPanelHeight) {
+        if (newHeight > mMaxPanelHeight) {
+            // we only adapt the max height if it's bigger
             mMaxPanelHeight = newHeight;
             // If the user isn't actively poking us, let's rubberband to the content
             if (!mTracking && !mTimeAnimator.isStarted()
@@ -695,6 +697,12 @@
         mExpandedFraction = Math.min(1f, (fh == 0) ? 0 : h / fh);
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        mMaxPanelHeight = -1;
+    }
+
     protected void onHeightUpdated(float expandedHeight) {
         requestLayout();
     }
@@ -706,6 +714,7 @@
      * @return the default implementation simply returns the maximum height.
      */
     protected int getMaxPanelHeight() {
+        mMaxPanelHeight = Math.max(mMaxPanelHeight, getHeight());
         return mMaxPanelHeight;
     }
 
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 d3b5f96..4e1ffa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -106,6 +106,7 @@
 import com.android.systemui.statusbar.NotificationData.Entry;
 import com.android.systemui.statusbar.NotificationOverflowContainer;
 import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.SpeedBumpView;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -634,6 +635,10 @@
         mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
         mStackScroller.addView(mKeyguardIconOverflowContainer);
 
+        SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
+                        R.layout.status_bar_notification_speed_bump, mStackScroller, false);
+        mStackScroller.setSpeedBumpView(speedBump);
+
         mExpandedContents = mStackScroller;
 
         mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
@@ -1150,7 +1155,7 @@
         ArrayList<View> toRemove = new ArrayList<View>();
         for (int i=0; i< mStackScroller.getChildCount(); i++) {
             View child = mStackScroller.getChildAt(i);
-            if (!toShow.contains(child) && child != mKeyguardIconOverflowContainer) {
+            if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
                 toRemove.add(child);
             }
         }
@@ -2722,7 +2727,7 @@
         setBarState(StatusBarState.SHADE);
         if (mLeaveOpenOnKeyguardHide) {
             mLeaveOpenOnKeyguardHide = false;
-            mNotificationPanel.animateNextTopPaddingChange();
+            mNotificationPanel.animateToFullShade();
         } else {
             instantCollapseNotificationPanel();
         }
@@ -2894,7 +2899,7 @@
             mLeaveOpenOnKeyguardHide = true;
             showBouncer();
         } else {
-            mNotificationPanel.animateNextTopPaddingChange();
+            mNotificationPanel.animateToFullShade();
             setBarState(StatusBarState.SHADE_LOCKED);
             updateKeyguardState();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index deab757..b21e12c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -30,6 +30,7 @@
     private View mActivatedChild;
     private float mOverScrollTopAmount;
     private float mOverScrollBottomAmount;
+    private int mSpeedBumpIndex = -1;
 
     public int getScrollY() {
         return mScrollY;
@@ -86,4 +87,12 @@
     public float getOverScrollAmount(boolean top) {
         return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
     }
+
+    public int getSpeedBumpIndex() {
+        return mSpeedBumpIndex;
+    }
+
+    public void setSpeedBumpIndex(int speedBumpIndex) {
+        mSpeedBumpIndex = speedBumpIndex;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index fbb6695..f125c9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -39,6 +39,7 @@
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.SpeedBumpView;
 import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 
@@ -126,6 +127,8 @@
     private boolean mActivateNeedsAnimation;
     private boolean mIsExpanded = true;
     private boolean mChildrenUpdateRequested;
+    private SpeedBumpView mSpeedBumpView;
+    private boolean mIsExpansionChanging;
     private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
@@ -244,6 +247,22 @@
         requestChildrenUpdate();
     }
 
+    public void updateSpeedBumpIndex(int newIndex) {
+        int currentIndex = indexOfChild(mSpeedBumpView);
+
+        // If we are currently layouted before the new speed bump index, we have to decrease it.
+        boolean validIndex = newIndex > 0;
+        if (newIndex > getChildCount() - 1) {
+            validIndex = false;
+            newIndex = -1;
+        }
+        if (validIndex && currentIndex != newIndex) {
+            changeViewPosition(mSpeedBumpView, newIndex);
+        }
+        updateSpeedBump(validIndex);
+        mAmbientState.setSpeedBumpIndex(newIndex);
+    }
+
     public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
         mListener = listener;
     }
@@ -1044,6 +1063,10 @@
         mCurrentStackScrollState.removeViewStateForView(child);
         mStackScrollAlgorithm.notifyChildrenChanged(this);
         updateScrollStateForRemovedChild(child);
+        generateRemoveAnimation(child);
+    }
+
+    private void generateRemoveAnimation(View child) {
         if (mIsExpanded) {
 
             if (!mChildrenToAddAnimated.contains(child)) {
@@ -1120,7 +1143,9 @@
      */
     public void changeViewPosition(View child, int newIndex) {
         if (child != null && child.getParent() == this) {
-            // TODO: handle this
+            removeView(child);
+            addView(child, newIndex);
+            // TODO: handle events
         }
     }
 
@@ -1362,10 +1387,12 @@
     }
 
     public void onExpansionStarted() {
+        mIsExpansionChanging = true;
         mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
     }
 
     public void onExpansionStopped() {
+        mIsExpansionChanging = false;
         mStackScrollAlgorithm.onExpansionStopped();
     }
 
@@ -1374,6 +1401,7 @@
         mStackScrollAlgorithm.setIsExpanded(isExpanded);
         if (!isExpanded) {
             mOwnScrollY = 0;
+            mSpeedBumpView.collapse();
         }
     }
 
@@ -1432,6 +1460,34 @@
         }
     }
 
+    public void setSpeedBumpView(SpeedBumpView speedBumpView) {
+        mSpeedBumpView = speedBumpView;
+        addView(speedBumpView);
+    }
+
+    private void updateSpeedBump(boolean visible) {
+        int newVisibility = visible ? VISIBLE : GONE;
+        int oldVisibility = mSpeedBumpView.getVisibility();
+        if (newVisibility != oldVisibility) {
+            mSpeedBumpView.setVisibility(newVisibility);
+            if (visible) {
+                mSpeedBumpView.collapse();
+                // Make invisible to ensure that the appear animation is played.
+                mSpeedBumpView.setInvisible();
+                if (!mIsExpansionChanging) {
+                    generateAddAnimation(mSpeedBumpView);
+                }
+            } else {
+                mSpeedBumpView.performVisibilityAnimation(false);
+                generateRemoveAnimation(mSpeedBumpView);
+            }
+        }
+    }
+
+    public void goToFullShade() {
+        updateSpeedBump(true);
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 8fc26d8..011411c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -23,6 +23,7 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.SpeedBumpView;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -167,13 +168,50 @@
                         clipHeight,
                         (int) (newHeight - (previousNotificationStart - newYTranslation)));
 
-                previousNotificationStart = newYTranslation + child.getClipTopAmount();
-                previousNotificationEnd = newNotificationEnd;
-                previousNotificationIsSwiped = child.getTranslationX() != 0;
+                if (!child.isTransparent()) {
+                    // Only update the previous values if we are not transparent,
+                    // otherwise we would clip to a transparent view.
+                    previousNotificationStart = newYTranslation + child.getClipTopAmount();
+                    previousNotificationEnd = newNotificationEnd;
+                    previousNotificationIsSwiped = child.getTranslationX() != 0;
+                }
+
+                if(child instanceof SpeedBumpView) {
+                    performSpeedBumpAnimation(i, (SpeedBumpView) child, newNotificationEnd,
+                            newYTranslation);
+                }
             }
         }
     }
 
+    private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd,
+            float speedBumpStart) {
+        View nextChild = getNextChildNotGone(i);
+        if (nextChild != null) {
+            ViewState nextState = getViewStateForView(nextChild);
+            boolean startIsAboveNext = nextState.yTranslation > speedBumpStart;
+            speedBump.animateDivider(startIsAboveNext);
+
+            // handle expanded case
+            if (speedBump.isExpanded()) {
+                boolean endIsAboveNext = nextState.yTranslation > speedBumpEnd;
+                speedBump.animateExplanationText(endIsAboveNext);
+            }
+
+        }
+    }
+
+    private View getNextChildNotGone(int childIndex) {
+        int childCount = mHostView.getChildCount();
+        for (int i = childIndex + 1; i < childCount; i++) {
+            View child = mHostView.getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                return child;
+            }
+        }
+        return null;
+    }
+
     /**
      * Updates the shadow outline and the clipping for a view.
      *
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index e26747c..be20616 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -36,12 +36,14 @@
 import android.media.AudioService;
 import android.os.AsyncTask;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -49,6 +51,7 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 
@@ -56,6 +59,7 @@
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
+import com.google.android.util.AbstractMessageParser.MusicTrack;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -91,6 +95,10 @@
     final SparseArray<HashMap<String, Ops>> mUidOps
             = new SparseArray<HashMap<String, Ops>>();
 
+    private int mDeviceOwnerUid;
+    private final SparseIntArray mProfileOwnerUids = new SparseIntArray();
+    private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>();
+
     public final static class Ops extends SparseArray<Op> {
         public final String packageName;
         public final int uid;
@@ -548,6 +556,9 @@
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
         synchronized (this) {
+            if (isOpRestricted(uid, code)) {
+                return AppOpsManager.MODE_IGNORED;
+            }
             Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
             if (op == null) {
                 return AppOpsManager.opToDefaultMode(code);
@@ -631,6 +642,9 @@
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
+            if (isOpRestricted(uid, code)) {
+                return AppOpsManager.MODE_IGNORED;
+            }
             if (op.duration == -1) {
                 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
                         + " code " + code + " time=" + op.time + " duration=" + op.duration);
@@ -665,6 +679,9 @@
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
+            if (isOpRestricted(uid, code)) {
+                return AppOpsManager.MODE_IGNORED;
+            }
             final int switchCode = AppOpsManager.opToSwitch(code);
             final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
             if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
@@ -830,6 +847,23 @@
         return op;
     }
 
+    private boolean isOpRestricted(int uid, int code) {
+        int userHandle = UserHandle.getUserId(uid);
+        boolean[] opRestrictions = mOpRestrictions.get(userHandle);
+        if ((opRestrictions != null) && opRestrictions[code]) {
+            if (userHandle == UserHandle.USER_OWNER) {
+                if (uid != mDeviceOwnerUid) {
+                    return true;
+                }
+            } else {
+                if (uid != mProfileOwnerUids.get(userHandle, -1)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     void readState() {
         synchronized (mFile) {
             synchronized (this) {
@@ -1167,4 +1201,66 @@
         int mode;
         ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
     }
+
+    @Override
+    public void setDeviceOwner(String packageName) throws RemoteException {
+        checkSystemUid("setDeviceOwner");
+        try {
+            mDeviceOwnerUid = mContext.getPackageManager().getPackageUid(packageName,
+                    UserHandle.USER_OWNER);
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Could not find Device Owner UID");
+            mDeviceOwnerUid = -1;
+            throw new IllegalArgumentException("Could not find device owner package "
+                    + packageName);
+        }
+    }
+
+    @Override
+    public void setProfileOwner(String packageName, int userHandle) throws RemoteException {
+        checkSystemUid("setProfileOwner");
+        try {
+            int uid = mContext.getPackageManager().getPackageUid(packageName,
+                    userHandle);
+            mProfileOwnerUids.put(userHandle, uid);
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Could not find Profile Owner UID");
+            mProfileOwnerUids.put(userHandle, -1);
+            throw new IllegalArgumentException("Could not find profile owner package "
+                    + packageName);
+        }
+    }
+
+    @Override
+    public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException {
+        checkSystemUid("setUserRestrictions");
+        boolean[] opRestrictions = mOpRestrictions.get(userHandle);
+        if (opRestrictions == null) {
+            opRestrictions = new boolean[AppOpsManager._NUM_OP];
+            mOpRestrictions.put(userHandle, opRestrictions);
+        }
+        for (int i = 0; i < opRestrictions.length; ++i) {
+            String restriction = AppOpsManager.opToRestriction(i);
+            if (restriction != null) {
+                opRestrictions[i] = restrictions.getBoolean(restriction, false);
+            } else {
+                opRestrictions[i] = false;
+            }
+        }
+    }
+
+    @Override
+    public void removeUser(int userHandle) throws RemoteException {
+        checkSystemUid("removeUser");
+        mOpRestrictions.remove(userHandle);
+        mProfileOwnerUids.removeAt(mProfileOwnerUids.indexOfKey(userHandle));
+    }
+
+    private void checkSystemUid(String function) {
+        int uid = Binder.getCallingUid();
+        if (uid != Process.SYSTEM_UID) {
+            throw new SecurityException(function + " must by called by the system");
+        }
+    }
+
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 982dce0..2d0f6d1 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3216,6 +3216,7 @@
             // tell the network currently servicing this that it's no longer interested
             NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId);
             if (affectedNetwork != null) {
+                mNetworkForRequestId.remove(nri.request.requestId);
                 affectedNetwork.networkRequests.remove(nri.request.requestId);
                 if (VDBG) {
                     log(" Removing from current network " + affectedNetwork.name() + ", leaving " +
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bab5b9c..7abc75f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7087,50 +7087,7 @@
         rti.description = tr.lastDescription;
         rti.stackId = tr.stack.mStackId;
         rti.userId = tr.userId;
-
-        // Traverse upwards looking for any break between main task activities and
-        // utility activities.
-        final ArrayList<ActivityRecord> activities = tr.mActivities;
-        int activityNdx;
-        final int numActivities = activities.size();
-        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
-             ++activityNdx) {
-            final ActivityRecord r = activities.get(activityNdx);
-            if (r.intent != null &&
-                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
-                            != 0) {
-                break;
-            }
-        }
-        if (activityNdx > 0) {
-            // Traverse downwards starting below break looking for set label, icon.
-            // Note that if there are activities in the task but none of them set the
-            // recent activity values, then we do not fall back to the last set
-            // values in the TaskRecord.
-            rti.activityValues = new ActivityManager.RecentsActivityValues();
-            for (--activityNdx; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.activityValues != null) {
-                    if (rti.activityValues.label == null) {
-                        rti.activityValues.label = r.activityValues.label;
-                        tr.lastActivityValues.label = r.activityValues.label;
-                    }
-                    if (rti.activityValues.icon == null) {
-                        rti.activityValues.icon = r.activityValues.icon;
-                        tr.lastActivityValues.icon = r.activityValues.icon;
-                    }
-                    if (rti.activityValues.colorPrimary == 0) {
-                        rti.activityValues.colorPrimary = r.activityValues.colorPrimary;
-                        tr.lastActivityValues.colorPrimary = r.activityValues.colorPrimary;
-                    }
-                }
-            }
-        } else {
-            // If there are no activity records in this task, then we use the last
-            // resolved values
-            rti.activityValues =
-                    new ActivityManager.RecentsActivityValues(tr.lastActivityValues);
-        }
+        rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
         return rti;
     }
 
@@ -7261,11 +7218,12 @@
     }
 
     @Override
-    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues rav) {
+    public void setTaskDescription(IBinder token, ActivityManager.TaskDescription td) {
         synchronized (this) {
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.activityValues = rav;
+                r.taskDescription = td;
+                r.task.updateTaskDescription();
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 9582ac7..dbe2ca1 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -149,7 +149,7 @@
     boolean mStartingWindowShown = false;
     ActivityContainer mInitialActivityContainer;
 
-    ActivityManager.RecentsActivityValues activityValues; // the recents information for this activity
+    ActivityManager.TaskDescription taskDescription; // the recents information for this activity
 
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 908bfbd..249422b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -623,8 +623,8 @@
         pw.println("  --charged: only output data since last charged.");
         pw.println("  --reset: reset the stats, clearing all current data.");
         pw.println("  --write: force write current collected stats to disk.");
-        pw.println("  --enable: enable an option: full-wake-history.");
-        pw.println("  --disable: disable an option: full-wake-history.");
+        pw.println("  --enable: enable an option: full-wake-history, no-auto-reset.");
+        pw.println("  --disable: disable an option: full-wake-history, no-auto-reset.");
         pw.println("  -h: print this help text.");
         pw.println("  <package.name>: optional name of package to filter output by.");
     }
@@ -640,6 +640,10 @@
             synchronized (mStats) {
                 mStats.setRecordAllWakeLocksLocked(enable);
             }
+        } else if ("no-auto-reset".equals(args[i])) {
+            synchronized (mStats) {
+                mStats.setNoAutoReset(enable);
+            }
         } else {
             pw.println("Unknown enable/disable option: " + args[i]);
             dumpHelp(pw);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index be884e7..6d66b29 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -58,8 +58,8 @@
 
     // This represents the last resolved activity values for this task
     // NOTE: This value needs to be persisted with each task
-    ActivityManager.RecentsActivityValues lastActivityValues =
-            new ActivityManager.RecentsActivityValues();
+    ActivityManager.TaskDescription lastTaskDescription =
+            new ActivityManager.TaskDescription();
 
     /** List of all activities in the task arranged in history order */
     final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
@@ -486,6 +486,48 @@
         return null;
     }
 
+    /** Updates the last task description values. */
+    void updateTaskDescription() {
+        // Traverse upwards looking for any break between main task activities and
+        // utility activities.
+        int activityNdx;
+        final int numActivities = mActivities.size();
+        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
+             ++activityNdx) {
+            final ActivityRecord r = mActivities.get(activityNdx);
+            if (r.intent != null &&
+                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
+                            != 0) {
+                break;
+            }
+        }
+        if (activityNdx > 0) {
+            // Traverse downwards starting below break looking for set label, icon.
+            // Note that if there are activities in the task but none of them set the
+            // recent activity values, then we do not fall back to the last set
+            // values in the TaskRecord.
+            String label = null;
+            Bitmap icon = null;
+            int colorPrimary = 0;
+            for (--activityNdx; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = mActivities.get(activityNdx);
+                if (r.taskDescription != null) {
+                    if (label == null) {
+                        label = r.taskDescription.getLabel();
+                    }
+                    if (icon == null) {
+                        icon = r.taskDescription.getIcon();
+                    }
+                    if (colorPrimary == 0) {
+                        colorPrimary = r.taskDescription.getPrimaryColor();
+
+                    }
+                }
+            }
+            lastTaskDescription = new ActivityManager.TaskDescription(label, icon, colorPrimary);
+        }
+    }
+
     void dump(PrintWriter pw, String prefix) {
         if (numActivities != 0 || rootWasReset || userId != 0 || numFullscreen != 0) {
             pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 3884ab0..096ab66 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -74,6 +74,14 @@
         mIsStarted = false;
         mIsRunning = false;
         mLP = new LinkProperties();
+
+        // If this is a runtime restart, it's possible that clatd is already
+        // running, but we don't know about it. If so, stop it.
+        try {
+            if (mNMService.isClatdStarted()) {
+                mNMService.stopClatd();
+            }
+        } catch(RemoteException e) {}  // Well, we tried.
     }
 
     /**
@@ -198,13 +206,13 @@
                 NetworkUtils.resetConnections(
                     CLAT_INTERFACE_NAME,
                     NetworkUtils.RESET_IPV4_ADDRESSES);
+                mBaseLP.removeStackedLink(mLP);
+                updateConnectivityService();
             }
             Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
                    " removed, mIsRunning = " + mIsRunning + " -> false");
             mIsRunning = false;
-            mBaseLP.removeStackedLink(mLP);
             mLP.clear();
-            updateConnectivityService();
             Slog.i(TAG, "mLP = " + mLP);
         }
     }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 60212bf..131d05b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -40,6 +40,7 @@
 import android.os.IUserManager;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.AtomicFile;
@@ -50,6 +51,7 @@
 import android.util.TimeUtils;
 import android.util.Xml;
 
+import com.android.internal.app.IAppOpsService;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
@@ -162,6 +164,8 @@
     private int mNextSerialNumber;
     private int mUserVersion = 0;
 
+    private IAppOpsService mAppOpsService;
+
     private static UserManagerService sInstance;
 
     public static UserManagerService getInstance() {
@@ -236,6 +240,15 @@
     void systemReady() {
         mUserPackageMonitor.register(mContext, null, UserHandle.ALL, false);
         userForeground(UserHandle.USER_OWNER);
+        mAppOpsService = IAppOpsService.Stub.asInterface(
+                ServiceManager.getService(Context.APP_OPS_SERVICE));
+        for (int i = 0; i < mUserIds.length; ++i) {
+            try {
+                mAppOpsService.setUserRestrictions(mUserRestrictions.get(mUserIds[i]), mUserIds[i]);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
+            }
+        }
     }
 
     @Override
@@ -482,6 +495,14 @@
         synchronized (mPackagesLock) {
             mUserRestrictions.get(userId).clear();
             mUserRestrictions.get(userId).putAll(restrictions);
+            long token = Binder.clearCallingIdentity();
+            try {
+                mAppOpsService.setUserRestrictions(mUserRestrictions.get(userId), userId);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
             writeUserLocked(mUsers.get(userId));
         }
     }
@@ -1116,6 +1137,11 @@
                 return false;
             }
             mRemovingUserIds.put(userHandle, true);
+            try {
+                mAppOpsService.removeUser(userHandle);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);
+            }
             // Set this to a partially created user, so that the user will be purged
             // on next startup, in case the runtime stops now before stopping and
             // removing the user completely.
@@ -1125,6 +1151,14 @@
             user.flags |= UserInfo.FLAG_DISABLED;
             writeUserLocked(user);
         }
+
+        if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+                && user.isManagedProfile()) {
+            // Send broadcast to notify system that the user removed was a
+            // managed user.
+            sendProfileRemovedBroadcast(user.profileGroupId, user.id);
+        }
+
         if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
         int res;
         try {
@@ -1151,7 +1185,6 @@
         // wiping the user's system directory and removing from the user list
         long ident = Binder.clearCallingIdentity();
         try {
-            final boolean isManaged = getUserInfo(userHandle).isManagedProfile();
             Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
             addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
             mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,
@@ -1172,11 +1205,6 @@
                                             removeUserStateLocked(userHandle);
                                         }
                                     }
-                                    // Send broadcast to notify system that the user removed was a
-                                    // managed user.
-                                    if (isManaged) {
-                                        sendProfileRemovedBroadcast(userHandle);
-                                    }
                                 }
                             }.start();
                         }
@@ -1228,11 +1256,11 @@
         parent.delete();
     }
 
-    private void sendProfileRemovedBroadcast(int userHandle) {
+    private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) {
         Intent managedProfileIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-        managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(userHandle));
-        // Note: This makes an assumption that the parent owner is user 0.
-        mContext.sendBroadcastAsUser(managedProfileIntent, UserHandle.OWNER, null);
+        managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(removedUserId));
+        mContext.sendBroadcastAsUser(managedProfileIntent, new UserHandle(parentUserId), null);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/task/StateChangedListener.java b/services/core/java/com/android/server/task/StateChangedListener.java
index a87bf95..db2d4ee 100644
--- a/services/core/java/com/android/server/task/StateChangedListener.java
+++ b/services/core/java/com/android/server/task/StateChangedListener.java
@@ -19,9 +19,9 @@
 import com.android.server.task.controllers.TaskStatus;
 
 /**
- * Interface through which a {@link StateController} informs the
- * {@link com.android.server.task.TaskManagerService} that there are some tasks potentially ready
- * to be run.
+ * Interface through which a {@link com.android.server.task.controllers.StateController} informs
+ * the {@link com.android.server.task.TaskManagerService} that there are some tasks potentially
+ * ready to be run.
  */
 public interface StateChangedListener {
     /**
diff --git a/services/core/java/com/android/server/task/TaskCompletedListener.java b/services/core/java/com/android/server/task/TaskCompletedListener.java
new file mode 100644
index 0000000..0210442
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskCompletedListener.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task;
+
+/**
+ * Used for communication between {@link com.android.server.task.TaskServiceContext} and the
+ * {@link com.android.server.task.TaskManagerService}.
+ */
+public interface TaskCompletedListener {
+
+    /**
+     * Callback for when a task is completed.
+     * @param needsReschedule Whether the implementing class should reschedule this task.
+     */
+    public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule);
+
+    /**
+     * Callback for when the implementing class needs to clean up the
+     * {@link com.android.server.task.TaskServiceContext}. The scheduler can get this callback
+     * several times if the TaskServiceContext got into a bad state (for e.g. the client crashed
+     * and it needs to clean up).
+     */
+    public void onAllTasksCompleted(int serviceToken);
+}
diff --git a/services/core/java/com/android/server/task/TaskList.java b/services/core/java/com/android/server/task/TaskList.java
deleted file mode 100644
index d2b8440..0000000
--- a/services/core/java/com/android/server/task/TaskList.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.task;
-
-import android.content.ComponentName;
-import android.content.Task;
-
-import com.android.server.task.controllers.TaskStatus;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Maintain a list of classes, and accessor methods/logic for these tasks.
- * This class offers the following functionality:
- *     - When a task is added, it will determine if the task requirements have changed (update) and
- *       whether the controllers need to be updated.
- *     - Persists Tasks, figures out when to to rewrite the Task to disk.
- *     - Is threadsafe.
- *     - Handles rescheduling of tasks.
- *       - When a periodic task is executed and must be re-added.
- *       - When a task fails and the client requests that it be retried with backoff.
- */
-public class TaskList {
-
-    final List<TaskStatus> mTasks;
-
-    TaskList() {
-        mTasks = intialiseTaskMapFromDisk();
-    }
-
-    /**
-     * Add a task to the master list, persisting it if necessary.
-     * @param task Task to add.
-     * @param persistable true if the TaskQueue should persist this task to the disk.
-     * @return true if this operation was successful. If false, this task was neither added nor
-     * persisted.
-     */
-    // TODO: implement this when i decide whether i want to key by TaskStatus
-    public boolean add(Task task, boolean persistable) {
-        return true;
-    }
-
-    /**
-     * Remove the provided task. Will also delete the task if it was persisted. Note that this
-     * function does not return the validity of the operation, as we assume a delete will always
-     * succeed.
-     * @param task Task to remove.
-     */
-    public void remove(Task task) {
-
-    }
-
-    /**
-     *
-     * @return
-     */
-    // TODO: Implement this.
-    private List<TaskStatus> intialiseTaskMapFromDisk() {
-        return new ArrayList<TaskStatus>();
-    }
-}
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
index 5df4b2a..6d208ff 100644
--- a/services/core/java/com/android/server/task/TaskManagerService.java
+++ b/services/core/java/com/android/server/task/TaskManagerService.java
@@ -17,16 +17,15 @@
 package com.android.server.task;
 
 import android.content.Context;
+import android.content.Task;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.server.task.controllers.TaskStatus;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Responsible for taking tasks representing work to be performed by a client app, and determining
  * based on the criteria specified when that task should be run against the client application's
@@ -34,25 +33,29 @@
  * @hide
  */
 public class TaskManagerService extends com.android.server.SystemService
-        implements StateChangedListener {
+        implements StateChangedListener, TaskCompletedListener {
+    static final String TAG = "TaskManager";
 
     /** Master list of tasks. */
-    private final TaskList mTaskList;
+    private final TaskStore mTasks;
+
+    /** Check the pending queue and start any tasks. */
+    static final int MSG_RUN_PENDING = 0;
+    /** Initiate the stop task flow. */
+    static final int MSG_STOP_TASK = 1;
+    /** */
+    static final int MSG_CHECK_TASKS = 2;
 
     /**
      * Track Services that have currently active or pending tasks. The index is provided by
      * {@link TaskStatus#getServiceToken()}
      */
-    private final SparseArray<TaskServiceContext> mPendingTaskServices =
+    private final SparseArray<TaskServiceContext> mActiveServices =
             new SparseArray<TaskServiceContext>();
 
     private final TaskHandler mHandler;
 
     private class TaskHandler extends Handler {
-        /** Check the pending queue and start any tasks. */
-        static final int MSG_RUN_PENDING = 0;
-        /** Initiate the stop task flow. */
-        static final int MSG_STOP_TASK = 1;
 
         public TaskHandler(Looper looper) {
             super(looper);
@@ -67,21 +70,42 @@
                 case MSG_STOP_TASK:
 
                     break;
+                case MSG_CHECK_TASKS:
+                    checkTasks();
+                    break;
             }
         }
 
         /**
-         * Helper to post a message to this handler that will run through the pending queue and
-         * start any tasks it can.
+         * Called when we need to run through the list of all tasks and start/stop executing one or
+         * more of them.
          */
-        void sendRunPendingTasksMessage() {
-            Message m = Message.obtain(this, MSG_RUN_PENDING);
-            m.sendToTarget();
+        private void checkTasks() {
+            synchronized (mTasks) {
+                final SparseArray<TaskStatus> tasks = mTasks.getTasks();
+                for (int i = 0; i < tasks.size(); i++) {
+                    TaskStatus ts = tasks.valueAt(i);
+                    if (ts.isReady() && ! isCurrentlyActive(ts)) {
+                        assignTaskToServiceContext(ts);
+                    }
+                }
+            }
         }
+    }
 
-        void sendOnStopMessage(TaskStatus taskStatus) {
-
-        }
+    /**
+     * Entry point from client to schedule the provided task.
+     * This will add the task to the
+     * @param task Task object containing execution parameters
+     * @param userId The id of the user this task is for.
+     * @param uId The package identifier of the application this task is for.
+     * @param canPersistTask Whether or not the client has the appropriate permissions for persisting
+     *                    of this task.
+     * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
+     */
+    public int schedule(Task task, int userId, int uId, boolean canPersistTask) {
+        TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask);
+        return 0;
     }
 
     /**
@@ -95,7 +119,7 @@
      */
     public TaskManagerService(Context context) {
         super(context);
-        mTaskList = new TaskList();
+        mTasks = new TaskStore(context);
         mHandler = new TaskHandler(context.getMainLooper());
     }
 
@@ -104,20 +128,18 @@
 
     }
 
+    // StateChangedListener implementations.
+
     /**
-     * Offboard work to our handler thread as quickly as possible, b/c this call is probably being
+     * Off-board work to our handler thread as quickly as possible, b/c this call is probably being
      * made on the main thread.
-     * @param taskStatus The state of the task which has changed.
+     * For now this takes the task and if it's ready to run it will run it. In future we might not
+     * provide the task, so that the StateChangedListener has to run through its list of tasks to
+     * see which are ready. This will further decouple the controllers from the execution logic.
      */
     @Override
     public void onTaskStateChanged(TaskStatus taskStatus) {
-        if (taskStatus.isReady()) {
-
-        } else {
-            if (mPendingTaskServices.get(taskStatus.getServiceToken()) != null) {
-                // The task is either pending or being executed, which we have to cancel.
-            }
-        }
+        postCheckTasksMessage();
 
     }
 
@@ -125,4 +147,60 @@
     public void onTaskDeadlineExpired(TaskStatus taskStatus) {
 
     }
+
+    // TaskCompletedListener implementations.
+
+    /**
+     * A task just finished executing. We fetch the
+     * {@link com.android.server.task.controllers.TaskStatus} from the store and depending on
+     * whether we want to reschedule we readd it to the controllers.
+     * @param serviceToken key for the service context in {@link #mActiveServices}.
+     * @param taskId Id of the task that is complete.
+     * @param needsReschedule Whether the implementing class should reschedule this task.
+     */
+    @Override
+    public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule) {
+        final TaskServiceContext serviceContext = mActiveServices.get(serviceToken);
+        if (serviceContext == null) {
+            Log.e(TAG, "Task completed for invalid service context; " + serviceToken);
+            return;
+        }
+
+    }
+
+    @Override
+    public void onAllTasksCompleted(int serviceToken) {
+        
+    }
+
+    private void assignTaskToServiceContext(TaskStatus ts) {
+        TaskServiceContext serviceContext =
+                mActiveServices.get(ts.getServiceToken());
+        if (serviceContext == null) {
+            serviceContext = new TaskServiceContext(this, mHandler.getLooper(), ts);
+            mActiveServices.put(ts.getServiceToken(), serviceContext);
+        }
+        serviceContext.addPendingTask(ts);
+    }
+
+    /**
+     * @param ts TaskStatus we are querying against.
+     * @return Whether or not the task represented by the status object is currently being run or
+     * is pending.
+     */
+    private boolean isCurrentlyActive(TaskStatus ts) {
+        TaskServiceContext serviceContext = mActiveServices.get(ts.getServiceToken());
+        if (serviceContext == null) {
+            return false;
+        }
+        return serviceContext.hasTaskPending(ts);
+    }
+
+    /**
+     * Post a message to {@link #mHandler} to run through the list of tasks and start/stop any that
+     * are eligible.
+     */
+    private void postCheckTasksMessage() {
+        mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
+    }
 }
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/task/TaskServiceContext.java
index 65c6fa5..b51cbb3 100644
--- a/services/core/java/com/android/server/task/TaskServiceContext.java
+++ b/services/core/java/com/android/server/task/TaskServiceContext.java
@@ -16,79 +16,500 @@
 
 package com.android.server.task;
 
+import android.app.ActivityManager;
 import android.app.task.ITaskCallback;
 import android.app.task.ITaskService;
+import android.app.task.TaskParams;
 import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
 import android.content.ServiceConnection;
-import android.content.Task;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.server.task.controllers.TaskStatus;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 /**
  * Maintains information required to bind to a {@link android.app.task.TaskService}. This binding
- * can then be reused to start concurrent tasks on the TaskService. Information here is unique
- * within this service.
+ * is reused to start concurrent tasks on the TaskService. Information here is unique
+ * to the service.
  * Functionality provided by this class:
  *     - Managages wakelock for the service.
  *     - Sends onStartTask() and onStopTask() messages to client app, and handles callbacks.
  *     -
  */
 public class TaskServiceContext extends ITaskCallback.Stub implements ServiceConnection {
+    private static final String TAG = "TaskServiceContext";
+    /** Define the maximum # of tasks allowed to run on a service at once. */
+    private static final int defaultMaxActiveTasksPerService =
+            ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
+    /** Amount of time a task is allowed to execute for before being considered timed-out. */
+    private static final long EXECUTING_TIMESLICE_MILLIS = 5 * 60 * 1000;
+    /** Amount of time the TaskManager will wait for a response from an app for a message. */
+    private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
+    /** String prefix for all wakelock names. */
+    private static final String TM_WAKELOCK_PREFIX = "*task*/";
 
+    private static final String[] VERB_STRINGS = {
+            "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_PENDING"
+    };
+
+    // States that a task occupies while interacting with the client.
+    private static final int VERB_STARTING = 0;
+    private static final int VERB_EXECUTING = 1;
+    private static final int VERB_STOPPING = 2;
+    private static final int VERB_PENDING = 3;
+
+    // Messages that result from interactions with the client service.
+    /** System timed out waiting for a response. */
+    private static final int MSG_TIMEOUT = 0;
+    /** Received a callback from client. */
+    private static final int MSG_CALLBACK = 1;
+    /** Run through list and start any ready tasks.*/
+    private static final int MSG_CHECK_PENDING = 2;
+    /** Cancel an active task. */
+    private static final int MSG_CANCEL = 3;
+    /** Add a pending task. */
+    private static final int MSG_ADD_PENDING = 4;
+    /** Client crashed, so we need to wind things down. */
+    private static final int MSG_SHUTDOWN = 5;
+
+    /** Used to identify this task service context when communicating with the TaskManager. */
+    final int token;
     final ComponentName component;
-    int uid;
+    final int userId;
     ITaskService service;
+    private final Handler mCallbackHandler;
+    /** Tasks that haven't been sent to the client for execution yet. */
+    private final SparseArray<ActiveTask> mPending;
+    /** Used for service binding, etc. */
+    private final Context mContext;
+    /** Make callbacks to {@link TaskManagerService} to inform on task completion status. */
+    final private TaskCompletedListener mCompletedListener;
+    private final PowerManager.WakeLock mWakeLock;
 
     /** Whether this service is actively bound. */
     boolean mBound;
 
-    TaskServiceContext(Task task) {
-        this.component = task.getService();
-    }
-
-    public void stopTask() {
-
-    }
-
-    public void startTask(Task task) {
-
+    TaskServiceContext(TaskManagerService taskManager, Looper looper, TaskStatus taskStatus) {
+        mContext = taskManager.getContext();
+        this.component = taskStatus.getServiceComponent();
+        this.token = taskStatus.getServiceToken();
+        this.userId = taskStatus.getUserId();
+        mCallbackHandler = new TaskServiceHandler(looper);
+        mPending = new SparseArray<ActiveTask>();
+        mCompletedListener = taskManager;
+        final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                TM_WAKELOCK_PREFIX + component.getPackageName());
+        mWakeLock.setWorkSource(new WorkSource(taskStatus.getUid()));
+        mWakeLock.setReferenceCounted(false);
     }
 
     @Override
     public void taskFinished(int taskId, boolean reschedule) {
-
+        mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+                .sendToTarget();
     }
 
     @Override
-    public void acknowledgeStopMessage(int taskId) {
-
+    public void acknowledgeStopMessage(int taskId, boolean reschedule) {
+        mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+                .sendToTarget();
     }
 
     @Override
-    public void acknowledgeStartMessage(int taskId) {
+    public void acknowledgeStartMessage(int taskId, boolean ongoing) {
+        mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, ongoing ? 1 : 0).sendToTarget();
+    }
 
+    /**
+     * Queue up this task to run on the client. This will execute the task as quickly as possible.
+     * @param ts Status of the task to run.
+     */
+    public void addPendingTask(TaskStatus ts) {
+        final TaskParams params = new TaskParams(ts.getTaskId(), ts.getExtras(), this);
+        final ActiveTask newTask = new ActiveTask(params, VERB_PENDING);
+        mCallbackHandler.obtainMessage(MSG_ADD_PENDING, newTask).sendToTarget();
+        if (!mBound) {
+            Intent intent = new Intent().setComponent(component);
+            boolean binding = mContext.bindServiceAsUser(intent, this,
+                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
+                    new UserHandle(userId));
+            if (!binding) {
+                Log.e(TAG, component.getShortClassName() + " unavailable.");
+                cancelPendingTask(ts);
+            }
+        }
+    }
+
+    /**
+     * Called externally when a task that was scheduled for execution should be cancelled.
+     * @param ts The status of the task to cancel.
+     */
+    public void cancelPendingTask(TaskStatus ts) {
+        mCallbackHandler.obtainMessage(MSG_CANCEL, ts.getTaskId(), -1 /* arg2 */)
+                .sendToTarget();
+    }
+
+    /**
+     * MSG_TIMEOUT is sent with the {@link com.android.server.task.TaskServiceContext.ActiveTask}
+     * set in the {@link Message#obj} field. This makes it easier to remove timeouts for a given
+     * ActiveTask.
+     * @param op Operation that is taking place.
+     */
+    private void scheduleOpTimeOut(ActiveTask op) {
+        mCallbackHandler.removeMessages(MSG_TIMEOUT, op);
+
+        final long timeoutMillis = (op.verb == VERB_EXECUTING) ?
+                EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
+        if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+            Slog.d(TAG, "Scheduling time out for '" + component.getShortClassName() + "' tId: " +
+                    op.params.getTaskId() + ", in " + (timeoutMillis / 1000) + " s");
+        }
+        Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT, op);
+        mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
     }
 
     /**
      * @return true if this task is pending or active within this context.
      */
     public boolean hasTaskPending(TaskStatus taskStatus) {
-        return true;
+        synchronized (mPending) {
+            return mPending.get(taskStatus.getTaskId()) != null;
+        }
     }
 
     public boolean isBound() {
         return mBound;
     }
 
+    /**
+     * We acquire/release the wakelock on onServiceConnected/unbindService. This mirrors the work
+     * we intend to send to the client - we stop sending work when the service is unbound so until
+     * then we keep the wakelock.
+     * @param name The concrete component name of the service that has
+     * been connected.
+     * @param service The IBinder of the Service's communication channel,
+     */
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
-
         mBound = true;
+        this.service = ITaskService.Stub.asInterface(service);
+        // Remove all timeouts. We've just connected to the client so there are no other
+        // MSG_TIMEOUTs at this point.
+        mCallbackHandler.removeMessages(MSG_TIMEOUT);
+        mWakeLock.acquire();
+        mCallbackHandler.obtainMessage(MSG_CHECK_PENDING).sendToTarget();
     }
 
+    /**
+     * When the client service crashes we can have a couple tasks executing, in various stages of
+     * undress. We'll cancel all of them and request that they be rescheduled.
+     * @param name The concrete component name of the service whose
+     */
     @Override
     public void onServiceDisconnected(ComponentName name) {
-        mBound = false;
+        // Service disconnected... probably client crashed.
+        startShutdown();
+    }
+
+    /**
+     * We don't just shutdown outright - we make sure the scheduler isn't going to send us any more
+     * tasks, then we do the shutdown.
+     */
+    private void startShutdown() {
+        mCompletedListener.onAllTasksCompleted(token);
+        mCallbackHandler.obtainMessage(MSG_SHUTDOWN).sendToTarget();
+    }
+
+    /** Tracks a task across its various state changes. */
+    private static class ActiveTask {
+        final TaskParams params;
+        int verb;
+        AtomicBoolean cancelled = new AtomicBoolean();
+
+        ActiveTask(TaskParams params, int verb) {
+            this.params = params;
+            this.verb = verb;
+        }
+
+        @Override
+        public String toString() {
+            return params.getTaskId() + " " + VERB_STRINGS[verb];
+        }
+    }
+
+    /**
+     * Handles the lifecycle of the TaskService binding/callbacks, etc. The convention within this
+     * class is to append 'H' to each function name that can only be called on this handler. This
+     * isn't strictly necessary because all of these functions are private, but helps clarity.
+     */
+    private class TaskServiceHandler extends Handler {
+        TaskServiceHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_ADD_PENDING:
+                    if (message.obj != null) {
+                        ActiveTask pendingTask = (ActiveTask) message.obj;
+                        mPending.put(pendingTask.params.getTaskId(), pendingTask);
+                    }
+                    // fall through.
+                case MSG_CHECK_PENDING:
+                    checkPendingTasksH();
+                    break;
+                case MSG_CALLBACK:
+                    ActiveTask receivedCallback = mPending.get(message.arg1);
+                    removeMessages(MSG_TIMEOUT, receivedCallback);
+
+                    if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+                        Log.d(TAG, "MSG_CALLBACK of : " + receivedCallback);
+                    }
+
+                    if (receivedCallback.verb == VERB_STARTING) {
+                        final boolean workOngoing = message.arg2 == 1;
+                        handleStartedH(receivedCallback, workOngoing);
+                    } else if (receivedCallback.verb == VERB_EXECUTING ||
+                            receivedCallback.verb == VERB_STOPPING) {
+                        final boolean reschedule = message.arg2 == 1;
+                        handleFinishedH(receivedCallback, reschedule);
+                    } else {
+                        if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+                            Log.d(TAG, "Unrecognised callback: " + receivedCallback);
+                        }
+                    }
+                    break;
+                case MSG_CANCEL:
+                    ActiveTask cancelled = mPending.get(message.arg1);
+                    handleCancelH(cancelled);
+                    break;
+                case MSG_TIMEOUT:
+                    // Timeout msgs have the ActiveTask ref so we can remove them easily.
+                    handleOpTimeoutH((ActiveTask) message.obj);
+                    break;
+                case MSG_SHUTDOWN:
+                    handleShutdownH();
+                    break;
+                default:
+                    Log.e(TAG, "Unrecognised message: " + message);
+            }
+        }
+
+        /**
+         * State behaviours.
+         * VERB_STARTING   -> Successful start, change task to VERB_EXECUTING and post timeout.
+         *     _PENDING    -> Error
+         *     _EXECUTING  -> Error
+         *     _STOPPING   -> Error
+         */
+        private void handleStartedH(ActiveTask started, boolean workOngoing) {
+            switch (started.verb) {
+                case VERB_STARTING:
+                    started.verb = VERB_EXECUTING;
+                    if (!workOngoing) {
+                        // Task is finished already so fast-forward to handleFinished.
+                        handleFinishedH(started, false);
+                        return;
+                    } else if (started.cancelled.get()) {
+                        // Cancelled *while* waiting for acknowledgeStartMessage from client.
+                        handleCancelH(started);
+                        return;
+                    } else {
+                        scheduleOpTimeOut(started);
+                    }
+                    break;
+                default:
+                    Log.e(TAG, "Handling started task but task wasn't starting! " + started);
+                    return;
+            }
+        }
+
+        /**
+         * VERB_EXECUTING  -> Client called taskFinished(), clean up and notify done.
+         *     _STOPPING   -> Successful finish, clean up and notify done.
+         *     _STARTING   -> Error
+         *     _PENDING    -> Error
+         */
+        private void handleFinishedH(ActiveTask executedTask, boolean reschedule) {
+            switch (executedTask.verb) {
+                case VERB_EXECUTING:
+                case VERB_STOPPING:
+                    closeAndCleanupTaskH(executedTask, reschedule);
+                    break;
+                default:
+                    Log.e(TAG, "Got an execution complete message for a task that wasn't being" +
+                            "executed. " + executedTask);
+            }
+        }
+
+        /**
+         * A task can be in various states when a cancel request comes in:
+         * VERB_PENDING    -> Remove from queue.
+         *     _STARTING   -> Mark as cancelled and wait for {@link #acknowledgeStartMessage(int)}.
+         *     _EXECUTING  -> call {@link #sendStopMessageH}}.
+         *     _ENDING     -> No point in doing anything here, so we ignore.
+         */
+        private void handleCancelH(ActiveTask cancelledTask) {
+            switch (cancelledTask.verb) {
+                case VERB_PENDING:
+                    mPending.remove(cancelledTask.params.getTaskId());
+                    break;
+                case VERB_STARTING:
+                    cancelledTask.cancelled.set(true);
+                    break;
+                case VERB_EXECUTING:
+                    cancelledTask.verb = VERB_STOPPING;
+                    sendStopMessageH(cancelledTask);
+                    break;
+                case VERB_STOPPING:
+                    // Nada.
+                    break;
+                default:
+                    Log.e(TAG, "Cancelling a task without a valid verb: " + cancelledTask);
+                    break;
+            }
+        }
+
+        /**
+         * This TaskServiceContext is shutting down. Remove all the tasks from the pending queue
+         * and reschedule them as if they had failed.
+         * Before posting this message, caller must invoke
+         * {@link com.android.server.task.TaskCompletedListener#onAllTasksCompleted(int)}.
+         */
+        private void handleShutdownH() {
+            for (int i = 0; i < mPending.size(); i++) {
+                ActiveTask at = mPending.valueAt(i);
+                closeAndCleanupTaskH(at, true /* needsReschedule */);
+            }
+            mWakeLock.release();
+            mContext.unbindService(TaskServiceContext.this);
+            service = null;
+            mBound = false;
+        }
+
+        /**
+         * MSG_TIMEOUT gets processed here.
+         * @param timedOutTask The task that timed out.
+         */
+        private void handleOpTimeoutH(ActiveTask timedOutTask) {
+            if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+                Log.d(TAG, "MSG_TIMEOUT of " + component.getShortClassName() + " : "
+                        + timedOutTask.params.getTaskId());
+            }
+
+            final int taskId = timedOutTask.params.getTaskId();
+            switch (timedOutTask.verb) {
+                case VERB_STARTING:
+                    // Client unresponsive - wedged or failed to respond in time. We don't really
+                    // know what happened so let's log it and notify the TaskManager
+                    // FINISHED/NO-RETRY.
+                    Log.e(TAG, "No response from client for onStartTask '" +
+                            component.getShortClassName() + "' tId: " + taskId);
+                    closeAndCleanupTaskH(timedOutTask, false /* needsReschedule */);
+                    break;
+                case VERB_STOPPING:
+                    // At least we got somewhere, so fail but ask the TaskManager to reschedule.
+                    Log.e(TAG, "No response from client for onStopTask, '" +
+                            component.getShortClassName() + "' tId: " + taskId);
+                    closeAndCleanupTaskH(timedOutTask, true /* needsReschedule */);
+                    break;
+                case VERB_EXECUTING:
+                    // Not an error - client ran out of time.
+                    Log.i(TAG, "Client timed out while executing (no taskFinished received)." +
+                            " Reporting failure and asking for reschedule. "  +
+                            component.getShortClassName() + "' tId: " + taskId);
+                    sendStopMessageH(timedOutTask);
+                    break;
+                default:
+                    Log.e(TAG, "Handling timeout for an unknown active task state: "
+                            + timedOutTask);
+                    return;
+            }
+        }
+
+        /**
+         * Called on the handler thread. Checks the state of the pending queue and starts the task
+         * if it can. The task only starts if there is capacity on the service.
+         */
+        private void checkPendingTasksH() {
+            if (!mBound) {
+                return;
+            }
+            for (int i = 0; i < mPending.size() && i < defaultMaxActiveTasksPerService; i++) {
+                ActiveTask at = mPending.valueAt(i);
+                if (at.verb != VERB_PENDING) {
+                    continue;
+                }
+                sendStartMessageH(at);
+            }
+        }
+
+        /**
+         * Already running, need to stop. Rund on handler.
+         * @param stoppingTask Task we are sending onStopMessage for. This task will be moved from
+         *                     VERB_EXECUTING -> VERB_STOPPING.
+         */
+        private void sendStopMessageH(ActiveTask stoppingTask) {
+            mCallbackHandler.removeMessages(MSG_TIMEOUT, stoppingTask);
+            if (stoppingTask.verb != VERB_EXECUTING) {
+                Log.e(TAG, "Sending onStopTask for a task that isn't started. " + stoppingTask);
+                // TODO: Handle error?
+                return;
+            }
+            try {
+                service.stopTask(stoppingTask.params);
+                stoppingTask.verb = VERB_STOPPING;
+                scheduleOpTimeOut(stoppingTask);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error sending onStopTask to client.", e);
+                closeAndCleanupTaskH(stoppingTask, false);
+            }
+        }
+
+        /** Start the task on the service. */
+        private void sendStartMessageH(ActiveTask pendingTask) {
+            if (pendingTask.verb != VERB_PENDING) {
+                Log.e(TAG, "Sending onStartTask for a task that isn't pending. " + pendingTask);
+                // TODO: Handle error?
+            }
+            try {
+                service.startTask(pendingTask.params);
+                pendingTask.verb = VERB_STARTING;
+                scheduleOpTimeOut(pendingTask);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error sending onStart message to '" + component.getShortClassName()
+                        + "' ", e);
+            }
+        }
+
+        /**
+         * The provided task has finished, either by calling
+         * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
+         * or from acknowledging the stop message we sent. Either way, we're done tracking it and
+         * we want to clean up internally.
+         */
+        private void closeAndCleanupTaskH(ActiveTask completedTask, boolean reschedule) {
+            removeMessages(MSG_TIMEOUT, completedTask);
+            mPending.remove(completedTask.params.getTaskId());
+            if (mPending.size() == 0) {
+                startShutdown();
+            }
+            mCompletedListener.onTaskCompleted(token, completedTask.params.getTaskId(), reschedule);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/task/TaskStore.java
new file mode 100644
index 0000000..3bfc8a5
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskStore.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task;
+
+import android.content.Context;
+import android.content.Task;
+import android.util.SparseArray;
+
+import com.android.server.task.controllers.TaskStatus;
+
+/**
+ * Maintain a list of classes, and accessor methods/logic for these tasks.
+ * This class offers the following functionality:
+ *     - When a task is added, it will determine if the task requirements have changed (update) and
+ *       whether the controllers need to be updated.
+ *     - Persists Tasks, figures out when to to rewrite the Task to disk.
+ *     - Is threadsafe.
+ *     - Handles rescheduling of tasks.
+ *       - When a periodic task is executed and must be re-added.
+ *       - When a task fails and the client requests that it be retried with backoff.
+ *       - This class is <strong>not</strong> thread-safe.
+ */
+public class TaskStore {
+
+    /**
+     * Master list, indexed by {@link com.android.server.task.controllers.TaskStatus#hashCode()}.
+     */
+    final SparseArray<TaskStatus> mTasks;
+    final Context mContext;
+
+    TaskStore(Context context) {
+        mTasks = intialiseTaskMapFromDisk();
+        mContext = context;
+    }
+
+    /**
+     * Add a task to the master list, persisting it if necessary.
+     * Will first check to see if the task already exists. If so, it will replace it.
+     * {@link android.content.pm.PackageManager} is queried to see if the calling package has
+     * permission to
+     * @param task Task to add.
+     * @return The initialised TaskStatus object if this operation was successful, null if it
+     * failed.
+     */
+    public TaskStatus addNewTaskForUser(Task task, int userId, int uId,
+                                                     boolean canPersistTask) {
+        TaskStatus taskStatus = TaskStatus.getForTaskAndUser(task, userId, uId);
+        if (canPersistTask && task.isPeriodic()) {
+            if (writeStatusToDisk()) {
+                mTasks.put(taskStatus.hashCode(), taskStatus);
+            }
+        }
+        return taskStatus;
+    }
+
+    /**
+     * Remove the provided task. Will also delete the task if it was persisted. Note that this
+     * function does not return the validity of the operation, as we assume a delete will always
+     * succeed.
+     * @param task Task to remove.
+     */
+    public void remove(Task task) {
+
+    }
+
+    /**
+     * Every time the state changes we write all the tasks in one swathe, instead of trying to
+     * track incremental changes.
+     */
+    private boolean writeStatusToDisk() {
+        return true;
+    }
+
+    /**
+     *
+     * @return
+     */
+    // TODO: Implement this.
+    private SparseArray<TaskStatus> intialiseTaskMapFromDisk() {
+        return new SparseArray<TaskStatus>();
+    }
+
+    /**
+     * @return The live array of TaskStatus objects.
+     */
+    public SparseArray<TaskStatus> getTasks() {
+        return mTasks;
+    }
+}
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
index 5cca77c..6a4e1f3 100644
--- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
@@ -41,6 +41,11 @@
     private final BroadcastReceiver mConnectivityChangedReceiver =
             new ConnectivityChangedReceiver();
 
+    /** Track whether the latest active network is metered. */
+    private boolean mMetered;
+    /** Track whether the latest active network is connected. */
+    private boolean mConnectivity;
+
     public ConnectivityController(TaskManagerService service) {
         super(service);
         // Register connectivity changed BR.
@@ -53,6 +58,8 @@
     @Override
     public void maybeTrackTaskState(TaskStatus taskStatus) {
         if (taskStatus.hasConnectivityConstraint() || taskStatus.hasMeteredConstraint()) {
+            taskStatus.connectivityConstraintSatisfied.set(mConnectivity);
+            taskStatus.meteredConstraintSatisfied.set(mMetered);
             mTrackedTasks.add(taskStatus);
         }
     }
@@ -63,19 +70,16 @@
     }
 
     /**
-     * @param isConnected Whether the active network is connected for the given uid
-     * @param isMetered Whether the active network is metered for the given uid. This is
-     *                  necessarily false if <code>isConnected</code> is false.
      * @param userId Id of the user for whom we are updating the connectivity state.
      */
-    private void updateTrackedTasks(boolean isConnected, boolean isMetered, int userId) {
+    private void updateTrackedTasks(int userId) {
         for (TaskStatus ts : mTrackedTasks) {
             if (ts.userId != userId) {
                 continue;
             }
-            boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(isConnected);
-            boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(isMetered);
-            if (prevIsConnected != isConnected || prevIsMetered != isMetered) {
+            boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(mConnectivity);
+            boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(mMetered);
+            if (prevIsConnected != mConnectivity || prevIsMetered != mMetered) {
                     mStateChangedListener.onTaskStateChanged(ts);
             }
         }
@@ -83,12 +87,13 @@
 
     class ConnectivityChangedReceiver extends BroadcastReceiver {
         /**
-         * We'll receive connectivity changes for each user here, which we'll process independently.
+         * We'll receive connectivity changes for each user here, which we process independently.
          * We are only interested in the active network here. We're only interested in the active
          * network, b/c the end result of this will be for apps to try to hit the network.
          * @param context The Context in which the receiver is running.
          * @param intent The Intent being received.
          */
+        // TODO: Test whether this will be called twice for each user.
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
@@ -103,13 +108,13 @@
                 // This broadcast gets sent a lot, only update if the active network has changed.
                 if (activeNetwork.getType() == networkType) {
                     final int userid = context.getUserId();
-                    boolean isMetered = false;
-                    boolean isConnected =
+                    mMetered = false;
+                    mConnectivity =
                             !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
-                    if (isConnected) {  // No point making the call if we know there's no conn.
-                        isMetered = connManager.isActiveNetworkMetered();
+                    if (mConnectivity) {  // No point making the call if we know there's no conn.
+                        mMetered = connManager.isActiveNetworkMetered();
                     }
-                    updateTrackedTasks(isConnected, isMetered, userid);
+                    updateTrackedTasks(userid);
                 }
             } else {
                 Log.w(TAG, "Unrecognised action in intent: " + action);
diff --git a/services/core/java/com/android/server/task/controllers/IdleController.java b/services/core/java/com/android/server/task/controllers/IdleController.java
new file mode 100644
index 0000000..a319a31
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/IdleController.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task.controllers;
+
+import java.util.ArrayList;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import com.android.server.task.TaskManagerService;
+
+public class IdleController extends StateController {
+    private static final String TAG = "IdleController";
+    private static final boolean DEBUG = false;
+
+    // Policy: we decide that we're "idle" if the device has been unused /
+    // screen off or dreaming for at least this long
+    private static final long INACTIVITY_IDLE_THRESHOLD = 71 * 60 * 1000; // millis; 71 min
+    private static final long IDLE_WINDOW_SLOP = 5 * 60 * 1000; // 5 minute window, to be nice
+
+    private static final String ACTION_TRIGGER_IDLE =
+            "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
+
+    final ArrayList<TaskStatus> mTrackedTasks = new ArrayList<TaskStatus>();
+    IdlenessTracker mIdleTracker;
+
+    // Singleton factory
+    private static Object sCreationLock = new Object();
+    private static volatile IdleController sController;
+
+    public IdleController getController(TaskManagerService service) {
+        synchronized (sCreationLock) {
+            if (sController == null) {
+                sController = new IdleController(service);
+            }
+            return sController;
+        }
+    }
+
+    private IdleController(TaskManagerService service) {
+        super(service);
+        initIdleStateTracking();
+    }
+
+    /**
+     * StateController interface
+     */
+    @Override
+    public void maybeTrackTaskState(TaskStatus taskStatus) {
+        if (taskStatus.hasIdleConstraint()) {
+            synchronized (mTrackedTasks) {
+                mTrackedTasks.add(taskStatus);
+                taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle());
+            }
+        }
+    }
+
+    @Override
+    public void removeTaskStateIfTracked(TaskStatus taskStatus) {
+        synchronized (mTrackedTasks) {
+            mTrackedTasks.remove(taskStatus);
+        }
+    }
+
+    /**
+     * Interaction with the task manager service
+     */
+    void reportNewIdleState(boolean isIdle) {
+        synchronized (mTrackedTasks) {
+            for (TaskStatus task : mTrackedTasks) {
+                task.idleConstraintSatisfied.set(isIdle);
+                mStateChangedListener.onTaskStateChanged(task);
+            }
+        }
+    }
+
+    /**
+     * Idle state tracking, and messaging with the task manager when
+     * significant state changes occur
+     */
+    private void initIdleStateTracking() {
+        mIdleTracker = new IdlenessTracker();
+        mIdleTracker.startTracking();
+    }
+
+    class IdlenessTracker extends BroadcastReceiver {
+        private AlarmManager mAlarm;
+        private PendingIntent mIdleTriggerIntent;
+        boolean mIdle;
+
+        public IdlenessTracker() {
+            mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
+            Intent intent = new Intent(ACTION_TRIGGER_IDLE);
+            intent.setComponent(new ComponentName(mContext, this.getClass()));
+            mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+
+            // at boot we presume that the user has just "interacted" with the
+            // device in some meaningful way
+            mIdle = false;
+        }
+
+        public boolean isIdle() {
+            return mIdle;
+        }
+
+        public void startTracking() {
+            IntentFilter filter = new IntentFilter();
+
+            // Screen state
+            filter.addAction(Intent.ACTION_SCREEN_ON);
+            filter.addAction(Intent.ACTION_SCREEN_OFF);
+
+            // Dreaming state
+            filter.addAction(Intent.ACTION_DREAMING_STARTED);
+            filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+
+            mContext.registerReceiver(this, filter);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+
+            if (action.equals(Intent.ACTION_SCREEN_ON)
+                    || action.equals(Intent.ACTION_DREAMING_STOPPED)) {
+                // possible transition to not-idle
+                if (mIdle) {
+                    if (DEBUG) {
+                        Slog.v(TAG, "exiting idle : " + action);
+                    }
+                    mAlarm.cancel(mIdleTriggerIntent);
+                    mIdle = false;
+                    reportNewIdleState(mIdle);
+                }
+            } else if (action.equals(Intent.ACTION_SCREEN_OFF)
+                    || action.equals(Intent.ACTION_DREAMING_STARTED)) {
+                // when the screen goes off or dreaming starts, we schedule the
+                // alarm that will tell us when we have decided the device is
+                // truly idle.
+                long when = SystemClock.elapsedRealtime() + INACTIVITY_IDLE_THRESHOLD;
+                if (DEBUG) {
+                    Slog.v(TAG, "Scheduling idle : " + action + " when=" + when);
+                }
+                mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                        when, IDLE_WINDOW_SLOP, mIdleTriggerIntent);
+            } else if (action.equals(ACTION_TRIGGER_IDLE)) {
+                // idle time starts now
+                if (!mIdle) {
+                    if (DEBUG) {
+                        Slog.v(TAG, "Idle trigger fired @ " + SystemClock.elapsedRealtime());
+                    }
+                    mIdle = true;
+                    reportNewIdleState(mIdle);
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
index 230b049..d96fedc 100644
--- a/services/core/java/com/android/server/task/controllers/TaskStatus.java
+++ b/services/core/java/com/android/server/task/controllers/TaskStatus.java
@@ -18,6 +18,8 @@
 
 import android.content.ComponentName;
 import android.content.Task;
+import android.content.pm.PackageParser;
+import android.os.Bundle;
 import android.os.SystemClock;
 
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -36,7 +38,9 @@
 public class TaskStatus {
     final int taskId;
     final int userId;
-    ComponentName component;
+    final int uId;
+    final ComponentName component;
+    final Bundle extras;
 
     final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
     final AtomicBoolean timeConstraintSatisfied = new AtomicBoolean();
@@ -60,15 +64,17 @@
 
     /** Generate a TaskStatus object for a given task and uid. */
     // TODO: reimplement this to reuse these objects instead of creating a new one each time?
-    static TaskStatus getForTaskAndUid(Task task, int uId) {
-        return new TaskStatus(task, uId);
+    public static TaskStatus getForTaskAndUser(Task task, int userId, int uId) {
+        return new TaskStatus(task, userId, uId);
     }
 
     /** Set up the state of a newly scheduled task. */
-    TaskStatus(Task task, int userId) {
+    TaskStatus(Task task, int userId, int uId) {
         this.taskId = task.getTaskId();
         this.userId = userId;
         this.component = task.getService();
+        this.extras = task.getExtras();
+        this.uId = uId;
 
         hasChargingConstraint = task.isRequireCharging();
         hasIdleConstraint = task.isRequireDeviceIdle();
@@ -94,6 +100,26 @@
         hasConnectivityConstraint = task.getNetworkCapabilities() == Task.NetworkType.ANY;
     }
 
+    public int getTaskId() {
+        return taskId;
+    }
+
+    public ComponentName getServiceComponent() {
+        return component;
+    }
+
+    public int getUserId() {
+        return userId;
+    }
+
+    public int getUid() {
+        return uId;
+    }
+
+    public Bundle getExtras() {
+        return extras;
+    }
+
     boolean hasConnectivityConstraint() {
         return hasConnectivityConstraint;
     }
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index a83fa87..d8d3da1 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -52,7 +52,7 @@
 
     // Trust state
     private boolean mTrusted;
-    private String mMessage;
+    private CharSequence mMessage;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -60,7 +60,7 @@
             switch (msg.what) {
                 case MSG_ENABLE_TRUST:
                     mTrusted = true;
-                    mMessage = (String) msg.obj;
+                    mMessage = (CharSequence) msg.obj;
                     boolean initiatedByUser = msg.arg1 != 0;
                     // TODO: Handle handle user initiated trust changes.
                     mTrustManagerService.updateTrust(mUserId);
@@ -79,7 +79,8 @@
 
     private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
 
-        public void enableTrust(String userMessage, long durationMs, boolean initiatedByUser) {
+        @Override
+        public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) {
             if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
                         + ", initiatedByUser = " + initiatedByUser + ")");
 
@@ -91,6 +92,7 @@
             }
         }
 
+        @Override
         public void revokeTrust() {
             if (DEBUG) Slog.v(TAG, "revokeTrust()");
             mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
@@ -155,7 +157,7 @@
         return mTrusted;
     }
 
-    public String getMessage() {
+    public CharSequence getMessage() {
         return mMessage;
     }
 
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 9061f96..c1b9a33 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -24,11 +24,14 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.Manifest;
+import android.app.admin.DevicePolicyManager;
 import android.app.trust.ITrustListener;
 import android.app.trust.ITrustManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
@@ -46,6 +49,7 @@
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 import android.util.Xml;
 
 import java.io.IOException;
@@ -81,6 +85,8 @@
 
     private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
     private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
+    private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver();
+    private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
     private final Context mContext;
 
     private UserManager mUserManager;
@@ -105,8 +111,8 @@
     @Override
     public void onBootPhase(int phase) {
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
-            // Listen for package changes
             mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
+            mDevicePolicyReceiver.register(mContext);
             refreshAgentList();
         }
     }
@@ -158,8 +164,13 @@
         mObsoleteAgents.addAll(mActiveAgents);
 
         for (UserInfo userInfo : userInfos) {
+            int disabledFeatures = lockPatternUtils.getDevicePolicyManager()
+                    .getKeyguardDisabledFeatures(null, userInfo.id);
+            boolean disableTrustAgents =
+                    (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+
             List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
-            if (enabledAgents == null) {
+            if (disableTrustAgents || enabledAgents == null) {
                 continue;
             }
             List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
@@ -221,8 +232,8 @@
                 // Drain preamble.
             }
             String nodeName = parser.getName();
-            if (!"trust_agent".equals(nodeName)) {
-                Slog.w(TAG, "Meta-data does not start with trust_agent tag");
+            if (!"trust-agent".equals(nodeName)) {
+                Slog.w(TAG, "Meta-data does not start with trust-agent tag");
                 return null;
             }
             TypedArray sa = res
@@ -259,6 +270,9 @@
     // Agent dispatch and aggregation
 
     private boolean aggregateIsTrusted(int userId) {
+        if (!mUserHasAuthenticatedSinceBoot.get(userId)) {
+            return false;
+        }
         for (int i = 0; i < mActiveAgents.size(); i++) {
             AgentInfo info = mActiveAgents.valueAt(i);
             if (info.userId == userId) {
@@ -277,6 +291,11 @@
                 info.agent.onUnlockAttempt(successful);
             }
         }
+
+        if (successful && !mUserHasAuthenticatedSinceBoot.get(userId)) {
+            mUserHasAuthenticatedSinceBoot.put(userId, true);
+            updateTrust(userId);
+        }
     }
 
     // Listeners
@@ -384,4 +403,24 @@
             return true;
         }
     };
+
+    private class DevicePolicyReceiver extends BroadcastReceiver {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
+                    intent.getAction())) {
+                refreshAgentList();
+            }
+        }
+
+        public void register(Context context) {
+            context.registerReceiverAsUser(this,
+                    UserHandle.ALL,
+                    new IntentFilter(
+                            DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                    null /* permission */,
+                    null /* scheduler */);
+        }
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 1647425..674c6f4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -39,6 +39,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.HashMap;
+import java.util.Set;
 
 /**
  * Stores and restores state for the Device and Profile owners. By definition there can be
@@ -137,6 +138,10 @@
         return profileOwner != null ? profileOwner.name : null;
     }
 
+    Set<Integer> getProfileOwnerKeys() {
+        return mProfileOwners.keySet();
+    }
+
     boolean hasDeviceOwner() {
         return mDeviceOwner != null;
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1980d1e..e2cd4e2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
 
 import com.android.internal.R;
+import com.android.internal.app.IAppOpsService;
 import com.android.internal.os.storage.ExternalStorageFormatter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
@@ -237,6 +238,8 @@
         }
     };
 
+    private IAppOpsService mAppOpsService;
+
     static class ActiveAdmin {
         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
         private static final String TAG_DISABLE_CAMERA = "disable-camera";
@@ -1209,6 +1212,24 @@
             loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
             loadDeviceOwner();
         }
+        mAppOpsService = IAppOpsService.Stub.asInterface(
+                ServiceManager.getService(Context.APP_OPS_SERVICE));
+        if (mDeviceOwner != null) {
+            if (mDeviceOwner.hasDeviceOwner()) {
+                try {
+                    mAppOpsService.setDeviceOwner(mDeviceOwner.getDeviceOwnerPackageName());
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e);
+                }
+            }
+            for (Integer i : mDeviceOwner.getProfileOwnerKeys()) {
+                try {
+                    mAppOpsService.setProfileOwner(mDeviceOwner.getProfileOwnerPackageName(i), i);
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e);
+                }
+            }
+        }
     }
 
     private void handlePasswordExpirationNotification(int userHandle) {
@@ -2953,6 +2974,14 @@
                         "Trying to set device owner but device owner is already set.");
             }
 
+            long token = Binder.clearCallingIdentity();
+            try {
+                mAppOpsService.setDeviceOwner(packageName);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
             if (mDeviceOwner == null) {
                 // Device owner is not set and does not exist, set it.
                 mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
@@ -3029,6 +3058,14 @@
                 throw new IllegalStateException(
                         "Trying to set profile owner but user is already set-up.");
             }
+            long token = Binder.clearCallingIdentity();
+            try {
+                mAppOpsService.setProfileOwner(packageName, userHandle);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
             if (mDeviceOwner == null) {
                 // Device owner state does not exist, create it.
                 mDeviceOwner = DeviceOwner.createWithProfileOwner(packageName, ownerName,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7002744..2bf9ef1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1773,12 +1773,15 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
      * @param AID Application id. See ETSI 102.221 and 101.220.
      * @return The logical channel id which is negative on error.
      */
     public int iccOpenLogicalChannel(String AID) {
         try {
-          return getITelephony().iccOpenLogicalChannel(AID);
+            return getITelephony().iccOpenLogicalChannel(AID);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -1790,13 +1793,16 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
      * @param channel is the channel id to be closed as retruned by a successful
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      */
     public boolean iccCloseLogicalChannel(int channel) {
         try {
-          return getITelephony().iccCloseLogicalChannel(channel);
+            return getITelephony().iccCloseLogicalChannel(channel);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -1808,6 +1814,9 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
      * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
      * @param cla Class of the APDU command.
@@ -1823,8 +1832,30 @@
     public String iccTransmitApduLogicalChannel(int channel, int cla,
             int instruction, int p1, int p2, int p3, String data) {
         try {
-          return getITelephony().iccTransmitApduLogicalChannel(channel, cla,
-                  instruction, p1, p2, p3, data);
+            return getITelephony().iccTransmitApduLogicalChannel(channel, cla,
+                    instruction, p1, p2, p3, data);
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return "";
+    }
+
+    /**
+     * Send ENVELOPE to the SIM and return the response.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
+     * @param content String containing SAT/USAT response in hexadecimal
+     *                format starting with command tag. See TS 102 223 for
+     *                details.
+     * @return The APDU response from the ICC card, with the last 4 bytes
+     *         being the status word. If the command fails, returns an empty
+     *         string.
+     */
+    public String sendEnvelopeWithStatus(String content) {
+        try {
+            return getITelephony().sendEnvelopeWithStatus(content);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 72398ad..8b80bfa 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -373,6 +373,18 @@
             int p1, int p2, int p3, String data);
 
     /**
+     * Send ENVELOPE to the SIM and returns the response.
+     *
+     * @param contents  String containing SAT/USAT response in hexadecimal
+     *                  format starting with command tag. See TS 102 223 for
+     *                  details.
+     * @return The APDU response from the ICC card, with the last 4 bytes
+     *         being the status word. If the command fails, returns an empty
+     *         string.
+     */
+    String sendEnvelopeWithStatus(String content);
+
+    /**
      * Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
      * Used for device configuration by some CDMA operators.
      *
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 0d9cd18..c162bf2 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -350,7 +350,17 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
     @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+
     public void sendStickyBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
index e4ea936..4938579 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
@@ -108,6 +108,7 @@
 
             mToggle = !mToggle;
 
+            /*
             mRunningAnimations.add(new RenderNodeAnimator(
                     mX, mToggle ? 400.0f : 200.0f));
 
@@ -146,7 +147,7 @@
                     }
                 });
             }
-
+            */
             return true;
         }
     }
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 08e9d99..d31239b 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
@@ -567,7 +567,7 @@
         StyleResourceValue customStyleValues = null;
         if (customStyle != null) {
             ResourceValue item = mRenderResources.findResValue(customStyle,
-                    false /*forceFrameworkOnly*/);
+                    isPlatformFile /*forceFrameworkOnly*/);
 
             // resolve it in case it links to something else
             item = mRenderResources.resolveResValue(item);
@@ -1284,6 +1284,14 @@
     }
 
     @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        // pass
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent arg0) {
         // pass
 
diff --git a/tools/layoutlib/rename_font/README b/tools/layoutlib/rename_font/README
new file mode 100644
index 0000000..600b756
--- /dev/null
+++ b/tools/layoutlib/rename_font/README
@@ -0,0 +1,9 @@
+This tool is used to rename the PS name encoded inside the ttf font that we ship
+with the SDK. There is bug in Java that returns incorrect results for
+java.awt.Font#layoutGlyphVector() if two fonts with same name but differnt
+versions are loaded. As a workaround, we rename all the fonts that we ship with
+the SDK by appending the font version to its name.
+
+
+The build_font.py copies all files from input_dir to output_dir while renaming
+the font files (*.ttf) in the process.
diff --git a/tools/layoutlib/rename_font/Roboto-Regular.ttf b/tools/layoutlib/rename_font/Roboto-Regular.ttf
new file mode 100644
index 0000000..7469063
--- /dev/null
+++ b/tools/layoutlib/rename_font/Roboto-Regular.ttf
Binary files differ
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
new file mode 100755
index 0000000..ea3dccc
--- /dev/null
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Rename the PS name of all fonts in the input directory and copy them to the
+output directory.
+
+Usage: build_font.py /path/to/input_fonts/ /path/to/output_fonts/
+
+"""
+
+import sys
+# fontTools is available at platform/external/fonttools
+from fontTools import ttx
+import re
+import os
+from lxml import etree
+import shutil
+import glob
+
+def main(argv):
+  if len(argv) != 2:
+    print "Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/"
+    sys.exit(1)
+  if not os.path.isdir(argv[0]):
+    print argv[0] + "is not a valid directory"
+    sys.exit(1)
+  if not os.path.isdir(argv[1]):
+    print argv[1] + "is not a valid directory"
+    sys.exit(1)
+  cwd = os.getcwd()
+  os.chdir(argv[1])
+  files = glob.glob('*')
+  for filename in files:
+    os.remove(filename)
+  os.chdir(cwd)
+  for filename in os.listdir(argv[0]):
+    if not os.path.splitext(filename)[1].lower() == ".ttf":
+      shutil.copy(os.path.join(argv[0], filename), argv[1])
+      continue
+    print os.path.join(argv[0], filename)
+    old_ttf_path = os.path.join(argv[0], filename)
+    # run ttx to generate an xml file in the output folder which represents all
+    # its info
+    ttx_args = ["-d", argv[1], old_ttf_path]
+    ttx.main(ttx_args)
+    # the path to the output file. The file name is the fontfilename.ttx
+    ttx_path = os.path.join(argv[1], filename)
+    ttx_path = ttx_path[:-1] + "x"
+    # now parse the xml file to change its PS name.
+    tree = etree.parse(ttx_path)
+    encoding = tree.docinfo.encoding
+    root = tree.getroot()
+    for name in root.iter('name'):
+      [old_ps_name, version] = get_font_info(name)
+      new_ps_name = old_ps_name + version
+      update_name(name, new_ps_name)
+    tree.write(ttx_path, xml_declaration=True, encoding=encoding )
+    # generate the udpated font now.
+    ttx_args = ["-d", argv[1], ttx_path]
+    ttx.main(ttx_args)
+    # delete the temp ttx file.
+    os.remove(ttx_path)
+
+def get_font_info(tag):
+  ps_name = None
+  ps_version = None
+  for namerecord in tag.iter('namerecord'):
+    if 'nameID' in namerecord.attrib:
+      # if the tag has nameID=6, it is the postscript name of the font.
+      # see: http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#3054f18b
+      if namerecord.attrib['nameID'] == '6':
+        if ps_name is not None:
+          if not sanitize(namerecord.text) == ps_name:
+            sys.exit('found multiple possibilities of the font name')
+        else:
+          ps_name = sanitize(namerecord.text)
+      # nameID=5 means the font version
+      if namerecord.attrib['nameID'] == '5':
+        if ps_version is not None:
+          if not ps_version == get_version(namerecord.text):
+            sys.exit('found multiple possibilities of the font version')
+        else:
+          ps_version = get_version(namerecord.text)
+  if ps_name is not None and ps_version is not None:
+    return [ps_name, ps_version]
+  sys.exit('didn\'t find the font name or version')
+
+
+def update_name(tag, name):
+  for namerecord in tag.iter('namerecord'):
+    if 'nameID' in namerecord.attrib:
+      if namerecord.attrib['nameID'] == '6':
+        namerecord.text = name
+
+def sanitize(string):
+  return re.sub(r'[^\w-]+', '', string)
+
+def get_version(string):
+  # The string must begin with "Version n.nn "
+  # to extract n.nn, we return the second entry in the split strings.
+  string = string.strip()
+  if not string.startswith("Version "):
+    sys.exit('mal-formed font version')
+  return sanitize(string.split()[1])
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/tools/layoutlib/rename_font/test.py b/tools/layoutlib/rename_font/test.py
new file mode 100755
index 0000000..d4c86cb
--- /dev/null
+++ b/tools/layoutlib/rename_font/test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+"""Tests build_font.py by renaming a font.
+
+The test copies Roboto-Regular.ttf to a tmp directory and ask build_font.py to rename it and put in another dir.
+We then use ttx to dump the new font to its xml and check if rename was successful
+
+To test locally, use:
+PYTHONPATH="$PYTHONPATH:/path/to/android/checkout/external/fonttools/Lib" ./test.py
+"""
+
+import unittest
+import build_font
+
+from fontTools import ttx
+import os
+from lxml import etree
+import shutil
+import tempfile
+
+class MyTest(unittest.TestCase):
+  def test(self):
+    font_name = "Roboto-Regular.ttf"
+    srcdir = tempfile.mkdtemp()
+    print "srcdir: " + srcdir
+    shutil.copy(font_name, srcdir)
+    destdir = tempfile.mkdtemp()
+    print "destdir: " + destdir
+    self.assertTrue(build_font.main([srcdir, destdir]) is None)
+    out_path = os.path.join(destdir, font_name)
+    ttx.main([out_path])
+    ttx_path = out_path[:-1] + "x"
+    tree = etree.parse(ttx_path)
+    root = tree.getroot()
+    name_tag = root.find('name')
+    [f_name, f_version] = build_font.get_font_info(name_tag)
+    shutil.rmtree(srcdir)
+    shutil.rmtree(destdir)
+    self.assertEqual(f_name, "Roboto-Regular1200310")
+
+
+
+if __name__ == '__main__':
+  unittest.main()