Merge "camera2: (LEGACY) Add face detection support and vstab modes" into lmp-dev
diff --git a/Android.mk b/Android.mk
index 52c2d16..5485e9f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -128,6 +128,7 @@
 	core/java/android/content/pm/IOnAppsChangedListener.aidl \
 	core/java/android/content/pm/IPackageDataObserver.aidl \
 	core/java/android/content/pm/IPackageDeleteObserver.aidl \
+	core/java/android/content/pm/IPackageDeleteObserver2.aidl \
 	core/java/android/content/pm/IPackageInstallObserver.aidl \
 	core/java/android/content/pm/IPackageInstallObserver2.aidl \
 	core/java/android/content/pm/IPackageInstaller.aidl \
diff --git a/api/current.txt b/api/current.txt
index ea842d5..5cafd6c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -479,6 +479,7 @@
     field public static final int dashWidth = 16843174; // 0x10101a6
     field public static final int data = 16842798; // 0x101002e
     field public static final int datePickerDialogTheme = 16843951; // 0x10104af
+    field public static final int datePickerMode = 16843958; // 0x10104b6
     field public static final int datePickerStyle = 16843612; // 0x101035c
     field public static final int dateTextAppearance = 16843593; // 0x1010349
     field public static final int dayOfWeekBackgroundColor = 16843926; // 0x1010496
@@ -1313,6 +1314,7 @@
     field public static final int tileModeX = 16843897; // 0x1010479
     field public static final int tileModeY = 16843898; // 0x101047a
     field public static final int timePickerDialogTheme = 16843936; // 0x10104a0
+    field public static final int timePickerMode = 16843959; // 0x10104b7
     field public static final int timePickerStyle = 16843935; // 0x101049f
     field public static final int timeZone = 16843724; // 0x10103cc
     field public static final int tint = 16843041; // 0x1010121
@@ -5834,7 +5836,7 @@
     field public static final int WIDGET_CATEGORY_RECENTS = 4; // 0x4
     field public int autoAdvanceViewId;
     field public android.content.ComponentName configure;
-    field public deprecated int icon;
+    field public int icon;
     field public int initialKeyguardLayout;
     field public int initialLayout;
     field public deprecated java.lang.String label;
@@ -5842,7 +5844,7 @@
     field public int minResizeHeight;
     field public int minResizeWidth;
     field public int minWidth;
-    field public deprecated int previewImage;
+    field public int previewImage;
     field public android.content.ComponentName provider;
     field public int resizeMode;
     field public int updatePeriodMillis;
@@ -8673,6 +8675,7 @@
     ctor public PackageInstaller.CommitCallback();
     method public abstract void onFailure(int, java.lang.String, android.os.Bundle);
     method public abstract void onSuccess();
+    method public abstract void onUserActionRequired(android.content.Intent);
     field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
     field public static final int FAILURE_CONFLICT = 2; // 0x2
     field public static final int FAILURE_INCOMPATIBLE = 4; // 0x4
@@ -8705,6 +8708,7 @@
     ctor public PackageInstaller.UninstallCallback();
     method public abstract void onFailure(java.lang.String);
     method public abstract void onSuccess();
+    method public abstract void onUserActionRequired(android.content.Intent);
   }
 
   public class PackageItemInfo {
@@ -11777,7 +11781,9 @@
     method public void setHotspotBounds(int, int, int, int);
     method public final boolean setLevel(int);
     method public boolean setState(int[]);
-    method public void setTint(android.content.res.ColorStateList, android.graphics.PorterDuff.Mode);
+    method public void setTint(int);
+    method public void setTintList(android.content.res.ColorStateList);
+    method public void setTintMode(android.graphics.PorterDuff.Mode);
     method public boolean setVisible(boolean, boolean);
     method public void unscheduleSelf(java.lang.Runnable);
   }
@@ -13230,10 +13236,10 @@
     method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
     method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
     field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+    field public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 16; // 0x10
     field public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 8; // 0x8
     field public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 2; // 0x2
     field public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1; // 0x1
-    field public static final int VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE = 16; // 0x10
     field public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 4; // 0x4
   }
 
@@ -16256,6 +16262,7 @@
     method public void disconnect();
     method public android.os.Bundle getExtras();
     method public android.net.Uri getRoot();
+    method public android.content.ComponentName getServiceComponent();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isConnected();
     method public void loadIcon(android.net.Uri, int, int, android.media.browse.MediaBrowser.IconCallback);
@@ -16394,7 +16401,7 @@
   public final class MediaProjection {
     method public void addCallback(android.media.projection.MediaProjection.Callback, android.os.Handler);
     method public android.media.AudioRecord createAudioRecord(int, int, int, int);
-    method public android.hardware.display.VirtualDisplay createVirtualDisplay(java.lang.String, int, int, int, boolean, android.view.Surface, android.hardware.display.VirtualDisplay.Callbacks, android.os.Handler);
+    method public android.hardware.display.VirtualDisplay createVirtualDisplay(java.lang.String, int, int, int, int, android.view.Surface, android.hardware.display.VirtualDisplay.Callbacks, android.os.Handler);
     method public void removeCallback(android.media.projection.MediaProjection.Callback);
     method public void stop();
   }
@@ -16656,12 +16663,14 @@
     method public void adjustVolume(int, int);
     method public android.media.routing.MediaRouter.Delegate createMediaRouterDelegate();
     method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
+    method public android.os.Bundle getExtras();
     method public long getFlags();
     method public android.app.PendingIntent getLaunchActivity();
     method public android.media.MediaMetadata getMetadata();
     method public java.lang.String getPackageName();
     method public android.media.session.PlaybackState getPlaybackState();
     method public java.util.List<android.media.session.MediaSession.Track> getQueue();
+    method public java.lang.CharSequence getQueueTitle();
     method public int getRatingType();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public android.media.session.MediaController.TransportControls getTransportControls();
@@ -22770,7 +22779,8 @@
 
   public class UserManager {
     method public android.os.Bundle getApplicationRestrictions(java.lang.String);
-    method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
+    method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
+    method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
@@ -27523,13 +27533,16 @@
 
   public static abstract interface AlwaysOnHotwordDetector.Callback {
     method public abstract void onAvailabilityChanged(int);
-    method public abstract void onDetected(android.service.voice.AlwaysOnHotwordDetector.TriggerAudio);
+    method public abstract void onDetected(android.service.voice.AlwaysOnHotwordDetector.EventPayload);
     method public abstract void onError();
+    method public abstract void onRecognitionPaused();
+    method public abstract void onRecognitionResumed();
   }
 
-  public static class AlwaysOnHotwordDetector.TriggerAudio {
+  public static class AlwaysOnHotwordDetector.EventPayload {
     field public final android.media.AudioFormat audioFormat;
     field public final byte[] data;
+    field public final boolean isTriggerAudio;
   }
 
   public class VoiceInteractionService extends android.app.Service {
@@ -28801,16 +28814,16 @@
     method public void changeCameraCapabilities(android.telecomm.CallCameraCapabilities);
     method public void changePeerDimensions(int, int);
     method public void handleCallSessionEvent(int);
-    method public abstract void onRequestCallDataUsage();
-    method public abstract void onRequestCameraCapabilities();
-    method public abstract void onSendSessionModifyRequest(android.telecomm.VideoCallProfile);
-    method public abstract void onSendSessionModifyResponse(android.telecomm.VideoCallProfile);
-    method public abstract void onSetCamera(java.lang.String);
-    method public abstract void onSetDeviceOrientation(int);
-    method public abstract void onSetDisplaySurface(android.view.Surface);
-    method public abstract void onSetPauseImage(java.lang.String);
-    method public abstract void onSetPreviewSurface(android.view.Surface);
-    method public abstract void onSetZoom(float);
+    method public void onRequestCallDataUsage();
+    method public void onRequestCameraCapabilities();
+    method public void onSendSessionModifyRequest(android.telecomm.VideoCallProfile);
+    method public void onSendSessionModifyResponse(android.telecomm.VideoCallProfile);
+    method public void onSetCamera(java.lang.String);
+    method public void onSetDeviceOrientation(int);
+    method public void onSetDisplaySurface(android.view.Surface);
+    method public void onSetPauseImage(java.lang.String);
+    method public void onSetPreviewSurface(android.view.Surface);
+    method public void onSetZoom(float);
     method public void receiveSessionModifyRequest(android.telecomm.VideoCallProfile);
     method public void receiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile);
   }
@@ -34263,7 +34276,7 @@
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public android.graphics.drawable.Drawable getBackground();
-    method public android.content.res.ColorStateList getBackgroundTint();
+    method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
     method public int getBaseline();
     method public final int getBottom();
@@ -34544,7 +34557,7 @@
     method public void setBackgroundColor(int);
     method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
     method public void setBackgroundResource(int);
-    method public void setBackgroundTint(android.content.res.ColorStateList);
+    method public void setBackgroundTintList(android.content.res.ColorStateList);
     method public void setBackgroundTintMode(android.graphics.PorterDuff.Mode);
     method public final void setBottom(int);
     method public void setCameraDistance(float);
@@ -37599,13 +37612,13 @@
     method public boolean getSplitTrack();
     method public android.graphics.drawable.Drawable getThumb();
     method public int getThumbOffset();
-    method public android.content.res.ColorStateList getThumbTint();
+    method public android.content.res.ColorStateList getThumbTintList();
     method public android.graphics.PorterDuff.Mode getThumbTintMode();
     method public void setKeyProgressIncrement(int);
     method public void setSplitTrack(boolean);
     method public void setThumb(android.graphics.drawable.Drawable);
     method public void setThumbOffset(int);
-    method public void setThumbTint(android.content.res.ColorStateList);
+    method public void setThumbTintList(android.content.res.ColorStateList);
     method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
   }
 
@@ -37992,12 +38005,12 @@
     ctor public CheckedTextView(android.content.Context, android.util.AttributeSet, int);
     ctor public CheckedTextView(android.content.Context, android.util.AttributeSet, int, int);
     method public android.graphics.drawable.Drawable getCheckMarkDrawable();
-    method public android.content.res.ColorStateList getCheckMarkTint();
+    method public android.content.res.ColorStateList getCheckMarkTintList();
     method public android.graphics.PorterDuff.Mode getCheckMarkTintMode();
     method public boolean isChecked();
     method public void setCheckMarkDrawable(int);
     method public void setCheckMarkDrawable(android.graphics.drawable.Drawable);
-    method public void setCheckMarkTint(android.content.res.ColorStateList);
+    method public void setCheckMarkTintList(android.content.res.ColorStateList);
     method public void setCheckMarkTintMode(android.graphics.PorterDuff.Mode);
     method public void setChecked(boolean);
     method public void toggle();
@@ -38027,12 +38040,12 @@
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet);
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int);
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int, int);
-    method public android.content.res.ColorStateList getButtonTint();
+    method public android.content.res.ColorStateList getButtonTintList();
     method public android.graphics.PorterDuff.Mode getButtonTintMode();
     method public boolean isChecked();
     method public void setButtonDrawable(int);
     method public void setButtonDrawable(android.graphics.drawable.Drawable);
-    method public void setButtonTint(android.content.res.ColorStateList);
+    method public void setButtonTintList(android.content.res.ColorStateList);
     method public void setButtonTintMode(android.graphics.PorterDuff.Mode);
     method public void setChecked(boolean);
     method public void setOnCheckedChangeListener(android.widget.CompoundButton.OnCheckedChangeListener);
@@ -38296,13 +38309,13 @@
     method public deprecated boolean getConsiderGoneChildrenWhenMeasuring();
     method public android.graphics.drawable.Drawable getForeground();
     method public int getForegroundGravity();
-    method public android.content.res.ColorStateList getForegroundTint();
+    method public android.content.res.ColorStateList getForegroundTintList();
     method public android.graphics.PorterDuff.Mode getForegroundTintMode();
     method public boolean getMeasureAllChildren();
     method protected void onLayout(boolean, int, int, int, int);
     method public void setForeground(android.graphics.drawable.Drawable);
     method public void setForegroundGravity(int);
-    method public void setForegroundTint(android.content.res.ColorStateList);
+    method public void setForegroundTintList(android.content.res.ColorStateList);
     method public void setForegroundTintMode(android.graphics.PorterDuff.Mode);
     method public void setMeasureAllChildren(boolean);
   }
@@ -38509,11 +38522,11 @@
     method public android.graphics.drawable.Drawable getDrawable();
     method public int getImageAlpha();
     method public android.graphics.Matrix getImageMatrix();
+    method public android.content.res.ColorStateList getImageTintList();
+    method public android.graphics.PorterDuff.Mode getImageTintMode();
     method public int getMaxHeight();
     method public int getMaxWidth();
     method public android.widget.ImageView.ScaleType getScaleType();
-    method public android.content.res.ColorStateList getTint();
-    method public android.graphics.PorterDuff.Mode getTintMode();
     method public int[] onCreateDrawableState(int);
     method public void setAdjustViewBounds(boolean);
     method public deprecated void setAlpha(int);
@@ -38531,12 +38544,12 @@
     method public void setImageMatrix(android.graphics.Matrix);
     method public void setImageResource(int);
     method public void setImageState(int[], boolean);
+    method public void setImageTintList(android.content.res.ColorStateList);
+    method public void setImageTintMode(android.graphics.PorterDuff.Mode);
     method public void setImageURI(android.net.Uri);
     method public void setMaxHeight(int);
     method public void setMaxWidth(int);
     method public void setScaleType(android.widget.ImageView.ScaleType);
-    method public void setTint(android.content.res.ColorStateList);
-    method public void setTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public static final class ImageView.ScaleType extends java.lang.Enum {
@@ -38911,18 +38924,18 @@
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int);
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int, int);
     method public android.graphics.drawable.Drawable getIndeterminateDrawable();
-    method public android.content.res.ColorStateList getIndeterminateTint();
+    method public android.content.res.ColorStateList getIndeterminateTintList();
     method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
     method public android.view.animation.Interpolator getInterpolator();
     method public synchronized int getMax();
     method public synchronized int getProgress();
-    method public android.content.res.ColorStateList getProgressBackgroundTint();
+    method public android.content.res.ColorStateList getProgressBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
     method public android.graphics.drawable.Drawable getProgressDrawable();
-    method public android.content.res.ColorStateList getProgressTint();
+    method public android.content.res.ColorStateList getProgressTintList();
     method public android.graphics.PorterDuff.Mode getProgressTintMode();
     method public synchronized int getSecondaryProgress();
-    method public android.content.res.ColorStateList getSecondaryProgressTint();
+    method public android.content.res.ColorStateList getSecondaryProgressTintList();
     method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
     method public final synchronized void incrementProgressBy(int);
     method public final synchronized void incrementSecondaryProgressBy(int);
@@ -38932,20 +38945,20 @@
     method public synchronized void setIndeterminate(boolean);
     method public void setIndeterminateDrawable(android.graphics.drawable.Drawable);
     method public void setIndeterminateDrawableTiled(android.graphics.drawable.Drawable);
-    method public void setIndeterminateTint(android.content.res.ColorStateList);
+    method public void setIndeterminateTintList(android.content.res.ColorStateList);
     method public void setIndeterminateTintMode(android.graphics.PorterDuff.Mode);
     method public void setInterpolator(android.content.Context, int);
     method public void setInterpolator(android.view.animation.Interpolator);
     method public synchronized void setMax(int);
     method public synchronized void setProgress(int);
-    method public void setProgressBackgroundTint(android.content.res.ColorStateList);
+    method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
     method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode);
     method public void setProgressDrawable(android.graphics.drawable.Drawable);
     method public void setProgressDrawableTiled(android.graphics.drawable.Drawable);
-    method public void setProgressTint(android.content.res.ColorStateList);
+    method public void setProgressTintList(android.content.res.ColorStateList);
     method public void setProgressTintMode(android.graphics.PorterDuff.Mode);
     method public synchronized void setSecondaryProgress(int);
-    method public void setSecondaryProgressTint(android.content.res.ColorStateList);
+    method public void setSecondaryProgressTintList(android.content.res.ColorStateList);
     method public void setSecondaryProgressTintMode(android.graphics.PorterDuff.Mode);
   }
 
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 1f25dd0..c5e91e3 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -19,12 +19,13 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
 import android.content.ComponentName;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageManager;
 import android.content.pm.InstallSessionInfo;
@@ -760,7 +761,7 @@
         String extraPackage;
 
         @Override
-        public void packageInstalled(String name, Bundle extras, int status) {
+        public void onPackageInstalled(String name, int status, String msg, Bundle extras) {
             synchronized (this) {
                 finished = true;
                 result = status;
@@ -790,6 +791,11 @@
         }
 
         @Override
+        public void onUserActionRequired(Intent intent) {
+            setResult(false, "Unexepected user action required!");
+        }
+
+        @Override
         public void onSuccess() {
             setResult(true, null);
         }
@@ -1268,11 +1274,12 @@
         }
     }
 
-    class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
+    class LocalPackageDeleteObserver extends PackageDeleteObserver {
         boolean finished;
         boolean result;
 
-        public void packageDeleted(String packageName, int returnCode) {
+        @Override
+        public void onPackageDeleted(String name, int returnCode, String msg) {
             synchronized (this) {
                 finished = true;
                 result = returnCode == PackageManager.DELETE_SUCCEEDED;
@@ -1346,9 +1353,9 @@
     }
 
     private boolean deletePackage(String packageName, int flags, int userId) {
-        PackageDeleteObserver obs = new PackageDeleteObserver();
+        LocalPackageDeleteObserver obs = new LocalPackageDeleteObserver();
         try {
-            mInstaller.uninstall(packageName, flags, obs, userId);
+            mInstaller.uninstall(packageName, flags, obs.getBinder(), userId);
 
             synchronized (obs) {
                 while (!obs.finished) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index fc200550..3bf8e2e 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -700,6 +700,13 @@
          */
         public int affiliatedTaskId;
 
+        /**
+         * Task affiliation color of the source task with the affiliated task id.
+         *
+         * @hide
+         */
+        public int affiliatedTaskColor;
+
         public RecentTaskInfo() {
         }
 
@@ -732,6 +739,7 @@
             dest.writeLong(firstActiveTime);
             dest.writeLong(lastActiveTime);
             dest.writeInt(affiliatedTaskId);
+            dest.writeInt(affiliatedTaskColor);
         }
 
         public void readFromParcel(Parcel source) {
@@ -747,6 +755,7 @@
             firstActiveTime = source.readLong();
             lastActiveTime = source.readLong();
             affiliatedTaskId = source.readInt();
+            affiliatedTaskColor = source.readInt();
         }
 
         public static final Creator<RecentTaskInfo> CREATOR
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index edcfd74..84b5516 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -28,6 +28,7 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageDeleteObserver2;
 import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
@@ -1287,6 +1288,7 @@
             // Should never happen!
         }
     }
+
     @Override
     public void clearApplicationUserData(String packageName,
                                          IPackageDataObserver observer) {
@@ -1661,7 +1663,8 @@
         }
 
         @Override
-        public void packageInstalled(String basePackageName, Bundle extras, int returnCode) {
+        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+                Bundle extras) {
             try {
                 mLegacy.packageInstalled(basePackageName, returnCode);
             } catch (RemoteException ignored) {
@@ -1669,6 +1672,22 @@
         }
     }
 
+    private static class LegacyPackageDeleteObserver extends PackageDeleteObserver {
+        private final IPackageDeleteObserver mLegacy;
+
+        public LegacyPackageDeleteObserver(IPackageDeleteObserver legacy) {
+            mLegacy = legacy;
+        }
+
+        @Override
+        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
+            try {
+                mLegacy.packageDeleted(basePackageName, returnCode);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
     private final ContextImpl mContext;
     private final IPackageManager mPM;
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 797a0a0..90b8b86 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -32,7 +32,6 @@
 import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.BadParcelableException;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -1900,8 +1899,7 @@
             mPriority = PRIORITY_DEFAULT;
             mPeople = new ArrayList<String>();
 
-            mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L ?
-                    NotificationColorUtil.getInstance() : null;
+            mColorUtil = NotificationColorUtil.getInstance();
         }
 
         /**
@@ -2562,7 +2560,7 @@
             // Note: This assumes that the current user can read the profile badge of the
             // originating user.
             UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            Drawable badge = userManager.getBadgeForUser(new UserHandle(mOriginatingUserId));
+            Drawable badge = userManager.getBadgeForUser(new UserHandle(mOriginatingUserId), 0);
             if (badge == null) {
                 return null;
             }
@@ -2577,7 +2575,8 @@
 
         private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
             Bitmap profileIcon = getProfileBadge();
-            RemoteViews contentView = new BuilderRemoteViews(mContext.getPackageName(), resId);
+            RemoteViews contentView = new BuilderRemoteViews(mContext.getPackageName(),
+                    mOriginatingUserId, resId);
             boolean showLine3 = false;
             boolean showLine2 = false;
 
@@ -4576,8 +4575,8 @@
             super(parcel);
         }
 
-        public BuilderRemoteViews(String packageName, int layoutId) {
-            super(packageName, layoutId);
+        public BuilderRemoteViews(String packageName, int userId, int layoutId) {
+            super(packageName, userId, layoutId);
         }
 
         @Override
diff --git a/core/java/android/app/PackageDeleteObserver.java b/core/java/android/app/PackageDeleteObserver.java
new file mode 100644
index 0000000..9b83ec1
--- /dev/null
+++ b/core/java/android/app/PackageDeleteObserver.java
@@ -0,0 +1,46 @@
+/*
+ * 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 android.app;
+
+import android.content.Intent;
+import android.content.pm.IPackageDeleteObserver2;
+
+/** {@hide} */
+public class PackageDeleteObserver {
+    private final IPackageDeleteObserver2.Stub mBinder = new IPackageDeleteObserver2.Stub() {
+        @Override
+        public void onUserActionRequired(Intent intent) {
+            PackageDeleteObserver.this.onUserActionRequired(intent);
+        }
+
+        @Override
+        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
+            PackageDeleteObserver.this.onPackageDeleted(basePackageName, returnCode, msg);
+        }
+    };
+
+    /** {@hide} */
+    public IPackageDeleteObserver2 getBinder() {
+        return mBinder;
+    }
+
+    public void onUserActionRequired(Intent intent) {
+    }
+
+    public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
+    }
+}
diff --git a/core/java/android/app/PackageInstallObserver.java b/core/java/android/app/PackageInstallObserver.java
index 1b2504e..ff28679 100644
--- a/core/java/android/app/PackageInstallObserver.java
+++ b/core/java/android/app/PackageInstallObserver.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.content.Intent;
 import android.content.pm.IPackageInstallObserver2;
 import android.os.Bundle;
 
@@ -23,9 +24,15 @@
 public class PackageInstallObserver {
     private final IPackageInstallObserver2.Stub mBinder = new IPackageInstallObserver2.Stub() {
         @Override
-        public void packageInstalled(String basePackageName, Bundle extras, int returnCode,
-                String msg) {
-            PackageInstallObserver.this.packageInstalled(basePackageName, extras, returnCode, msg);
+        public void onUserActionRequired(Intent intent) {
+            PackageInstallObserver.this.onUserActionRequired(intent);
+        }
+
+        @Override
+        public void onPackageInstalled(String basePackageName, int returnCode,
+                String msg, Bundle extras) {
+            PackageInstallObserver.this.onPackageInstalled(basePackageName, returnCode, msg,
+                    extras);
         }
     };
 
@@ -34,6 +41,9 @@
         return mBinder;
     }
 
+    public void onUserActionRequired(Intent intent) {
+    }
+
     /**
      * This method will be called to report the result of the package
      * installation attempt.
@@ -49,11 +59,7 @@
      *            basic outcome
      * @hide
      */
-    public void packageInstalled(String basePackageName, Bundle extras, int returnCode) {
-    }
-
-    public void packageInstalled(String basePackageName, Bundle extras, int returnCode,
-            String msg) {
-        packageInstalled(basePackageName, extras, returnCode);
+    public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+            Bundle extras) {
     }
 }
diff --git a/core/java/android/app/PackageUninstallObserver.java b/core/java/android/app/PackageUninstallObserver.java
deleted file mode 100644
index 83fc380..0000000
--- a/core/java/android/app/PackageUninstallObserver.java
+++ /dev/null
@@ -1,37 +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 android.app;
-
-import android.content.pm.IPackageDeleteObserver;
-
-/** {@hide} */
-public class PackageUninstallObserver {
-    private final IPackageDeleteObserver.Stub mBinder = new IPackageDeleteObserver.Stub() {
-        @Override
-        public void packageDeleted(String basePackageName, int returnCode) {
-            PackageUninstallObserver.this.onUninstallFinished(basePackageName, returnCode);
-        }
-    };
-
-    /** {@hide} */
-    public IPackageDeleteObserver getBinder() {
-        return mBinder;
-    }
-
-    public void onUninstallFinished(String basePackageName, int returnCode) {
-    }
-}
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index be8108c..df0365e 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.SystemApi;
 import android.app.backup.RestoreSession;
 import android.app.backup.IBackupManager;
 import android.app.backup.IRestoreSession;
@@ -114,7 +115,7 @@
             try {
                 sService.dataChanged(packageName);
             } catch (RemoteException e) {
-                Log.d(TAG, "dataChanged(pkg) couldn't connect");
+                Log.e(TAG, "dataChanged(pkg) couldn't connect");
             }
         }
     }
@@ -150,7 +151,7 @@
                     result = session.restorePackage(mContext.getPackageName(), observer);
                 }
             } catch (RemoteException e) {
-                Log.w(TAG, "restoreSelf() unable to contact service");
+                Log.e(TAG, "restoreSelf() unable to contact service");
             } finally {
                 if (session != null) {
                     session.endRestoreSession();
@@ -176,9 +177,142 @@
                     session = new RestoreSession(mContext, binder);
                 }
             } catch (RemoteException e) {
-                Log.w(TAG, "beginRestoreSession() couldn't connect");
+                Log.e(TAG, "beginRestoreSession() couldn't connect");
             }
         }
         return session;
     }
+
+    // system APIs start here
+
+    /**
+     * Enable/disable the backup service entirely.  When disabled, no backup
+     * or restore operations will take place.  Data-changed notifications will
+     * still be observed and collected, however, so that changes made while the
+     * mechanism was disabled will still be backed up properly if it is enabled
+     * at some point in the future.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void setBackupEnabled(boolean isEnabled) {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                sService.setBackupEnabled(isEnabled);
+            } catch (RemoteException e) {
+                Log.e(TAG, "setBackupEnabled() couldn't connect");
+            }
+        }
+    }
+
+    /**
+     * Report whether the backup mechanism is currently enabled.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isBackupEnabled() {
+        if (sService != null) {
+            try {
+                return sService.isBackupEnabled();
+            } catch (RemoteException e) {
+                Log.e(TAG, "isBackupEnabled() couldn't connect");
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Identify the currently selected transport.  Callers must hold the
+     * android.permission.BACKUP permission to use this method.
+     * @return The name of the currently active backup transport.  In case of
+     *   failure or if no transport is currently active, this method returns {@code null}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public String getCurrentTransport() {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                return sService.getCurrentTransport();
+            } catch (RemoteException e) {
+                Log.e(TAG, "getCurrentTransport() couldn't connect");
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Request a list of all available backup transports' names.  Callers must
+     * hold the android.permission.BACKUP permission to use this method.
+     *
+     * @hide
+     */
+    @SystemApi
+    public String[] listAllTransports() {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                return sService.listAllTransports();
+            } catch (RemoteException e) {
+                Log.e(TAG, "listAllTransports() couldn't connect");
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Specify the current backup transport.  Callers must hold the
+     * android.permission.BACKUP permission to use this method.
+     *
+     * @param transport The name of the transport to select.  This should be one
+     *   of the names returned by {@link #listAllTransports()}.
+     * @return The name of the previously selected transport.  If the given transport
+     *   name is not one of the currently available transports, no change is made to
+     *   the current transport setting and the method returns null.
+     *
+     * @hide
+     */
+    @SystemApi
+    public String selectBackupTransport(String transport) {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                return sService.selectBackupTransport(transport);
+            } catch (RemoteException e) {
+                Log.e(TAG, "selectBackupTransport() couldn't connect");
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Schedule an immediate backup attempt for all pending key/value updates.  This
+     * is primarily intended for transports to use when they detect a suitable
+     * opportunity for doing a backup pass.  If there are no pending updates to
+     * be sent, no action will be taken.  Even if some updates are pending, the
+     * transport will still be asked to confirm via the usual requestBackupTime()
+     * method.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void backupNow() {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                sService.backupNow();
+            } catch (RemoteException e) {
+                Log.e(TAG, "backupNow() couldn't connect");
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 446c03e..dc3bbc0 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.SystemApi;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
 import android.os.IBinder;
@@ -30,6 +31,7 @@
  *
  * @hide
  */
+@SystemApi
 public class BackupTransport {
     // Zero return always means things are okay.  If returned from
     // getNextFullRestoreDataChunk(), it means that no data could be delivered at
diff --git a/core/java/android/app/backup/RestoreDescription.java b/core/java/android/app/backup/RestoreDescription.java
index 50ab0b4..611ff07 100644
--- a/core/java/android/app/backup/RestoreDescription.java
+++ b/core/java/android/app/backup/RestoreDescription.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -28,6 +29,7 @@
  *
  * @hide
  */
+@SystemApi
 public class RestoreDescription implements Parcelable {
     private final String mPackageName;
     private final int mDataType;
diff --git a/core/java/android/app/backup/RestoreSession.java b/core/java/android/app/backup/RestoreSession.java
index 7181c61..0a885b6 100644
--- a/core/java/android/app/backup/RestoreSession.java
+++ b/core/java/android/app/backup/RestoreSession.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.SystemApi;
 import android.app.backup.RestoreObserver;
 import android.app.backup.RestoreSet;
 import android.app.backup.IRestoreObserver;
@@ -30,6 +31,7 @@
  * Interface for managing a restore session.
  * @hide
  */
+@SystemApi
 public class RestoreSession {
     static final String TAG = "RestoreSession";
 
diff --git a/core/java/android/app/backup/RestoreSet.java b/core/java/android/app/backup/RestoreSet.java
index 0431977..aacaf7c 100644
--- a/core/java/android/app/backup/RestoreSet.java
+++ b/core/java/android/app/backup/RestoreSet.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -25,6 +26,7 @@
  *
  * @hide
  */
+@SystemApi
 public class RestoreSet implements Parcelable {
     /**
      * Name of this restore set.  May be user generated, may simply be the name
diff --git a/core/java/android/app/trust/ITrustListener.aidl b/core/java/android/app/trust/ITrustListener.aidl
index 45a066d..d80f58c 100644
--- a/core/java/android/app/trust/ITrustListener.aidl
+++ b/core/java/android/app/trust/ITrustListener.aidl
@@ -22,6 +22,6 @@
  * {@hide}
  */
 oneway interface ITrustListener {
-    void onTrustChanged(boolean enabled, int userId);
+    void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser);
     void onTrustManagedChanged(boolean managed, int userId);
 }
\ No newline at end of file
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 796e3cc..3d262b1 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -34,6 +34,7 @@
     private static final int MSG_TRUST_MANAGED_CHANGED = 2;
 
     private static final String TAG = "TrustManager";
+    private static final String DATA_INITIATED_BY_USER = "initiatedByUser";
 
     private final ITrustManager mService;
     private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
@@ -95,14 +96,17 @@
         try {
             ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
                 @Override
-                public void onTrustChanged(boolean enabled, int userId) throws RemoteException {
-                    mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
-                            trustListener).sendToTarget();
+                public void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser) {
+                    Message m = mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
+                            trustListener);
+                    if (initiatedByUser) {
+                        m.getData().putBoolean(DATA_INITIATED_BY_USER, initiatedByUser);
+                    }
+                    m.sendToTarget();
                 }
 
                 @Override
-                public void onTrustManagedChanged(boolean managed, int userId)
-                        throws RemoteException {
+                public void onTrustManagedChanged(boolean managed, int userId) {
                     mHandler.obtainMessage(MSG_TRUST_MANAGED_CHANGED, (managed ? 1 : 0), userId,
                             trustListener).sendToTarget();
                 }
@@ -139,7 +143,11 @@
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case MSG_TRUST_CHANGED:
-                    ((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2);
+                    boolean initiatedByUser = msg.peekData() != null &&
+                            msg.peekData().getBoolean(DATA_INITIATED_BY_USER);
+                    ((TrustListener)msg.obj).onTrustChanged(
+                            msg.arg1 != 0, msg.arg2, initiatedByUser);
+
                     break;
                 case MSG_TRUST_MANAGED_CHANGED:
                     ((TrustListener)msg.obj).onTrustManagedChanged(msg.arg1 != 0, msg.arg2);
@@ -153,8 +161,10 @@
          * Reports that the trust state has changed.
          * @param enabled if true, the system believes the environment to be trusted.
          * @param userId the user, for which the trust changed.
+         * @param initiatedByUser indicates that the user has explicitly initiated an action that
+         *                        proves the user is about to use the device.
          */
-        void onTrustChanged(boolean enabled, int userId);
+        void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser);
 
         /**
          * Reports that whether trust is managed has changed
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index e7b68f5..66a6eb6 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -32,7 +32,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
 import android.widget.RemoteViews;
@@ -57,7 +56,6 @@
     private DisplayMetrics mDisplayMetrics;
 
     Context mContext;
-    String mPackageName;
     Handler mHandler;
     int mHostId;
     Callbacks mCallbacks = new Callbacks();
@@ -154,10 +152,7 @@
         int[] updatedIds;
         ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
         try {
-            if (mPackageName == null) {
-                mPackageName = mContext.getPackageName();
-            }
-            updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId,
+            updatedIds = sService.startListening(mCallbacks, mContext.getPackageName(), mHostId,
                     updatedViews);
         }
         catch (RemoteException e) {
@@ -176,7 +171,7 @@
      */
     public void stopListening() {
         try {
-            sService.stopListening(mPackageName, mHostId);
+            sService.stopListening(mContext.getPackageName(), mHostId);
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -194,10 +189,7 @@
      */
     public int allocateAppWidgetId() {
         try {
-            if (mPackageName == null) {
-                mPackageName = mContext.getPackageName();
-            }
-            return sService.allocateAppWidgetId(mPackageName, mHostId);
+            return sService.allocateAppWidgetId(mContext.getPackageName(), mHostId);
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -326,7 +318,7 @@
         }
         RemoteViews views;
         try {
-            views = sService.getAppWidgetViews(mPackageName, appWidgetId);
+            views = sService.getAppWidgetViews(mContext.getPackageName(), appWidgetId);
         } catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
         }
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index e4dad5a..6835368 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -20,13 +20,11 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.content.ComponentName;
 import android.os.UserHandle;
-import android.os.UserManager;
 
 /**
  * Describes the meta data for an installed AppWidget provider.  The fields in this class
@@ -166,10 +164,7 @@
      *
      * <p>This field corresponds to the <code>android:icon</code> attribute in
      * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
-     *
-     * @deprecated Use {@link #loadIcon(android.content.Context, int)}.
      */
-    @Deprecated
     public int icon;
 
     /**
@@ -186,10 +181,7 @@
      *
      * <p>This field corresponds to the <code>android:previewImage</code> attribute in
      * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
-     *
-     * @deprecated User {@link #loadPreviewImage(android.content.Context, int)}.
      */
-    @Deprecated
     public int previewImage;
 
     /**
@@ -271,16 +263,11 @@
      * The loaded icon corresponds to the <code>android:icon</code> attribute in
      * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
      * </p>
-     * <p>
-     * <strong>Note:</strong> If you care about widgets from different profiles, you
-     * should use this method to load the icon as the system will apply the correct
-     * badging when applicable, so the user knows which profile a widget comes from.
-     * </p>
      *
      * @param context Context for accessing resources.
      * @param density The optional desired density as per
      *         {@link android.util.DisplayMetrics#densityDpi}.
-     * @return The potentially badged provider icon.
+     * @return The provider icon.
      */
     public final Drawable loadIcon(Context context, int density) {
         return loadDrawable(context, density, providerInfo.getIconResource());
@@ -296,19 +283,12 @@
      * The loaded image corresponds to the <code>android:previewImage</code> attribute
      * in the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
      * </p>
-     * <p>
-     * <strong>Note:</strong> If you care about widgets from different profiles, you
-     * should use this method to load the preview image as the system will apply the
-     * correct badging when applicable, so the user knows which profile a previewed
-     * widget comes from.
-     * </p>
      *
      * @param context Context for accessing resources.
      * @param density The optional desired density as per
      *         {@link android.util.DisplayMetrics#densityDpi}.
-     * @return The potentially badged widget preview image.
+     * @return The widget preview image.
      */
-    @SuppressWarnings("deprecation")
     public final Drawable loadPreviewImage(Context context, int density) {
         return loadDrawable(context, density, previewImage);
     }
@@ -384,27 +364,16 @@
         try {
             Resources resources = context.getPackageManager().getResourcesForApplication(
                     providerInfo.applicationInfo);
-
-            final Drawable drawable;
             if (resourceId > 0) {
                 if (density <= 0) {
                     density = context.getResources().getDisplayMetrics().densityDpi;
                 }
-                drawable = resources.getDrawableForDensity(resourceId, density);
-            } else {
-                drawable = providerInfo.loadIcon(context.getPackageManager());
-            }
-
-            if (drawable instanceof BitmapDrawable) {
-                UserManager userManager = (UserManager) context.getSystemService(
-                        Context.USER_SERVICE);
-                return userManager.getBadgedDrawableForUser(drawable, getProfile());
+                return resources.getDrawableForDensity(resourceId, density);
             }
         } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
             /* ignore */
         }
-
-        return null;
+        return providerInfo.loadIcon(context.getPackageManager());
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
index 0eb9d21..da992f5 100644
--- a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
+++ b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
@@ -124,8 +124,7 @@
     }
 
     @Override
-    public void onFoundOrLost(boolean onFound, String address, int rssi, byte[] advData)
-            throws RemoteException {
+    public void onFoundOrLost(boolean onFound, ScanResult scanResult) throws RemoteException {
     }
 
 }
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index f14cce0..00b6b1b 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -69,6 +69,5 @@
                                   in AdvertiseSettings advertiseSettings);
     void onConfigureMTU(in String address, in int mtu, in int status);
     void onConnectionCongested(in String address, in boolean congested);
-    void onFoundOrLost(in boolean onFound, in String address, in int rssi,
-                             in byte[] advData);
+    void onFoundOrLost(in boolean onFound, in ScanResult scanResult);
 }
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 45e466f..6667cc4 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -322,22 +322,27 @@
         }
 
         @Override
-        public void onFoundOrLost(boolean onFound, String address, int rssi,
-                byte[] advData) {
+        public void onFoundOrLost(final boolean onFound, final ScanResult scanResult) {
             if (DBG) {
-                Log.d(TAG, "onFoundOrLost() - Device=" + address);
+                Log.d(TAG, "onFoundOrLost() - onFound = " + onFound +
+                        " " + scanResult.toString());
             }
-            // ToDo: Fix issue with underlying reporting from chipset
-            BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
-                    address);
-            long scanNanos = SystemClock.elapsedRealtimeNanos();
-            ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(advData), rssi,
-                    scanNanos);
-            if (onFound) {
-                mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH, result);
-            } else {
-                mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST, result);
+
+            // Check null in case the scan has been stopped
+            synchronized (this) {
+                if (mClientIf <= 0) return;
             }
+            Handler handler = new Handler(Looper.getMainLooper());
+            handler.post(new Runnable() {
+                    @Override
+                public void run() {
+                    if (onFound) {
+                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH, scanResult);
+                    } else {
+                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST, scanResult);
+                    }
+                }
+            });
         }
     }
 
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7417208..5f046c5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2616,6 +2616,7 @@
      *
      * @see #getSystemService
      */
+    @SystemApi
     public static final String BACKUP_SERVICE = "backup";
 
     /**
diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl b/core/java/android/content/pm/IPackageDeleteObserver2.aidl
similarity index 71%
copy from core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl
copy to core/java/android/content/pm/IPackageDeleteObserver2.aidl
index 1615910..bff3baa 100644
--- a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl
+++ b/core/java/android/content/pm/IPackageDeleteObserver2.aidl
@@ -14,6 +14,12 @@
  * limitations under the License.
  */
 
-package android.hardware.hdmi;
+package android.content.pm;
 
-parcelable HdmiCecDeviceInfo;
+import android.content.Intent;
+
+/** {@hide} */
+oneway interface IPackageDeleteObserver2 {
+    void onUserActionRequired(in Intent intent);
+    void onPackageDeleted(String packageName, int returnCode, String msg);
+}
diff --git a/core/java/android/content/pm/IPackageInstallObserver2.aidl b/core/java/android/content/pm/IPackageInstallObserver2.aidl
index 824d730..bb5f22a 100644
--- a/core/java/android/content/pm/IPackageInstallObserver2.aidl
+++ b/core/java/android/content/pm/IPackageInstallObserver2.aidl
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import android.content.IntentSender;
+import android.content.Intent;
 import android.os.Bundle;
 
 /**
@@ -25,6 +25,8 @@
  * @hide
  */
 oneway interface IPackageInstallObserver2 {
+    void onUserActionRequired(in Intent intent);
+
     /**
      * The install operation has completed.  {@code returnCode} holds a numeric code
      * indicating success or failure.  In certain cases the {@code extras} Bundle will
@@ -40,5 +42,5 @@
      * </tr>
      * </table>
      */
-    void packageInstalled(String basePackageName, in Bundle extras, int returnCode, String msg);
+    void onPackageInstalled(String basePackageName, int returnCode, String msg, in Bundle extras);
 }
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 0c65034..cc0d569 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -16,12 +16,11 @@
 
 package android.content.pm;
 
-import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageDeleteObserver2;
 import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
 import android.content.pm.InstallSessionInfo;
 import android.content.pm.InstallSessionParams;
-import android.os.ParcelFileDescriptor;
 
 /** {@hide} */
 interface IPackageInstaller {
@@ -35,6 +34,6 @@
     void registerCallback(IPackageInstallerCallback callback, int userId);
     void unregisterCallback(IPackageInstallerCallback callback);
 
-    void uninstall(String packageName, int flags, in IPackageDeleteObserver observer, int userId);
-    void uninstallSplit(String packageName, String splitName, int flags, in IPackageDeleteObserver observer, int userId);
+    void uninstall(String packageName, int flags, in IPackageDeleteObserver2 observer, int userId);
+    void uninstallSplit(String packageName, String splitName, int flags, in IPackageDeleteObserver2 observer, int userId);
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 2d6d3c9..44478d4 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -24,10 +24,10 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.FeatureInfo;
-import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageDeleteObserver2;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
@@ -202,6 +202,10 @@
 
     void setInstallerPackageName(in String targetPackage, in String installerPackageName);
 
+    /** @deprecated rawr, don't call AIDL methods directly! */
+    void deletePackageAsUser(in String packageName, IPackageDeleteObserver observer,
+            int userId, int flags);
+
     /**
      * Delete a package for a specific user.
      *
@@ -210,8 +214,7 @@
      * @param userId the id of the user for whom to delete the package
      * @param flags - possible values: {@link #DONT_DELETE_DATA}
      */
-    void deletePackageAsUser(in String packageName, IPackageDeleteObserver observer,
-            int userId, int flags);
+    void deletePackage(in String packageName, IPackageDeleteObserver2 observer, int userId, int flags);
 
     String getInstallerPackageName(in String packageName);
 
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 5d48868..0cff08b 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -179,8 +179,7 @@
         }
 
         if (originalIcon instanceof BitmapDrawable) {
-            return mUm.getBadgedDrawableForUser(
-                    originalIcon, mUser);
+            return mUm.getBadgedIconForUser(originalIcon, mUser);
         } else {
             Log.e(TAG, "Unable to create badged icon for " + mActivityInfo);
         }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8c37e9e..268919c 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -210,20 +210,6 @@
      * Starts an activity in the specified profile.
      *
      * @param component The ComponentName of the activity to launch
-     * @param sourceBounds The Rect containing the source bounds of the clicked icon
-     * @param opts Options to pass to startActivity
-     * @param user The UserHandle of the profile
-     * @hide remove before ship
-     */
-    public void startActivityForProfile(ComponentName component, Rect sourceBounds,
-            Bundle opts, UserHandle user) {
-        startActivityForProfile(component, user, sourceBounds, opts);
-    }
-
-    /**
-     * Starts an activity in the specified profile.
-     *
-     * @param component The ComponentName of the activity to launch
      * @param user The UserHandle of the profile
      * @param sourceBounds The Rect containing the source bounds of the clicked icon
      * @param opts Options to pass to startActivity
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 299afff..01c080d 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -20,8 +20,9 @@
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
-import android.app.PackageUninstallObserver;
+import android.content.Intent;
 import android.os.Bundle;
 import android.os.FileBridge;
 import android.os.Handler;
@@ -536,15 +537,25 @@
     }
 
     /**
-     * Final result of an uninstall request.
+     * Events for a specific uninstall request.
      */
     public static abstract class UninstallCallback {
+        /**
+         * User action is required to proceed. You can start the given intent
+         * activity to involve the user and continue.
+         * <p>
+         * You may choose to immediately launch the intent if the user is
+         * actively using your app. However, you should use a notification to
+         * guide the user back into your app if not currently active.
+         */
+        public abstract void onUserActionRequired(Intent intent);
+
         public abstract void onSuccess();
         public abstract void onFailure(String msg);
     }
 
     /** {@hide} */
-    private static class UninstallCallbackDelegate extends PackageUninstallObserver {
+    private static class UninstallCallbackDelegate extends PackageDeleteObserver {
         private final UninstallCallback target;
 
         public UninstallCallbackDelegate(UninstallCallback target) {
@@ -552,11 +563,16 @@
         }
 
         @Override
-        public void onUninstallFinished(String basePackageName, int returnCode) {
+        public void onUserActionRequired(Intent intent) {
+            target.onUserActionRequired(intent);
+        }
+
+        @Override
+        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
             if (returnCode == PackageManager.DELETE_SUCCEEDED) {
                 target.onSuccess();
             } else {
-                final String msg = PackageManager.deleteStatusToString(returnCode);
+                msg = PackageManager.deleteStatusToString(returnCode) + ": " + msg;
                 target.onFailure(msg);
             }
         }
@@ -612,6 +628,16 @@
 
         public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
 
+        /**
+         * User action is required to proceed. You can start the given intent
+         * activity to involve the user and continue.
+         * <p>
+         * You may choose to immediately launch the intent if the user is
+         * actively using your app. However, you should use a notification to
+         * guide the user back into your app if not currently active.
+         */
+        public abstract void onUserActionRequired(Intent intent);
+
         public abstract void onSuccess();
         public abstract void onFailure(int failureReason, String msg, Bundle extras);
     }
@@ -625,8 +651,13 @@
         }
 
         @Override
-        public void packageInstalled(String basePackageName, Bundle extras, int returnCode,
-                String msg) {
+        public void onUserActionRequired(Intent intent) {
+            target.onUserActionRequired(intent);
+        }
+
+        @Override
+        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+                Bundle extras) {
             if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
                 target.onSuccess();
             } else {
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index c461511..6a9d565 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -130,15 +130,6 @@
     public abstract String getId();
 
     /**
-     * <p>Set up a new output set of Surfaces for the camera device.</p>
-     *
-     * @deprecated Use {@link #createCaptureSession} instead
-     * @hide
-     */
-    @Deprecated
-    public abstract void configureOutputs(List<Surface> outputs) throws CameraAccessException;
-
-    /**
      * <p>Create a new camera capture session by providing the target output set of Surfaces to the
      * camera device.</p>
      *
@@ -276,68 +267,6 @@
             throws CameraAccessException;
 
     /**
-     * <p>Submit a request for an image to be captured by this CameraDevice.</p>
-     *
-     * @deprecated Use {@link CameraCaptureSession#capture} instead
-     * @hide
-     */
-    @Deprecated
-    public abstract int capture(CaptureRequest request, CaptureListener listener, Handler handler)
-            throws CameraAccessException;
-
-    /**
-     * Submit a list of requests to be captured in sequence as a burst.
-     *
-     * @deprecated Use {@link CameraCaptureSession#captureBurst} instead
-     * @hide
-     */
-    @Deprecated
-    public abstract int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
-            Handler handler) throws CameraAccessException;
-
-    /**
-     * Request endlessly repeating capture of images by this CameraDevice.
-     *
-     * @deprecated Use {@link CameraCaptureSession#setRepeatingRequest} instead
-     * @hide
-     */
-    @Deprecated
-    public abstract int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
-            Handler handler) throws CameraAccessException;
-
-    /**
-     * <p>Request endlessly repeating capture of a sequence of images by this
-     * CameraDevice.</p>
-     *
-     * @deprecated Use {@link CameraCaptureSession#setRepeatingBurst} instead
-     * @hide
-     */
-    @Deprecated
-    public abstract int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
-            Handler handler) throws CameraAccessException;
-
-    /**
-     * <p>Cancel any ongoing repeating capture set by either
-     * {@link #setRepeatingRequest setRepeatingRequest} or
-     * {@link #setRepeatingBurst}.
-     *
-     * @deprecated Use {@link CameraCaptureSession#stopRepeating} instead
-     * @hide
-     */
-    @Deprecated
-    public abstract void stopRepeating() throws CameraAccessException;
-
-    /**
-     * Flush all captures currently pending and in-progress as fast as
-     * possible.
-     *
-     * @deprecated Use {@link CameraCaptureSession#abortCaptures} instead
-     * @hide
-     */
-    @Deprecated
-    public abstract void flush() throws CameraAccessException;
-
-    /**
      * Close the connection to this camera device as quickly as possible.
      *
      * <p>Immediately after this call, all calls to the camera device or active session interface
@@ -356,96 +285,6 @@
     public abstract void close();
 
     /**
-     * <p>A listener for tracking the progress of a {@link CaptureRequest}
-     * submitted to the camera device.</p>
-     *
-     * @deprecated Use {@link CameraCaptureSession.CaptureListener} instead
-     * @hide
-     */
-    @Deprecated
-    public static abstract class CaptureListener {
-
-        /**
-         * This constant is used to indicate that no images were captured for
-         * the request.
-         *
-         * @hide
-         */
-        public static final int NO_FRAMES_CAPTURED = -1;
-
-        /**
-         * This method is called when the camera device has started capturing
-         * the output image for the request, at the beginning of image exposure.
-         *
-         * @see android.media.MediaActionSound
-         */
-        public void onCaptureStarted(CameraDevice camera,
-                CaptureRequest request, long timestamp) {
-            // default empty implementation
-        }
-
-        /**
-         * This method is called when some results from an image capture are
-         * available.
-         *
-         * @hide
-         */
-        public void onCapturePartial(CameraDevice camera,
-                CaptureRequest request, CaptureResult result) {
-            // default empty implementation
-        }
-
-        /**
-         * This method is called when an image capture makes partial forward progress; some
-         * (but not all) results from an image capture are available.
-         *
-         */
-        public void onCaptureProgressed(CameraDevice camera,
-                CaptureRequest request, CaptureResult partialResult) {
-            // default empty implementation
-        }
-
-        /**
-         * This method is called when an image capture has fully completed and all the
-         * result metadata is available.
-         */
-        public void onCaptureCompleted(CameraDevice camera,
-                CaptureRequest request, TotalCaptureResult result) {
-            // default empty implementation
-        }
-
-        /**
-         * This method is called instead of {@link #onCaptureCompleted} when the
-         * camera device failed to produce a {@link CaptureResult} for the
-         * request.
-         */
-        public void onCaptureFailed(CameraDevice camera,
-                CaptureRequest request, CaptureFailure failure) {
-            // default empty implementation
-        }
-
-        /**
-         * This method is called independently of the others in CaptureListener,
-         * when a capture sequence finishes and all {@link CaptureResult}
-         * or {@link CaptureFailure} for it have been returned via this listener.
-         */
-        public void onCaptureSequenceCompleted(CameraDevice camera,
-                int sequenceId, long frameNumber) {
-            // default empty implementation
-        }
-
-        /**
-         * This method is called independently of the others in CaptureListener,
-         * when a capture sequence aborts before any {@link CaptureResult}
-         * or {@link CaptureFailure} for it have been returned via this listener.
-         */
-        public void onCaptureSequenceAborted(CameraDevice camera,
-                int sequenceId) {
-            // default empty implementation
-        }
-    }
-
-    /**
      * A listener for notifications about the state of a camera
      * device.
      *
@@ -542,40 +381,6 @@
         public abstract void onOpened(CameraDevice camera); // Must implement
 
         /**
-         * The method called when a camera device has no outputs configured.
-         *
-         * @deprecated Use {@link #onOpened} instead.
-         * @hide
-         */
-        @Deprecated
-        public void onUnconfigured(CameraDevice camera) {
-            // Default empty implementation
-        }
-
-        /**
-         * The method called when a camera device begins processing
-         * {@link CaptureRequest capture requests}.
-         *
-         * @deprecated Use {@link CameraCaptureSession.StateListener#onActive} instead.
-         * @hide
-         */
-        @Deprecated
-        public void onActive(CameraDevice camera) {
-            // Default empty implementation
-        }
-
-        /**
-         * The method called when a camera device is busy.
-         *
-         * @deprecated Use {@link CameraCaptureSession.StateListener#onConfigured} instead.
-         * @hide
-         */
-        @Deprecated
-        public void onBusy(CameraDevice camera) {
-            // Default empty implementation
-        }
-
-        /**
          * The method called when a camera device has been closed with
          * {@link CameraDevice#close}.
          *
@@ -591,18 +396,6 @@
         }
 
         /**
-         * The method called when a camera device has finished processing all
-         * submitted capture requests and has reached an idle state.
-         *
-         * @deprecated Use {@link CameraCaptureSession.StateListener#onReady} instead.
-         * @hide
-         */
-        @Deprecated
-        public void onIdle(CameraDevice camera) {
-            // Default empty implementation
-        }
-
-        /**
          * The method called when a camera device is no longer available for
          * use.
          *
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index f829f5e..a15028c 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -103,7 +103,7 @@
          * Use the same handler as the device's StateListener for all the internal coming events
          *
          * This ensures total ordering between CameraDevice.StateListener and
-         * CameraDevice.CaptureListener events.
+         * CameraDeviceImpl.CaptureListener events.
          */
         mSequenceDrainer = new TaskDrainer<>(mDeviceHandler, new SequenceDrainListener(),
                 /*name*/"seq");
@@ -141,7 +141,7 @@
         checkNotClosed();
         checkLegalToCapture();
 
-        handler = checkHandler(handler);
+        handler = checkHandler(handler, listener);
 
         if (VERBOSE) {
             Log.v(TAG, "capture - request " + request + ", listener " + listener + " handler" +
@@ -164,7 +164,7 @@
         checkNotClosed();
         checkLegalToCapture();
 
-        handler = checkHandler(handler);
+        handler = checkHandler(handler, listener);
 
         if (VERBOSE) {
             CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]);
@@ -186,7 +186,7 @@
         checkNotClosed();
         checkLegalToCapture();
 
-        handler = checkHandler(handler);
+        handler = checkHandler(handler, listener);
 
         if (VERBOSE) {
             Log.v(TAG, "setRepeatingRequest - request " + request + ", listener " + listener +
@@ -209,7 +209,7 @@
         checkNotClosed();
         checkLegalToCapture();
 
-        handler = checkHandler(handler);
+        handler = checkHandler(handler, listener);
 
         if (VERBOSE) {
             CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]);
@@ -261,9 +261,12 @@
      * <p>The semantics are identical to {@link #close}, except that unconfiguring will be skipped.
      * <p>
      *
+     * <p>After this call completes, the session will not call any further methods on the camera
+     * device.</p>
+     *
      * @see CameraCaptureSession#close
      */
-    synchronized void replaceSessionClose(CameraCaptureSession other) {
+    synchronized void replaceSessionClose() {
         /*
          * In order for creating new sessions to be fast, the new session should be created
          * before the old session is closed.
@@ -278,13 +281,17 @@
 
         if (VERBOSE) Log.v(TAG, "replaceSessionClose");
 
-        // #close was already called explicitly, keep going the slow route
-        if (mClosed) {
-            if (VERBOSE) Log.v(TAG, "replaceSessionClose - close was already called");
-            return;
-        }
-
+        // Set up fast shutdown. Possible alternative paths:
+        // - This session is active, so close() below starts the shutdown drain
+        // - This session is mid-shutdown drain, and hasn't yet reached the idle drain listener.
+        // - This session is already closed and has executed the idle drain listener, and
+        //   configureOutputs(null) has already been called.
+        //
+        // Do not call configureOutputs(null) going forward, since it would race with the
+        // configuration for the new session. If it was already called, then we don't care, since it
+        // won't get called again.
         mSkipUnconfigure = true;
+
         close();
     }
 
@@ -347,7 +354,7 @@
 
     /**
      * Forward callbacks from
-     * CameraDevice.CaptureListener to the CameraCaptureSession.CaptureListener.
+     * CameraDeviceImpl.CaptureListener to the CameraCaptureSession.CaptureListener.
      *
      * <p>In particular, all calls are automatically split to go both to our own
      * internal listener, and to the user-specified listener (by transparently posting
@@ -356,9 +363,9 @@
      * <p>When a capture sequence finishes, update the pending checked sequences set.</p>
      */
     @SuppressWarnings("deprecation")
-    private CameraDevice.CaptureListener createCaptureListenerProxy(
+    private CameraDeviceImpl.CaptureListener createCaptureListenerProxy(
             Handler handler, CaptureListener listener) {
-        CameraDevice.CaptureListener localListener = new CameraDevice.CaptureListener() {
+        CameraDeviceImpl.CaptureListener localListener = new CameraDeviceImpl.CaptureListener() {
             @Override
             public void onCaptureSequenceCompleted(CameraDevice camera,
                     int sequenceId, long frameNumber) {
@@ -379,27 +386,30 @@
          * - then forward the call to a handler
          * - then finally invoke the destination method on the session listener object
          */
-        Dispatchable<CaptureListener> userListenerSink;
-        if (listener == null) { // OK: API allows the user to not specify a listener
-            userListenerSink = new NullDispatcher<>();
-        } else {
-            userListenerSink = new InvokeDispatcher<>(listener);
+        if (listener == null) {
+            // OK: API allows the user to not specify a listener, and the handler may
+            // also be null in that case. Collapse whole dispatch chain to only call the local
+            // listener
+            return localListener;
         }
 
-        InvokeDispatcher<CameraDevice.CaptureListener> localSink =
+        InvokeDispatcher<CameraDeviceImpl.CaptureListener> localSink =
                 new InvokeDispatcher<>(localListener);
+
+        InvokeDispatcher<CaptureListener> userListenerSink =
+                new InvokeDispatcher<>(listener);
         HandlerDispatcher<CaptureListener> handlerPassthrough =
                 new HandlerDispatcher<>(userListenerSink, handler);
-        DuckTypingDispatcher<CameraDevice.CaptureListener, CaptureListener> duckToSession
+        DuckTypingDispatcher<CameraDeviceImpl.CaptureListener, CaptureListener> duckToSession
                 = new DuckTypingDispatcher<>(handlerPassthrough, CaptureListener.class);
-        ArgumentReplacingDispatcher<CameraDevice.CaptureListener, CameraCaptureSessionImpl>
-            replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession,
-                    /*argumentIndex*/0, this);
+        ArgumentReplacingDispatcher<CameraDeviceImpl.CaptureListener, CameraCaptureSessionImpl>
+                replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession,
+                        /*argumentIndex*/0, this);
 
-        BroadcastDispatcher<CameraDevice.CaptureListener> broadcaster =
-                new BroadcastDispatcher<CameraDevice.CaptureListener>(
-                        replaceDeviceWithSession,
-                        localSink);
+        BroadcastDispatcher<CameraDeviceImpl.CaptureListener> broadcaster =
+                new BroadcastDispatcher<CameraDeviceImpl.CaptureListener>(
+                    replaceDeviceWithSession,
+                    localSink);
 
         return new ListenerProxies.DeviceCaptureListenerProxy(broadcaster);
     }
@@ -415,10 +425,10 @@
      * </ul>
      * </p>
      * */
-    CameraDevice.StateListener getDeviceStateListener() {
+    CameraDeviceImpl.StateListenerKK getDeviceStateListener() {
         final CameraCaptureSession session = this;
 
-        return new CameraDevice.StateListener() {
+        return new CameraDeviceImpl.StateListenerKK() {
             private boolean mBusy = false;
             private boolean mActive = false;
 
@@ -596,6 +606,8 @@
                  *
                  * This operation is idempotent; a session will not be closed twice.
                  */
+                if (VERBOSE) Log.v(TAG, "Session drain complete, skip unconfigure: " +
+                        mSkipUnconfigure);
 
                 // Fast path: A new capture session has replaced this one; don't unconfigure.
                 if (mSkipUnconfigure) {
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 18b1202..71eb0e9 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -21,8 +21,10 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.TotalCaptureResult;
@@ -47,7 +49,7 @@
 /**
  * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
  */
-public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
+public class CameraDeviceImpl extends CameraDevice {
 
     private final String TAG;
     private final boolean DEBUG;
@@ -62,7 +64,7 @@
     private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
 
     private final StateListener mDeviceListener;
-    private volatile StateListener mSessionStateListener;
+    private volatile StateListenerKK mSessionStateListener;
     private final Handler mDeviceHandler;
 
     private volatile boolean mClosing = false;
@@ -103,7 +105,7 @@
     private final Runnable mCallOnOpened = new Runnable() {
         @Override
         public void run() {
-            StateListener sessionListener = null;
+            StateListenerKK sessionListener = null;
             synchronized(mInterfaceLock) {
                 if (mRemoteDevice == null) return; // Camera already closed
 
@@ -119,7 +121,7 @@
     private final Runnable mCallOnUnconfigured = new Runnable() {
         @Override
         public void run() {
-            StateListener sessionListener = null;
+            StateListenerKK sessionListener = null;
             synchronized(mInterfaceLock) {
                 if (mRemoteDevice == null) return; // Camera already closed
 
@@ -128,14 +130,13 @@
             if (sessionListener != null) {
                 sessionListener.onUnconfigured(CameraDeviceImpl.this);
             }
-            mDeviceListener.onUnconfigured(CameraDeviceImpl.this);
         }
     };
 
     private final Runnable mCallOnActive = new Runnable() {
         @Override
         public void run() {
-            StateListener sessionListener = null;
+            StateListenerKK sessionListener = null;
             synchronized(mInterfaceLock) {
                 if (mRemoteDevice == null) return; // Camera already closed
 
@@ -144,14 +145,13 @@
             if (sessionListener != null) {
                 sessionListener.onActive(CameraDeviceImpl.this);
             }
-            mDeviceListener.onActive(CameraDeviceImpl.this);
         }
     };
 
     private final Runnable mCallOnBusy = new Runnable() {
         @Override
         public void run() {
-            StateListener sessionListener = null;
+            StateListenerKK sessionListener = null;
             synchronized(mInterfaceLock) {
                 if (mRemoteDevice == null) return; // Camera already closed
 
@@ -160,7 +160,6 @@
             if (sessionListener != null) {
                 sessionListener.onBusy(CameraDeviceImpl.this);
             }
-            mDeviceListener.onBusy(CameraDeviceImpl.this);
         }
     };
 
@@ -172,7 +171,7 @@
             if (mClosedOnce) {
                 throw new AssertionError("Don't post #onClosed more than once");
             }
-            StateListener sessionListener = null;
+            StateListenerKK sessionListener = null;
             synchronized(mInterfaceLock) {
                 sessionListener = mSessionStateListener;
             }
@@ -187,7 +186,7 @@
     private final Runnable mCallOnIdle = new Runnable() {
         @Override
         public void run() {
-            StateListener sessionListener = null;
+            StateListenerKK sessionListener = null;
             synchronized(mInterfaceLock) {
                 if (mRemoteDevice == null) return; // Camera already closed
 
@@ -196,14 +195,13 @@
             if (sessionListener != null) {
                 sessionListener.onIdle(CameraDeviceImpl.this);
             }
-            mDeviceListener.onIdle(CameraDeviceImpl.this);
         }
     };
 
     private final Runnable mCallOnDisconnected = new Runnable() {
         @Override
         public void run() {
-            StateListener sessionListener = null;
+            StateListenerKK sessionListener = null;
             synchronized(mInterfaceLock) {
                 if (mRemoteDevice == null) return; // Camera already closed
 
@@ -313,7 +311,6 @@
         return mCameraId;
     }
 
-    @Override
     public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
         // Treat a null input the same an empty list
         if (outputs == null) {
@@ -390,7 +387,11 @@
 
             checkIfCameraClosedOrInError();
 
-            // TODO: we must be in UNCONFIGURED mode to begin with, or using another session
+            // Notify current session that it's going away, before starting camera operations
+            // After this call completes, the session is not allowed to call into CameraDeviceImpl
+            if (mCurrentSession != null) {
+                mCurrentSession.replaceSessionClose();
+            }
 
             // TODO: dont block for this
             boolean configureSuccess = true;
@@ -410,10 +411,6 @@
                     new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
                             configureSuccess);
 
-            if (mCurrentSession != null) {
-                mCurrentSession.replaceSessionClose(newSession);
-            }
-
             // TODO: wait until current session closes, then create the new session
             mCurrentSession = newSession;
 
@@ -425,6 +422,15 @@
         }
     }
 
+    /**
+     * For use by backwards-compatibility code only.
+     */
+    public void setSessionListener(StateListenerKK sessionListener) {
+        synchronized(mInterfaceLock) {
+            mSessionStateListener = sessionListener;
+        }
+    }
+
     @Override
     public CaptureRequest.Builder createCaptureRequest(int templateType)
             throws CameraAccessException {
@@ -449,7 +455,6 @@
         }
     }
 
-    @Override
     public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
             throws CameraAccessException {
         if (DEBUG) {
@@ -460,7 +465,6 @@
         return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
     }
 
-    @Override
     public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
             Handler handler) throws CameraAccessException {
         if (requests == null || requests.isEmpty()) {
@@ -543,9 +547,7 @@
 
         // Need a valid handler, or current thread needs to have a looper, if
         // listener is valid
-        if (listener != null) {
-            handler = checkHandler(handler);
-        }
+        handler = checkHandler(handler, listener);
 
         // Make sure that there all requests have at least 1 surface; all surfaces are non-null
         for (CaptureRequest request : requestList) {
@@ -613,7 +615,6 @@
         }
     }
 
-    @Override
     public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
             Handler handler) throws CameraAccessException {
         List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
@@ -621,7 +622,6 @@
         return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
     }
 
-    @Override
     public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
             Handler handler) throws CameraAccessException {
         if (requests == null || requests.isEmpty()) {
@@ -630,7 +630,6 @@
         return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
     }
 
-    @Override
     public void stopRepeating() throws CameraAccessException {
 
         synchronized(mInterfaceLock) {
@@ -681,7 +680,6 @@
         }
     }
 
-    @Override
     public void flush() throws CameraAccessException {
         synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
@@ -739,6 +737,133 @@
         }
     }
 
+    /**
+     * <p>A listener for tracking the progress of a {@link CaptureRequest}
+     * submitted to the camera device.</p>
+     *
+     */
+    public static abstract class CaptureListener {
+
+        /**
+         * This constant is used to indicate that no images were captured for
+         * the request.
+         *
+         * @hide
+         */
+        public static final int NO_FRAMES_CAPTURED = -1;
+
+        /**
+         * This method is called when the camera device has started capturing
+         * the output image for the request, at the beginning of image exposure.
+         *
+         * @see android.media.MediaActionSound
+         */
+        public void onCaptureStarted(CameraDevice camera,
+                CaptureRequest request, long timestamp) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called when some results from an image capture are
+         * available.
+         *
+         * @hide
+         */
+        public void onCapturePartial(CameraDevice camera,
+                CaptureRequest request, CaptureResult result) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called when an image capture makes partial forward progress; some
+         * (but not all) results from an image capture are available.
+         *
+         */
+        public void onCaptureProgressed(CameraDevice camera,
+                CaptureRequest request, CaptureResult partialResult) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called when an image capture has fully completed and all the
+         * result metadata is available.
+         */
+        public void onCaptureCompleted(CameraDevice camera,
+                CaptureRequest request, TotalCaptureResult result) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called instead of {@link #onCaptureCompleted} when the
+         * camera device failed to produce a {@link CaptureResult} for the
+         * request.
+         */
+        public void onCaptureFailed(CameraDevice camera,
+                CaptureRequest request, CaptureFailure failure) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called independently of the others in CaptureListener,
+         * when a capture sequence finishes and all {@link CaptureResult}
+         * or {@link CaptureFailure} for it have been returned via this listener.
+         */
+        public void onCaptureSequenceCompleted(CameraDevice camera,
+                int sequenceId, long frameNumber) {
+            // default empty implementation
+        }
+
+        /**
+         * This method is called independently of the others in CaptureListener,
+         * when a capture sequence aborts before any {@link CaptureResult}
+         * or {@link CaptureFailure} for it have been returned via this listener.
+         */
+        public void onCaptureSequenceAborted(CameraDevice camera,
+                int sequenceId) {
+            // default empty implementation
+        }
+    }
+
+    /**
+     * A listener for notifications about the state of a camera device, adding in the callbacks that
+     * were part of the earlier KK API design, but now only used internally.
+     */
+    public static abstract class StateListenerKK extends StateListener {
+        /**
+         * The method called when a camera device has no outputs configured.
+         *
+         */
+        public void onUnconfigured(CameraDevice camera) {
+            // Default empty implementation
+        }
+
+        /**
+         * The method called when a camera device begins processing
+         * {@link CaptureRequest capture requests}.
+         *
+         */
+        public void onActive(CameraDevice camera) {
+            // Default empty implementation
+        }
+
+        /**
+         * The method called when a camera device is busy.
+         *
+         */
+        public void onBusy(CameraDevice camera) {
+            // Default empty implementation
+        }
+
+        /**
+         * The method called when a camera device has finished processing all
+         * submitted capture requests and has reached an idle state.
+         *
+         */
+        public void onIdle(CameraDevice camera) {
+            // Default empty implementation
+        }
+    }
+
     static class CaptureListenerHolder {
 
         private final boolean mRepeating;
@@ -1155,6 +1280,18 @@
         return handler;
     }
 
+    /**
+     * Default handler management, conditional on there being a listener.
+     *
+     * <p>If the listener isn't null, check the handler, otherwise pass it through.</p>
+     */
+    static <T> Handler checkHandler(Handler handler, T listener) {
+        if (listener != null) {
+            return checkHandler(handler);
+        }
+        return handler;
+    }
+
     private void checkIfCameraClosedOrInError() throws CameraAccessException {
         if (mInError) {
             throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
diff --git a/core/java/android/hardware/camera2/impl/ListenerProxies.java b/core/java/android/hardware/camera2/impl/ListenerProxies.java
index ab9a4d5..f44f9ad 100644
--- a/core/java/android/hardware/camera2/impl/ListenerProxies.java
+++ b/core/java/android/hardware/camera2/impl/ListenerProxies.java
@@ -36,13 +36,13 @@
 
     // TODO: replace with codegen
 
-    public static class DeviceStateListenerProxy extends CameraDevice.StateListener {
-        private final MethodNameInvoker<CameraDevice.StateListener> mProxy;
+    public static class DeviceStateListenerProxy extends CameraDeviceImpl.StateListenerKK {
+        private final MethodNameInvoker<CameraDeviceImpl.StateListenerKK> mProxy;
 
         public DeviceStateListenerProxy(
-                Dispatchable<CameraDevice.StateListener> dispatchTarget) {
+                Dispatchable<CameraDeviceImpl.StateListenerKK> dispatchTarget) {
             dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
-            mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDevice.StateListener.class);
+            mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.StateListenerKK.class);
         }
 
         @Override
@@ -87,13 +87,13 @@
     }
 
     @SuppressWarnings("deprecation")
-    public static class DeviceCaptureListenerProxy extends CameraDevice.CaptureListener {
-        private final MethodNameInvoker<CameraDevice.CaptureListener> mProxy;
+    public static class DeviceCaptureListenerProxy extends CameraDeviceImpl.CaptureListener {
+        private final MethodNameInvoker<CameraDeviceImpl.CaptureListener> mProxy;
 
         public DeviceCaptureListenerProxy(
-                Dispatchable<CameraDevice.CaptureListener> dispatchTarget) {
+                Dispatchable<CameraDeviceImpl.CaptureListener> dispatchTarget) {
             dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
-            mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDevice.CaptureListener.class);
+            mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.CaptureListener.class);
         }
 
         @Override
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 1efabb1..2e6b9ae 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -813,6 +813,7 @@
         switch (format) {
             case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
             case HAL_PIXEL_FORMAT_BLOB:
+            case HAL_PIXEL_FORMAT_RAW_OPAQUE:
                 return format;
             case ImageFormat.JPEG:
                 throw new IllegalArgumentException(
@@ -843,12 +844,6 @@
      * @throws IllegalArgumentException if the format was not user-defined
      */
     static int checkArgumentFormat(int format) {
-        // TODO: remove this hack , CTS shouldn't have been using internal constants
-        if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
-            Log.w(TAG, "RAW_OPAQUE is not yet a published format; allowing it anyway");
-            return format;
-        }
-
         if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
             throw new IllegalArgumentException(String.format(
                     "format 0x%x was not defined in either ImageFormat or PixelFormat", format));
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index d4e6df5..51b7229 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -96,11 +96,9 @@
      * windows on the display and the system may mirror the contents of other displays
      * onto it.
      * </p><p>
-     * Creating a public virtual display requires the
-     * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
-     * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
-     * These permissions are reserved for use by system components and are not available to
-     * third-party applications.
+     * Creating a public virtual display that isn't restricted to own-content only implicitly
+     * creates an auto-mirroring display. See {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} for
+     * restrictions on who is allowed to create an auto-mirroring display.
      * </p>
      *
      * <h3>Private virtual displays</h3>
@@ -108,6 +106,8 @@
      * When this flag is not set, the virtual display is private as defined by the
      * {@link Display#FLAG_PRIVATE} display flag.
      * </p>
+     *
+     * <p>
      * A private virtual display belongs to the application that created it.
      * Only the a owner of a private virtual display is allowed to place windows upon it.
      * The private virtual display also does not participate in display mirroring: it will
@@ -115,10 +115,11 @@
      * be mirrored elsewhere.  More precisely, the only processes that are allowed to
      * enumerate or interact with the private display are those that have the same UID as the
      * application that originally created the private virtual display.
-      * </p>
+     * </p>
      *
      * @see #createVirtualDisplay
      * @see #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+     * @see #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
      */
     public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0;
 
@@ -187,29 +188,51 @@
      * will be blanked instead if it has no windows.
      * </p>
      *
+     * <p>
+     * This flag is mutually exclusive with {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.  If both
+     * flags are specified then the own-content only behavior will be applied.
+     * </p>
+     *
+     * <p>
+     * This behavior of this flag is implied whenever neither {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}
+     * nor {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} have been set.  This flag is only required to
+     * override the default behavior when creating a public display.
+     * </p>
+     *
      * @see #createVirtualDisplay
      */
     public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 1 << 3;
 
 
     /**
-     * Virtual display flag: Indicates that the display is being created for
-     * the purpose of screen sharing.  This implies
-     * VIRTUAL_DISPLAY_FLAG_PRIVATE.  Other flags are not allowed (especially
-     * not VIRTUAL_DISPLAY_FLAG_PUBLIC or PRESENTATION).
+     * Virtual display flag: Allows content to be mirrored on private displays when no content is
+     * being shown.
      *
      * <p>
-     * Requires screen share permission for use.
+     * This flag is mutually exclusive with {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
+     * If both flags are specified then the own-content only behavior will be applied.
      * </p>
      *
      * <p>
-     * While a display of this type exists, the system will show some sort of
-     * notification to the user indicating that the screen is being shared.
+     * The behavior of this flag is implied whenever {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC} is set
+     * and {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY} has not been set.   This flag is only
+     * required to override the default behavior when creating a private display.
+     * </p>
+     *
+     * <p>
+     * Creating an auto-mirroing virtual display requires the
+     * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
+     * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
+     * These permissions are reserved for use by system components and are not available to
+     * third-party applications.
+     *
+     * Alternatively, an appropriate {@link MediaProjection} may be used to create an
+     * auto-mirroring virtual display.
      * </p>
      *
      * @see #createVirtualDisplay
      */
-    public static final int VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE = 1 << 4;
+    public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 1 << 4;
 
     /** @hide */
     public DisplayManager(Context context) {
@@ -489,7 +512,7 @@
      * @param flags A combination of virtual display flags:
      * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION},
      * {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
-     * or {@link #VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE}.
+     * or {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
      * @param callbacks Callbacks to call when the state of the {@link VirtualDisplay} changes
      * @param handler The handler on which the listener should be invoked, or null
      * if the listener should be invoked on the calling thread's looper.
diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
deleted file mode 100644
index 6e1844a..0000000
--- a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
+++ /dev/null
@@ -1,273 +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 android.hardware.hdmi;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A class to encapsulate device information for HDMI-CEC. This container
- * include basic information such as logical address, physical address and
- * device type, and additional information like vendor id and osd name.
- * Also used to keep the information of non-CEC devices for which only
- * port ID, physical address are meaningful.
- *
- * @hide
- */
-@SystemApi
-public final class HdmiCecDeviceInfo implements Parcelable {
-
-    /** TV device type. */
-    public static final int DEVICE_TV = 0;
-
-    /** Recording device type. */
-    public static final int DEVICE_RECORDER = 1;
-
-    /** Device type reserved for future usage. */
-    public static final int DEVICE_RESERVED = 2;
-
-    /** Tuner device type. */
-    public static final int DEVICE_TUNER = 3;
-
-    /** Playback device type. */
-    public static final int DEVICE_PLAYBACK = 4;
-
-    /** Audio system device type. */
-    public static final int DEVICE_AUDIO_SYSTEM = 5;
-
-    /** @hide Pure CEC switch device type. */
-    public static final int DEVICE_PURE_CEC_SWITCH = 6;
-
-    /** @hide Video processor device type. */
-    public static final int DEVICE_VIDEO_PROCESSOR = 7;
-
-    // Value indicating the device is not an active source.
-    public static final int DEVICE_INACTIVE = -1;
-
-    /**
-     * Logical address used to indicate the source comes from internal device.
-     * The logical address of TV(0) is used.
-     */
-    public static final int ADDR_INTERNAL = 0;
-
-    /**
-     * Physical address used to indicate the source comes from internal device.
-     * The physical address of TV(0) is used.
-     */
-    public static final int PATH_INTERNAL = 0x0000;
-
-    /** Invalid physical address (routing path) */
-    public static final int PATH_INVALID = 0xFFFF;
-
-    /** Invalid port ID */
-    public static final int PORT_INVALID = -1;
-
-    // Logical address, physical address, device type, vendor id and display name
-    // are immutable value.
-    private final int mLogicalAddress;
-    private final int mPhysicalAddress;
-    private final int mPortId;
-    private final int mDeviceType;
-    private final int mVendorId;
-    private final String mDisplayName;
-    private final boolean mIsCecDevice;
-
-    /**
-     * A helper class to deserialize {@link HdmiCecDeviceInfo} for a parcel.
-     */
-    public static final Parcelable.Creator<HdmiCecDeviceInfo> CREATOR =
-            new Parcelable.Creator<HdmiCecDeviceInfo>() {
-                @Override
-                public HdmiCecDeviceInfo createFromParcel(Parcel source) {
-                    int logicalAddress = source.readInt();
-                    int physicalAddress = source.readInt();
-                    int portId = source.readInt();
-                    int deviceType = source.readInt();
-                    int vendorId = source.readInt();
-                    String displayName = source.readString();
-                    return new HdmiCecDeviceInfo(logicalAddress, physicalAddress, portId,
-                            deviceType, vendorId, displayName);
-                }
-
-                @Override
-                public HdmiCecDeviceInfo[] newArray(int size) {
-                    return new HdmiCecDeviceInfo[size];
-                }
-            };
-
-    /**
-     * Constructor. Used to initialize the instance for CEC device.
-     *
-     * @param logicalAddress logical address of HDMI-CEC device
-     * @param physicalAddress physical address of HDMI-CEC device
-     * @param portId HDMI port ID (1 for HDMI1)
-     * @param deviceType type of device
-     * @param vendorId vendor id of device. Used for vendor specific command.
-     * @param displayName name of device
-     * @hide
-     */
-    public HdmiCecDeviceInfo(int logicalAddress, int physicalAddress, int portId, int deviceType,
-            int vendorId, String displayName) {
-        mLogicalAddress = logicalAddress;
-        mPhysicalAddress = physicalAddress;
-        mPortId = portId;
-        mDeviceType = deviceType;
-        mDisplayName = displayName;
-        mVendorId = vendorId;
-        mIsCecDevice = true;
-    }
-
-    /**
-     * Constructor. Used to initialize the instance for non-CEC device.
-     *
-     * @param physicalAddress physical address of HDMI device
-     * @param portId HDMI port ID (1 for HDMI1)
-     * @hide
-     */
-    public HdmiCecDeviceInfo(int physicalAddress, int portId) {
-        mLogicalAddress = -1;
-        mPhysicalAddress = physicalAddress;
-        mPortId = portId;
-        mDeviceType = DEVICE_RESERVED;
-        mDisplayName = null;
-        mVendorId = 0;
-        mIsCecDevice = false;
-    }
-
-    /**
-     * Return the logical address of the device.
-     */
-    public int getLogicalAddress() {
-        return mLogicalAddress;
-    }
-
-    /**
-     * Return the physical address of the device.
-     */
-    public int getPhysicalAddress() {
-        return mPhysicalAddress;
-    }
-
-    /**
-     * Return the port ID.
-     */
-    public int getPortId() {
-        return mPortId;
-    }
-
-    /**
-     * Return type of the device. For more details, refer constants between
-     * {@link DEVICE_TV} and {@link DEVICE_INACTIVE}.
-     */
-    public int getDeviceType() {
-        return mDeviceType;
-    }
-
-    /**
-     * Return {@code true} if the device is of a type that can be an input source.
-     */
-    public boolean isSourceType() {
-        return mDeviceType == DEVICE_PLAYBACK
-                || mDeviceType == DEVICE_RECORDER
-                || mDeviceType == DEVICE_TUNER;
-    }
-
-    /**
-     * Return {@code true} if the device represents an HDMI-CEC device. {@code false}
-     * if the device is either MHL or non-CEC device.
-     */
-    public boolean isCecDevice() {
-        return mIsCecDevice;
-    }
-
-    /**
-     * Return display (OSD) name of the device.
-     */
-    public String getDisplayName() {
-        return mDisplayName;
-    }
-
-    /**
-     * Return vendor id of the device. Vendor id is used to distinguish devices
-     * built by other manufactures. This is required for vendor-specific command
-     * on CEC standard.
-     */
-    public int getVendorId() {
-        return mVendorId;
-    }
-
-    /**
-     * Describe the kinds of special objects contained in this Parcelable's
-     * marshalled representation.
-     */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * Serialize this object into a {@link Parcel}.
-     *
-     * @param dest The Parcel in which the object should be written.
-     * @param flags Additional flags about how the object should be written.
-     *        May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mLogicalAddress);
-        dest.writeInt(mPhysicalAddress);
-        dest.writeInt(mPortId);
-        dest.writeInt(mDeviceType);
-        dest.writeInt(mVendorId);
-        dest.writeString(mDisplayName);
-    }
-
-    @Override
-    public String toString() {
-        StringBuffer s = new StringBuffer();
-        if (isCecDevice()) {
-            s.append("CEC: ");
-            s.append("logical_address: ").append(mLogicalAddress).append(", ");
-            s.append("physical_address: ").append(mPhysicalAddress).append(", ");
-            s.append("port_id: ").append(mPortId).append(", ");
-            s.append("device_type: ").append(mDeviceType).append(", ");
-            s.append("vendor_id: ").append(mVendorId).append(", ");
-            s.append("display_name: ").append(mDisplayName);
-        } else {
-            s.append("Non-CEC: ");
-            s.append("physical_address: ").append(mPhysicalAddress).append(", ");
-            s.append("port_id: ").append(mPortId).append(", ");
-        }
-        return s.toString();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof HdmiCecDeviceInfo)) {
-            return false;
-        }
-
-        HdmiCecDeviceInfo other = (HdmiCecDeviceInfo) obj;
-        return mLogicalAddress == other.mLogicalAddress
-                && mPhysicalAddress == other.mPhysicalAddress
-                && mPortId == other.mPortId
-                && mDeviceType == other.mDeviceType
-                && mVendorId == other.mVendorId
-                && mDisplayName.equals(other.mDisplayName);
-    }
-}
diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java
index 5d26a57..f95ed0f 100644
--- a/core/java/android/hardware/hdmi/HdmiClient.java
+++ b/core/java/android/hardware/hdmi/HdmiClient.java
@@ -28,10 +28,10 @@
     /**
      * Returns the active source information.
      *
-     * @return {@link HdmiCecDeviceInfo} object that describes the active source
+     * @return {@link HdmiDeviceInfo} object that describes the active source
      *         or active routing path
      */
-    public HdmiCecDeviceInfo getActiveSource() {
+    public HdmiDeviceInfo getActiveSource() {
         try {
             return mService.getActiveSource();
         } catch (RemoteException e) {
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index e7bd3e4..7cfa211 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -228,8 +228,8 @@
                 // Do nothing.
             }
         }
-        mHasTvDevice = hasDeviceType(types, HdmiCecDeviceInfo.DEVICE_TV);
-        mHasPlaybackDevice = hasDeviceType(types, HdmiCecDeviceInfo.DEVICE_PLAYBACK);
+        mHasTvDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_TV);
+        mHasPlaybackDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PLAYBACK);
     }
 
     private static boolean hasDeviceType(int[] types, int type) {
@@ -249,8 +249,8 @@
      *
      * @param type CEC device type
      * @return {@link HdmiClient} instance. {@code null} on failure.
-     * @see {@link HdmiCecDeviceInfo#DEVICE_PLAYBACK}
-     * @see {@link HdmiCecDeviceInfo#DEVICE_TV}
+     * See {@link HdmiDeviceInfo#DEVICE_PLAYBACK}
+     * See {@link HdmiDeviceInfo#DEVICE_TV}
      */
     @Nullable
     public HdmiClient getClient(int type) {
@@ -258,9 +258,9 @@
             return null;
         }
         switch (type) {
-            case HdmiCecDeviceInfo.DEVICE_TV:
+            case HdmiDeviceInfo.DEVICE_TV:
                 return mHasTvDevice ? new HdmiTvClient(mService) : null;
-            case HdmiCecDeviceInfo.DEVICE_PLAYBACK:
+            case HdmiDeviceInfo.DEVICE_PLAYBACK:
                 return mHasPlaybackDevice ? new HdmiPlaybackClient(mService) : null;
             default:
                 return null;
@@ -278,7 +278,7 @@
      */
     @Nullable
     public HdmiPlaybackClient getPlaybackClient() {
-        return (HdmiPlaybackClient) getClient(HdmiCecDeviceInfo.DEVICE_PLAYBACK);
+        return (HdmiPlaybackClient) getClient(HdmiDeviceInfo.DEVICE_PLAYBACK);
     }
 
     /**
@@ -292,7 +292,7 @@
      */
     @Nullable
     public HdmiTvClient getTvClient() {
-        return (HdmiTvClient) getClient(HdmiCecDeviceInfo.DEVICE_TV);
+        return (HdmiTvClient) getClient(HdmiDeviceInfo.DEVICE_TV);
     }
 
     /**
diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl b/core/java/android/hardware/hdmi/HdmiDeviceInfo.aidl
similarity index 95%
rename from core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl
rename to core/java/android/hardware/hdmi/HdmiDeviceInfo.aidl
index 1615910..cb76dc8 100644
--- a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl
+++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.aidl
@@ -16,4 +16,4 @@
 
 package android.hardware.hdmi;
 
-parcelable HdmiCecDeviceInfo;
+parcelable HdmiDeviceInfo;
diff --git a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
new file mode 100644
index 0000000..2391d3a
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
@@ -0,0 +1,411 @@
+/*
+ * 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 android.hardware.hdmi;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class to encapsulate device information for HDMI devices including CEC and MHL. In terms of
+ * CEC, this container includes basic information such as logical address, physical address and
+ * device type, and additional information like vendor id and osd name. In terms of MHL device, this
+ * container includes adopter id and device type. Otherwise, it keeps the information of other type
+ * devices for which only port ID, physical address are meaningful.
+ *
+ * @hide
+ */
+@SystemApi
+public class HdmiDeviceInfo implements Parcelable {
+
+    /** TV device type. */
+    public static final int DEVICE_TV = 0;
+
+    /** Recording device type. */
+    public static final int DEVICE_RECORDER = 1;
+
+    /** Device type reserved for future usage. */
+    public static final int DEVICE_RESERVED = 2;
+
+    /** Tuner device type. */
+    public static final int DEVICE_TUNER = 3;
+
+    /** Playback device type. */
+    public static final int DEVICE_PLAYBACK = 4;
+
+    /** Audio system device type. */
+    public static final int DEVICE_AUDIO_SYSTEM = 5;
+
+    /** @hide Pure CEC switch device type. */
+    public static final int DEVICE_PURE_CEC_SWITCH = 6;
+
+    /** @hide Video processor device type. */
+    public static final int DEVICE_VIDEO_PROCESSOR = 7;
+
+    // Value indicating the device is not an active source.
+    public static final int DEVICE_INACTIVE = -1;
+
+    /**
+     * Logical address used to indicate the source comes from internal device. The logical address
+     * of TV(0) is used.
+     */
+    public static final int ADDR_INTERNAL = 0;
+
+    /**
+     * Physical address used to indicate the source comes from internal device. The physical address
+     * of TV(0) is used.
+     */
+    public static final int PATH_INTERNAL = 0x0000;
+
+    /** Invalid physical address (routing path) */
+    public static final int PATH_INVALID = 0xFFFF;
+
+    /** Invalid port ID */
+    public static final int PORT_INVALID = -1;
+
+    private static final int HDMI_DEVICE_TYPE_OTHER = 0;
+    private static final int HDMI_DEVICE_TYPE_CEC = 1;
+    private static final int HDMI_DEVICE_TYPE_MHL = 2;
+
+    // Common parameters for all device.
+    private final int mHdmiDeviceType;
+    private final int mPhysicalAddress;
+    private final int mPortId;
+
+    // CEC only parameters.
+    private final int mLogicalAddress;
+    private final int mDeviceType;
+    private final int mVendorId;
+    private final String mDisplayName;
+    private final int mDevicePowerStatus;
+
+    // MHL only parameters.
+    private final int mDeviceId;
+    private final int mAdopterId;
+
+    /**
+     * A helper class to deserialize {@link HdmiDeviceInfo} for a parcel.
+     */
+    public static final Parcelable.Creator<HdmiDeviceInfo> CREATOR =
+            new Parcelable.Creator<HdmiDeviceInfo>() {
+                @Override
+                public HdmiDeviceInfo createFromParcel(Parcel source) {
+                    int hdmiDeviceType = source.readInt();
+                    int physicalAddress = source.readInt();
+                    int portId = source.readInt();
+
+                    switch (hdmiDeviceType) {
+                        case HDMI_DEVICE_TYPE_CEC:
+                            int logicalAddress = source.readInt();
+                            int deviceType = source.readInt();
+                            int vendorId = source.readInt();
+                            int powerStatus = source.readInt();
+                            String displayName = source.readString();
+                            return new HdmiDeviceInfo(logicalAddress, physicalAddress, portId,
+                                    deviceType, vendorId, displayName, powerStatus);
+                        case HDMI_DEVICE_TYPE_MHL:
+                            int deviceId = source.readInt();
+                            int adopterId = source.readInt();
+                            return new HdmiDeviceInfo(physicalAddress, portId, adopterId, deviceId);
+                        case HDMI_DEVICE_TYPE_OTHER:
+                            return new HdmiDeviceInfo(physicalAddress, portId);
+                        default:
+                            return null;
+                    }
+                }
+
+                @Override
+                public HdmiDeviceInfo[] newArray(int size) {
+                    return new HdmiDeviceInfo[size];
+                }
+            };
+
+    /**
+     * Constructor. Used to initialize the instance for CEC device.
+     *
+     * @param logicalAddress logical address of HDMI-CEC device
+     * @param physicalAddress physical address of HDMI-CEC device
+     * @param portId HDMI port ID (1 for HDMI1)
+     * @param deviceType type of device
+     * @param vendorId vendor id of device. Used for vendor specific command.
+     * @param displayName name of device
+     * @param powerStatus device power status
+     * @hide
+     */
+    public HdmiDeviceInfo(int logicalAddress, int physicalAddress, int portId, int deviceType,
+            int vendorId, String displayName, int powerStatus) {
+        mHdmiDeviceType = HDMI_DEVICE_TYPE_CEC;
+        mPhysicalAddress = physicalAddress;
+        mPortId = portId;
+
+        mLogicalAddress = logicalAddress;
+        mDeviceType = deviceType;
+        mVendorId = vendorId;
+        mDevicePowerStatus = powerStatus;
+        mDisplayName = displayName;
+
+        mDeviceId = -1;
+        mAdopterId = -1;
+    }
+
+    /**
+     * Constructor. Used to initialize the instance for CEC device.
+     *
+     * @param logicalAddress logical address of HDMI-CEC device
+     * @param physicalAddress physical address of HDMI-CEC device
+     * @param portId HDMI port ID (1 for HDMI1)
+     * @param deviceType type of device
+     * @param vendorId vendor id of device. Used for vendor specific command.
+     * @param displayName name of device
+     * @hide
+     */
+    public HdmiDeviceInfo(int logicalAddress, int physicalAddress, int portId, int deviceType,
+            int vendorId, String displayName) {
+        this(logicalAddress, physicalAddress, portId, deviceType,
+                vendorId, displayName, HdmiControlManager.POWER_STATUS_UNKNOWN);
+    }
+
+    /**
+     * Constructor. Used to initialize the instance for other device.
+     *
+     * @param physicalAddress physical address of HDMI device
+     * @param portId HDMI port ID (1 for HDMI1)
+     * @hide
+     */
+    public HdmiDeviceInfo(int physicalAddress, int portId) {
+        mHdmiDeviceType = HDMI_DEVICE_TYPE_OTHER;
+        mPhysicalAddress = physicalAddress;
+        mPortId = portId;
+
+        mLogicalAddress = -1;
+        mDeviceType = DEVICE_RESERVED;
+        mVendorId = 0;
+        mDevicePowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
+        mDisplayName = "HDMI" + portId;
+
+        mDeviceId = -1;
+        mAdopterId = -1;
+
+    }
+
+    /**
+     * Constructor. Used to initialize the instance for MHL device.
+     *
+     * @param physicalAddress physical address of HDMI device
+     * @param portId portId HDMI port ID (1 for HDMI1)
+     * @param adopterId adopter id of MHL
+     * @param deviceId device id of MHL
+     * @hide
+     */
+    public HdmiDeviceInfo(int physicalAddress, int portId, int adopterId, int deviceId) {
+        mHdmiDeviceType = HDMI_DEVICE_TYPE_MHL;
+        mPhysicalAddress = physicalAddress;
+        mPortId = portId;
+
+        mLogicalAddress = -1;
+        mDeviceType = DEVICE_RESERVED;
+        mVendorId = 0;
+        mDevicePowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
+        mDisplayName = "MHL";
+
+        mDeviceId = adopterId;
+        mAdopterId = deviceId;
+    }
+
+    /**
+     * Return the CEC logical address of the device.
+     */
+    public int getLogicalAddress() {
+        return mLogicalAddress;
+    }
+
+    /**
+     * Return the physical address of the device.
+     */
+    public int getPhysicalAddress() {
+        return mPhysicalAddress;
+    }
+
+    /**
+     * Return the port ID.
+     */
+    public int getPortId() {
+        return mPortId;
+    }
+
+    /**
+     * Return CEC type of the device. For more details, refer constants between {@link #DEVICE_TV}
+     * and {@link #DEVICE_INACTIVE}.
+     */
+    public int getDeviceType() {
+        return mDeviceType;
+    }
+
+    /**
+     * Return device's power status. It should be one of the following values.
+     * <ul>
+     * <li>{@link HdmiControlManager#POWER_STATUS_ON}
+     * <li>{@link HdmiControlManager#POWER_STATUS_STANDBY}
+     * <li>{@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_ON}
+     * <li>{@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_STANDBY}
+     * <li>{@link HdmiControlManager#POWER_STATUS_UNKNOWN}
+     * </ul>
+     */
+    public int getDevicePowerStatus() {
+        return mDevicePowerStatus;
+    }
+
+    /**
+     * Return MHL device id. Return -1 for non-MHL device.
+     */
+    public int getDeviceId() {
+        return mDeviceId;
+    }
+
+    /**
+     * Return MHL adopter id. Return -1 for non-MHL device.
+     */
+    public int getAdopterId() {
+        return mAdopterId;
+    }
+
+    /**
+     * Return {@code true} if the device is of a type that can be an input source.
+     */
+    public boolean isSourceType() {
+        return mDeviceType == DEVICE_PLAYBACK
+                || mDeviceType == DEVICE_RECORDER
+                || mDeviceType == DEVICE_TUNER;
+    }
+
+    /**
+     * Return {@code true} if the device represents an HDMI-CEC device. {@code false} if the device
+     * is either MHL or other device.
+     */
+    public boolean isCecDevice() {
+        return mHdmiDeviceType == HDMI_DEVICE_TYPE_CEC;
+    }
+
+    /**
+     * Return {@code true} if the device represents an MHL device. {@code false} if the device is
+     * either CEC or other device.
+     */
+    public boolean isMhlDevice() {
+        return mHdmiDeviceType == HDMI_DEVICE_TYPE_MHL;
+    }
+
+    /**
+     * Return display (OSD) name of the device.
+     */
+    public String getDisplayName() {
+        return mDisplayName;
+    }
+
+    /**
+     * Return vendor id of the device. Vendor id is used to distinguish devices built by other
+     * manufactures. This is required for vendor-specific command on CEC standard.
+     */
+    public int getVendorId() {
+        return mVendorId;
+    }
+
+    /**
+     * Describe the kinds of special objects contained in this Parcelable's marshalled
+     * representation.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Serialize this object into a {@link Parcel}.
+     *
+     * @param dest The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written. May be 0 or
+     *            {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mHdmiDeviceType);
+        dest.writeInt(mPhysicalAddress);
+        dest.writeInt(mPortId);
+        switch (mHdmiDeviceType) {
+            case HDMI_DEVICE_TYPE_CEC:
+                dest.writeInt(mLogicalAddress);
+                dest.writeInt(mDeviceType);
+                dest.writeInt(mVendorId);
+                dest.writeInt(mDevicePowerStatus);
+                dest.writeString(mDisplayName);
+                break;
+            case HDMI_DEVICE_TYPE_MHL:
+                dest.writeInt(mDeviceId);
+                dest.writeInt(mAdopterId);
+                break;
+            default:
+                // no-op
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer s = new StringBuffer();
+        switch (mHdmiDeviceType) {
+            case HDMI_DEVICE_TYPE_CEC:
+                s.append("CEC: ");
+                s.append("logical_address: ").append(mLogicalAddress).append(", ");
+                s.append("device_type: ").append(mDeviceType).append(", ");
+                s.append("vendor_id: ").append(mVendorId).append(", ");
+                s.append("display_name: ").append(mDisplayName).append(", ");
+                s.append("power_status: ").append(mDevicePowerStatus).append(", ");
+                break;
+            case HDMI_DEVICE_TYPE_MHL:
+                s.append("MHL: ");
+                break;
+
+            case HDMI_DEVICE_TYPE_OTHER:
+                s.append("Other: ");
+                s.append("device_id: ").append(mDeviceId).append(", ");
+                s.append("adopter_id: ").append(mAdopterId).append(", ");
+                break;
+            default:
+                return "";
+        }
+        s.append("physical_address: ").append(mPhysicalAddress).append(", ");
+        s.append("port_id: ").append(mPortId);
+        return s.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof HdmiDeviceInfo)) {
+            return false;
+        }
+
+        HdmiDeviceInfo other = (HdmiDeviceInfo) obj;
+        return mHdmiDeviceType == other.mHdmiDeviceType
+                && mPhysicalAddress == other.mPhysicalAddress
+                && mPortId == other.mPortId
+                && mLogicalAddress == other.mLogicalAddress
+                && mDeviceType == other.mDeviceType
+                && mVendorId == other.mVendorId
+                && mDevicePowerStatus == other.mDevicePowerStatus
+                && mDisplayName.equals(other.mDisplayName)
+                && mDeviceId == other.mDeviceId
+                && mAdopterId == other.mAdopterId;
+    }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
index 74cdc4e..85ccb74 100644
--- a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
+++ b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
@@ -52,12 +52,14 @@
         /**
          * Called when display device status is reported.
          *
-         * @param status display device status
-         * @see {@link HdmiControlManager#POWER_STATUS_ON}
-         * @see {@link HdmiControlManager#POWER_STATUS_STANDBY}
-         * @see {@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_ON}
-         * @see {@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_STANDBY}
-         * @see {@link HdmiControlManager#POWER_STATUS_UNKNOWN}
+         * @param status display device status. It should be one of the following values.
+         *            <ul>
+         *            <li>{@link HdmiControlManager#POWER_STATUS_ON}
+         *            <li>{@link HdmiControlManager#POWER_STATUS_STANDBY}
+         *            <li>{@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_ON}
+         *            <li>{@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_STANDBY}
+         *            <li>{@link HdmiControlManager#POWER_STATUS_UNKNOWN}
+         *            </ul>
          */
         public void onComplete(int status);
     }
@@ -82,8 +84,9 @@
         }
     }
 
+    @Override
     public int getDeviceType() {
-        return HdmiCecDeviceInfo.DEVICE_PLAYBACK;
+        return HdmiDeviceInfo.DEVICE_PLAYBACK;
     }
 
     /**
@@ -93,7 +96,6 @@
      *         of the result
      */
     public void queryDisplayStatus(DisplayStatusCallback callback) {
-        // TODO: PendingResult.
         try {
             mService.queryDisplayStatus(getCallbackWrapper(callback));
         } catch (RemoteException e) {
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index 077a17e..a9040cf 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -96,7 +96,7 @@
 
     @Override
     public int getDeviceType() {
-        return HdmiCecDeviceInfo.DEVICE_TV;
+        return HdmiDeviceInfo.DEVICE_TV;
     }
 
     /**
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 920a1f4..d6cb492 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -16,7 +16,7 @@
 
 package android.hardware.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.hdmi.IHdmiDeviceEventListener;
@@ -37,7 +37,7 @@
  */
 interface IHdmiControlService {
     int[] getSupportedTypes();
-    HdmiCecDeviceInfo getActiveSource();
+    HdmiDeviceInfo getActiveSource();
     void oneTouchPlay(IHdmiControlCallback callback);
     void queryDisplayStatus(IHdmiControlCallback callback);
     void addHotplugEventListener(IHdmiHotplugEventListener listener);
@@ -59,7 +59,7 @@
     void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex);
     void setSystemAudioMute(boolean mute);
     void setInputChangeListener(IHdmiInputChangeListener listener);
-    List<HdmiCecDeviceInfo> getInputDevices();
+    List<HdmiDeviceInfo> getInputDevices();
     void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
             boolean hasVendorId);
     void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
diff --git a/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl b/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl
index c4e5989..94fd14f 100644
--- a/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl
@@ -16,7 +16,7 @@
 
 package android.hardware.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 
 /**
  * Callback interface definition for HDMI client to get informed of
@@ -27,9 +27,9 @@
 oneway interface IHdmiDeviceEventListener {
 
     /**
-     * @param deviceInfo {@link HdmiCecDeviceInfo} of the logical device whose
+     * @param deviceInfo {@link HdmiDeviceInfo} of the logical device whose
      *                   status has changed
      * @param activated true if the device gets activated
      */
-    void onStatusChanged(in HdmiCecDeviceInfo deviceInfo, in boolean activated);
+    void onStatusChanged(in HdmiDeviceInfo deviceInfo, in boolean activated);
 }
diff --git a/core/java/android/hardware/hdmi/IHdmiInputChangeListener.aidl b/core/java/android/hardware/hdmi/IHdmiInputChangeListener.aidl
index 98ad300..46a20c7 100644
--- a/core/java/android/hardware/hdmi/IHdmiInputChangeListener.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiInputChangeListener.aidl
@@ -16,7 +16,7 @@
 
 package android.hardware.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 
 /**
  * Callback interface definition for TV to get informed of
@@ -25,5 +25,5 @@
  * @hide
  */
 oneway interface IHdmiInputChangeListener {
-    void onChanged(in HdmiCecDeviceInfo device);
+    void onChanged(in HdmiDeviceInfo device);
 }
diff --git a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
index f279668..2f6dbe7 100644
--- a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
+++ b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
@@ -34,4 +34,12 @@
      * @param status The error code that was seen.
      */
     void onError(int status);
+    /**
+     * Called when the recognition is paused temporarily for some reason.
+     */
+    void onRecognitionPaused();
+    /**
+     * Called when the recognition is resumed after it was temporarily paused.
+     */
+    void onRecognitionResumed();
 }
\ No newline at end of file
diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java
deleted file mode 100644
index 89c17c7..0000000
--- a/core/java/android/net/CaptivePortalTracker.java
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * 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.
- */
-
-package android.net;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.telephony.CellIdentityCdma;
-import android.telephony.CellIdentityGsm;
-import android.telephony.CellIdentityLte;
-import android.telephony.CellIdentityWcdma;
-import android.telephony.CellInfo;
-import android.telephony.CellInfoCdma;
-import android.telephony.CellInfoGsm;
-import android.telephony.CellInfoLte;
-import android.telephony.CellInfoWcdma;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.util.List;
-
-/**
- * This class allows captive portal detection on a network.
- * @hide
- */
-public class CaptivePortalTracker extends StateMachine {
-    private static final boolean DBG = true;
-    private static final String TAG = "CaptivePortalTracker";
-
-    private static final String DEFAULT_SERVER = "clients3.google.com";
-
-    private static final int SOCKET_TIMEOUT_MS = 10000;
-
-    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
-            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
-    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
-    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
-    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
-    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
-    public static final String EXTRA_CELL_ID = "extra_cellid";
-    public static final String EXTRA_SSID = "extra_ssid";
-    public static final String EXTRA_BSSID = "extra_bssid";
-    /** real time since boot */
-    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
-    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
-
-    private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
-            "android.permission.ACCESS_NETWORK_CONDITIONS";
-
-    private String mServer;
-    private String mUrl;
-    private boolean mIsCaptivePortalCheckEnabled = false;
-    private final IConnectivityManager mConnService;
-    private final TelephonyManager mTelephonyManager;
-    private final WifiManager mWifiManager;
-    private final Context mContext;
-    private NetworkInfo mNetworkInfo;
-
-    private static final int CMD_CONNECTIVITY_CHANGE    = 1;
-    private static final int CMD_DELAYED_CAPTIVE_CHECK  = 2;
-
-    /* This delay happens every time before we do a captive check on a network */
-    private static final int DELAYED_CHECK_INTERVAL_MS = 10000;
-    private int mDelayedCheckToken = 0;
-
-    private final State mDefaultState = new DefaultState();
-    private final State mNoActiveNetworkState = new NoActiveNetworkState();
-    private final State mActiveNetworkState = new ActiveNetworkState();
-    private final State mDelayedCaptiveCheckState = new DelayedCaptiveCheckState();
-
-    private static final String SETUP_WIZARD_PACKAGE = "com.google.android.setupwizard";
-    private boolean mDeviceProvisioned = false;
-    @SuppressWarnings("unused")
-    private final ProvisioningObserver mProvisioningObserver;
-
-    private CaptivePortalTracker(Context context, IConnectivityManager cs) {
-        super(TAG);
-
-        mContext = context;
-        mConnService = cs;
-        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-        mProvisioningObserver = new ProvisioningObserver();
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE);
-        mContext.registerReceiver(mReceiver, filter);
-
-        mServer = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.CAPTIVE_PORTAL_SERVER);
-        if (mServer == null) mServer = DEFAULT_SERVER;
-
-        mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
-
-        addState(mDefaultState);
-            addState(mNoActiveNetworkState, mDefaultState);
-            addState(mActiveNetworkState, mDefaultState);
-                addState(mDelayedCaptiveCheckState, mActiveNetworkState);
-        setInitialState(mNoActiveNetworkState);
-    }
-
-    private class ProvisioningObserver extends ContentObserver {
-        ProvisioningObserver() {
-            super(new Handler());
-            mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.DEVICE_PROVISIONED), false, this);
-            onChange(false); // load initial value
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            mDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.DEVICE_PROVISIONED, 0) != 0;
-        }
-    }
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            // Normally, we respond to CONNECTIVITY_ACTION, allowing time for the change in
-            // connectivity to stabilize, but if the device is not yet provisioned, respond
-            // immediately to speed up transit through the setup wizard.
-            if ((mDeviceProvisioned && action.equals(ConnectivityManager.CONNECTIVITY_ACTION))
-                    || (!mDeviceProvisioned
-                            && action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE))) {
-                NetworkInfo info = intent.getParcelableExtra(
-                        ConnectivityManager.EXTRA_NETWORK_INFO);
-                sendMessage(obtainMessage(CMD_CONNECTIVITY_CHANGE, info));
-            }
-        }
-    };
-
-    public static CaptivePortalTracker makeCaptivePortalTracker(Context context,
-            IConnectivityManager cs) {
-        CaptivePortalTracker captivePortal = new CaptivePortalTracker(context, cs);
-        captivePortal.start();
-        return captivePortal;
-    }
-
-    private class DefaultState extends State {
-
-        @Override
-        public boolean processMessage(Message message) {
-            loge("Ignoring " + message);
-            return HANDLED;
-        }
-    }
-
-    private class NoActiveNetworkState extends State {
-        @Override
-        public void enter() {
-            setNotificationOff();
-            mNetworkInfo = null;
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) log(getName() + message.toString());
-            InetAddress server;
-            NetworkInfo info;
-            switch (message.what) {
-                case CMD_CONNECTIVITY_CHANGE:
-                    info = (NetworkInfo) message.obj;
-                    if (info.getType() == ConnectivityManager.TYPE_WIFI) {
-                        if (info.isConnected() && isActiveNetwork(info)) {
-                            mNetworkInfo = info;
-                            transitionTo(mDelayedCaptiveCheckState);
-                        }
-                    } else {
-                        log(getName() + " not a wifi connectivity change, ignore");
-                    }
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            return HANDLED;
-        }
-    }
-
-    private class ActiveNetworkState extends State {
-        @Override
-        public boolean processMessage(Message message) {
-            NetworkInfo info;
-            switch (message.what) {
-               case CMD_CONNECTIVITY_CHANGE:
-                    info = (NetworkInfo) message.obj;
-                    if (!info.isConnected()
-                            && info.getType() == mNetworkInfo.getType()) {
-                        if (DBG) log("Disconnected from active network " + info);
-                        transitionTo(mNoActiveNetworkState);
-                    } else if (info.getType() != mNetworkInfo.getType() &&
-                            info.isConnected() &&
-                            isActiveNetwork(info)) {
-                        if (DBG) log("Active network switched " + info);
-                        deferMessage(message);
-                        transitionTo(mNoActiveNetworkState);
-                    }
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            return HANDLED;
-        }
-    }
-
-
-
-    private class DelayedCaptiveCheckState extends State {
-        @Override
-        public void enter() {
-            Message message = obtainMessage(CMD_DELAYED_CAPTIVE_CHECK, ++mDelayedCheckToken, 0);
-            if (mDeviceProvisioned) {
-                sendMessageDelayed(message, DELAYED_CHECK_INTERVAL_MS);
-            } else {
-                sendMessage(message);
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) log(getName() + message.toString());
-            switch (message.what) {
-                case CMD_DELAYED_CAPTIVE_CHECK:
-                    setNotificationOff();
-
-                    if (message.arg1 == mDelayedCheckToken) {
-                        InetAddress server = lookupHost(mServer);
-                        boolean captive = server != null && isCaptivePortal(server);
-                        if (captive) {
-                            if (DBG) log("Captive network " + mNetworkInfo);
-                        } else {
-                            if (DBG) log("Not captive network " + mNetworkInfo);
-                        }
-                        notifyPortalCheckCompleted(mNetworkInfo, captive);
-                        if (mDeviceProvisioned) {
-                            if (captive) {
-                                // Setup Wizard will assist the user in connecting to a captive
-                                // portal, so make the notification visible unless during setup
-                                try {
-                                    mConnService.setProvisioningNotificationVisible(true,
-                                        mNetworkInfo.getType(), mNetworkInfo.getExtraInfo(), mUrl);
-                                } catch(RemoteException e) {
-                                    e.printStackTrace();
-                                }
-                            }
-                        } else {
-                            Intent intent = new Intent(
-                                    ConnectivityManager.ACTION_CAPTIVE_PORTAL_TEST_COMPLETED);
-                            intent.putExtra(ConnectivityManager.EXTRA_IS_CAPTIVE_PORTAL, captive);
-                            intent.setPackage(SETUP_WIZARD_PACKAGE);
-                            mContext.sendBroadcast(intent);
-                        }
-
-                        transitionTo(mActiveNetworkState);
-                    }
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            return HANDLED;
-        }
-    }
-
-    private void notifyPortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
-        if (info == null) {
-            loge("notifyPortalCheckComplete on null");
-            return;
-        }
-        try {
-            if (DBG) log("notifyPortalCheckCompleted: captive=" + isCaptivePortal + " ni=" + info);
-            mConnService.captivePortalCheckCompleted(info, isCaptivePortal);
-        } catch(RemoteException e) {
-            e.printStackTrace();
-        }
-    }
-
-    private boolean isActiveNetwork(NetworkInfo info) {
-        try {
-            NetworkInfo active = mConnService.getActiveNetworkInfo();
-            if (active != null && active.getType() == info.getType()) {
-                return true;
-            }
-        } catch (RemoteException e) {
-            e.printStackTrace();
-        }
-        return false;
-    }
-
-    private void setNotificationOff() {
-        try {
-            if (mNetworkInfo != null) {
-                mConnService.setProvisioningNotificationVisible(false, mNetworkInfo.getType(),
-                    null, null);
-            }
-        } catch (RemoteException e) {
-            log("setNotificationOff: " + e);
-        }
-    }
-
-    /**
-     * Do a URL fetch on a known server to see if we get the data we expect.
-     * Measure the response time and broadcast that.
-     */
-    private boolean isCaptivePortal(InetAddress server) {
-        HttpURLConnection urlConnection = null;
-        if (!mIsCaptivePortalCheckEnabled) return false;
-
-        mUrl = "http://" + server.getHostAddress() + "/generate_204";
-        if (DBG) log("Checking " + mUrl);
-        long requestTimestamp = -1;
-        try {
-            URL url = new URL(mUrl);
-            urlConnection = (HttpURLConnection) url.openConnection();
-            urlConnection.setInstanceFollowRedirects(false);
-            urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
-            urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
-            urlConnection.setUseCaches(false);
-
-            // Time how long it takes to get a response to our request
-            requestTimestamp = SystemClock.elapsedRealtime();
-
-            urlConnection.getInputStream();
-
-            // Time how long it takes to get a response to our request
-            long responseTimestamp = SystemClock.elapsedRealtime();
-
-            // we got a valid response, but not from the real google
-            int rspCode = urlConnection.getResponseCode();
-            boolean isCaptivePortal = rspCode != 204;
-
-            sendNetworkConditionsBroadcast(true /* response received */, isCaptivePortal,
-                    requestTimestamp, responseTimestamp);
-
-            if (DBG) log("isCaptivePortal: ret=" + isCaptivePortal + " rspCode=" + rspCode);
-            return isCaptivePortal;
-        } catch (IOException e) {
-            if (DBG) log("Probably not a portal: exception " + e);
-            if (requestTimestamp != -1) {
-                sendFailedCaptivePortalCheckBroadcast(requestTimestamp);
-            } // else something went wrong with setting up the urlConnection
-            return false;
-        } finally {
-            if (urlConnection != null) {
-                urlConnection.disconnect();
-            }
-        }
-    }
-
-    private InetAddress lookupHost(String hostname) {
-        InetAddress inetAddress[];
-        try {
-            inetAddress = InetAddress.getAllByName(hostname);
-        } catch (UnknownHostException e) {
-            sendFailedCaptivePortalCheckBroadcast(SystemClock.elapsedRealtime());
-            return null;
-        }
-
-        for (InetAddress a : inetAddress) {
-            if (a instanceof Inet4Address) return a;
-        }
-
-        sendFailedCaptivePortalCheckBroadcast(SystemClock.elapsedRealtime());
-        return null;
-    }
-
-    private void sendFailedCaptivePortalCheckBroadcast(long requestTimestampMs) {
-        sendNetworkConditionsBroadcast(false /* response received */, false /* ignored */,
-                requestTimestampMs, 0 /* ignored */);
-    }
-
-    /**
-     * @param responseReceived - whether or not we received a valid HTTP response to our request.
-     * If false, isCaptivePortal and responseTimestampMs are ignored
-     */
-    private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
-            long requestTimestampMs, long responseTimestampMs) {
-        if (Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0) {
-            if (DBG) log("Don't send network conditions - lacking user consent.");
-            return;
-        }
-
-        Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED);
-        switch (mNetworkInfo.getType()) {
-            case ConnectivityManager.TYPE_WIFI:
-                WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
-                if (currentWifiInfo != null) {
-                    // NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not
-                    // surrounded by double quotation marks (thus violating the Javadoc), but this
-                    // was changed to match the Javadoc in API 17. Since clients may have started
-                    // sanitizing the output of this method since API 17 was released, we should
-                    // not change it here as it would become impossible to tell whether the SSID is
-                    // simply being surrounded by quotes due to the API, or whether those quotes
-                    // are actually part of the SSID.
-                    latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
-                    latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
-                } else {
-                    if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
-                    return;
-                }
-                break;
-            case ConnectivityManager.TYPE_MOBILE:
-                latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType());
-                List<CellInfo> info = mTelephonyManager.getAllCellInfo();
-                if (info == null) return;
-                int numRegisteredCellInfo = 0;
-                for (CellInfo cellInfo : info) {
-                    if (cellInfo.isRegistered()) {
-                        numRegisteredCellInfo++;
-                        if (numRegisteredCellInfo > 1) {
-                            if (DBG) log("more than one registered CellInfo.  Can't " +
-                                    "tell which is active.  Bailing.");
-                            return;
-                        }
-                        if (cellInfo instanceof CellInfoCdma) {
-                            CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
-                        } else if (cellInfo instanceof CellInfoGsm) {
-                            CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
-                        } else if (cellInfo instanceof CellInfoLte) {
-                            CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
-                        } else if (cellInfo instanceof CellInfoWcdma) {
-                            CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
-                        } else {
-                            if (DBG) logw("Registered cellinfo is unrecognized");
-                            return;
-                        }
-                    }
-                }
-                break;
-            default:
-                return;
-        }
-        latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkInfo.getType());
-        latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived);
-        latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs);
-
-        if (responseReceived) {
-            latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal);
-            latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs);
-        }
-        mContext.sendBroadcast(latencyBroadcast, PERMISSION_ACCESS_NETWORK_CONDITIONS);
-    }
-}
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 786439e..3f18519 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.SystemApi;
 import android.app.DownloadManager;
 import android.app.backup.BackupManager;
 import android.content.Context;
@@ -127,6 +128,16 @@
     }
 
     /**
+     * System API for backup-related support components to tag network traffic
+     * appropriately.
+     * @hide
+     */
+    @SystemApi
+    public static void setThreadStatsTagBackup() {
+        setThreadStatsTag(TAG_SYSTEM_BACKUP);
+    }
+
+    /**
      * Get the active tag used when accounting {@link Socket} traffic originating
      * from the current thread. Only one active tag per thread is supported.
      * {@link #tagSocket(Socket)}.
@@ -160,11 +171,13 @@
      *
      * @hide
      */
+    @SystemApi
     public static void setThreadStatsUid(int uid) {
         NetworkManagementSocketTagger.setThreadSocketStatsUid(uid);
     }
 
     /** {@hide} */
+    @SystemApi
     public static void clearThreadStatsUid() {
         NetworkManagementSocketTagger.setThreadSocketStatsUid(-1);
     }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 545b19a..ba79f91 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -33,6 +33,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
+import android.view.Display;
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
 
@@ -1596,6 +1597,27 @@
      */
     public abstract long computeBatteryTimeRemaining(long curTime);
 
+    // The part of a step duration that is the actual time.
+    public static final long STEP_LEVEL_TIME_MASK = 0x000000ffffffffffL;
+
+    // Bits in a step duration that are the new battery level we are at.
+    public static final long STEP_LEVEL_LEVEL_MASK = 0x0000ff0000000000L;
+    public static final long STEP_LEVEL_LEVEL_SHIFT = 40;
+
+    // Bits in a step duration that are the initial mode we were in at that step.
+    public static final long STEP_LEVEL_INITIAL_MODE_MASK = 0x00ff000000000000L;
+    public static final long STEP_LEVEL_INITIAL_MODE_SHIFT = 48;
+
+    // Bits in a step duration that indicate which modes changed during that step.
+    public static final long STEP_LEVEL_MODIFIED_MODE_MASK = 0xff00000000000000L;
+    public static final long STEP_LEVEL_MODIFIED_MODE_SHIFT = 56;
+
+    // Step duration mode: the screen is on, off, dozed, etc; value is Display.STATE_* - 1.
+    public static final int STEP_LEVEL_MODE_SCREEN_STATE = 0x03;
+
+    // Step duration mode: power save is on.
+    public static final int STEP_LEVEL_MODE_POWER_SAVE = 0x04;
+
     /**
      * Return the historical number of discharge steps we currently have.
      */
@@ -3620,14 +3642,60 @@
         if (!checkin) {
             pw.println(header);
         }
-        String[] lineArgs = new String[1];
+        String[] lineArgs = new String[4];
         for (int i=0; i<count; i++) {
+            long duration = steps[i] & STEP_LEVEL_TIME_MASK;
+            int level = (int)((steps[i] & STEP_LEVEL_LEVEL_MASK)
+                    >> STEP_LEVEL_LEVEL_SHIFT);
+            long initMode = (steps[i] & STEP_LEVEL_INITIAL_MODE_MASK)
+                    >> STEP_LEVEL_INITIAL_MODE_SHIFT;
+            long modMode = (steps[i] & STEP_LEVEL_MODIFIED_MODE_MASK)
+                    >> STEP_LEVEL_MODIFIED_MODE_SHIFT;
             if (checkin) {
-                lineArgs[0] = Long.toString(steps[i]);
+                lineArgs[0] = Long.toString(duration);
+                lineArgs[1] = Integer.toString(level);
+                if ((modMode&STEP_LEVEL_MODE_SCREEN_STATE) == 0) {
+                    switch ((int)(initMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) {
+                        case Display.STATE_OFF: lineArgs[2] = "s-"; break;
+                        case Display.STATE_ON: lineArgs[2] = "s+"; break;
+                        case Display.STATE_DOZE: lineArgs[2] = "sd"; break;
+                        case Display.STATE_DOZE_SUSPEND: lineArgs[2] = "sds"; break;
+                        default: lineArgs[1] = "?"; break;
+                    }
+                } else {
+                    lineArgs[2] = "";
+                }
+                if ((modMode&STEP_LEVEL_MODE_POWER_SAVE) == 0) {
+                    lineArgs[3] = (initMode&STEP_LEVEL_MODE_POWER_SAVE) != 0 ? "p+" : "p-";
+                } else {
+                    lineArgs[3] = "";
+                }
                 dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs);
             } else {
                 pw.print("  #"); pw.print(i); pw.print(": ");
-                TimeUtils.formatDuration(steps[i], pw);
+                TimeUtils.formatDuration(duration, pw);
+                pw.print(" to "); pw.print(level);
+                boolean haveModes = false;
+                if ((modMode&STEP_LEVEL_MODE_SCREEN_STATE) == 0) {
+                    pw.print(" (");
+                    switch ((int)(initMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) {
+                        case Display.STATE_OFF: pw.print("screen-off"); break;
+                        case Display.STATE_ON: pw.print("screen-on"); break;
+                        case Display.STATE_DOZE: pw.print("screen-doze"); break;
+                        case Display.STATE_DOZE_SUSPEND: pw.print("screen-doze-suspend"); break;
+                        default: lineArgs[1] = "screen-?"; break;
+                    }
+                    haveModes = true;
+                }
+                if ((modMode&STEP_LEVEL_MODE_POWER_SAVE) == 0) {
+                    pw.print(haveModes ? ", " : " (");
+                    pw.print((initMode&STEP_LEVEL_MODE_POWER_SAVE) != 0
+                            ? "power-save-on" : "power-save-off");
+                    haveModes = true;
+                }
+                if (haveModes) {
+                    pw.print(")");
+                }
                 pw.println();
             }
         }
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index d6ee8e0..6d4a302 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -312,6 +312,11 @@
      */
     void setDnsServersForNetwork(int netId, in String[] servers, String domains);
 
+    /**
+     * Flush the DNS cache associated with the specified network.
+     */
+    void flushNetworkDnsCache(int netId);
+
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
     void setFirewallInterfaceRule(String iface, boolean allow);
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index c43644a..713fcd8 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -18,7 +18,6 @@
 package android.os;
 
 import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
 import android.content.pm.UserInfo;
 import android.content.RestrictionEntry;
 import android.graphics.Bitmap;
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index afbf983..5ce9d5c 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.SystemApi;
 import android.util.SparseArray;
 
 import java.io.PrintWriter;
@@ -237,6 +238,16 @@
         return getUserId(Process.myUid());
     }
 
+    /**
+     * Returns true if this UserHandle refers to the owner user; false otherwise.
+     * @return true if this UserHandle refers to the owner user; false otherwise.
+     * @hide
+     */
+    @SystemApi
+    public final boolean isOwner() {
+        return this.equals(OWNER);
+    }
+
     /** @hide */
     public UserHandle(int h) {
         mHandle = h;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 13f93a7..04e6227 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -755,17 +755,50 @@
     /**
      * If the target user is a managed profile of the calling user or the caller
      * is itself a managed profile, then this returns a badged copy of the given
-     * icon to be able to distinguish it from the original icon.
-     * <P>
-     * If the original drawable is not a BitmapDrawable, then the original
-     * drawable is returned.
-     * </P>
+     * icon to be able to distinguish it from the original icon. For badging an
+     * arbitrary drawable use {@link #getBadgedDrawableForUser(
+     * android.graphics.drawable.Drawable, UserHandle, android.graphics.Rect, int)}.
+     * <p>
+     * If the original drawable is a BitmapDrawable and the backing bitmap is
+     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+     * is performed in place and the original drawable is returned.
+     * </p>
      *
      * @param icon The icon to badge.
      * @param user The target user.
      * @return A drawable that combines the original icon and a badge as
      *         determined by the system.
      */
+    public Drawable getBadgedIconForUser(Drawable icon, UserHandle user) {
+        final int badgeResId = getBadgeResIdForUser(user.getIdentifier());
+        if (badgeResId == 0) {
+            return icon;
+        }
+        Drawable badgeIcon = mContext.getPackageManager()
+                .getDrawable("system", badgeResId, null);
+        return getBadgedDrawable(icon, badgeIcon, null, true);
+    }
+
+    /**
+     * If the target user is a managed profile of the calling user or the caller
+     * is itself a managed profile, then this returns a badged copy of the given
+     * icon to be able to distinguish it from the original icon.
+     * <p>
+     * If the original drawable is not a BitmapDrawable, then the original
+     * drawable is returned.
+     * </p>
+     *
+     * @param icon The icon to badge.
+     * @param user The target user.
+     * @return A drawable that combines the original icon and a badge as
+     *         determined by the system.
+     *
+     * @deprecation Use {@link #getBadgedIconForUser(
+     *     android.graphics.drawable.Drawable, UserHandle)}
+     *
+     * @hide
+     */
+    @Deprecated
     public Drawable getBadgedDrawableForUser(Drawable icon, UserHandle user) {
         int badgeResId = getBadgeResIdForUser(user.getIdentifier());
         if (badgeResId == 0) {
@@ -773,12 +806,45 @@
         } else {
             Drawable badgeIcon = mContext.getPackageManager()
                     .getDrawable("system", badgeResId, null);
-            return getMergedDrawable(icon, badgeIcon);
+            return getBadgedDrawable(icon, badgeIcon, null, false);
         }
     }
 
     /**
      * If the target user is a managed profile of the calling user or the caller
+     * is itself a managed profile, then this returns a badged copy of the given
+     * drawable allowing the user to distinguish it from the original drawable.
+     * The caller can specify the location in the bounds of the drawable to be
+     * badged where the badge should be applied as well as the density of the
+     * badge to be used.
+     * <p>
+     * If the original drawable is a BitmapDrawable and the backing bitmap is
+     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+     * is performed in place and the original drawable is returned.
+     * </p>
+     *
+     * @param badgedDrawable The drawable to badge.
+     * @param user The target user.
+     * @param badgeLocation Where in the bounds of the badged drawable to place
+     *         the badge. If not provided, the badge is applied on top of the entire
+     *         drawable being badged.
+     * @param badgeDensity The optional desired density for the badge as per
+     *         {@link android.util.DisplayMetrics#densityDpi}. If not provided,
+     *         the density of the display is used.
+     * @return A drawable that combines the original drawable and a badge as
+     *         determined by the system.
+     */
+    public Drawable getBadgedDrawableForUser(Drawable badgedDrawable, UserHandle user,
+            Rect badgeLocation, int badgeDensity) {
+        Drawable badgeDrawable = getBadgeForUser(user, badgeDensity);
+        if (badgeDrawable == null) {
+            return badgedDrawable;
+        }
+        return getBadgedDrawable(badgedDrawable, badgeDrawable, badgeLocation, true);
+    }
+
+    /**
+     * If the target user is a managed profile of the calling user or the caller
      * is itself a managed profile, then this returns a copy of the label with
      * badging for accessibility services like talkback. E.g. passing in "Email"
      * and it might return "Work Email" for Email in the work profile.
@@ -812,14 +878,20 @@
      * icon to include in a view to distinguish it from the original icon.
      *
      * @param user The target user.
+     * @param density The optional desired density for the badge as per
+     *         {@link android.util.DisplayMetrics#densityDpi}. If not provided
+     *         the density of the current display is used.
      * @return the drawable or null if no drawable is required.
      * @hide
      */
-    public Drawable getBadgeForUser(UserHandle user) {
+    public Drawable getBadgeForUser(UserHandle user, int density) {
         UserInfo userInfo = getUserIfProfile(user.getIdentifier());
         if (userInfo != null && userInfo.isManagedProfile()) {
-            return Resources.getSystem().getDrawable(
-                    com.android.internal.R.drawable.ic_corp_badge);
+            if (density <= 0) {
+                density = mContext.getResources().getDisplayMetrics().densityDpi;
+            }
+            return Resources.getSystem().getDrawableForDensity(
+                    com.android.internal.R.drawable.ic_corp_badge, density);
         }
         return null;
     }
@@ -847,20 +919,57 @@
         return null;
     }
 
-    private Drawable getMergedDrawable(Drawable icon, Drawable badge) {
-        final int width = icon.getIntrinsicWidth();
-        final int height = icon.getIntrinsicHeight();
-        Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        icon.setBounds(0, 0, width, height);
-        icon.draw(canvas);
-        badge.setBounds(0, 0, width, height);
-        badge.draw(canvas);
-        BitmapDrawable merged = new BitmapDrawable(bitmap);
-        if (icon instanceof BitmapDrawable) {
-            merged.setTargetDensity(((BitmapDrawable) icon).getBitmap().getDensity());
+    private Drawable getBadgedDrawable(Drawable badgedDrawable, Drawable badgeDrawable,
+            Rect badgeLocation, boolean tryBadgeInPlace) {
+        final int badgedWidth = badgedDrawable.getIntrinsicWidth();
+        final int badgedHeight = badgedDrawable.getIntrinsicHeight();
+        final boolean canBadgeInPlace = tryBadgeInPlace
+                && (badgedDrawable instanceof BitmapDrawable)
+                && ((BitmapDrawable) badgedDrawable).getBitmap().isMutable();
+
+        final Bitmap bitmap;
+        if (canBadgeInPlace) {
+            bitmap = ((BitmapDrawable) badgedDrawable).getBitmap();
+        } else {
+            bitmap = Bitmap.createBitmap(badgedWidth, badgedHeight, Config.ARGB_8888);
         }
-        return merged;
+        Canvas canvas = new Canvas(bitmap);
+
+        if (!canBadgeInPlace) {
+            badgedDrawable.setBounds(0, 0, badgedWidth, badgedHeight);
+            badgedDrawable.draw(canvas);
+        }
+
+        if (badgeLocation != null) {
+            if (badgeLocation.left < 0 || badgeLocation.top < 0
+                    || badgeLocation.right > badgedWidth || badgeLocation.bottom > badgedHeight) {
+                throw new IllegalArgumentException("Badge location " + badgeLocation
+                        + " not in badged drawable bounds "
+                        + new Rect(0, 0, badgedWidth, badgedHeight));
+            }
+            badgeDrawable.setBounds(0, 0, badgeLocation.width(), badgeLocation.height());
+
+            canvas.save();
+            canvas.translate(badgeLocation.left, badgeLocation.top);
+            badgeDrawable.draw(canvas);
+            canvas.restore();
+        } else {
+            badgeDrawable.setBounds(0, 0, badgedWidth, badgedHeight);
+            badgeDrawable.draw(canvas);
+        }
+
+        if (!canBadgeInPlace) {
+            BitmapDrawable mergedDrawable = new BitmapDrawable(mContext.getResources(), bitmap);
+
+            if (badgedDrawable instanceof BitmapDrawable) {
+                BitmapDrawable bitmapDrawable = (BitmapDrawable) badgedDrawable;
+                mergedDrawable.setTargetDensity(bitmapDrawable.getBitmap().getDensity());
+            }
+
+            return mergedDrawable;
+        }
+
+        return badgedDrawable;
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4b7e615..733ab32 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2375,6 +2375,16 @@
         public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
 
         /**
+         * Whether automatic routing of system audio to USB audio peripheral is disabled.
+         * The value is boolean (1 or 0), where 1 means automatic routing is disabled,
+         * and 0 means automatic routing is enabled.
+         *
+         * @hide
+         */
+        public static final String USB_AUDIO_AUTOMATIC_ROUTING_DISABLED =
+                "usb_audio_automatic_routing_disabled";
+
+        /**
          * Whether the audible DTMF tones are played by the dialer when dialing. The value is
          * boolean (1 or 0).
          */
@@ -4722,6 +4732,13 @@
         public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms";
 
         /**
+         * This preference enables notification display on the lockscreen.
+         * @hide
+         */
+        public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS =
+                "lock_screen_show_notifications";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -6365,15 +6382,6 @@
          */
         public static final String POLICY_CONTROL = "policy_control";
 
-
-        /**
-         * This preference enables notification display even over a securely
-         * locked screen.
-         * @hide
-         */
-        public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS =
-                "lock_screen_show_notifications";
-
         /**
          * Defines global zen mode.  ZEN_MODE_OFF, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
          * or ZEN_MODE_NO_INTERRUPTIONS.
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index b0ff947..4860b44 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -161,6 +161,8 @@
     private static final int MSG_AVAILABILITY_CHANGED = 1;
     private static final int MSG_HOTWORD_DETECTED = 2;
     private static final int MSG_DETECTION_ERROR = 3;
+    private static final int MSG_DETECTION_PAUSE = 4;
+    private static final int MSG_DETECTION_RESUME = 5;
 
     private final String mText;
     private final String mLocale;
@@ -180,21 +182,27 @@
     private int mAvailability = STATE_NOT_READY;
 
     /**
-     * Details of the audio that triggered the keyphrase.
+     * Additional payload for {@link Callback#onDetected}.
      */
-    public static class TriggerAudio {
+    public static class EventPayload {
         /**
-         * Format of {@code data}.
+         * Indicates if {@code data} is the audio that triggered the keyphrase.
          */
-        @NonNull
+        public final boolean isTriggerAudio;
+        /**
+         * Format of {@code data}. May be null if {@code isTriggerAudio} is false.
+         */
+        @Nullable
         public final AudioFormat audioFormat;
         /**
-         * Raw audio data that triggered they keyphrase.
+         * Raw data associated with the event.
+         * This is the audio that triggered the keyphrase if {@code isTriggerAudio} is true.
          */
-        @NonNull
+        @Nullable
         public final byte[] data;
 
-        private TriggerAudio(AudioFormat _audioFormat, byte[] _data) {
+        private EventPayload(boolean _isTriggerAudio, AudioFormat _audioFormat, byte[] _data) {
+            isTriggerAudio = _isTriggerAudio;
             audioFormat = _audioFormat;
             data = _data;
         }
@@ -224,14 +232,27 @@
          * Clients should start a recognition again once they are done handling this
          * detection.
          *
-         * @param triggerAudio Optional trigger audio data, if it was requested during
+         * @param eventPayload Payload data for the detection event.
+         *        This may contain the trigger audio, if requested when calling
          *        {@link AlwaysOnHotwordDetector#startRecognition(int)}.
          */
-        void onDetected(@Nullable TriggerAudio triggerAudio);
+        void onDetected(@NonNull EventPayload eventPayload);
         /**
          * Called when the detection fails due to an error.
          */
         void onError();
+        /**
+         * Called when the recognition is paused temporarily for some reason.
+         * This is an informational callback, and the clients shouldn't be doing anything here
+         * except showing an indication on their UI if they have to.
+         */
+        void onRecognitionPaused();
+        /**
+         * Called when the recognition is resumed after it was temporarily paused.
+         * This is an informational callback, and the clients shouldn't be doing anything here
+         * except showing an indication on their UI if they have to.
+         */
+        void onRecognitionResumed();
     }
 
     /**
@@ -487,22 +508,13 @@
         @Override
         public void onDetected(KeyphraseRecognitionEvent event) {
             if (DBG) {
-                Slog.d(TAG, "OnDetected(" + event + ")");
+                Slog.d(TAG, "onDetected(" + event + ")");
             } else {
                 Slog.i(TAG, "onDetected");
             }
-            Message message = Message.obtain(mHandler, MSG_HOTWORD_DETECTED);
-            // FIXME: Check whether the event contains trigger data or not.
-            // FIXME: Read the audio format from the event.
-            if (event.data != null) {
-                AudioFormat audioFormat = new AudioFormat.Builder()
-                        .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
-                        .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
-                        .setSampleRate(16000)
-                        .build();
-                message.obj = new TriggerAudio(audioFormat, event.data);
-            }
-            message.sendToTarget();
+            Message.obtain(mHandler, MSG_HOTWORD_DETECTED,
+                    new EventPayload(event.triggerInData, event.captureFormat, event.data))
+                    .sendToTarget();
         }
 
         @Override
@@ -510,6 +522,18 @@
             Slog.i(TAG, "onError: " + status);
             mHandler.sendEmptyMessage(MSG_DETECTION_ERROR);
         }
+
+        @Override
+        public void onRecognitionPaused() {
+            Slog.i(TAG, "onRecognitionPaused");
+            mHandler.sendEmptyMessage(MSG_DETECTION_PAUSE);
+        }
+
+        @Override
+        public void onRecognitionResumed() {
+            Slog.i(TAG, "onRecognitionResumed");
+            mHandler.sendEmptyMessage(MSG_DETECTION_RESUME);
+        }
     }
 
     class MyHandler extends Handler {
@@ -527,11 +551,17 @@
                     mExternalCallback.onAvailabilityChanged(msg.arg1);
                     break;
                 case MSG_HOTWORD_DETECTED:
-                    mExternalCallback.onDetected((TriggerAudio) msg.obj);
+                    mExternalCallback.onDetected((EventPayload) msg.obj);
                     break;
                 case MSG_DETECTION_ERROR:
                     mExternalCallback.onError();
                     break;
+                case MSG_DETECTION_PAUSE:
+                    mExternalCallback.onRecognitionPaused();
+                    break;
+                case MSG_DETECTION_RESUME:
+                    mExternalCallback.onRecognitionResumed();
+                    break;
                 default:
                     super.handleMessage(msg);
             }
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index e3e328c..19d14bf 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -448,6 +448,7 @@
     }
 
     void doDestroy() {
+        onDestroy();
         if (mInitialized) {
             mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
                     mInsetsComputer);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index d14f226..f9333d5 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -276,12 +276,12 @@
         if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
             HardwareCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
             try {
-                canvas.save();
+                final int saveCount = canvas.save();
                 canvas.translate(mInsetLeft, mInsetTop);
                 callbacks.onHardwarePreDraw(canvas);
                 canvas.drawRenderNode(view.getDisplayList());
                 callbacks.onHardwarePostDraw(canvas);
-                canvas.restore();
+                canvas.restoreToCount(saveCount);
                 mRootNodeNeedsUpdate = false;
             } finally {
                 mRootNode.end(canvas);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9eda8e0..328d67c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3176,7 +3176,7 @@
 
     @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_")
     private Drawable mBackground;
-    private ColorStateList mBackgroundTint = null;
+    private ColorStateList mBackgroundTintList = null;
     private PorterDuff.Mode mBackgroundTintMode = PorterDuff.Mode.SRC_ATOP;
     private boolean mHasBackgroundTint = false;
 
@@ -4016,7 +4016,7 @@
                     break;
                 case R.styleable.View_backgroundTint:
                     // This will get applied later during setBackground().
-                    mBackgroundTint = a.getColorStateList(R.styleable.View_backgroundTint);
+                    mBackgroundTintList = a.getColorStateList(R.styleable.View_backgroundTint);
                     mHasBackgroundTint = true;
                     break;
                 case R.styleable.View_backgroundTintMode:
@@ -15912,16 +15912,16 @@
      * <p>
      * Subsequent calls to {@link #setBackground(Drawable)} will automatically
      * mutate the drawable and apply the specified tint and tint mode using
-     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     * {@link Drawable#setTintList(ColorStateList)}.
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      *
      * @attr ref android.R.styleable#View_backgroundTint
-     * @see #getBackgroundTint()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #getBackgroundTintList()
+     * @see Drawable#setTintList(ColorStateList)
      */
-    public void setBackgroundTint(@Nullable ColorStateList tint) {
-        mBackgroundTint = tint;
+    public void setBackgroundTintList(@Nullable ColorStateList tint) {
+        mBackgroundTintList = tint;
         mHasBackgroundTint = true;
 
         applyBackgroundTint();
@@ -15930,23 +15930,23 @@
     /**
      * @return the tint applied to the background drawable
      * @attr ref android.R.styleable#View_backgroundTint
-     * @see #setBackgroundTint(ColorStateList)
+     * @see #setBackgroundTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getBackgroundTint() {
-        return mBackgroundTint;
+    public ColorStateList getBackgroundTintList() {
+        return mBackgroundTintList;
     }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
-     * {@link #setBackgroundTint(ColorStateList)}} to the background drawable.
+     * {@link #setBackgroundTintList(ColorStateList)}} to the background drawable.
      * The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
      *
      * @param tintMode the blending mode used to apply the tint, may be
      *                 {@code null} to clear tint
      * @attr ref android.R.styleable#View_backgroundTintMode
      * @see #getBackgroundTintMode()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
      */
     public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
         mBackgroundTintMode = tintMode;
@@ -15967,7 +15967,8 @@
     private void applyBackgroundTint() {
         if (mBackground != null && mHasBackgroundTint) {
             mBackground = mBackground.mutate();
-            mBackground.setTint(mBackgroundTint, mBackgroundTintMode);
+            mBackground.setTintList(mBackgroundTintList);
+            mBackground.setTintMode(mBackgroundTintMode);
         }
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 671aa10..a326aad 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -735,15 +735,23 @@
 
     void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
         synchronized (this) {
-            int oldSoftInputMode = mWindowAttributes.softInputMode;
+            final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
+            final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
+            final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
+            final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
+            final int oldSoftInputMode = mWindowAttributes.softInputMode;
+
             // Keep track of the actual window flags supplied by the client.
             mClientWindowLayoutFlags = attrs.flags;
-            // preserve compatible window flag if exists.
-            int compatibleWindowFlag = mWindowAttributes.privateFlags
+
+            // Preserve compatible window flag if exists.
+            final int compatibleWindowFlag = mWindowAttributes.privateFlags
                     & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-            // transfer over system UI visibility values as they carry current state.
+
+            // Transfer over system UI visibility values as they carry current state.
             attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
             attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
+
             mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
             if ((mWindowAttributesChangesFlag
                     & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
@@ -755,20 +763,25 @@
             }
             mWindowAttributes.privateFlags |= compatibleWindowFlag;
 
+            // Restore old surface insets.
+            mWindowAttributes.surfaceInsets.set(
+                    oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
+
             applyKeepScreenOnFlag(mWindowAttributes);
 
             if (newView) {
                 mSoftInputMode = attrs.softInputMode;
                 requestLayout();
             }
+
             // Don't lose the mode we last auto-computed.
-            if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+            if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
                     == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
                 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
                         & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
-                        | (oldSoftInputMode
-                                & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
+                        | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
             }
+
             mWindowAttributesChanged = true;
             scheduleTraversals();
         }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index aa0b94f..129476c 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3857,13 +3857,17 @@
                                     firstChildTop == contentTop - mOverscrollDistance) ||
                               (mFirstPosition + childCount == mItemCount &&
                                     lastChildBottom == contentBottom + mOverscrollDistance))) {
-                        if (mFlingRunnable == null) {
-                            mFlingRunnable = new FlingRunnable();
+                        if (!dispatchNestedPreFling(0, -initialVelocity)) {
+                            if (mFlingRunnable == null) {
+                                mFlingRunnable = new FlingRunnable();
+                            }
+                            reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
+                            mFlingRunnable.start(-initialVelocity);
+                            dispatchNestedFling(0, -initialVelocity, true);
+                        } else {
+                            mTouchMode = TOUCH_MODE_REST;
+                            reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
                         }
-                        reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
-
-                        mFlingRunnable.start(-initialVelocity);
-                        dispatchNestedFling(0, -initialVelocity, true);
                     } else {
                         mTouchMode = TOUCH_MODE_REST;
                         reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
@@ -4029,7 +4033,9 @@
             if (mFlingRunnable == null) {
                 mFlingRunnable = new FlingRunnable();
             }
-            mFlingRunnable.start((int) velocityY);
+            if (!dispatchNestedPreFling(0, velocityY)) {
+                mFlingRunnable.start((int) velocityY);
+            }
             return true;
         }
         return dispatchNestedFling(velocityX, velocityY, consumed);
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 2708525..39cd7e3 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -41,7 +41,7 @@
     private final Rect mTempRect = new Rect();
 
     private Drawable mThumb;
-    private ColorStateList mThumbTint = null;
+    private ColorStateList mThumbTintList = null;
     private PorterDuff.Mode mThumbTintMode = PorterDuff.Mode.SRC_ATOP;
     private boolean mHasThumbTint = false;
 
@@ -100,7 +100,7 @@
                 R.styleable.SeekBar_thumbTintMode, -1), mThumbTintMode);
 
         if (a.hasValue(R.styleable.SeekBar_thumbTint)) {
-            mThumbTint = a.getColorStateList(R.styleable.SeekBar_thumbTint);
+            mThumbTintList = a.getColorStateList(R.styleable.SeekBar_thumbTint);
             mHasThumbTint = true;
 
             applyThumbTint();
@@ -193,16 +193,16 @@
      * <p>
      * Subsequent calls to {@link #setThumb(Drawable)} will automatically
      * mutate the drawable and apply the specified tint and tint mode using
-     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     * {@link Drawable#setTintList(ColorStateList)}.
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      *
      * @attr ref android.R.styleable#SeekBar_thumbTint
-     * @see #getThumbTint()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #getThumbTintList()
+     * @see Drawable#setTintList(ColorStateList)
      */
-    public void setThumbTint(@Nullable ColorStateList tint) {
-        mThumbTint = tint;
+    public void setThumbTintList(@Nullable ColorStateList tint) {
+        mThumbTintList = tint;
         mHasThumbTint = true;
 
         applyThumbTint();
@@ -211,16 +211,16 @@
     /**
      * @return the tint applied to the thumb drawable
      * @attr ref android.R.styleable#SeekBar_thumbTint
-     * @see #setThumbTint(ColorStateList)
+     * @see #setThumbTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getThumbTint() {
-        return mThumbTint;
+    public ColorStateList getThumbTintList() {
+        return mThumbTintList;
     }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
-     * {@link #setThumbTint(ColorStateList)}} to the thumb drawable. The
+     * {@link #setThumbTintList(ColorStateList)}} to the thumb drawable. The
      * default mode is {@link PorterDuff.Mode#SRC_ATOP}.
      *
      * @param tintMode the blending mode used to apply the tint, may be
@@ -228,7 +228,7 @@
      *
      * @attr ref android.R.styleable#SeekBar_thumbTintMode
      * @see #getThumbTintMode()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
      */
     public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) {
         mThumbTintMode = tintMode;
@@ -249,7 +249,8 @@
     private void applyThumbTint() {
         if (mThumb != null && mHasThumbTint) {
             mThumb = mThumb.mutate();
-            mThumb.setTint(mThumbTint, mThumbTintMode);
+            mThumb.setTintList(mThumbTintList);
+            mThumb.setTintMode(mThumbTintMode);
         }
     }
 
diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java
index 3b026bd..285dee8 100644
--- a/core/java/android/widget/AdapterViewFlipper.java
+++ b/core/java/android/widget/AdapterViewFlipper.java
@@ -105,7 +105,17 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(Intent.ACTION_USER_PRESENT);
-        getContext().registerReceiver(mReceiver, filter);
+
+        // OK, this is gross but needed. This class is supported by the
+        // remote views machanism and as a part of that the remote views
+        // can be inflated by a context for another user without the app
+        // having interact users permission - just for loading resources.
+        // For exmaple, when adding widgets from a user profile to the
+        // home screen. Therefore, we register the receiver as the current
+        // user not the one the context is for.
+        getContext().registerReceiverAsUser(mReceiver, android.os.Process.myUserHandle(),
+                filter, null, mHandler);
+
 
         if (mAutoStart) {
             // Automatically start when requested
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 791151c..ccd0480 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -47,7 +47,7 @@
 
     private int mCheckMarkResource;
     private Drawable mCheckMarkDrawable;
-    private ColorStateList mCheckMarkTint = null;
+    private ColorStateList mCheckMarkTintList = null;
     private PorterDuff.Mode mCheckMarkTintMode = PorterDuff.Mode.SRC_ATOP;
     private boolean mHasCheckMarkTint = false;
 
@@ -86,7 +86,7 @@
                 R.styleable.CompoundButton_buttonTintMode, -1), mCheckMarkTintMode);
 
         if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
-            mCheckMarkTint = a.getColorStateList(R.styleable.CompoundButton_buttonTint);
+            mCheckMarkTintList = a.getColorStateList(R.styleable.CompoundButton_buttonTint);
             mHasCheckMarkTint = true;
 
             applyCheckMarkTint();
@@ -189,16 +189,16 @@
      * Subsequent calls to {@link #setCheckMarkDrawable(Drawable)} will
      * automatically mutate the drawable and apply the specified tint and
      * tint mode using
-     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     * {@link Drawable#setTintList(ColorStateList)}.
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      *
      * @attr ref android.R.styleable#CheckedTextView_checkMarkTint
-     * @see #getCheckMarkTint()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #getCheckMarkTintList()
+     * @see Drawable#setTintList(ColorStateList)
      */
-    public void setCheckMarkTint(@Nullable ColorStateList tint) {
-        mCheckMarkTint = tint;
+    public void setCheckMarkTintList(@Nullable ColorStateList tint) {
+        mCheckMarkTintList = tint;
         mHasCheckMarkTint = true;
 
         applyCheckMarkTint();
@@ -207,23 +207,23 @@
     /**
      * @return the tint applied to the check mark drawable
      * @attr ref android.R.styleable#CheckedTextView_checkMarkTint
-     * @see #setCheckMarkTint(ColorStateList)
+     * @see #setCheckMarkTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getCheckMarkTint() {
-        return mCheckMarkTint;
+    public ColorStateList getCheckMarkTintList() {
+        return mCheckMarkTintList;
     }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
-     * {@link #setCheckMarkTint(ColorStateList)} to the check mark
+     * {@link #setCheckMarkTintList(ColorStateList)} to the check mark
      * drawable. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
      *
      * @param tintMode the blending mode used to apply the tint, may be
      *                 {@code null} to clear tint
      * @attr ref android.R.styleable#CheckedTextView_checkMarkTintMode
-     * @see #setCheckMarkTint(ColorStateList)
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #setCheckMarkTintList(ColorStateList)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
      */
     public void setCheckMarkTintMode(@Nullable PorterDuff.Mode tintMode) {
         mCheckMarkTintMode = tintMode;
@@ -244,7 +244,8 @@
     private void applyCheckMarkTint() {
         if (mCheckMarkDrawable != null && mHasCheckMarkTint) {
             mCheckMarkDrawable = mCheckMarkDrawable.mutate();
-            mCheckMarkDrawable.setTint(mCheckMarkTint, mCheckMarkTintMode);
+            mCheckMarkDrawable.setTintList(mCheckMarkTintList);
+            mCheckMarkDrawable.setTintMode(mCheckMarkTintMode);
         }
     }
 
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index a45777e..c1d8cb3 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -53,7 +53,7 @@
     private boolean mBroadcasting;
 
     private Drawable mButtonDrawable;
-    private ColorStateList mButtonTint = null;
+    private ColorStateList mButtonTintList = null;
     private PorterDuff.Mode mButtonTintMode = PorterDuff.Mode.SRC_ATOP;
     private boolean mHasButtonTint = false;
 
@@ -91,7 +91,7 @@
                 R.styleable.CompoundButton_buttonTintMode, -1), mButtonTintMode);
 
         if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
-            mButtonTint = a.getColorStateList(R.styleable.CompoundButton_buttonTint);
+            mButtonTintList = a.getColorStateList(R.styleable.CompoundButton_buttonTint);
             mHasButtonTint = true;
 
             applyButtonTint();
@@ -245,16 +245,16 @@
      * Subsequent calls to {@link #setButtonDrawable(Drawable)} will
      * automatically mutate the drawable and apply the specified tint and tint
      * mode using
-     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     * {@link Drawable#setTintList(ColorStateList)}.
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      *
      * @attr ref android.R.styleable#CompoundButton_buttonTint
-     * @see #setButtonTint(ColorStateList)
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #setButtonTintList(ColorStateList)
+     * @see Drawable#setTintList(ColorStateList)
      */
-    public void setButtonTint(@Nullable ColorStateList tint) {
-        mButtonTint = tint;
+    public void setButtonTintList(@Nullable ColorStateList tint) {
+        mButtonTintList = tint;
         mHasButtonTint = true;
 
         applyButtonTint();
@@ -263,23 +263,23 @@
     /**
      * @return the tint applied to the button drawable
      * @attr ref android.R.styleable#CompoundButton_buttonTint
-     * @see #setButtonTint(ColorStateList)
+     * @see #setButtonTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getButtonTint() {
-        return mButtonTint;
+    public ColorStateList getButtonTintList() {
+        return mButtonTintList;
     }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
-     * {@link #setButtonTint(ColorStateList)}} to the button drawable. The
+     * {@link #setButtonTintList(ColorStateList)}} to the button drawable. The
      * default mode is {@link PorterDuff.Mode#SRC_ATOP}.
      *
      * @param tintMode the blending mode used to apply the tint, may be
      *                 {@code null} to clear tint
      * @attr ref android.R.styleable#CompoundButton_buttonTintMode
      * @see #getButtonTintMode()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
      */
     public void setButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
         mButtonTintMode = tintMode;
@@ -300,7 +300,8 @@
     private void applyButtonTint() {
         if (mButtonDrawable != null && mHasButtonTint) {
             mButtonDrawable = mButtonDrawable.mutate();
-            mButtonDrawable.setTint(mButtonTint, mButtonTintMode);
+            mButtonDrawable.setTintList(mButtonTintList);
+            mButtonDrawable.setTintMode(mButtonTintMode);
         }
     }
 
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 74c66c8..d0a2eab 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -84,6 +84,9 @@
 public class DatePicker extends FrameLayout {
     private static final String LOG_TAG = DatePicker.class.getSimpleName();
 
+    private static final int MODE_SPINNER = 1;
+    private static final int MODE_CALENDAR = 2;
+
     private final DatePickerDelegate mDelegate;
 
     /**
@@ -120,24 +123,28 @@
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
                 defStyleAttr, defStyleRes);
-        final boolean legacyMode = a.getBoolean(R.styleable.DatePicker_legacyMode, true);
+        int mode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
         a.recycle();
 
-        if (legacyMode) {
-            mDelegate = createLegacyUIDelegate(context, attrs, defStyleAttr, defStyleRes);
-        } else {
-            mDelegate = createNewUIDelegate(context, attrs, defStyleAttr, defStyleRes);
+        switch (mode) {
+            case MODE_CALENDAR:
+                mDelegate = createCalendarUIDelegate(context, attrs, defStyleAttr, defStyleRes);
+                break;
+            case MODE_SPINNER:
+            default:
+                mDelegate = createSpinnerUIDelegate(context, attrs, defStyleAttr, defStyleRes);
+                break;
         }
     }
 
-    private DatePickerDelegate createLegacyUIDelegate(Context context, AttributeSet attrs,
+    private DatePickerDelegate createSpinnerUIDelegate(Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
-        return new LegacyDatePickerDelegate(this, context, attrs, defStyleAttr, defStyleRes);
+        return new DatePickerSpinnerDelegate(this, context, attrs, defStyleAttr, defStyleRes);
     }
 
-    private DatePickerDelegate createNewUIDelegate(Context context, AttributeSet attrs,
+    private DatePickerDelegate createCalendarUIDelegate(Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
-        return new android.widget.DatePickerDelegate(this, context, attrs, defStyleAttr,
+        return new DatePickerCalendarDelegate(this, context, attrs, defStyleAttr,
                 defStyleRes);
     }
 
@@ -454,7 +461,7 @@
     /**
      * A delegate implementing the basic DatePicker
      */
-    private static class LegacyDatePickerDelegate extends AbstractDatePickerDelegate {
+    private static class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
 
         private static final String DATE_FORMAT = "MM/dd/yyyy";
 
@@ -500,7 +507,7 @@
 
         private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
 
-        LegacyDatePickerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
+        DatePickerSpinnerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
                 int defStyleAttr, int defStyleRes) {
             super(delegator, context);
 
diff --git a/core/java/android/widget/DatePickerDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
similarity index 99%
rename from core/java/android/widget/DatePickerDelegate.java
rename to core/java/android/widget/DatePickerCalendarDelegate.java
index ddc565d..c0c76ac 100644
--- a/core/java/android/widget/DatePickerDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -52,7 +52,7 @@
 /**
  * A delegate for picking up a date (day / month / year).
  */
-class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implements
+class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate implements
         View.OnClickListener, DatePickerController {
 
     private static final int UNINITIALIZED = -1;
@@ -113,7 +113,7 @@
 
     private HashSet<OnDateChangedListener> mListeners = new HashSet<OnDateChangedListener>();
 
-    public DatePickerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
+    public DatePickerCalendarDelegate(DatePicker delegator, Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(delegator, context);
 
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 66c4b81..58f9801 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -19,6 +19,7 @@
 import android.content.UndoManager;
 import android.content.UndoOperation;
 import android.content.UndoOwner;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.InputFilter;
@@ -26,6 +27,7 @@
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
+import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.widget.EditableInputConnection;
 
 import android.R;
@@ -2810,7 +2812,12 @@
 
         @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-            TypedArray styledAttributes = mTextView.getContext().obtainStyledAttributes(
+            final boolean legacy = mTextView.getContext().getApplicationInfo().targetSdkVersion <
+                    Build.VERSION_CODES.L;
+            final Context context = !legacy && menu instanceof MenuBuilder ?
+                    ((MenuBuilder) menu).getContext() :
+                    mTextView.getContext();
+            final TypedArray styledAttributes = context.obtainStyledAttributes(
                     com.android.internal.R.styleable.SelectionModeDrawables);
 
             mode.setTitle(mTextView.getContext().getString(
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 81dfcbb..4fb7e62 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -67,7 +67,7 @@
 
     @ViewDebug.ExportedProperty(category = "drawing")
     private Drawable mForeground;
-    private ColorStateList mForegroundTint = null;
+    private ColorStateList mForegroundTintList = null;
     private PorterDuff.Mode mForegroundTintMode = PorterDuff.Mode.SRC_ATOP;
     private boolean mHasForegroundTint = false;
 
@@ -131,7 +131,7 @@
                 R.styleable.FrameLayout_foregroundTintMode, -1), mForegroundTintMode);
 
         if (a.hasValue(R.styleable.FrameLayout_foregroundTint)) {
-            mForegroundTint = a.getColorStateList(R.styleable.FrameLayout_foregroundTint);
+            mForegroundTintList = a.getColorStateList(R.styleable.FrameLayout_foregroundTint);
             mHasForegroundTint = true;
 
             applyForegroundTint();
@@ -301,40 +301,21 @@
     }
 
     /**
-     * Applies a tint to the foreground drawable.
-     * <p>
-     * Subsequent calls to {@link #setForeground(Drawable)} will automatically
-     * mutate the drawable and apply the specified tint and tint mode using
-     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
-     *
-     * @param tint the tint to apply, may be {@code null} to clear tint
-     * @param tintMode the blending mode used to apply the tint, may be
-     *                 {@code null} to clear tint
-     *
-     * @attr ref android.R.styleable#FrameLayout_foregroundTint
-     * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
-     */
-    private void setForegroundTint(@Nullable ColorStateList tint,
-            @Nullable PorterDuff.Mode tintMode) {
-    }
-
-    /**
      * Applies a tint to the foreground drawable. Does not modify the current
      * tint mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
      * <p>
      * Subsequent calls to {@link #setForeground(Drawable)} will automatically
      * mutate the drawable and apply the specified tint and tint mode using
-     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     * {@link Drawable#setTintList(ColorStateList)}.
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      *
      * @attr ref android.R.styleable#FrameLayout_foregroundTint
-     * @see #getForegroundTint()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #getForegroundTintList()
+     * @see Drawable#setTintList(ColorStateList)
      */
-    public void setForegroundTint(@Nullable ColorStateList tint) {
-        mForegroundTint = tint;
+    public void setForegroundTintList(@Nullable ColorStateList tint) {
+        mForegroundTintList = tint;
         mHasForegroundTint = true;
 
         applyForegroundTint();
@@ -343,23 +324,23 @@
     /**
      * @return the tint applied to the foreground drawable
      * @attr ref android.R.styleable#FrameLayout_foregroundTint
-     * @see #setForegroundTint(ColorStateList)
+     * @see #setForegroundTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getForegroundTint() {
-        return mForegroundTint;
+    public ColorStateList getForegroundTintList() {
+        return mForegroundTintList;
     }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
-     * {@link #setForegroundTint(ColorStateList)}} to the foreground drawable.
+     * {@link #setForegroundTintList(ColorStateList)}} to the foreground drawable.
      * The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
      *
      * @param tintMode the blending mode used to apply the tint, may be
      *                 {@code null} to clear tint
      * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
      * @see #getForegroundTintMode()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
      */
     public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
         mForegroundTintMode = tintMode;
@@ -381,7 +362,8 @@
     private void applyForegroundTint() {
         if (mForeground != null && mHasForegroundTint) {
             mForeground = mForeground.mutate();
-            mForeground.setTint(mForegroundTint, mForegroundTintMode);
+            mForeground.setTintList(mForegroundTintList);
+            mForeground.setTintMode(mForegroundTintMode);
         }
     }
 
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 0881f3e..6a15078 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -175,7 +175,7 @@
             mDrawableTint = a.getColorStateList(R.styleable.ImageView_tint);
             mHasDrawableTint = true;
 
-            applyDrawableTint();
+            applyImageTint();
         }
 
         final int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
@@ -454,62 +454,63 @@
      * <p>
      * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
      * mutate the drawable and apply the specified tint and tint mode using
-     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     * {@link Drawable#setTintList(ColorStateList)}.
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      *
      * @attr ref android.R.styleable#ImageView_tint
-     * @see #getTint()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #getImageTintList()
+     * @see Drawable#setTintList(ColorStateList)
      */
-    public void setTint(@Nullable ColorStateList tint) {
+    public void setImageTintList(@Nullable ColorStateList tint) {
         mDrawableTint = tint;
         mHasDrawableTint = true;
 
-        applyDrawableTint();
+        applyImageTint();
     }
 
     /**
      * @return the tint applied to the image drawable
      * @attr ref android.R.styleable#ImageView_tint
-     * @see #setTint(ColorStateList)
+     * @see #setImageTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getTint() {
+    public ColorStateList getImageTintList() {
         return mDrawableTint;
     }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
-     * {@link #setTint(ColorStateList)}} to the image drawable. The default
+     * {@link #setImageTintList(ColorStateList)}} to the image drawable. The default
      * mode is {@link PorterDuff.Mode#SRC_ATOP}.
      *
      * @param tintMode the blending mode used to apply the tint, may be
      *                 {@code null} to clear tint
      * @attr ref android.R.styleable#ImageView_tintMode
-     * @see #getTintMode()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #getImageTintMode()
+     * @see Drawable#setTintMode(PorterDuff.Mode)
      */
-    public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
+    public void setImageTintMode(@Nullable PorterDuff.Mode tintMode) {
         mDrawableTintMode = tintMode;
 
-        applyDrawableTint();
+        applyImageTint();
     }
 
     /**
      * @return the blending mode used to apply the tint to the image drawable
      * @attr ref android.R.styleable#ImageView_tintMode
-     * @see #setTintMode(PorterDuff.Mode)
+     * @see #setImageTintMode(PorterDuff.Mode)
      */
     @Nullable
-    public PorterDuff.Mode getTintMode() {
+    public PorterDuff.Mode getImageTintMode() {
         return mDrawableTintMode;
     }
 
-    private void applyDrawableTint() {
+    private void applyImageTint() {
         if (mDrawable != null && mHasDrawableTint) {
             mDrawable = mDrawable.mutate();
-            mDrawable.setTint(mDrawableTint, mDrawableTintMode);
+            mDrawable.setTintList(mDrawableTint);
+            mDrawable.setTintMode(mDrawableTintMode);
         }
     }
 
@@ -801,7 +802,7 @@
             d.setLevel(mLevel);
             mDrawableWidth = d.getIntrinsicWidth();
             mDrawableHeight = d.getIntrinsicHeight();
-            applyDrawableTint();
+            applyImageTint();
             applyColorMod();
             configureBounds();
         } else {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 4a30809..c0fa6e5 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -216,21 +216,21 @@
     private boolean mHasAnimation;
 
     private Drawable mIndeterminateDrawable;
-    private ColorStateList mIndeterminateTint = null;
+    private ColorStateList mIndeterminateTintList = null;
     private PorterDuff.Mode mIndeterminateTintMode = PorterDuff.Mode.SRC_ATOP;
     private boolean mHasIndeterminateTint = false;
 
     private Drawable mProgressDrawable;
 
-    private ColorStateList mProgressTint = null;
+    private ColorStateList mProgressTintList = null;
     private PorterDuff.Mode mProgressTintMode = PorterDuff.Mode.SRC_ATOP;
     private boolean mHasProgressTint = false;
 
-    private ColorStateList mProgressBackgroundTint = null;
+    private ColorStateList mProgressBackgroundTintList = null;
     private PorterDuff.Mode mProgressBackgroundTintMode = PorterDuff.Mode.SRC_ATOP;
     private boolean mHasProgressBackgroundTint = false;
 
-    private ColorStateList mSecondaryProgressTint = null;
+    private ColorStateList mSecondaryProgressTintList = null;
     private PorterDuff.Mode mSecondaryProgressTintMode = PorterDuff.Mode.SRC_ATOP;
     private boolean mHasSecondaryProgressTint = false;
 
@@ -332,11 +332,11 @@
                 R.styleable.ProgressBar_progressBackgroundTintMode, -1), mProgressTintMode);
 
         if (a.hasValue(R.styleable.ProgressBar_progressTint)) {
-            mProgressTint = a.getColorStateList(
+            mProgressTintList = a.getColorStateList(
                     R.styleable.ProgressBar_progressTint);
             mHasProgressTint = true;
 
-            applyProgressLayerTint(R.id.progress, mProgressTint,
+            applyProgressLayerTint(R.id.progress, mProgressTintList,
                     mProgressTintMode, true);
         }
 
@@ -344,11 +344,11 @@
                 R.styleable.ProgressBar_progressTintMode, -1), mProgressBackgroundTintMode);
 
         if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTint)) {
-            mProgressBackgroundTint = a.getColorStateList(
+            mProgressBackgroundTintList = a.getColorStateList(
                     R.styleable.ProgressBar_progressBackgroundTint);
             mHasProgressBackgroundTint = true;
 
-            applyProgressLayerTint(R.id.background, mProgressBackgroundTint,
+            applyProgressLayerTint(R.id.background, mProgressBackgroundTintList,
                     mProgressBackgroundTintMode, false);
         }
 
@@ -356,11 +356,11 @@
                 R.styleable.ProgressBar_secondaryProgressTintMode, -1), mSecondaryProgressTintMode);
 
         if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTint)) {
-            mSecondaryProgressTint = a.getColorStateList(
+            mSecondaryProgressTintList = a.getColorStateList(
                     R.styleable.ProgressBar_secondaryProgressTint);
             mHasSecondaryProgressTint = true;
 
-            applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint,
+            applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTintList,
                     mSecondaryProgressTintMode, false);
         }
 
@@ -368,7 +368,7 @@
                 R.styleable.ProgressBar_indeterminateTintMode, -1), mIndeterminateTintMode);
 
         if (a.hasValue(R.styleable.ProgressBar_indeterminateTint)) {
-            mIndeterminateTint = a.getColorStateList(
+            mIndeterminateTintList = a.getColorStateList(
                     R.styleable.ProgressBar_indeterminateTint);
             mHasIndeterminateTint = true;
 
@@ -430,7 +430,8 @@
             shapeDrawable.getPaint().setShader(bitmapShader);
 
             // Ensure the tint and filter are propagated in the correct order.
-            shapeDrawable.setTint(bitmap.getTint(), bitmap.getTintMode());
+            shapeDrawable.setTintList(bitmap.getTint());
+            shapeDrawable.setTintMode(bitmap.getTintMode());
             shapeDrawable.setColorFilter(bitmap.getColorFilter());
 
             return clip ? new ClipDrawable(
@@ -582,16 +583,16 @@
      * Subsequent calls to {@link #setIndeterminateDrawable(Drawable)} will
      * automatically mutate the drawable and apply the specified tint and
      * tint mode using
-     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     * {@link Drawable#setTintList(ColorStateList)}.
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      *
      * @attr ref android.R.styleable#ProgressBar_indeterminateTint
-     * @see #getIndeterminateTint()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #getIndeterminateTintList()
+     * @see Drawable#setTintList(ColorStateList)
      */
-    public void setIndeterminateTint(@Nullable ColorStateList tint) {
-        mIndeterminateTint = tint;
+    public void setIndeterminateTintList(@Nullable ColorStateList tint) {
+        mIndeterminateTintList = tint;
         mHasIndeterminateTint = true;
 
         applyIndeterminateTint();
@@ -600,23 +601,23 @@
     /**
      * @return the tint applied to the indeterminate drawable
      * @attr ref android.R.styleable#ProgressBar_indeterminateTint
-     * @see #setIndeterminateTint(ColorStateList)
+     * @see #setIndeterminateTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getIndeterminateTint() {
-        return mIndeterminateTint;
+    public ColorStateList getIndeterminateTintList() {
+        return mIndeterminateTintList;
     }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
-     * {@link #setIndeterminateTint(ColorStateList)} to the indeterminate
+     * {@link #setIndeterminateTintList(ColorStateList)} to the indeterminate
      * drawable. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
      *
      * @param tintMode the blending mode used to apply the tint, may be
      *                 {@code null} to clear tint
      * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
-     * @see #setIndeterminateTint(ColorStateList)
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #setIndeterminateTintList(ColorStateList)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
      */
     public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
         mIndeterminateTintMode = tintMode;
@@ -637,7 +638,8 @@
     private void applyIndeterminateTint() {
         if (mIndeterminateDrawable != null && mHasIndeterminateTint) {
             mIndeterminateDrawable = mIndeterminateDrawable.mutate();
-            mIndeterminateDrawable.setTint(mIndeterminateTint, mIndeterminateTintMode);
+            mIndeterminateDrawable.setTintList(mIndeterminateTintList);
+            mIndeterminateDrawable.setTintMode(mIndeterminateTintMode);
         }
     }
 
@@ -704,16 +706,17 @@
                 }
 
                 if (mHasProgressTint) {
-                    applyProgressLayerTint(R.id.progress, mProgressTint, mProgressTintMode, true);
+                    applyProgressLayerTint(R.id.progress, mProgressTintList,
+                            mProgressTintMode, true);
                 }
 
                 if (mHasProgressBackgroundTint) {
-                    applyProgressLayerTint(R.id.background, mProgressBackgroundTint,
+                    applyProgressLayerTint(R.id.background, mProgressBackgroundTintList,
                             mProgressBackgroundTintMode, false);
                 }
 
                 if (mHasSecondaryProgressTint) {
-                    applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint,
+                    applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTintList,
                             mSecondaryProgressTintMode, false);
                 }
             }
@@ -743,16 +746,16 @@
      * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
      * automatically mutate the drawable and apply the specified tint and
      * tint mode using
-     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     * {@link Drawable#setTintList(ColorStateList)}.
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      *
      * @attr ref android.R.styleable#ProgressBar_progressTint
-     * @see #getProgressTint()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #getProgressTintList()
+     * @see Drawable#setTintList(ColorStateList)
      */
-    public void setProgressTint(@Nullable ColorStateList tint) {
-        mProgressTint = tint;
+    public void setProgressTintList(@Nullable ColorStateList tint) {
+        mProgressTintList = tint;
         mHasProgressTint = true;
 
         applyProgressLayerTint(R.id.progress, tint, mProgressTintMode, true);
@@ -761,28 +764,28 @@
     /**
      * @return the tint applied to the progress drawable
      * @attr ref android.R.styleable#ProgressBar_progressTint
-     * @see #setProgressTint(ColorStateList)
+     * @see #setProgressTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getProgressTint() {
-        return mProgressTint;
+    public ColorStateList getProgressTintList() {
+        return mProgressTintList;
     }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
-     * {@link #setProgressTint(ColorStateList)}} to the progress
+     * {@link #setProgressTintList(ColorStateList)}} to the progress
      * indicator. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
      *
      * @param tintMode the blending mode used to apply the tint, may be
      *                 {@code null} to clear tint
      * @attr ref android.R.styleable#ProgressBar_progressTintMode
      * @see #getProgressTintMode()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
      */
     public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
         mProgressTintMode = tintMode;
 
-        applyProgressLayerTint(R.id.progress, mProgressTint, tintMode, true);
+        applyProgressLayerTint(R.id.progress, mProgressTintList, tintMode, true);
     }
 
     /**
@@ -807,16 +810,16 @@
      * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
      * drawable contains a progress background will automatically mutate the
      * drawable and apply the specified tint and tint mode using
-     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     * {@link Drawable#setTintList(ColorStateList)}.
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      *
      * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
-     * @see #getProgressBackgroundTint()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #getProgressBackgroundTintList()
+     * @see Drawable#setTintList(ColorStateList)
      */
-    public void setProgressBackgroundTint(@Nullable ColorStateList tint) {
-        mProgressBackgroundTint = tint;
+    public void setProgressBackgroundTintList(@Nullable ColorStateList tint) {
+        mProgressBackgroundTintList = tint;
         mHasProgressBackgroundTint = true;
 
         applyProgressLayerTint(R.id.background, tint, mProgressBackgroundTintMode, false);
@@ -825,28 +828,28 @@
     /**
      * @return the tint applied to the progress background
      * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
-     * @see #setProgressBackgroundTint(ColorStateList)
+     * @see #setProgressBackgroundTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getProgressBackgroundTint() {
-        return mProgressBackgroundTint;
+    public ColorStateList getProgressBackgroundTintList() {
+        return mProgressBackgroundTintList;
     }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
-     * {@link #setProgressBackgroundTint(ColorStateList)}} to the progress
+     * {@link #setProgressBackgroundTintList(ColorStateList)}} to the progress
      * background. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
      *
      * @param tintMode the blending mode used to apply the tint, may be
      *                 {@code null} to clear tint
      * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
-     * @see #setProgressBackgroundTint(ColorStateList)
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #setProgressBackgroundTintList(ColorStateList)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
      */
     public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
         mProgressBackgroundTintMode = tintMode;
 
-        applyProgressLayerTint(R.id.background, mProgressBackgroundTint, tintMode, false);
+        applyProgressLayerTint(R.id.background, mProgressBackgroundTintList, tintMode, false);
     }
 
     /**
@@ -872,16 +875,16 @@
      * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
      * drawable contains a secondary progress indicator will automatically
      * mutate the drawable and apply the specified tint and tint mode using
-     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     * {@link Drawable#setTintList(ColorStateList)}.
      *
      * @param tint the tint to apply, may be {@code null} to clear tint
      *
      * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
-     * @see #getSecondaryProgressTint()
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #getSecondaryProgressTintList()
+     * @see Drawable#setTintList(ColorStateList)
      */
-    public void setSecondaryProgressTint(@Nullable ColorStateList tint) {
-        mSecondaryProgressTint = tint;
+    public void setSecondaryProgressTintList(@Nullable ColorStateList tint) {
+        mSecondaryProgressTintList = tint;
         mHasSecondaryProgressTint = true;
 
         applyProgressLayerTint(R.id.secondaryProgress, tint, mSecondaryProgressTintMode, false);
@@ -890,29 +893,29 @@
     /**
      * @return the tint applied to the secondary progress drawable
      * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
-     * @see #setSecondaryProgressTint(ColorStateList)
+     * @see #setSecondaryProgressTintList(ColorStateList)
      */
     @Nullable
-    public ColorStateList getSecondaryProgressTint() {
-        return mSecondaryProgressTint;
+    public ColorStateList getSecondaryProgressTintList() {
+        return mSecondaryProgressTintList;
     }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
-     * {@link #setSecondaryProgressTint(ColorStateList)}} to the secondary
+     * {@link #setSecondaryProgressTintList(ColorStateList)}} to the secondary
      * progress indicator. The default mode is
      * {@link PorterDuff.Mode#SRC_ATOP}.
      *
      * @param tintMode the blending mode used to apply the tint, may be
      *                 {@code null} to clear tint
      * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
-     * @see #setSecondaryProgressTint(ColorStateList)
-     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     * @see #setSecondaryProgressTintList(ColorStateList)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
      */
     public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
         mSecondaryProgressTintMode = tintMode;
 
-        applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint, tintMode, false);
+        applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTintList, tintMode, false);
     }
 
     /**
@@ -942,7 +945,8 @@
             }
 
             if (layer != null) {
-                layer.setTint(tint, tintMode);
+                layer.setTintList(tint);
+                layer.setTintMode(tintMode);
             }
         }
     }
@@ -1066,7 +1070,9 @@
             layer = d;
         }
 
-        layer.mutate().setTint(tint, tintMode);
+        layer.mutate();
+        layer.setTintList(tint);
+        layer.setTintMode(tintMode);
     }
 
     private float getScale(float progress) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 1098fa2..8aef304 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -18,6 +18,7 @@
 
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
+import android.app.Application;
 import android.app.PendingIntent;
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
@@ -81,12 +82,6 @@
     private ApplicationInfo mApplication;
 
     /**
-     * The package name of the package containing the layout
-     * resource. (Added to the parcel)
-     */
-    private final String mPackage;
-
-    /**
      * The resource ID of the layout file. (Added to the parcel)
      */
     private final int mLayoutId;
@@ -1635,11 +1630,34 @@
      * @param layoutId The id of the layout resource
      */
     public RemoteViews(String packageName, int layoutId) {
-        mPackage = packageName;
+        this(getApplicationInfo(packageName, UserHandle.myUserId()), layoutId);
+    }
+
+    /**
+     * Create a new RemoteViews object that will display the views contained
+     * in the specified layout file.
+     *
+     * @param packageName Name of the package that contains the layout resource.
+     * @param userId The user under which the package is running.
+     * @param layoutId The id of the layout resource.
+     *
+     * @hide
+     */
+    public RemoteViews(String packageName, int userId, int layoutId) {
+        this(getApplicationInfo(packageName, userId), layoutId);
+    }
+
+    /**
+     * Create a new RemoteViews object that will display the views contained
+     * in the specified layout file.
+     *
+     * @param application The application whose content is shown by the views.
+     * @param layoutId The id of the layout resource.
+     */
+    private RemoteViews(ApplicationInfo application, int layoutId) {
+        mApplication = application;
         mLayoutId = layoutId;
         mBitmapCache = new BitmapCache();
-        mApplication = ActivityThread.currentApplication().getApplicationInfo();
-
         // setup the memory usage statistics
         mMemoryUsageCounter = new MemoryUsageCounter();
         recalculateMemoryUsage();
@@ -1660,10 +1678,11 @@
         if (landscape == null || portrait == null) {
             throw new RuntimeException("Both RemoteViews must be non-null");
         }
-        if (landscape.getPackage().compareTo(portrait.getPackage()) != 0) {
-            throw new RuntimeException("Both RemoteViews must share the same package");
+        if (landscape.mApplication.uid != portrait.mApplication.uid
+                || !landscape.mApplication.packageName.equals(portrait.mApplication.packageName)) {
+            throw new RuntimeException("Both RemoteViews must share the same package and user");
         }
-        mPackage = portrait.getPackage();
+        mApplication = portrait.mApplication;
         mLayoutId = portrait.getLayoutId();
 
         mLandscape = landscape;
@@ -1700,7 +1719,7 @@
         }
 
         if (mode == MODE_NORMAL) {
-            mPackage = parcel.readString();
+            mApplication = parcel.readParcelable(null);
             mLayoutId = parcel.readInt();
             mIsWidgetCollectionChild = parcel.readInt() == 1;
 
@@ -1764,12 +1783,10 @@
             // MODE_HAS_LANDSCAPE_AND_PORTRAIT
             mLandscape = new RemoteViews(parcel, mBitmapCache);
             mPortrait = new RemoteViews(parcel, mBitmapCache);
-            mPackage = mPortrait.getPackage();
+            mApplication = mPortrait.mApplication;
             mLayoutId = mPortrait.getLayoutId();
         }
 
-        mApplication = parcel.readParcelable(null);
-
         // setup the memory usage statistics
         mMemoryUsageCounter = new MemoryUsageCounter();
         recalculateMemoryUsage();
@@ -1786,7 +1803,7 @@
     }
 
     public String getPackage() {
-        return mPackage;
+        return mApplication.packageName;
     }
 
     /**
@@ -2565,19 +2582,7 @@
                 return context.createApplicationContext(mApplication,
                         Context.CONTEXT_RESTRICTED);
             } catch (NameNotFoundException e) {
-                Log.e(LOG_TAG, "Package name " + mPackage + " not found");
-            }
-        }
-
-        if (mPackage != null) {
-            if (context.getPackageName().equals(mPackage)) {
-                return context;
-            }
-            try {
-                return context.createPackageContext(
-                        mPackage, Context.CONTEXT_RESTRICTED);
-            } catch (NameNotFoundException e) {
-                Log.e(LOG_TAG, "Package name " + mPackage + " not found");
+                Log.e(LOG_TAG, "Package name " + mApplication.packageName + " not found");
             }
         }
 
@@ -2614,7 +2619,7 @@
             if (mIsRoot) {
                 mBitmapCache.writeBitmapsToParcel(dest, flags);
             }
-            dest.writeString(mPackage);
+            dest.writeParcelable(mApplication, flags);
             dest.writeInt(mLayoutId);
             dest.writeInt(mIsWidgetCollectionChild ? 1 : 0);
             int count;
@@ -2638,8 +2643,28 @@
             mLandscape.writeToParcel(dest, flags);
             mPortrait.writeToParcel(dest, flags);
         }
+    }
 
-        dest.writeParcelable(mApplication, 0);
+    private static ApplicationInfo getApplicationInfo(String packageName, int userId) {
+        // Get the application for the passed in package and user.
+        Application application = ActivityThread.currentApplication();
+        if (application == null) {
+            throw new IllegalStateException("Cannot create remote views out of an aplication.");
+        }
+
+        ApplicationInfo applicationInfo = application.getApplicationInfo();
+        if (UserHandle.getUserId(applicationInfo.uid) != userId
+                || !applicationInfo.packageName.equals(packageName)) {
+            try {
+                Context context = application.getApplicationContext().createPackageContextAsUser(
+                        packageName, 0, new UserHandle(userId));
+                applicationInfo = context.getApplicationInfo();
+            } catch (NameNotFoundException nnfe) {
+                throw new IllegalArgumentException("No such package " + packageName);
+            }
+        }
+
+        return applicationInfo;
     }
 
     /**
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index fd04890..dd312a6 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1577,9 +1577,11 @@
     private void flingWithNestedDispatch(int velocityY) {
         final boolean canFling = (mScrollY > 0 || velocityY > 0) &&
                 (mScrollY < getScrollRange() || velocityY < 0);
-        dispatchNestedFling(0, velocityY, canFling);
-        if (canFling) {
-            fling(velocityY);
+        if (!dispatchNestedPreFling(0, velocityY)) {
+            dispatchNestedFling(0, velocityY, canFling);
+            if (canFling) {
+                fling(velocityY);
+            }
         }
     }
 
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index 1a0ce9c..5e88a96 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -589,10 +589,10 @@
         @Override
         public float getInterpolation(float input) {
             final float interpolated = VISCOUS_FLUID_NORMALIZE * viscousFluid(input);
-            if (input > 0) {
-                return input + VISCOUS_FLUID_OFFSET;
+            if (interpolated > 0) {
+                return interpolated + VISCOUS_FLUID_OFFSET;
             }
-            return input;
+            return interpolated;
         }
     }
 }
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 026a8ee..c488666 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -45,6 +45,9 @@
  */
 @Widget
 public class TimePicker extends FrameLayout {
+    private static final int MODE_SPINNER = 1;
+    private static final int MODE_CLOCK = 2;
+
     private final TimePickerDelegate mDelegate;
 
     /**
@@ -77,15 +80,19 @@
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
-        final boolean legacyMode = a.getBoolean(R.styleable.TimePicker_legacyMode, true);
+        int mode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
         a.recycle();
 
-        if (legacyMode) {
-            mDelegate = new LegacyTimePickerDelegate(
-                    this, context, attrs, defStyleAttr, defStyleRes);
-        } else {
-            mDelegate = new android.widget.TimePickerDelegate(
-                    this, context, attrs, defStyleAttr, defStyleRes);
+        switch (mode) {
+            case MODE_CLOCK:
+                mDelegate = new TimePickerSpinnerDelegate(
+                        this, context, attrs, defStyleAttr, defStyleRes);
+                break;
+            case MODE_SPINNER:
+            default:
+                mDelegate = new TimePickerClockDelegate(
+                        this, context, attrs, defStyleAttr, defStyleRes);
+                break;
         }
     }
 
diff --git a/core/java/android/widget/LegacyTimePickerDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
similarity index 97%
rename from core/java/android/widget/LegacyTimePickerDelegate.java
rename to core/java/android/widget/TimePickerClockDelegate.java
index 70db211..8102c4a 100644
--- a/core/java/android/widget/LegacyTimePickerDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.os.Parcel;
@@ -44,7 +45,7 @@
 /**
  * A delegate implementing the basic TimePicker
  */
-class LegacyTimePickerDelegate extends TimePicker.AbstractTimePickerDelegate {
+class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
 
     private static final boolean DEFAULT_ENABLED_STATE = true;
 
@@ -100,8 +101,8 @@
                 }
             };
 
-    public LegacyTimePickerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
-                                    int defStyleAttr, int defStyleRes) {
+    public TimePickerClockDelegate(TimePicker delegator, Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
         super(delegator, context);
 
         // process style attributes
@@ -171,7 +172,10 @@
         mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
             /* Get the localized am/pm strings and use them in the spinner */
-        mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
+        final Resources res = context.getResources();
+        final String amText = res.getString(R.string.time_picker_am_label);
+        final String pmText = res.getString(R.string.time_picker_pm_label);
+        mAmPmStrings = new String[] {amText, pmText};
 
         // am/pm
         View amPmView = mDelegator.findViewById(R.id.amPm);
diff --git a/core/java/android/widget/TimePickerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
similarity index 99%
rename from core/java/android/widget/TimePickerDelegate.java
rename to core/java/android/widget/TimePickerSpinnerDelegate.java
index c68619c..523965c 100644
--- a/core/java/android/widget/TimePickerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -51,7 +51,7 @@
 /**
  * A view for selecting the time of day, in either 24 hour or AM/PM mode.
  */
-class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implements
+class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate implements
         RadialTimePickerView.OnValueSelectedListener {
 
     private static final String TAG = "TimePickerDelegate";
@@ -119,8 +119,8 @@
 
     private Calendar mTempCalendar;
 
-    public TimePickerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
-                              int defStyleAttr, int defStyleRes) {
+    public TimePickerSpinnerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
         super(delegator, context);
 
         // process style attributes
@@ -134,6 +134,8 @@
         mSelectHours = res.getString(R.string.select_hours);
         mMinutePickerDescription = res.getString(R.string.minute_picker_description);
         mSelectMinutes = res.getString(R.string.select_minutes);
+        mAmText = res.getString(R.string.time_picker_am_label);
+        mPmText = res.getString(R.string.time_picker_pm_label);
 
         final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
                 R.layout.time_picker_holo);
@@ -182,10 +184,6 @@
                 R.id.radial_picker);
         mDoneButton = (Button) mainView.findViewById(R.id.done_button);
 
-        String[] amPmTexts = new DateFormatSymbols().getAmPmStrings();
-        mAmText = amPmTexts[0];
-        mPmText = amPmTexts[1];
-
         setupListeners();
 
         mAllowAutoAdvance = true;
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 5655506..40965f0 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -18,6 +18,7 @@
 
 import com.android.internal.os.BatteryStatsImpl;
 
+import android.os.ParcelFileDescriptor;
 import android.os.WorkSource;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.SignalStrength;
@@ -37,6 +38,8 @@
     // Remaining methods are only used in Java.
     byte[] getStatistics();
 
+    ParcelFileDescriptor getStatisticsStream();
+
     // Return the computed amount of time remaining on battery, in milliseconds.
     // Returns -1 if nothing could be computed.
     long computeBatteryTimeRemaining();
diff --git a/core/java/com/android/internal/os/AtomicFile.java b/core/java/com/android/internal/os/AtomicFile.java
index 445d10a..5a83f33 100644
--- a/core/java/com/android/internal/os/AtomicFile.java
+++ b/core/java/com/android/internal/os/AtomicFile.java
@@ -40,7 +40,7 @@
  * appropriate mutual exclusion invariants whenever it accesses the file.
  * </p>
  */
-public class AtomicFile {
+public final class AtomicFile {
     private final File mBaseName;
     private final File mBackupName;
     
@@ -129,7 +129,16 @@
         } catch (IOException e) {
         }
     }
-    
+
+    public boolean exists() {
+        return mBaseName.exists() || mBackupName.exists();
+    }
+
+    public void delete() {
+        mBaseName.delete();
+        mBackupName.delete();
+    }
+
     public FileInputStream openRead() throws FileNotFoundException {
         if (mBackupName.exists()) {
             mBaseName.delete();
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 6c9b4b8..63be2d4 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -30,19 +30,26 @@
 import android.os.BatteryStats;
 import android.os.BatteryStats.Uid;
 import android.os.Bundle;
+import android.os.MemoryFile;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.telephony.SignalStrength;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BatterySipper.DrainType;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -55,7 +62,7 @@
  * The caller must initialize this class as soon as activity object is ready to use (for example, in
  * onAttach() for Fragment), call create() in onCreate() and call destroy() in onDestroy().
  */
-public class BatteryStatsHelper {
+public final class BatteryStatsHelper {
 
     private static final boolean DEBUG = false;
 
@@ -63,6 +70,7 @@
 
     private static BatteryStats sStatsXfer;
     private static Intent sBatteryBroadcastXfer;
+    private static ArrayMap<File, BatteryStats> sFileXfer = new ArrayMap<>();
 
     final private Context mContext;
     final private boolean mCollectBatteryBroadcast;
@@ -117,6 +125,68 @@
         mCollectBatteryBroadcast = collectBatteryBroadcast;
     }
 
+    public void storeStatsHistoryInFile(String fname) {
+        synchronized (sFileXfer) {
+            File path = makeFilePath(mContext, fname);
+            sFileXfer.put(path, this.getStats());
+            FileOutputStream fout = null;
+            try {
+                fout = new FileOutputStream(path);
+                Parcel hist = Parcel.obtain();
+                getStats().writeToParcelWithoutUids(hist, 0);
+                byte[] histData = hist.marshall();
+                fout.write(histData);
+            } catch (IOException e) {
+                Log.w(TAG, "Unable to write history to file", e);
+            } finally {
+                if (fout != null) {
+                    try {
+                        fout.close();
+                    } catch (IOException e) {
+                    }
+                }
+            }
+        }
+    }
+
+    public static BatteryStats statsFromFile(Context context, String fname) {
+        synchronized (sFileXfer) {
+            File path = makeFilePath(context, fname);
+            BatteryStats stats = sFileXfer.get(path);
+            if (stats != null) {
+                return stats;
+            }
+            FileInputStream fin = null;
+            try {
+                fin = new FileInputStream(path);
+                byte[] data = readFully(fin);
+                Parcel parcel = Parcel.obtain();
+                parcel.unmarshall(data, 0, data.length);
+                parcel.setDataPosition(0);
+                return com.android.internal.os.BatteryStatsImpl.CREATOR.createFromParcel(parcel);
+            } catch (IOException e) {
+                Log.w(TAG, "Unable to read history to file", e);
+            } finally {
+                if (fin != null) {
+                    try {
+                        fin.close();
+                    } catch (IOException e) {
+                    }
+                }
+            }
+        }
+        return getStats(IBatteryStats.Stub.asInterface(
+                        ServiceManager.getService(BatteryStats.SERVICE_NAME)));
+    }
+
+    public static void dropFile(Context context, String fname) {
+        makeFilePath(context, fname).delete();
+    }
+
+    private static File makeFilePath(Context context, String fname) {
+        return new File(context.getFilesDir(), fname);
+    }
+
     /** Clears the current stats and forces recreating for future use. */
     public void clearStats() {
         mStats = null;
@@ -853,25 +923,64 @@
 
     public long getChargeTimeRemaining() { return mChargeTimeRemaining; }
 
+    public static byte[] readFully(FileInputStream stream) throws java.io.IOException {
+        return readFully(stream, stream.available());
+    }
+
+    public static byte[] readFully(FileInputStream stream, int avail) throws java.io.IOException {
+        int pos = 0;
+        byte[] data = new byte[avail];
+        while (true) {
+            int amt = stream.read(data, pos, data.length-pos);
+            //Log.i("foo", "Read " + amt + " bytes at " + pos
+            //        + " of avail " + data.length);
+            if (amt <= 0) {
+                //Log.i("foo", "**** FINISHED READING: pos=" + pos
+                //        + " len=" + data.length);
+                return data;
+            }
+            pos += amt;
+            avail = stream.available();
+            if (avail > data.length-pos) {
+                byte[] newData = new byte[pos+avail];
+                System.arraycopy(data, 0, newData, 0, pos);
+                data = newData;
+            }
+        }
+    }
+
     private void load() {
         if (mBatteryInfo == null) {
             return;
         }
-        try {
-            byte[] data = mBatteryInfo.getStatistics();
-            Parcel parcel = Parcel.obtain();
-            parcel.unmarshall(data, 0, data.length);
-            parcel.setDataPosition(0);
-            BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR
-                    .createFromParcel(parcel);
-            stats.distributeWorkLocked(BatteryStats.STATS_SINCE_CHARGED);
-            mStats = stats;
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException:", e);
-        }
+        mStats = getStats(mBatteryInfo);
         if (mCollectBatteryBroadcast) {
             mBatteryBroadcast = mContext.registerReceiver(null,
                     new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
         }
     }
+
+    private static BatteryStatsImpl getStats(IBatteryStats service) {
+        try {
+            ParcelFileDescriptor pfd = service.getStatisticsStream();
+            if (pfd != null) {
+                FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+                try {
+                    byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
+                    Parcel parcel = Parcel.obtain();
+                    parcel.unmarshall(data, 0, data.length);
+                    parcel.setDataPosition(0);
+                    BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR
+                            .createFromParcel(parcel);
+                    stats.distributeWorkLocked(BatteryStats.STATS_SINCE_CHARGED);
+                    return stats;
+                } catch (IOException e) {
+                    Log.w(TAG, "Unable to read statistics stream", e);
+                }
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "RemoteException:", e);
+        }
+        return null;
+    }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index aad1156..50b86d0 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -109,6 +109,7 @@
     private static int sNumSpeedSteps;
 
     private final JournaledFile mFile;
+    public final AtomicFile mCheckinFile;
 
     static final int MSG_UPDATE_WAKELOCKS = 1;
     static final int MSG_REPORT_POWER_CHANGE = 2;
@@ -142,7 +143,7 @@
         }
     }
 
-    private final MyHandler mHandler;
+    public final MyHandler mHandler;
 
     private BatteryCallback mCallback;
 
@@ -199,8 +200,8 @@
     boolean mRecordingHistory = false;
     int mNumHistoryItems;
 
-    static final int MAX_HISTORY_BUFFER = 128*1024; // 128KB
-    static final int MAX_MAX_HISTORY_BUFFER = 144*1024; // 144KB
+    static final int MAX_HISTORY_BUFFER = 256*1024; // 256KB
+    static final int MAX_MAX_HISTORY_BUFFER = 320*1024; // 320KB
     final Parcel mHistoryBuffer = Parcel.obtain();
     final HistoryItem mHistoryLastWritten = new HistoryItem();
     final HistoryItem mHistoryLastLastWritten = new HistoryItem();
@@ -240,7 +241,7 @@
 
     int mWakeLockNesting;
     boolean mWakeLockImportant;
-    boolean mRecordAllWakeLocks;
+    boolean mRecordAllHistory;
     boolean mNoAutoReset;
 
     int mScreenState = Display.STATE_UNKNOWN;
@@ -342,6 +343,10 @@
 
     static final int MAX_LEVEL_STEPS = 100;
 
+    int mInitStepMode = 0;
+    int mCurStepMode = 0;
+    int mModStepMode = 0;
+
     int mLastDischargeStepLevel;
     long mLastDischargeStepTime;
     int mMinDischargeStepLevel;
@@ -429,10 +434,11 @@
     @GuardedBy("this")
     private String[] mWifiIfaces = new String[0];
 
-    // For debugging
     public BatteryStatsImpl() {
         mFile = null;
+        mCheckinFile = null;
         mHandler = null;
+        clearHistoryLocked();
     }
 
     public static interface TimeBaseObs {
@@ -2353,6 +2359,9 @@
         if (!mActiveEvents.updateState(HistoryItem.EVENT_PROC_START, name, uid, 0)) {
             return;
         }
+        if (!mRecordAllHistory) {
+            return;
+        }
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         final long uptime = SystemClock.uptimeMillis();
         addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_START, name, uid);
@@ -2371,9 +2380,12 @@
         }
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         final long uptime = SystemClock.uptimeMillis();
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_FINISH, name, uid);
         getUidStatsLocked(uid).updateProcessStateLocked(name, Uid.PROCESS_STATE_NONE,
                 elapsedRealtime);
+        if (!mRecordAllHistory) {
+            return;
+        }
+        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_FINISH, name, uid);
     }
 
     public void noteSyncStartLocked(String name, int uid) {
@@ -2427,11 +2439,41 @@
         }
     }
 
-    public void setRecordAllWakeLocksLocked(boolean enabled) {
-        mRecordAllWakeLocks = enabled;
+    public void setRecordAllHistoryLocked(boolean enabled) {
+        mRecordAllHistory = enabled;
         if (!enabled) {
             // Clear out any existing state.
             mActiveEvents.removeEvents(HistoryItem.EVENT_WAKE_LOCK);
+            // Record the currently running processes as stopping, now that we are no
+            // longer tracking them.
+            HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
+                    HistoryItem.EVENT_PROC);
+            if (active != null) {
+                long mSecRealtime = SystemClock.elapsedRealtime();
+                final long mSecUptime = SystemClock.uptimeMillis();
+                for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
+                    SparseIntArray uids = ent.getValue();
+                    for (int j=0; j<uids.size(); j++) {
+                        addHistoryEventLocked(mSecRealtime, mSecUptime,
+                                HistoryItem.EVENT_PROC_FINISH, ent.getKey(), uids.keyAt(j));
+                    }
+                }
+            }
+        } else {
+            // Record the currently running processes as starting, now that we are tracking them.
+            HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
+                    HistoryItem.EVENT_PROC);
+            if (active != null) {
+                long mSecRealtime = SystemClock.elapsedRealtime();
+                final long mSecUptime = SystemClock.uptimeMillis();
+                for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
+                    SparseIntArray uids = ent.getValue();
+                    for (int j=0; j<uids.size(); j++) {
+                        addHistoryEventLocked(mSecRealtime, mSecUptime,
+                                HistoryItem.EVENT_PROC_START, ent.getKey(), uids.keyAt(j));
+                    }
+                }
+            }
         }
     }
 
@@ -2452,7 +2494,7 @@
             if (historyName == null) {
                 historyName = name;
             }
-            if (mRecordAllWakeLocks) {
+            if (mRecordAllHistory) {
                 if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
                         uid, 0)) {
                     addHistoryEventLocked(elapsedRealtime, uptime,
@@ -2496,7 +2538,7 @@
         uid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             mWakeLockNesting--;
-            if (mRecordAllWakeLocks) {
+            if (mRecordAllHistory) {
                 if (historyName == null) {
                     historyName = name;
                 }
@@ -2788,6 +2830,18 @@
             if (DEBUG) Slog.v(TAG, "Screen state: oldState=" + Display.stateToString(oldState)
                     + ", newState=" + Display.stateToString(state));
 
+            if (state != Display.STATE_UNKNOWN) {
+                int stepState = state-1;
+                if (stepState < 4) {
+                    mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_SCREEN_STATE) ^ stepState;
+                    mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_SCREEN_STATE) | stepState;
+                } else {
+                    Slog.wtf(TAG, "Unexpected screen state: " + state);
+                }
+            }
+
+            mInitStepMode = mCurStepMode;
+            mModStepMode = 0;
             if (state == Display.STATE_ON) {
                 // Screen turning on.
                 final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -2924,6 +2978,9 @@
 
     public void noteLowPowerMode(boolean enabled) {
         if (mLowPowerModeEnabled != enabled) {
+            int stepState = enabled ? STEP_LEVEL_MODE_POWER_SAVE : 0;
+            mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_POWER_SAVE) ^ stepState;
+            mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState;
             final long elapsedRealtime = SystemClock.elapsedRealtime();
             final long uptime = SystemClock.uptimeMillis();
             mLowPowerModeEnabled = enabled;
@@ -6032,8 +6089,14 @@
         }
     }
 
-    public BatteryStatsImpl(String filename, Handler handler) {
-        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
+    public BatteryStatsImpl(File systemDir, Handler handler) {
+        if (systemDir != null) {
+            mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
+                    new File(systemDir, "batterystats.bin.tmp"));
+        } else {
+            mFile = null;
+        }
+        mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
         mHandler = new MyHandler(handler.getLooper());
         mStartCount++;
         mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
@@ -6095,6 +6158,7 @@
 
     public BatteryStatsImpl(Parcel p) {
         mFile = null;
+        mCheckinFile = null;
         mHandler = null;
         clearHistoryLocked();
         readFromParcel(p);
@@ -6390,6 +6454,10 @@
 
     private void initActiveHistoryEventsLocked(long elapsedRealtimeMs, long uptimeMs) {
         for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
+            if (!mRecordAllHistory && i == HistoryItem.EVENT_PROC) {
+                // Not recording process starts/stops.
+                continue;
+            }
             HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(i);
             if (active == null) {
                 continue;
@@ -6455,7 +6523,37 @@
             boolean reset = false;
             if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
                     || level >= 90
-                    || (mDischargeCurrentLevel < 20 && level >= 80))) {
+                    || getLowDischargeAmountSinceCharge() >= 60)
+                    || (getHighDischargeAmountSinceCharge() >= 60
+                            && mHistoryBuffer.dataSize() >= MAX_HISTORY_BUFFER)) {
+                // Before we write, collect a snapshot of the final aggregated
+                // stats to be reported in the next checkin.  Only do this if we have
+                // a sufficient amount of data to make it interesting.
+                if (getLowDischargeAmountSinceCharge() >= 20) {
+                    final Parcel parcel = Parcel.obtain();
+                    writeSummaryToParcel(parcel, true);
+                    BackgroundThread.getHandler().post(new Runnable() {
+                        @Override public void run() {
+                            synchronized (mCheckinFile) {
+                                FileOutputStream stream = null;
+                                try {
+                                    stream = mCheckinFile.startWrite();
+                                    stream.write(parcel.marshall());
+                                    stream.flush();
+                                    FileUtils.sync(stream);
+                                    stream.close();
+                                    mCheckinFile.finishWrite(stream);
+                                } catch (IOException e) {
+                                    Slog.w("BatteryStats",
+                                            "Error writing checkin battery statistics", e);
+                                    mCheckinFile.failWrite(stream);
+                                } finally {
+                                    parcel.recycle();
+                                }
+                            }
+                        }
+                    });
+                }
                 doWrite = true;
                 resetAllStatsLocked();
                 mDischargeStartLevel = level;
@@ -6465,6 +6563,8 @@
             mLastDischargeStepLevel = level;
             mMinDischargeStepLevel = level;
             mLastDischargeStepTime = -1;
+            mInitStepMode = mCurStepMode;
+            mModStepMode = 0;
             pullPendingStateUpdatesLocked();
             mHistoryCur.batteryLevel = (byte)level;
             mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
@@ -6504,6 +6604,8 @@
             mLastChargeStepLevel = level;
             mMaxChargeStepLevel = level;
             mLastChargeStepTime = -1;
+            mInitStepMode = mCurStepMode;
+            mModStepMode = 0;
         }
         if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
             if (mFile != null) {
@@ -6529,14 +6631,17 @@
     private static final int BATTERY_PLUGGED_NONE = 0;
 
     private static int addLevelSteps(long[] steps, int stepCount, long lastStepTime,
-            int numStepLevels, long elapsedRealtime) {
+            int numStepLevels, long modeBits, long elapsedRealtime) {
         if (lastStepTime >= 0 && numStepLevels > 0) {
             long duration = elapsedRealtime - lastStepTime;
             for (int i=0; i<numStepLevels; i++) {
                 System.arraycopy(steps, 0, steps, 1, steps.length-1);
                 long thisDuration = duration / (numStepLevels-i);
                 duration -= thisDuration;
-                steps[0] = thisDuration;
+                if (thisDuration > STEP_LEVEL_TIME_MASK) {
+                    thisDuration = STEP_LEVEL_TIME_MASK;
+                }
+                steps[0] = thisDuration | modeBits;
             }
             stepCount += numStepLevels;
             if (stepCount > steps.length) {
@@ -6623,23 +6728,30 @@
                 if (changed) {
                     addHistoryRecordLocked(elapsedRealtime, uptime);
                 }
+                long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
+                        | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
+                        | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
                 if (onBattery) {
                     if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
                         mNumDischargeStepDurations = addLevelSteps(mDischargeStepDurations,
                                 mNumDischargeStepDurations, mLastDischargeStepTime,
-                                mLastDischargeStepLevel - level, elapsedRealtime);
+                                mLastDischargeStepLevel - level, modeBits, elapsedRealtime);
                         mLastDischargeStepLevel = level;
                         mMinDischargeStepLevel = level;
                         mLastDischargeStepTime = elapsedRealtime;
+                        mInitStepMode = mCurStepMode;
+                        mModStepMode = 0;
                     }
                 } else {
                     if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
                         mNumChargeStepDurations = addLevelSteps(mChargeStepDurations,
                                 mNumChargeStepDurations, mLastChargeStepTime,
-                                level - mLastChargeStepLevel, elapsedRealtime);
+                                level - mLastChargeStepLevel, modeBits, elapsedRealtime);
                         mLastChargeStepLevel = level;
                         mMaxChargeStepLevel = level;
                         mLastChargeStepTime = elapsedRealtime;
+                        mInitStepMode = mCurStepMode;
+                        mModStepMode = 0;
                     }
                 }
             }
@@ -6863,7 +6975,7 @@
         }
         long total = 0;
         for (int i=0; i<numSteps; i++) {
-            total += steps[i];
+            total += steps[i] & STEP_LEVEL_TIME_MASK;
         }
         return total / numSteps;
         /*
@@ -6875,7 +6987,7 @@
             long totalTime = 0;
             int num = 0;
             for (int j=0; j<numToAverage && (i+j)<numSteps; j++) {
-                totalTime += steps[i+j];
+                totalTime += steps[i+j] & STEP_LEVEL_TIME_MASK;
                 num++;
             }
             buckets[numBuckets] = totalTime / num;
@@ -7213,7 +7325,7 @@
         }
 
         Parcel out = Parcel.obtain();
-        writeSummaryToParcel(out);
+        writeSummaryToParcel(out, true);
         mLastWriteTime = SystemClock.elapsedRealtime();
 
         if (mPendingWrite != null) {
@@ -7224,14 +7336,11 @@
         if (sync) {
             commitPendingDataToDisk();
         } else {
-            Thread thr = new Thread("BatteryStats-Write") {
-                @Override
-                public void run() {
-                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+            BackgroundThread.getHandler().post(new Runnable() {
+                @Override public void run() {
                     commitPendingDataToDisk();
                 }
-            };
-            thr.start();
+            });
         }
     }
 
@@ -7263,29 +7372,6 @@
         }
     }
 
-    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
-        int pos = 0;
-        int avail = stream.available();
-        byte[] data = new byte[avail];
-        while (true) {
-            int amt = stream.read(data, pos, data.length-pos);
-            //Log.i("foo", "Read " + amt + " bytes at " + pos
-            //        + " of avail " + data.length);
-            if (amt <= 0) {
-                //Log.i("foo", "**** FINISHED READING: pos=" + pos
-                //        + " len=" + data.length);
-                return data;
-            }
-            pos += amt;
-            avail = stream.available();
-            if (avail > data.length-pos) {
-                byte[] newData = new byte[pos+avail];
-                System.arraycopy(data, 0, newData, 0, pos);
-                data = newData;
-            }
-        }
-    }
-
     public void readLocked() {
         if (mFile == null) {
             Slog.w("BatteryStats", "readLocked: no file associated with this instance");
@@ -7301,7 +7387,7 @@
             }
             FileInputStream stream = new FileInputStream(file);
 
-            byte[] raw = readFully(stream);
+            byte[] raw = BatteryStatsHelper.readFully(stream);
             Parcel in = Parcel.obtain();
             in.unmarshall(raw, 0, raw.length);
             in.setDataPosition(0);
@@ -7410,7 +7496,7 @@
         }
     }
 
-    void writeHistory(Parcel out, boolean andOldHistory) {
+    void writeHistory(Parcel out, boolean inclData, boolean andOldHistory) {
         if (DEBUG_HISTORY) {
             StringBuilder sb = new StringBuilder(128);
             sb.append("****************** WRITING mHistoryBaseTime: ");
@@ -7420,6 +7506,11 @@
             Slog.i(TAG, sb.toString());
         }
         out.writeLong(mHistoryBaseTime + mLastHistoryElapsedRealtime);
+        if (!inclData) {
+            out.writeInt(0);
+            out.writeInt(0);
+            return;
+        }
         out.writeInt(mHistoryTagPool.size());
         for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
             HistoryTag tag = ent.getKey();
@@ -7449,7 +7540,7 @@
         out.writeLong(-1);
     }
 
-    private void readSummaryFromParcel(Parcel in) {
+    public void readSummaryFromParcel(Parcel in) {
         final int version = in.readInt();
         if (version != VERSION) {
             Slog.w("BatteryStats", "readFromParcel: version got " + version
@@ -7742,7 +7833,7 @@
      *
      * @param out the Parcel to be written to.
      */
-    public void writeSummaryToParcel(Parcel out) {
+    public void writeSummaryToParcel(Parcel out, boolean inclHistory) {
         pullPendingStateUpdatesLocked();
 
         final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
@@ -7750,7 +7841,7 @@
 
         out.writeInt(VERSION);
 
-        writeHistory(out, true);
+        writeHistory(out, inclHistory, true);
 
         out.writeInt(mStartCount);
         out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
@@ -8194,7 +8285,7 @@
 
         out.writeInt(MAGIC);
 
-        writeHistory(out, false);
+        writeHistory(out, true, false);
 
         out.writeInt(mStartCount);
         out.writeLong(mStartClockTime);
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 3a02ab9..c4c4362 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -363,11 +363,7 @@
         if (argv[i][1] == '-' && argv[i][2] == 0) {
             return i+1;
         }
-
-        JavaVMOption opt;
-        memset(&opt, 0, sizeof(opt));
-        opt.optionString = (char*)argv[i];
-        mOptions.add(opt);
+        addOption(argv[i]);
     }
     return i;
 }
@@ -401,6 +397,14 @@
     //ALOGD("language=%s region=%s\n", language, region);
 }
 
+void AndroidRuntime::addOption(const char* optionString, void* extraInfo)
+{
+    JavaVMOption opt;
+    opt.optionString = optionString;
+    opt.extraInfo = extraInfo;
+    mOptions.add(opt);
+}
+
 /*
  * Parse a property containing space-separated options that should be
  * passed directly to the VM, e.g. "-Xmx32m -verbose:gc -Xregenmap".
@@ -413,8 +417,6 @@
  */
 void AndroidRuntime::parseExtraOpts(char* extraOptsBuf, const char* quotingArg)
 {
-    JavaVMOption opt;
-    memset(&opt, 0, sizeof(opt));
     char* start = extraOptsBuf;
     char* end = NULL;
     while (*start != '\0') {
@@ -429,13 +431,10 @@
         if (*end == ' ')
             *end++ = '\0';          /* mark end, advance to indicate more */
 
-        opt.optionString = start;
         if (quotingArg != NULL) {
-            JavaVMOption quotingOpt;
-            quotingOpt.optionString = quotingArg;
-            mOptions.add(quotingOpt);
+            addOption(quotingArg);
         }
-        mOptions.add(opt);
+        addOption(start);
         start = end;
     }
 }
@@ -463,13 +462,35 @@
     if (buffer[runtimeArgLen] == '\0') {
         return false;
     }
+    addOption(buffer);
+    return true;
+}
 
-    JavaVMOption opt;
-    memset(&opt, 0, sizeof(opt));
-
-    opt.optionString = buffer;
-    mOptions.add(opt);
-
+/*
+ * Reads a "property" into "buffer". If the property is non-empty, it
+ * is treated as a dex2oat compiler option that should be
+ * passed as a quoted option, e.g. "-Ximage-compiler-option --compiler-filter=verify-none".
+ *
+ * The "compilerArg" is a prefix for the option such as "--compiler-filter=".
+ *
+ * The "quotingArg" should be "-Ximage-compiler-option" or "-Xcompiler-option".
+ *
+ * If an option is found, it is added to mOptions and true is
+ * returned. Otherwise false is returned.
+ */
+bool AndroidRuntime::parseCompilerOption(const char* property,
+                                         char* buffer,
+                                         const char* compilerArg,
+                                         const char* quotingArg)
+{
+    strcpy(buffer, compilerArg);
+    size_t compilerArgLen = strlen(compilerArg);
+    property_get(property, buffer+compilerArgLen, "");
+    if (buffer[compilerArgLen] == '\0') {
+        return false;
+    }
+    addOption(quotingArg);
+    addOption(buffer);
     return true;
 }
 
@@ -497,22 +518,10 @@
     if (buffer[runtimeArgLen] == '\0') {
         return false;
     }
-
-    JavaVMOption opt;
-    memset(&opt, 0, sizeof(opt));
-
-    opt.optionString = quotingArg;
-    mOptions.add(opt);
-
-    opt.optionString = "--runtime-arg";
-    mOptions.add(opt);
-
-    opt.optionString = quotingArg;
-    mOptions.add(opt);
-
-    opt.optionString = buffer;
-    mOptions.add(opt);
-
+    addOption(quotingArg);
+    addOption("--runtime-arg");
+    addOption(quotingArg);
+    addOption(buffer);
     return true;
 }
 
@@ -536,7 +545,6 @@
 {
     int result = -1;
     JavaVMInitArgs initArgs;
-    JavaVMOption opt;
     char propBuf[PROPERTY_VALUE_MAX];
     char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX];
     char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
@@ -556,9 +564,12 @@
     char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
+    char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
+    char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
     char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
     char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
     char extraOptsBuf[PROPERTY_VALUE_MAX];
+    char voldDecryptBuf[PROPERTY_VALUE_MAX];
     enum {
       kEMDefault,
       kEMIntPortable,
@@ -594,16 +605,13 @@
     ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
     if (checkJni) {
         /* extended JNI checking */
-        opt.optionString = "-Xcheck:jni";
-        mOptions.add(opt);
+        addOption("-Xcheck:jni");
 
         /* set a cap on JNI global references */
-        opt.optionString = "-Xjnigreflimit:2000";
-        mOptions.add(opt);
+        addOption("-Xjnigreflimit:2000");
 
         /* with -Xcheck:jni, this provides a JNI function call trace */
-        //opt.optionString = "-verbose:jni";
-        //mOptions.add(opt);
+        //addOption("-verbose:jni");
     }
 
     property_get("dalvik.vm.execution-mode", propBuf, "");
@@ -620,15 +628,13 @@
     property_get("dalvik.vm.check-dex-sum", propBuf, "");
     if (strcmp(propBuf, "true") == 0) {
         /* perform additional DEX checksum tests */
-        opt.optionString = "-Xcheckdexsum";
-        mOptions.add(opt);
+        addOption("-Xcheckdexsum");
     }
 
     property_get("log.redirect-stdio", propBuf, "");
     if (strcmp(propBuf, "true") == 0) {
         /* convert stdout/stderr to log messages */
-        opt.optionString = "-Xlog-stdio";
-        mOptions.add(opt);
+        addOption("-Xlog-stdio");
     }
 
     strcpy(enableAssertBuf, "-ea:");
@@ -638,8 +644,7 @@
         if (strcmp(enableAssertBuf+sizeof("-ea:")-1, "all") == 0)
             enableAssertBuf[3] = '\0'; // truncate to "-ea"
         ALOGI("Assertions enabled: '%s'\n", enableAssertBuf);
-        opt.optionString = enableAssertBuf;
-        mOptions.add(opt);
+        addOption(enableAssertBuf);
     } else {
         ALOGV("Assertions disabled\n");
     }
@@ -650,27 +655,18 @@
     }
 
     /* route exit() to our handler */
-    opt.extraInfo = (void*) runtime_exit;
-    opt.optionString = "exit";
-    mOptions.add(opt);
+    addOption("exit", (void*) runtime_exit);
 
     /* route fprintf() to our handler */
-    opt.extraInfo = (void*) runtime_vfprintf;
-    opt.optionString = "vfprintf";
-    mOptions.add(opt);
+    addOption("vfprintf", (void*) runtime_vfprintf);
 
     /* register the framework-specific "is sensitive thread" hook */
-    opt.extraInfo = (void*) runtime_isSensitiveThread;
-    opt.optionString = "sensitiveThread";
-    mOptions.add(opt);
-
-    opt.extraInfo = NULL;
+    addOption("sensitiveThread", (void*) runtime_isSensitiveThread);
 
     /* enable verbose; standard options are { jni, gc, class } */
-    //options[curOpt++].optionString = "-verbose:jni";
-    opt.optionString = "-verbose:gc";
-    mOptions.add(opt);
-    //options[curOpt++].optionString = "-verbose:class";
+    //addOption("-verbose:jni");
+    addOption("-verbose:gc");
+    //addOption("-verbose:class");
 
     /*
      * The default starting and maximum size of the heap.  Larger
@@ -680,8 +676,7 @@
     parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
 
     // Increase the main thread's interpreter stack size for bug 6315322.
-    opt.optionString = "-XX:mainThreadStackSize=24K";
-    mOptions.add(opt);
+    addOption("-XX:mainThreadStackSize=24K");
 
     // Set the max jit code cache size.  Note: size of 0 will disable the JIT.
     parseRuntimeOption("dalvik.vm.jit.codecachesize",
@@ -697,8 +692,7 @@
 
     property_get("ro.config.low_ram", propBuf, "");
     if (strcmp(propBuf, "true") == 0) {
-      opt.optionString = "-XX:LowMemoryMode";
-      mOptions.add(opt);
+      addOption("-XX:LowMemoryMode");
     }
 
     parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");
@@ -723,8 +717,7 @@
             }
 
             if (val != NULL) {
-                opt.optionString = val;
-                mOptions.add(opt);
+                addOption(val);
             }
         }
 
@@ -739,27 +732,22 @@
             }
 
             if (val != NULL) {
-                opt.optionString = val;
-                mOptions.add(opt);
+                addOption(val);
             }
         }
 
         opc = strstr(dexoptFlagsBuf, "m=y");    /* register map */
         if (opc != NULL) {
-            opt.optionString = "-Xgenregmap";
-            mOptions.add(opt);
+            addOption("-Xgenregmap");
 
             /* turn on precise GC while we're at it */
-            opt.optionString = "-Xgc:precise";
-            mOptions.add(opt);
+            addOption("-Xgc:precise");
         }
     }
 
     /* enable debugging; set suspend=y to pause during VM init */
     /* use android ADB transport */
-    opt.optionString =
-        "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
-    mOptions.add(opt);
+    addOption("-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y");
 
     parseRuntimeOption("dalvik.vm.lockprof.threshold",
                        lockProfThresholdBuf,
@@ -772,14 +760,11 @@
     parseRuntimeOption("dalvik.vm.jit.method", jitMethodBuf, "-Xjitmethod:");
 
     if (executionMode == kEMIntPortable) {
-        opt.optionString = "-Xint:portable";
-        mOptions.add(opt);
+        addOption("-Xint:portable");
     } else if (executionMode == kEMIntFast) {
-        opt.optionString = "-Xint:fast";
-        mOptions.add(opt);
+        addOption("-Xint:fast");
     } else if (executionMode == kEMJitCompiler) {
-        opt.optionString = "-Xint:jit";
-        mOptions.add(opt);
+        addOption("-Xint:jit");
     }
 
     // libart tolerates libdvm flags, but not vice versa, so only pass some options if libart.
@@ -787,11 +772,27 @@
     bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0);
 
     if (libart) {
+        // If we booting without the real /data, don't spend time compiling.
+        property_get("vold.decrypt", voldDecryptBuf, "");
+        bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) ||
+                                 (strcmp(voldDecryptBuf, "1") == 0));
+
         // Extra options for boot.art/boot.oat image generation.
         parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
                                    "-Xms", "-Ximage-compiler-option");
         parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
                                    "-Xmx", "-Ximage-compiler-option");
+        if (skip_compilation) {
+            addOption("-Ximage-compiler-option");
+            addOption("--compiler-filter=verify-none");
+        } else {
+            parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
+                                "--compiler-filter=", "-Ximage-compiler-option");
+        }
+        addOption("-Ximage-compiler-option");
+        addOption("--image-classes-zip=/system/framework/framework.jar");
+        addOption("-Ximage-compiler-option");
+        addOption("--image-classes=preloaded-classes");
         property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
         parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
 
@@ -800,8 +801,16 @@
                                    "-Xms", "-Xcompiler-option");
         parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf,
                                    "-Xmx", "-Xcompiler-option");
+        if (skip_compilation) {
+            addOption("-Xcompiler-option");
+            addOption("--compiler-filter=interpret-only");
+        } else {
+            parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
+                                "--compiler-filter=", "-Xcompiler-option");
+        }
         property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
         parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");
+
     }
 
     /* extra options; parse this late so it overrides others */
@@ -813,11 +822,8 @@
         strcpy(langOption, "-Duser.language=");
         strcpy(regionOption, "-Duser.region=");
         readLocale(langOption, regionOption);
-        opt.extraInfo = NULL;
-        opt.optionString = langOption;
-        mOptions.add(opt);
-        opt.optionString = regionOption;
-        mOptions.add(opt);
+        addOption(langOption);
+        addOption(regionOption);
     }
 
     /*
@@ -827,16 +833,14 @@
         // Whether or not the profiler should be enabled.
         property_get("dalvik.vm.profiler", propBuf, "0");
         if (propBuf[0] == '1') {
-            opt.optionString = "-Xenable-profiler";
-            mOptions.add(opt);
+            addOption("-Xenable-profiler");
         }
 
         // Whether the profile should start upon app startup or be delayed by some random offset
         // (in seconds) that is bound between 0 and a fixed value.
         property_get("dalvik.vm.profile.start-immed", propBuf, "0");
         if (propBuf[0] == '1') {
-            opt.optionString = "-Xprofile-start-immediately";
-            mOptions.add(opt);
+            addOption("-Xprofile-start-immediately");
         }
 
         // Number of seconds during profile runs.
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
index b00e1ab..f64ad7d 100644
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -45,10 +45,9 @@
     FontStyle resolved = resolvedFace->fStyle;
 
     /* Prepare minikin FontStyle */
-    SkString langStr = paint->getPaintOptionsAndroid().getLanguage().getTag();
-    FontLanguage minikinLang(langStr.c_str(), langStr.size());
-    SkPaintOptionsAndroid::FontVariant var = paint->getPaintOptionsAndroid().getFontVariant();
-    FontVariant minikinVariant = var == SkPaintOptionsAndroid::kElegant_Variant ? VARIANT_ELEGANT
+    std::string lang = paint->getTextLocale();
+    FontLanguage minikinLang(lang.c_str(), lang.size());
+    FontVariant minikinVariant = (paint->getFontVariant() == VARIANT_ELEGANT) ? VARIANT_ELEGANT
             : VARIANT_COMPACT;
     FontStyle minikinStyle(minikinLang, minikinVariant, resolved.getWeight(), resolved.getItalic());
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index f6ced09..4bb31fc 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -365,27 +365,19 @@
         char langTag[ULOC_FULLNAME_CAPACITY];
         toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, localeChars.c_str());
 
-        SkPaintOptionsAndroid paintOpts = obj->getPaintOptionsAndroid();
-        paintOpts.setLanguage(langTag);
-        obj->setPaintOptionsAndroid(paintOpts);
+        obj->setTextLocale(langTag);
     }
 
     static jboolean isElegantTextHeight(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         Paint* obj = GraphicsJNI::getNativePaint(env, paint);
-        SkPaintOptionsAndroid paintOpts = obj->getPaintOptionsAndroid();
-        return paintOpts.getFontVariant() == SkPaintOptionsAndroid::kElegant_Variant;
+        return obj->getFontVariant() == VARIANT_ELEGANT;
     }
 
     static void setElegantTextHeight(JNIEnv* env, jobject paint, jboolean aa) {
         NPE_CHECK_RETURN_VOID(env, paint);
         Paint* obj = GraphicsJNI::getNativePaint(env, paint);
-        SkPaintOptionsAndroid::FontVariant variant =
-            aa ? SkPaintOptionsAndroid::kElegant_Variant :
-            SkPaintOptionsAndroid::kDefault_Variant;
-        SkPaintOptionsAndroid paintOpts = obj->getPaintOptionsAndroid();
-        paintOpts.setFontVariant(variant);
-        obj->setPaintOptionsAndroid(paintOpts);
+        obj->setFontVariant(aa ? VARIANT_ELEGANT : VARIANT_DEFAULT);
     }
 
     static jfloat getTextSize(JNIEnv* env, jobject paint) {
@@ -457,8 +449,7 @@
         // restore the original settings.
         paint->setTextSkewX(saveSkewX);
         paint->setFakeBoldText(savefakeBold);
-        SkPaintOptionsAndroid paintOpts = paint->getPaintOptionsAndroid();
-        if (paintOpts.getFontVariant() == SkPaintOptionsAndroid::kElegant_Variant) {
+        if (paint->getFontVariant() == VARIANT_ELEGANT) {
             SkScalar size = paint->getTextSize();
             metrics->fTop = -size * kElegantTop / 2048;
             metrics->fBottom = -size * kElegantBottom / 2048;
diff --git a/core/jni/android/graphics/Paint.h b/core/jni/android/graphics/Paint.h
index efc65be..a20bb4b 100644
--- a/core/jni/android/graphics/Paint.h
+++ b/core/jni/android/graphics/Paint.h
@@ -20,6 +20,8 @@
 #include <SkPaint.h>
 #include <string>
 
+#include <minikin/FontFamily.h>
+
 namespace android {
 
 class Paint : public SkPaint {
@@ -51,9 +53,27 @@
         return mFontFeatureSettings;
     }
 
+    void setTextLocale(const std::string &textLocale) {
+        mTextLocale = textLocale;
+    }
+
+    std::string getTextLocale() const {
+        return mTextLocale;
+    }
+
+    void setFontVariant(FontVariant variant) {
+        mFontVariant = variant;
+    }
+
+    FontVariant getFontVariant() const {
+        return mFontVariant;
+    }
+
 private:
     float mLetterSpacing;
     std::string mFontFeatureSettings;
+    std::string mTextLocale;
+    FontVariant mFontVariant;
 };
 
 }  // namespace android
diff --git a/core/jni/android/graphics/PaintImpl.cpp b/core/jni/android/graphics/PaintImpl.cpp
index 05020d2..e1b539e 100644
--- a/core/jni/android/graphics/PaintImpl.cpp
+++ b/core/jni/android/graphics/PaintImpl.cpp
@@ -23,11 +23,11 @@
 namespace android {
 
 Paint::Paint() : SkPaint(),
-        mLetterSpacing(0), mFontFeatureSettings() {
+        mLetterSpacing(0), mFontFeatureSettings(), mTextLocale(), mFontVariant(VARIANT_DEFAULT) {
 }
 
 Paint::Paint(const Paint& paint) : SkPaint(paint),
-        mLetterSpacing(0), mFontFeatureSettings() {
+        mLetterSpacing(0), mFontFeatureSettings(), mTextLocale(), mFontVariant(VARIANT_DEFAULT) {
 }
 
 Paint::~Paint() {
@@ -37,13 +37,17 @@
     SkPaint::operator=(other);
     mLetterSpacing = other.mLetterSpacing;
     mFontFeatureSettings = other.mFontFeatureSettings;
+    mTextLocale = other.mTextLocale;
+    mFontVariant = other.mFontVariant;
     return *this;
 }
 
 bool operator==(const Paint& a, const Paint& b) {
     return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b)
             && a.mLetterSpacing == b.mLetterSpacing
-            && a.mFontFeatureSettings == b.mFontFeatureSettings;
+            && a.mFontFeatureSettings == b.mFontFeatureSettings
+            && a.mTextLocale == b.mTextLocale
+            && a.mFontVariant == b.mFontVariant;
 }
 
 }
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index f9da127..33bb90bc 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1293,6 +1293,12 @@
     AudioSystem::setAudioPortCallback(callback);
 }
 
+static jint
+android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, jint sessionId)
+{
+    return (jint)AudioSystem::getAudioHwSyncForSession((audio_session_t)sessionId);
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
@@ -1332,6 +1338,8 @@
                                                 (void *)android_media_AudioSystem_listAudioPatches},
     {"setAudioPortConfig",   "(Landroid/media/AudioPortConfig;)I",
                                             (void *)android_media_AudioSystem_setAudioPortConfig},
+    {"getAudioHwSyncForSession", "(I)I",
+                                    (void *)android_media_AudioSystem_getAudioHwSyncForSession},
 };
 
 
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index d82fc96..81e887d 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -179,7 +179,10 @@
     env->ExceptionClear();
 
     jstring tagstr = env->NewStringUTF(LOG_TAG);
-    jstring msgstr = env->NewStringUTF(msg);
+    jstring msgstr = NULL;
+    if (tagstr != NULL) {
+        msgstr = env->NewStringUTF(msg);
+    }
 
     if ((tagstr == NULL) || (msgstr == NULL)) {
         env->ExceptionClear();      /* assume exception (OOM?) was thrown */
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index ce76b26..afcfaf6 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -348,7 +348,12 @@
 
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawBitmap(bitmap, left, top, paint);
+
+    // apply transform directly to canvas, so it affects shaders correctly
+    renderer->save(SkCanvas::kMatrix_SaveFlag);
+    renderer->translate(left, top);
+    renderer->drawBitmap(bitmap, paint);
+    renderer->restore();
 }
 
 static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject clazz,
@@ -375,7 +380,12 @@
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
     Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawBitmap(bitmap, *matrix, paint);
+
+    // apply transform directly to canvas, so it affects shaders correctly
+    renderer->save(SkCanvas::kMatrix_SaveFlag);
+    renderer->concatMatrix(*matrix);
+    renderer->drawBitmap(bitmap, paint);
+    renderer->restore();
 }
 
 static void android_view_GLES20Canvas_drawBitmapData(JNIEnv* env, jobject clazz,
@@ -399,7 +409,12 @@
 
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawBitmapData(bitmap, left, top, paint);
+
+    // apply transform directly to canvas, so it affects shaders correctly
+    renderer->save(SkCanvas::kMatrix_SaveFlag);
+    renderer->translate(left, top);
+    renderer->drawBitmapData(bitmap, paint);
+    renderer->restore();
 
     // Note - bitmap isn't deleted as DisplayListRenderer owns it now
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e3504fa..d57a8b8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -880,6 +880,15 @@
         android:description="@string/permdesc_bluetoothPriv"
         android:label="@string/permlab_bluetoothPriv" />
 
+    <!-- Control access to email providers exclusively for Bluetooth
+         @hide
+    -->
+    <permission android:name="android.permission.BLUETOOTH_MAP"
+        android:permissionGroup="android.permission-group.BLUETOOTH_NETWORK"
+        android:protectionLevel="signature"
+        android:description="@string/permdesc_bluetoothMap"
+        android:label="@string/permlab_bluetoothMap" />
+
     <!-- Allows bluetooth stack to access files
          @hide This should only be used by Bluetooth apk.
     -->
diff --git a/core/res/res/anim/launch_task_behind_source.xml b/core/res/res/anim/launch_task_behind_source.xml
index 426ee5d..cd3e30a 100644
--- a/core/res/res/anim/launch_task_behind_source.xml
+++ b/core/res/res/anim/launch_task_behind_source.xml
@@ -37,20 +37,20 @@
         android:interpolator="@interpolator/fast_out_slow_in"
         android:duration="350" />
 
-    <alpha android:fromAlpha="1.0" android:toAlpha="1.6"
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.6666666666"
         android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
         android:interpolator="@interpolator/decelerate_cubic"
         android:startOffset="433"
         android:duration="133"/>
 
-    <translate android:fromYDelta="0%" android:toYDelta="-10%"
+    <translate android:fromYDelta="0%" android:toYDelta="-8.8888888888%"
         android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
         android:interpolator="@interpolator/decelerate_cubic"
         android:startOffset="433"
         android:duration="350"/>
 
-    <scale android:fromXScale="1.0" android:toXScale="1.1"
-        android:fromYScale="1.0" android:toYScale="1.1"
+    <scale android:fromXScale="1.0" android:toXScale="1.1111111111"
+        android:fromYScale="1.0" android:toYScale="1.1111111111"
         android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
         android:pivotX="50%p" android:pivotY="50%p"
         android:interpolator="@interpolator/decelerate_cubic"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2baa599..771690e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4260,8 +4260,6 @@
         <attr name="internalLayout" format="reference"  />
         <!-- @hide The layout of the legacy DatePicker. -->
         <attr name="legacyLayout" />
-        <!-- @hide Enables or disable the use of the legacy layout for the DatePicker. -->
-        <attr name="legacyMode" />
         <!-- The background color for the date selector 's day of week. -->
         <attr name="dayOfWeekBackgroundColor" format="color" />
         <!-- The text color for the date selector's day of week. -->
@@ -4288,6 +4286,15 @@
              if the text color does not explicitly have a color set for the
              selected state. -->
         <attr name="calendarSelectedTextColor" format="color" />
+        <!-- Defines the look of the widget. Prior to the L release, the only choice was
+             spinner. As of L, with the Material theme selected, the default layout is calendar,
+             but this attribute can be used to force spinner to be used instead. -->
+        <attr name="datePickerMode">
+            <!-- Date picker with spinner controls to select the date. -->
+            <enum name="spinner" value="1" />
+            <!-- Date picker with calendar to select the date. -->
+            <enum name="calendar" value="2" />
+        </attr>
     </declare-styleable>
 
     <declare-styleable name="TwoLineListItem">
@@ -4557,8 +4564,6 @@
     </declare-styleable>
 
     <declare-styleable name="TimePicker">
-        <!-- @hide Enables or disable the use of the legacy layout for the TimePicker. -->
-        <attr name="legacyMode" format="boolean" />
         <!-- @hide The layout of the legacy time picker. -->
         <attr name="legacyLayout" format="reference" />
         <!-- @hide The layout of the time picker. -->
@@ -4587,6 +4592,15 @@
         <attr name="amPmSelectedBackgroundColor" format="color" />
         <!-- The color for the hours/minutes selector of the TimePicker. -->
         <attr name="numbersSelectorColor" format="color" />
+        <!-- Defines the look of the widget. Prior to the L release, the only choice was
+             spinner. As of L, with the Material theme selected, the default layout is clock,
+             but this attribute can be used to force spinner to be used instead. -->
+        <attr name="timePickerMode">
+            <!-- Time picker with spinner controls to select the time. -->
+            <enum name="spinner" value="1" />
+            <!-- Time picker with clock face to select the time. -->
+            <enum name="clock" value="2" />
+        </attr>
     </declare-styleable>
 
     <!-- ========================= -->
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 6988881..ccbb8bc 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -89,8 +89,8 @@
     <color name="material_teal_A200">#ff18ffff</color>
     <color name="material_teal_A400">#ff00e5ff</color>
 
-    <!-- Accent color used by Settings -->
-    <color name="material_dark_teal_A400">#ff009688</color>
+    <color name="material_deep_teal_A200">#ff80cbc4</color>
+    <color name="material_deep_teal_A500">#ff009688</color>
 
     <color name="material_green_100">#ffb7e1cd</color>
     <color name="material_green_300">#ff57bb8a</color>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 08398f0..73aaafd 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2562,4 +2562,7 @@
   <public type="raw" name="nodomain"/>
 
   <public type="attr" name="contentRatingSystemXml"/>
+
+  <public type="attr" name="datePickerMode"/>
+  <public type="attr" name="timePickerMode"/>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 21f4843..c34560d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1974,6 +1974,13 @@
     <string name="permdesc_bluetoothPriv" product="default">Allows the app to
       pair with remote devices without user interaction.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bluetoothMap">access Bluetooth MAP data</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bluetoothMap" product="tablet">Allows the app to access Bluetooth MAP data.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bluetoothMap" product="default">Allows the app to access Bluetooth MAP data.</string>
+
     <string name="permlab_accessWimaxState">connect and disconnect from WiMAX</string>
     <string name="permdesc_accessWimaxState">Allows the app to determine whether
      WiMAX is enabled and information about any WiMAX networks that are
@@ -4127,6 +4134,10 @@
     <string name="time_picker_increment_set_pm_button">Set PM</string>
     <!-- Description of the button to decrease the TimePicker's set AM value. [CHAR LIMIT=NONE] -->
     <string name="time_picker_decrement_set_am_button">Set AM</string>
+    <!-- Label for the TimePicker's PM button. [CHAR LIMIT=2] -->
+    <string name="time_picker_pm_label">PM</string>
+    <!-- Label for the TimePicker's AM button. [CHAR LIMIT=2] -->
+    <string name="time_picker_am_label">AM</string>
 
     <!-- DatePicker - accessibility support -->
     <!-- Description of the button to increase the DatePicker's month value. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4a70952..a5cac6b 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -568,12 +568,12 @@
     </style>
 
     <style name="Widget.TimePicker">
-        <item name="legacyMode">true</item>
+        <item name="timePickerMode">spinner</item>
         <item name="legacyLayout">@layout/time_picker_legacy</item>
     </style>
 
     <style name="Widget.DatePicker">
-        <item name="legacyMode">true</item>
+        <item name="datePickerMode">spinner</item>
         <item name="legacyLayout">@layout/date_picker_legacy</item>
         <item name="calendarViewShown">false</item>
     </style>
diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml
index d79e46d..2a54ccf 100644
--- a/core/res/res/values/styles_holo.xml
+++ b/core/res/res/values/styles_holo.xml
@@ -462,7 +462,7 @@
     </style>
 
     <style name="Widget.Holo.TimePicker" parent="Widget.TimePicker">
-        <item name="legacyMode">true</item>
+        <item name="timePickerMode">spinner</item>
         <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
         <!-- Attributes for new-style TimePicker. -->
         <item name="internalLayout">@layout/time_picker_holo</item>
@@ -479,7 +479,7 @@
     </style>
 
     <style name="Widget.Holo.DatePicker" parent="Widget.DatePicker">
-        <item name="legacyMode">true</item>
+        <item name="datePickerMode">spinner</item>
         <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
         <item name="internalLayout">@layout/date_picker_holo</item>
         <item name="calendarViewShown">true</item>
@@ -886,7 +886,7 @@
     <style name="Widget.Holo.Light.NumberPicker" parent="Widget.Holo.NumberPicker" />
 
     <style name="Widget.Holo.Light.TimePicker" parent="Widget.TimePicker">
-        <item name="legacyMode">true</item>
+        <item name="timePickerMode">spinner</item>
         <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
         <!-- Non-legacy styling -->
         <item name="internalLayout">@layout/time_picker_holo</item>
@@ -903,7 +903,7 @@
     </style>
 
     <style name="Widget.Holo.Light.DatePicker" parent="Widget.DatePicker">
-        <item name="legacyMode">true</item>
+        <item name="datePickerMode">spinner</item>
         <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
         <item name="internalLayout">@layout/date_picker_holo</item>
         <item name="calendarViewShown">true</item>
diff --git a/core/res/res/values/styles_leanback.xml b/core/res/res/values/styles_leanback.xml
index a899c4d..256ef00 100644
--- a/core/res/res/values/styles_leanback.xml
+++ b/core/res/res/values/styles_leanback.xml
@@ -23,12 +23,12 @@
     </style>
 
     <style name="Widget.Leanback.TimePicker" parent="Widget.Material.TimePicker">
-        <item name="legacyMode">true</item>
+        <item name="timePickerMode">spinner</item>
         <item name="legacyLayout">@layout/time_picker_legacy_leanback</item>
     </style>
 
     <style name="Widget.Leanback.DatePicker" parent="Widget.Material.DatePicker">
-        <item name="legacyMode">true</item>
+        <item name="datePickerMode">spinner</item>
     </style>
 
     <style name="Widget.Leanback.NumberPicker" parent="Widget.Material.NumberPicker">
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 2dc0438..97d4bf6 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -587,7 +587,7 @@
     </style>
 
     <style name="Widget.Material.TimePicker" parent="Widget.TimePicker">
-        <item name="legacyMode">false</item>
+        <item name="timePickerMode">clock</item>
         <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
         <!-- Attributes for new-style TimePicker. -->
         <item name="internalLayout">@layout/time_picker_holo</item>
@@ -604,7 +604,7 @@
     </style>
 
     <style name="Widget.Material.DatePicker" parent="Widget.DatePicker">
-        <item name="legacyMode">false</item>
+        <item name="datePickerMode">calendar</item>
         <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
         <!-- Attributes for new-style DatePicker. -->
         <item name="internalLayout">@layout/date_picker_holo</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 84bc62c..6030715 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1969,9 +1969,7 @@
   <java-symbol type="array" name="config_cdma_home_system" />
   <java-symbol type="attr" name="headerSelectedTextColor" />
   <java-symbol type="attr" name="amPmSelectedBackgroundColor" />
-
-  <!--From SmsMessage-->
-  <!--Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet
-     string that's stored in 8-bit unpacked format) characters.-->
   <java-symbol type="bool" name="config_sms_decode_gsm_8bit_data" />
+  <java-symbol type="string" name="time_picker_am_label" />
+  <java-symbol type="string" name="time_picker_pm_label" />
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 42ebb82..e7001c3 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -372,7 +372,7 @@
         <!-- Color palette -->
         <item name="colorPrimaryDark">@color/material_blue_grey_900</item>
         <item name="colorPrimary">@color/material_blue_grey_800</item>
-        <item name="colorAccent">@color/material_light_blue_A200</item>
+        <item name="colorAccent">@color/material_deep_teal_A200</item>
 
         <item name="colorControlNormal">?attr/textColorSecondary</item>
         <item name="colorControlActivated">?attr/colorAccent</item>
@@ -712,9 +712,9 @@
         <item name="fastScrollOverlayPosition">atThumb</item>
 
         <!-- Color palette -->
-        <item name="colorPrimaryDark">@color/material_blue_grey_600</item>
-        <item name="colorPrimary">@color/material_blue_grey_400</item>
-        <item name="colorAccent">@color/material_light_blue_A200</item>
+        <item name="colorPrimaryDark">@color/material_blue_grey_100</item>
+        <item name="colorPrimary">@color/material_blue_grey_50</item>
+        <item name="colorAccent">@color/material_deep_teal_A500</item>
 
         <item name="colorControlNormal">?attr/textColorSecondary</item>
         <item name="colorControlActivated">?attr/colorAccent</item>
@@ -1229,7 +1229,7 @@
     <style name="Theme.Material.Settings" parent="@style/Theme.Material.Light.DarkActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
-        <item name="colorAccent">@color/material_dark_teal_A400</item>
+        <item name="colorAccent">@color/material_deep_teal_A500</item>
     </style>
 
 </resources>
diff --git a/docs/html/images/tools/signadt3.png b/docs/html/images/tools/signadt3.png
new file mode 100644
index 0000000..3f5650b
--- /dev/null
+++ b/docs/html/images/tools/signadt3.png
Binary files differ
diff --git a/docs/html/images/tools/signadt4.png b/docs/html/images/tools/signadt4.png
new file mode 100644
index 0000000..2adfff0
--- /dev/null
+++ b/docs/html/images/tools/signadt4.png
Binary files differ
diff --git a/docs/html/images/tools/signadt5.png b/docs/html/images/tools/signadt5.png
new file mode 100644
index 0000000..e1861e8
--- /dev/null
+++ b/docs/html/images/tools/signadt5.png
Binary files differ
diff --git a/docs/html/images/tools/signstudio1.png b/docs/html/images/tools/signstudio1.png
new file mode 100644
index 0000000..374e04f
--- /dev/null
+++ b/docs/html/images/tools/signstudio1.png
Binary files differ
diff --git a/docs/html/images/tools/signstudio10.png b/docs/html/images/tools/signstudio10.png
new file mode 100644
index 0000000..5b9ae6d
--- /dev/null
+++ b/docs/html/images/tools/signstudio10.png
Binary files differ
diff --git a/docs/html/images/tools/signstudio11.png b/docs/html/images/tools/signstudio11.png
new file mode 100644
index 0000000..0bf0d51
--- /dev/null
+++ b/docs/html/images/tools/signstudio11.png
Binary files differ
diff --git a/docs/html/images/tools/signstudio2.png b/docs/html/images/tools/signstudio2.png
new file mode 100644
index 0000000..5e8e416
--- /dev/null
+++ b/docs/html/images/tools/signstudio2.png
Binary files differ
diff --git a/docs/html/images/tools/signstudio3.png b/docs/html/images/tools/signstudio3.png
new file mode 100644
index 0000000..f25bf00
--- /dev/null
+++ b/docs/html/images/tools/signstudio3.png
Binary files differ
diff --git a/docs/html/tools/publishing/app-signing.jd b/docs/html/tools/publishing/app-signing.jd
index 1de1fd7..53e6e65 100644
--- a/docs/html/tools/publishing/app-signing.jd
+++ b/docs/html/tools/publishing/app-signing.jd
@@ -4,33 +4,26 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Quickview</h2>
-
-<ul>
-<li>All Android apps <em>must</em> be signed</li>
-<li>You can sign with a self-signed key</li>
-<li>How you sign your apps is critical &mdash; read this document carefully</li>
-<li>Determine your signing strategy early in the development process</li>
-</ul>
-
 <h2>In this document</h2>
 
 <ol>
-<li><a href="#signing">Signing Process</a></li>
-<li><a href="#strategies">Signing Strategies</a></li>
-<li><a href="#setup">Basic Setup for Signing</a></li>
-<li><a href="#debugmode">Signing in Debug Mode</a></li>
-<li><a href="#releasemode">Signing Release Mode</a>
-    <ol>
-    <li><a href="#cert">Obtain a suitable private key</a></li>
-    <li><a href="#releasecompile">Compile the application in release mode</a></li>
-    <li><a href="#signapp">Sign your application with your private key</a></li>
-    <li><a href="#align">Align the final APK package</a></li>
-    <li><a href="#ExportWizard">Compile and sign with Eclipse ADT</a></li>
-    </ol>
+<li><a href="#overview">Signing Overview</a>
+  <ol>
+  	<li><a href="#debug-mode">Signing in Debug Mode</a></li>
+  	<li><a href="#release-mode">Signing in Release Mode</a></li>
+  	<li><a href="#wear-apps">Signing Android Wear Apps</a></li>
+  </ol>
 </li>
+<li><a href="#studio">Signing Your App in Android Studio</a>
+  <ol>
+  	<li><a href="sign-auto">Automatically Signing Your App</a></li>
+  </ol>
+</li>
+<li><a href="#adt">Signing Your App with the ADT plugin for Eclipse</a></li>
+<li><a href="#considerations">Signing Considerations</a></li>
 <li><a href="#secure-key">Securing Your Private Key</a></li>
-
+<li><a href="#expdebug">Expiry of the Debug Certificate</a></li>
+<li><a href="#signing-manually">Signing Your App Manually</a></li>
 </ol>
 
 <h2>See also</h2>
@@ -43,588 +36,288 @@
 </div>
 </div>
 
-<p>The Android system requires that all installed applications be digitally signed with a
-certificate whose private key is held by the application's developer. The Android system uses the
-certificate as a means of identifying the author of an application and establishing trust
-relationships between applications. The certificate is not used to control which applications the
-user can install. The certificate does not need to be signed by a certificate authority: it is
-perfectly allowable, and typical, for Android applications to use self-signed certificates.</p>
 
-<p>The important points to understand about signing Android applications are:</p>
-
-<ul>
-  <li>All applications <em>must</em> be signed. The system will not install an application
-on an emulator or a device if it is not signed.</li>
-  <li>To test and debug your application, the build tools sign your application with a special debug
-    key that is created by the Android SDK build tools.</li>
-  <li>When you are ready to release your application for end-users, you must sign it with a suitable
-    private key. You cannot publish an application that is signed with the debug key generated
-    by the SDK tools.</li>
-  <li>You can use self-signed certificates to sign your applications. No certificate authority is
-    needed.</li>
-  <li>The system tests a signer certificate's expiration date only at install time. If an
-application's signer certificate expires after the application is installed, the application
-will continue to function normally.</li>
-  <li>You can use standard tools &mdash; Keytool and Jarsigner &mdash; to generate keys and
-sign your application {@code .apk} files.</li>
-  <li>After you sign your application for release, we recommend that you use the
-    <code>zipalign</code> tool to optimize the final APK package.</li>
-</ul>
-
-<p>The Android system will not install or run an application that is not signed appropriately. This
-applies wherever the Android system is run, whether on an actual device or on the emulator.
-For this reason, you must <a href="#setup">set up signing</a> for your application before you can
-run it or debug it on an emulator or device.</p>
-
-<h2 id="signing">Signing Process</h3>
-
-<p>The Android build process signs your application differently depending on which build mode you
-use to build your application. There are two build modes: <em>debug mode</em> and <em>release
-mode</em>. You use debug mode when you are developing and testing your application. You use
-release mode when you want to build a release version of your application that you can
-distribute directly to users or publish on an application marketplace such as Google Play.</p>
-
-<p>When you build in <em>debug mode</em> the Android SDK build tools use the Keytool utility
-(included in the JDK) to create a debug key. Because the SDK build tools created the debug key,
-they know the debug key's alias and password. Each time you compile your application in debug mode,
-the build tools use the debug key along with the Jarsigner utility (also included in the JDK) to
-sign your application's <code>.apk</code> file. Because the alias and password are known to the SDK
-build tools, the tools don't need to prompt you for the debug key's alias and password each time
-you compile.</p>
-
-<p>When you build in <em>release mode</em> you use your own private key to sign your application. If
-you don't have a private key, you can use the Keytool utility to create one for you. When you
-compile your application in release mode, the build tools use your private key along with the
-Jarsigner utility to sign your application's <code>.apk</code> file. Because the certificate and
-private key you use are your own, you must provide the password for the keystore and key alias.</p>
-
-<p>The debug signing process happens automatically when you run or debug your application using
-Eclipse with the ADT plugin. Debug signing also happens automatically when you use the Ant build
-script with the <code>debug</code> option. You can automate the release signing process by using the
-Eclipse Export Wizard or by modifying the Ant build script and building with the
-<code>release</code> option.</p>
-
-<h2 id="strategies">Signing Strategies</h2>
-
-<p>Some aspects of application signing may affect how you approach the development
-of your application, especially if you are planning to release multiple
-applications. </p>
-
-<p>In general, the recommended strategy for all developers is to sign
-all of your applications with the same certificate, throughout the expected
-lifespan of your applications. There are several reasons why you should do so: </p>
-
-<ul>
-<li>Application upgrade &ndash; As you release updates to your application, you
-must continue to sign the updates with the same certificate or set of certificates,
-if you want users to be able to upgrade seamlessly to the new version. When
-the system is installing an update to an application, it compares the
-certificate(s) in the new version with those in the existing version. If the
-certificates match exactly, including both the certificate data and order, then
-the system allows the update. If you sign the new version without using matching
-certificates, you must also assign a different package name to the
-application &mdash; in this case, the user installs the new version as a
-completely new application. </li>
-
-<li>Application modularity &ndash; The Android system allows applications that
-are signed by the same certificate to run in the same process, if the
-applications so requests, so that the system treats them as a single application.
-In this way you can deploy your application in modules, and users can update
-each of the modules independently if needed.</li>
-
-<li>Code/data sharing through permissions &ndash; The Android system provides
-signature-based permissions enforcement, so that an application can expose
-functionality to another application that is signed with a specified
-certificate. By signing multiple applications with the same certificate and
-using signature-based permissions checks, your applications can share code and
-data in a secure manner. </li>
-
-</ul>
-
-<p>Another important consideration in determining your signing strategy is
-how to set the validity period of the key that you will use to sign your
-applications.</p>
-
-<ul>
-<li>If you plan to support upgrades for a single application, you should ensure
-that your key has a validity period that exceeds the expected lifespan of
-that application. A validity period of 25 years or more is recommended.
-When your key's validity period expires, users will no longer be
-able to seamlessly upgrade to new versions of your application.</li>
-
-<li>If you will sign multiple distinct applications with the same key,
-you should ensure that your key's validity period exceeds the expected
-lifespan of <em>all versions of all of the applications</em>, including
-dependent applications that may be added to the suite in the future. </li>
-
-<li>If you plan to publish your application(s) on Google Play, the
-key you use to sign the application(s) must have a validity period
-ending after 22 October 2033. Google Play enforces this requirement
-to ensure that users can seamlessly upgrade applications when
-new versions are available. </li>
-</ul>
-
-<p>As you design your application, keep these points in mind and make sure to
-use a <a href="#cert">suitable certificate</a> to sign your applications. </p>
-
-<h2 id="setup">Basic Setup for Signing</h2>
-
-<p>Before you begin, make sure that the Keytool utility and Jarsigner utility are available to
-the SDK build tools. Both of these tools are available in the JDK. In most cases, you can tell
-the SDK build tools how to find these utilities by setting your <code>JAVA_HOME</code> environment
-variable so it references a suitable JDK. Alternatively, you can add the JDK version of Keytool and
-Jarsigner to your <code>PATH</code> variable.</p>
-
-<p>If you are developing on a version of Linux that originally came with GNU Compiler for
-Java, make sure that the system is using the JDK version of Keytool, rather than the gcj
-version. If Keytool is already in your <code>PATH</code>, it might be pointing to a symlink at
-<code>/usr/bin/keytool</code>. In this case, check the symlink target to be sure it points
-to the Keytool in the JDK.</p>
-
-<h2 id="debugmode">Signing in Debug Mode</h2>
-
-<p>The Android build tools provide a debug signing mode that makes it easier for you
-to develop and debug your application, while still meeting the Android system
-requirement for signing your APK.
-When using debug mode to build your app, the SDK tools invoke Keytool to automatically create
-a debug keystore and key. This debug key is then used to automatically sign the APK, so
-you do not need to sign the package with your own key.</p>
-
-<p>The SDK tools create the debug keystore/key with predetermined names/passwords:</p>
-<ul>
-<li>Keystore name: "debug.keystore"</li>
-<li>Keystore password: "android"</li>
-<li>Key alias: "androiddebugkey"</li>
-<li>Key password: "android"</li>
-<li>CN: "CN=Android Debug,O=Android,C=US"</li>
-</ul>
-
-<p>If necessary, you can change the location/name of the debug keystore/key or
-supply a custom debug keystore/key to use. However, any custom debug
-keystore/key must use the same keystore/key names and passwords as the default
-debug key (as described above). (To do so in Eclipse/ADT, go to
-<strong>Windows</strong> &gt; <strong>Preferences</strong> &gt;
-<strong>Android</strong> &gt; <strong>Build</strong>.) </p>
-
-<p class="caution"><strong>Caution:</strong> You <em>cannot</em> release your application
-to the public when signed with the debug certificate.</p>
-
-<h3>Eclipse Users</h3>
-
-<p>If you are developing in Eclipse/ADT (and have set up Keytool and Jarsigner as described above in
-<a href="#setup">Basic Setup for Signing</a>),
-signing in debug mode is enabled by default. When you run or debug your
-application, ADT signs the {@code .apk} file with the debug certificate, runs {@code zipalign} on
-the package, then installs it on
-the selected emulator or connected device. No specific action on your part is needed,
-provided ADT has access to Keytool.</p>
-
-<h3>Ant Users</h3>
-
-<p>If you are using Ant to build your {@code .apk} file, debug signing mode
-is enabled by using the <code>debug</code> option with the <code>ant</code> command
-(assuming that you are using a <code>build.xml</code> file generated by the
-<code>android</code> tool). When you run <code>ant debug</code> to
-compile your app, the build script generates a keystore/key and signs the APK for you.
-The script then also aligns the APK with the <code>zipalign</code> tool.
-No other action on your part is needed. Read
-<a href="{@docRoot}tools/building/building-cmdline.html#DebugMode">Building and Running Apps
-on the Command Line</a> for more information.</p>
+<p>Android requires that all apps be digitally signed with a certificate before they can be
+installed. Android uses this certificate to identify the author of an app, and the certificate
+does not need to be signed by a certificate authority. Android apps often use self-signed
+certificates. The app developer holds the certificate's private key.</p>
 
 
-<h3 id="debugexpiry">Expiry of the Debug Certificate</h3>
+<h2 id="overview">Signing Overview</h2>
 
-<p>The self-signed certificate used to sign your application in debug mode (the default on
-Eclipse/ADT and Ant builds) will have an expiration date of 365 days from its creation date.</p>
+<p>You can sign an app in debug or release mode. You sign your app in debug mode during development
+and in release mode when you are ready to distribute your app. The Android SDK generates a
+certificate to sign apps in debug mode. To sign apps in release mode, you need to generate
+your own certificate.</p>
 
-<p>When the certificate expires, you will get a build error. On Ant builds, the error
-looks like this:</p>
+<h3 id="debug-mode">Signing in Debug Mode</h3>
 
-<pre>debug:
-[echo] Packaging bin/samples-debug.apk, and signing it with a debug key...
-[exec] Debug Certificate expired on 8/4/08 3:43 PM</pre>
+<p>In debug mode, you sign your app with a debug certificate generated by the Android SDK tools.
+This certificate has a private key with a known password, so you can run and debug your app
+without typing the password every time you make a change to your project.</p>
 
-<p>In Eclipse/ADT, you will see a similar error in the Android console.</p>
+<p>Android Studio and the ADT plugin for Eclipse sign your app in debug mode automatically when
+you run or debug your project from the IDE.</p>
 
-<p>To fix this problem, simply delete the <code>debug.keystore</code> file.
-The default storage location for AVDs is in <code>~/.android/</code> on OS X and Linux,
-in <code>C:\Documents and Settings\&lt;user>\.android\</code> on Windows XP, and in
-<code>C:\Users\&lt;user>\.android\</code> on Windows Vista and Windows 7.</p>
+<p>You can run and debug an app signed in debug mode on the emulator and on devices connected
+to your development manchine through USB, but you cannot distribute an app signed in debug
+mode.</p>
 
+<p>For more information about how to build and run apps in debug mode, see
+<a href="{@docRoot}tools/building/index.html">Building and Running</a>.</p>
 
-<p>The next time you build, the build tools will regenerate a new keystore and debug key.</p>
+<h3 id="release-mode">Signing in Release Mode</h3>
 
-<p>Note that, if your development machine is using a non-Gregorian locale, the build
-tools may erroneously generate an already-expired debug certificate, so that you get an
-error when trying to compile your application. For workaround information, see the
-troubleshooting topic <a href="{@docRoot}resources/faq/troubleshooting.html#signingcalendar">
-I&nbsp;can't&nbsp;compile my app because the build tools generated an expired debug
-certificate</a>. </p>
+<p>In release mode, you sign your app with your own certificate:</p>
 
-
-<h2 id="releasemode">Signing in Release Mode</h2>
-
-<p>When your application is ready for release to other users, you must:</p>
 <ol>
-  <li><a href="#cert">Obtain a suitable private key</a></li>
-  <li><a href="#releasecompile">Compile the application in release mode</a></li>
-  <li><a href="#signapp">Sign your application with your private key</a></li>
-  <li><a href="#align">Align the final APK package</a></li>
+<li><em>Create a keystore.</em> A <strong>keystore</strong> is a binary file that contains a
+set of private keys. You must keep your keystore in a safe and secure place.</li>
+<li><em>Create a private key.</em> A <strong>private key</strong> represents the entity to
+be identified with the app, such as a person or a company.</li>
+<li><em>Build your project</em>. Generate an unsigned APK for your app.</li>
+<li><em>Sign your app.</em> Use your private key to generate a signed version of your APK.</li>
 </ol>
 
-<p>If you are developing in Eclipse with the ADT plugin, you can use the Export Wizard
-to perform the compile, sign, and align procedures. The Export Wizard even allows you to
-generate a new keystore and private key in the process. So if you use Eclipse, you can
-skip to <a href="#ExportWizard">Compile and sign with Eclipse ADT</a>.</p>
+<p>After you complete this process, you can distribute your app and publish it on Google Play.</p>
 
-
-
-<h3 id="cert">1. Obtain a suitable private key</h3>
-
-<p>In preparation for signing your application, you must first ensure that
-you have a suitable private key with which to sign. A suitable private
-key is one that:</p>
-
-<ul>
-<li>Is in your possession</li>
-<li>Represents the personal, corporate, or organizational entity to be identified
-with the application</li>
-<li>Has a validity period that exceeds the expected lifespan of the application
-or application suite. A validity period of more than 25 years is recommended.
-<p>If you plan to publish your application(s) on Google Play, note that a
-validity period ending after 22 October 2033 is a requirement. You can not upload an
-application if it is signed with a key whose validity expires before that date.
-</p></li>
-<li>Is not the debug key generated by the Android SDK tools. </li>
-</ul>
-
-<p>The key may be self-signed. If you do not have a suitable key, you must
-generate one using Keytool. Make sure that you have Keytool available, as described
-in <a href="#setup">Basic Setup</a>.</p>
-
-<p>To generate a self-signed key with Keytool, use the <code>keytool</code>
-command and pass any of the options listed below (and any others, as
-needed). </p>
-
-<p class="warning"><strong>Warning:</strong> Keep your private key secure.
-Before you run Keytool, make sure to read
-<a href="#secure-key">Securing Your Private Key</a> for a discussion of how to keep
-your key secure and why doing so is critically important to you and to users. In
-particular, when you are generating your key, you should select strong passwords
-for both the keystore and key.</p>
-
-<p class="warning"><strong>Warning:</strong> Keep the keystore file you generate with Keytool
-in a safe, secure place. You must use the same key to sign future versions of your application. If
-you republish your app with a new key, Google Play will consider it a new app. For more information
-on settings that must remain constant over the life of your app, see the Android Developer Blog post
-<a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
-That Cannot Change</a>.</p>
-
-<table>
-<tr>
-<th>Keytool Option</th>
-<th>Description</th>
-</tr>
-<tr>
-<td><code>-genkey</code></td><td>Generate a key pair (public and private
-keys)</td>
-</tr>
-<tr>
-<td><code>-v</code></td><td>Enable verbose output.</td>
-</tr>
-<tr>
-<td><code>-alias &lt;alias_name&gt;</code></td><td>An alias for the key. Only
-the first 8 characters of the alias are used.</td>
-</tr>
-<tr>
-<td><code>-keyalg &lt;alg&gt;</code></td><td>The encryption algorithm to use
-when generating the key. Both DSA and RSA are supported.</td>
-</tr>
-<tr>
-<td><code>-keysize &lt;size&gt;</code></td><td>The size of each generated key
-(bits). If not supplied, Keytool uses a default key size of 1024 bits. In
-general, we recommend using a key size of 2048 bits or higher. </td>
-</tr>
-<tr>
-<td><code>-dname &lt;name&gt;</code></td><td><p>A Distinguished Name that describes
-who created the key. The value is used as the issuer and subject fields in the
-self-signed certificate. </p><p>Note that you do not need to specify this option
-in the command line. If not supplied, Jarsigner prompts you to enter each
-of the Distinguished Name fields (CN, OU, and so on).</p></td>
-</tr>
-<tr>
-<td><code>-keypass &lt;password&gt;</code></td><td><p>The password for the
-key.</p> <p>As a security precaution, do not include this option in your command
-line. If not supplied, Keytool prompts you to enter the password. In this way,
-your password is not stored in your shell history.</p></td>
-</tr>
-<tr>
-<td><code>-validity &lt;valdays&gt;</code></td><td><p>The validity period for the
-key, in days. </p><p><strong>Note:</strong> A value of 10000 or greater is recommended.</p></td>
-</tr>
-<tr>
-<td><code>-keystore&nbsp;&lt;keystore-name&gt;.keystore</code></td><td>A name
-for the keystore containing the private key.</td>
-</tr>
-<tr>
-<td><code>-storepass &lt;password&gt;</code></td><td><p>A password for the
-keystore.</p><p>As a security precaution, do not include this option in your
-command line. If not supplied, Keytool prompts you to enter the password. In
-this way, your password is not stored in your shell history.</p></td>
-</tr>
-</table>
-
-<p>Here's an example of a Keytool command that generates a private key:</p>
-
-<pre>$ keytool -genkey -v -keystore my-release-key.keystore
--alias alias_name -keyalg RSA -keysize 2048 -validity 10000</pre>
-
-<p>Running the example command above, Keytool prompts you to provide
-passwords for the keystore and key, and to provide the Distinguished
-Name fields for your key. It then generates the keystore as a file called
-<code>my-release-key.keystore</code>. The keystore and key are
-protected by the passwords you entered. The keystore contains
-a single key, valid for 10000 days. The alias is a name that you &mdash;
-will use later, to refer to this keystore when signing your application. </p>
-
-<p>For more information about Keytool, see the documentation at
-<a
-href="http://docs.oracle.com/javase/6/docs/technotes/tools/windows/keytool.html">
-http://docs.oracle.com/javase/6/docs/technotes/tools/windows/keytool.html</a></p>
-
-
-
-<h3 id="releasecompile">2. Compile the application in release mode</h3>
-
-<p>In order to release your application to users, you must compile it in release mode.
-In release mode, the compiled application is not signed by default and you will need
-to sign it with your private key.</p>
-
-<p class="caution"><strong>Caution:</strong>
-You can not release your application unsigned, or signed with the debug key.</p>
-
-<h4>With Eclipse</h4>
-
-<p>To export an <em>unsigned</em> APK from Eclipse, right-click the project in the Package
-Explorer and select <strong>Android Tools</strong> > <strong>Export Unsigned Application
-Package</strong>. Then specify the file location for the unsigned APK.
-(Alternatively, open your <code>AndroidManifest.xml</code> file in Eclipse, select
-the <strong>Manifest</strong> tab, and click <strong>Export an unsigned APK</strong>.)</p>
-
-<p>Note that you can combine the compiling and signing steps with the Export Wizard. See
-<a href="#ExportWizard">Compiling and signing with Eclipse ADT</a>.</p>
-
-<h4>With Ant</h4>
-
-<p>If you are using Ant, you can enable release mode by using the <code>release</code> option
-with the <code>ant</code> command. For example, if you are running Ant from the
-directory containing your {@code build.xml} file, the command would look like this:</p>
-
-<pre>$ ant release</pre>
-
-<p>By default, the build script compiles the application APK without signing it. The output file
-in your project {@code bin/} will be <code><em>&lt;your_project_name></em>-unsigned.apk</code>.
-Because the application APK is still unsigned, you must manually sign it with your private
-key and then align it using {@code zipalign}.</p>
-
-<p>However, the Ant build script can also perform the signing
-and aligning for you, if you have provided the path to your keystore and the name of
-your key alias in the project's {@code ant.properties} file. With this information provided,
-the build script will prompt you for your keystore and alias password when you perform
-<code>ant release</code>, it will sign the package and then align it. The final output
-file in {@code bin/} will instead be
-<code><em>&lt;your_project_name></em>-release.apk</code>. With these steps
-automated for you, you're able to skip the manual procedures below (steps 3 and 4).
-To learn how to specify your keystore and alias in the {@code ant.properties} file,
-see <a href="{@docRoot}tools/building/building-cmdline.html#ReleaseMode">
-Building and Running Apps on the Command Line</a>.</p>
-
-
-
-<h3 id="signapp">3. Sign your application with your private key</h3>
-
-<p>When you have an application package that is ready to be signed, you can do sign it
-using the Jarsigner tool. Make sure that you have Jarsigner available on your
-machine, as described in <a href="#setup">Basic Setup</a>. Also, make sure that
-the keystore containing your private key is  available.</p>
-
-<p>To sign your application, you run Jarsigner, referencing both the
-application's APK and the keystore containing the private key with which to
-sign the APK. The table below shows the options you could use. </p>
-
-<table>
-<tr>
-<th>Jarsigner Option</th>
-<th>Description</th>
-</tr>
-<tr>
-<td><code>-keystore&nbsp;&lt;keystore-name&gt;.keystore</code></td><td>The name of
-the keystore containing your private key.</td>
-</tr>
-<tr>
-<td><code>-verbose</code></td><td>Enable verbose output.</td>
-</tr>
-<tr>
-<td><code>-sigalg</code></td><td>The name of the signature algorithim to use in signing the APK.
-Use the value {@code SHA1withRSA}.</td>
-</tr>
-<tr>
-<td><code>-digestalg</code></td><td>The message digest algorithim to use in processing the entries
-of an APK. Use the value {@code SHA1}.</td>
-</tr>
-<tr>
-<td><code>-storepass &lt;password&gt;</code></td><td><p>The password for the
-keystore. </p><p>As a security precaution, do not include this option
-in your command line unless you are working at a secure computer.
-If not supplied, Jarsigner prompts you to enter the password. In this
-way, your password is not stored in your shell history.</p></td>
-</tr>
-<tr>
-<td><code>-keypass &lt;password&gt;</code></td><td><p>The password for the private
-key. </p><p>As a security precaution, do not include this option
-in your command line unless you are working at a secure computer.
-If not supplied, Jarsigner prompts you to enter the password. In this
-way, your password is not stored in your shell history.</p></td>
-</tr>
-</table>
-
-<p>Here's how you would use Jarsigner to sign an application package called
-<code>my_application.apk</code>, using the example keystore created above.
-</p>
-
-<pre>$ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore
-my_application.apk alias_name</pre>
-
-<p>Running the example command above, Jarsigner prompts you to provide
-passwords for the keystore and key. It then modifies the APK
-in-place, meaning the APK is now signed. Note that you can sign an
-APK multiple times with different keys.</p>
-
-<p class="caution"><strong>Caution:</strong> As of JDK 7, the default signing algorithim has
-changed, requiring you to specify the signature and digest algorithims ({@code -sigalg} and {@code
--digestalg}) when you sign an APK.</p>
-
-<p>To verify that your APK is signed, you can use a command like this:</p>
-
-<pre>$ jarsigner -verify my_signed.apk</pre>
-
-<p>If the APK is signed properly, Jarsigner prints "jar verified".
-If you want more details, you can try one of these commands:</p>
-
-<pre>$ jarsigner -verify -verbose my_application.apk</pre>
-
-<p>or</p>
-
-<pre>$ jarsigner -verify -verbose -certs my_application.apk</pre>
-
-<p>The command above, with the <code>-certs</code> option added, will show you the
-"CN=" line that describes who created the key.</p>
-
-<p class="note"><strong>Note:</strong> If you see "CN=Android Debug", this means the APK was
-signed with the debug key generated by the Android SDK. If you intend to release
-your application, you must sign it with your private key instead of the debug
+<p class="warning"><strong>Warning:</strong> Keep your keystore and private key in a safe and
+secure place, and ensure that you have secure backups of them. If you publish an app to Google
+Play and then lose the key with which you signed your app, you will not be able to publish
+any updates to your app, since you must always sign all versions of your app with the same
 key.</p>
 
-<p>For more information about Jarsigner, see the documentation at
-<a href="http://docs.oracle.com/javase/6/docs/technotes/tools/windows/jarsigner.html">
-http://docs.oracle.com/javase/6/docs/technotes/tools/windows/jarsigner.html</a></p>
+<p>The rest of this document provides detailed instructions about how to generate a private
+key and sign your apps in release mode with Android Studio and with the ADT plugin for Eclipse.</p>
+
+<h3 id="wear-apps">Signing Android Wear Apps</h3>
+
+<p>When publishing Android Wear apps, you package the wearable app inside of a handheld app,
+because users cannot browse and install apps directly on the wearable. Both apps must be signed.
+For more information on packaging and signing Android Wear apps, see
+<a href="{@docRoot}training/wearables/apps/packaging.html">Packaging Wearable Apps</a>.</p>
 
 
-<h3 id="align">4. Align the final APK package</h3>
+<h2 id="studio">Signing Your App in Android Studio</h2>
 
-<p>Once you have signed the APK with your private key, run <code>zipalign</code> on the file.
-This tool ensures that all uncompressed data starts with a particular byte alignment,
-relative to the start of the file. Ensuring alignment at 4-byte boundaries provides
-a performance optimization when installed on a device. When aligned, the Android
-system is able to read files with {@code mmap()}, even if
-they contain binary data with alignment restrictions, rather than copying all
-of the data from the package. The benefit is a reduction in the amount of
-RAM consumed by the running application.</p>
-
-<p>The <code>zipalign</code> tool is provided with the Android SDK, inside the
-<code>tools/</code> directory. To align your signed APK, execute:</p>
-
-<pre>$ zipalign -v 4 <em>your_project_name</em>-unaligned.apk <em>your_project_name</em>.apk</pre>
-
-<p>The {@code -v} flag turns on verbose output (optional). {@code 4} is the
-byte-alignment (don't use anything other than 4). The first file argument is
-your signed {@code .apk} file (the input) and the second file is the destination {@code .apk} file
-(the output). If you're overriding an existing APK, add the {@code -f} flag.</p>
-
-<p class="caution"><strong>Caution:</strong> Your input APK must be signed with your
-private key <strong>before</strong> you optimize the package with {@code zipalign}.
-If you sign it after using {@code zipalign}, it will undo the alignment.</p>
-
-<p>For more information, read about the
-<a href="{@docRoot}tools/help/zipalign.html">zipalign</a> tool.
-
-
-<h3 id="ExportWizard">Compile and sign with Eclipse ADT</h3>
-
-<p>If you are using Eclipse with the ADT plugin, you can use the Export Wizard to
-export a <em>signed</em> APK (and even create a new keystore,
-if necessary). The Export Wizard performs all the interaction with
-the Keytool and Jarsigner for you, which allows you to sign the package using a GUI
-instead of performing the manual procedures to compile, sign,
-and align, as discussed above. Once the wizard has compiled and signed your package,
-it will also perfom package alignment with {@code zipalign}.
-Because the Export Wizard uses both Keytool and Jarsigner, you should
-ensure that they are accessible on your computer, as described above
-in the <a href="#setup">Basic Setup for Signing</a>.</p>
-
-<p>To create a signed and aligned APK in Eclipse:</p>
+<p>To sign your app in release mode in Android Studio, follow these steps:</p>
 
 <ol>
-  <li>Select the project in the Package
-Explorer and select <strong>File > Export</strong>.</li>
-  <li>Open the Android folder, select Export Android Application,
-  and click <strong>Next</strong>.
-  <p>The Export Android Application wizard now starts, which will
-  guide you through the process of signing your application,
-  including steps for selecting the private key with which to sign the APK
-  (or creating a new keystore and private key).</p>
-  <li>Complete the Export Wizard and your application will be compiled,
-  signed, aligned, and ready for distribution.</li>
+<li>On the menu bar, click <strong>Build</strong> &gt; <strong>Generate Signed APK</strong>.</li>
+<li><p>On the <em>Generate Signed APK Wizard</em> window, click <strong>Create new</strong> to create
+a new keystore.</p><p>If you already have a keystore, go to step 4.</p></li>
+<li><p>On the <em>New Key Store</em> window, provide the required information as shown
+in figure 1.</p><p>Your key should be valid for at least 25 years, so you can sign app updates
+with the same key through the lifespan of your app.</p>
+<img src="{@docRoot}images/tools/signstudio2.png" alt=""
+     width="416" height="364" style="margin-top:15px"/>
+<p class="img-caption"><strong>Figure 1</strong>. Create a new keystore in Android Studio.</p>
+</li>
+<li><p>On the <em>Generate Signed APK Wizard</em> window, select a keystore, a private key, and enter
+the passwords for both. Then click <strong>Next</strong>.</p>
+<img src="{@docRoot}images/tools/signstudio1.png" alt=""
+     width="349" height="232" style="margin-top:15px"/>
+<p class="img-caption"><strong>Figure 2</strong>. Select a private key in Android Studio.</p>
+</li>
+<li><p>On the next window, select a destination for the signed APK and click
+<strong>Finish</strong>.</p>
+<img src="{@docRoot}images/tools/signstudio3.png" alt=""
+     width="350" height="175" style="margin-top:15px"/>
+<p class="img-caption"><strong>Figure 3</strong>. Generate a signed APK in Android Studio.</p>
+</li>
 </ol>
 
+<h3 id="sign-auto">Automatically Signing Your App</h3>
+
+<p>In Android Studio, you can configure your project to sign your release APK automatically
+during the build process:</p>
+
+<ol>
+<li>On the project browser, right click on your app and select <strong>Open Module
+Settings</strong>.</li>
+<li>On the <em>Project Structure</em> window, select your app's module under <em>Modules</em>.</li>
+<li>Click on the <strong>Signing</strong> tab.</li>
+<li><p>Select your keystore file, enter a name for this signing configuration (as you may create
+more than one), and enter the required information.</p>
+<img src="{@docRoot}images/tools/signstudio10.png" alt=""
+     width="623" height="372" style="margin-top:15px"/>
+<p class="img-caption"><strong>Figure 4</strong>. Create a signing configuration in Android Studio.</p>
+</li>
+<li>Click on the <strong>Build Types</strong> tab.</li>
+<li>Select the <strong>release</strong> build.</li>
+<li><p>Under <em>Signing Config</em>, select the signing configuration you just created.</p>
+<img src="{@docRoot}images/tools/signstudio11.png" alt=""
+     width="623" height="372" style="margin-top:15px"/>
+<p class="img-caption"><strong>Figure 5</strong>. Select a signing configuration in Android Studio.</p>
+</li>
+<li>Click <strong>OK</strong>.</li>
+</ol>
+
+<p>You can also specify your signing settings in Gradle configuration files. For more information,
+see <a href="{@docRoot}sdk/installing/studio-build.html#configureSigning">Signing settings</a>.</p>
+
+
+<h2 id="adt">Signing Your App with the ADT Plugin for Eclipse</h2>
+
+<p>To sign your app in release mode in ADT, follow these steps:</p>
+
+<ol>
+<li>Select the project in the Package Explorer and select <strong>File</strong> >
+<strong>Export</strong>.</li>
+<li>On the <em>Export</em> window, select <strong>Export Android Application</strong> and click
+<strong>Next</strong>.</li>
+<li>On the <em>Export Android Application</em> window, select the project you want to sign and
+click <strong>Next</strong>.</li>
+<li>
+<p>On the next window, enter the location to create a keystore and a keystore password. If you
+already have a keystore, select <strong>Use existing keystore</strong>, enter your keystore's
+location and password, and go to step 6.</p>
+<img src="{@docRoot}images/tools/signadt3.png" alt=""
+     width="488" height="270" style="margin-top:15px"/>
+<p class="img-caption"><strong>Figure 6</strong>. Select a keystore in ADT.</p>
+</li>
+<li><p>On the next window, provide the required information as shown in figure 5.<p>
+<p>Your key should be valid for at least 25 years, so you can sign app updates with the same key
+through the lifespan of your app.</p>
+<img src="{@docRoot}images/tools/signadt4.png" alt=""
+     width="488" height="448" style="margin-top:15px"/>
+<p class="img-caption"><strong>Figure 7</strong>. Create a private key in ADT.</p>
+</li>
+<li><p>On the next window, select the location to export the signed APK.</p>
+<img src="{@docRoot}images/tools/signadt5.png" alt=""
+     width="488" height="217" style="margin-top:15px"/>
+<p class="img-caption"><strong>Figure 8</strong>. Export the signed APK in ADT.</p>
+</li>
+</ol>
+
+
+<h2 id="considerations">Signing Considerations</h2>
+
+<p>You should sign all of your apps with the same certificate throughout the expected lifespan
+of your applications. There are several reasons why you should do so:</p>
+
+<ul>
+<li>App upgrade: When the system is installing an update to an app, it compares the certificate(s)
+in the new version with those in the existing version. The system allows the update if the
+certificates match. If you sign the new version with a different certificate, you must assign a
+different package name to the application&mdash;in this case, the user installs the new version as
+a completely new application.</li>
+<li>App modularity: Android allows apps signed by the same certificate to run in the same process,
+if the applications so requests, so that the system treats them as a single application. In this
+way you can deploy your app in modules, and users can update each of the modules independently.</li>
+<li>Code/data sharing through permissions: Android provides signature-based permissions
+enforcement, so that an app can expose functionality to another app that is signed with a
+specified certificate. By signing multiple apps with the same certificate and using
+signature-based permissions checks, your apps can share code and data in a secure manner.</li>
+</ul>
+
+<p>If you plan to support upgrades for an app, ensure that your key has a validity
+period that exceeds the expected lifespan of that app. A validity period of 25 years or more is
+recommended. When your key's validity period expires, users will no longer be able to seamlessly
+upgrade to new versions of your application.</p>
+
+<p>If you plan to publish your apps on Google Play, the key you use to sign these apps must have
+a validity period ending after 22 October 2033. Google Play enforces this requirement to ensure
+that users can seamlessly upgrade apps when new versions are available.</p>
 
 
 <h2 id="secure-key">Securing Your Private Key</h2>
 
-<p>Maintaining the security of your private key is of critical importance, both
-to you and to the user. If you allow someone to use your key, or if you leave
-your keystore and passwords in an unsecured location such that a third-party
-could find and use them, your authoring identity and the trust of the user
-are compromised. </p>
+<p>Maintaining the security of your private key is of critical importance, both to you and to
+the user. If you allow someone to use your key, or if you leave your keystore and passwords in
+an unsecured location such that a third-party could find and use them, your authoring identity
+and the trust of the user are compromised.</p>
 
-<p>If a third party should manage to take your key without your knowledge or
-permission, that person could sign and distribute applications that maliciously
-replace your authentic applications or corrupt them. Such a person could also
-sign and distribute applications under your identity that attack other
-applications or the system itself, or corrupt or steal user data. </p>
+<p>If a third party should manage to take your key without your knowledge or permission, that
+person could sign and distribute apps that maliciously replace your authentic apps or corrupt
+them. Such a person could also sign and distribute apps under your identity that attack
+other apps or the system itself, or corrupt or steal user data.</p>
 
-<p>Your private key is required for signing all future versions of your application. If you lose or
-misplace your key, you will not be able to publish updates to your existing application. You cannot
+<p>Your private key is required for signing all future versions of your app. If you lose or
+misplace your key, you will not be able to publish updates to your existing appn. You cannot
 regenerate a previously generated key.</p>
 
-<p>Your reputation as a developer entity depends on your securing your private
-key properly, at all times, until the key is expired. Here are some tips for
-keeping your key secure: </p>
+<p>Your reputation as a developer entity depends on your securing your private key properly, at
+all times, until the key is expired. Here are some tips for keeping your key secure:</p>
 
 <ul>
 <li>Select strong passwords for the keystore and key.</li>
-<li>When you generate your key with Keytool, <em>do not</em> supply the
-<code>-storepass</code> and <code>-keypass</code> options at the command line.
-If you do so, your passwords will be available in your shell history,
-which any user on your computer could access.</li>
-<li>Similarly, when signing your applications with Jarsigner,
-<em>do not</em> supply the <code>-storepass</code> and <code>-keypass</code>
-options at the command line. </li>
-<li>Do not give or lend anyone your private key, and do not let unauthorized
-persons know your keystore and key passwords.</li>
-<li>Keep the keystore file containing your private key that you <a href="#cert">generate with the
-Keytool</a> in a safe, secure place.</li>
+<li>Do not give or lend anyone your private key, and do not let unauthorized persons know your
+keystore and key passwords.</li>
+<li>Keep the keystore file containing your private key in a safe, secure place.</li>
 </ul>
 
-<p>In general, if you follow common-sense precautions when generating, using,
-and storing your key, it will remain secure. </p>
+<p>In general, if you follow common-sense precautions when generating, using, and storing
+your key, it will remain secure.</p>
+
+
+<h2 id="expdebug">Expiry of the Debug Certificate</h2>
+
+<p>The self-signed certificate used to sign your application in debug mode has an expiration date
+of 365 days from its creation date. When the certificate expires, you will get a build error.</p>
+
+<p>To fix this problem, simply delete the <code>debug.keystore</code> file. The default storage
+location is in <code>~/.android/</code> on OS X and Linux, in <code>C:\Documents and
+Settings\&lt;user&gt;\.android\</code> on Windows XP, and in
+<code>C:\Users\&lt;user&gt;\.android\</code> on Windows Vista and Windows 7.</p>
+
+<p>The next time you build, the build tools will regenerate a new keystore and debug key.</p>
+
+<p>Note that, if your development machine is using a non-Gregorian locale, the build tools may
+erroneously generate an already-expired debug certificate, so that you get an error when trying
+to compile your application. For workaround information, see the troubleshooting topic
+<a href="{@docRoot}resources/faq/troubleshooting.html#signingcalendar">I can't compile my app
+because the build tools generated an expired debug certificate</a>.</p>
+
+
+<h2 id="signing-manually">Signing Your App Manually</h2>
+
+<p>You do not need Android Studio or the ADT plugin for Eclipse to sign your app. You can sign
+your app from the command line using standard tools from the Android SDK and the JDK. To sign
+an app in release mode from the command line:</p>
+
+<ol>
+<li>
+  <p>Generate a private key using
+  <code><a href="http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html">keytool</a></code>.
+  For example:</p>
+<pre>
+$ keytool -genkey -v -keystore my-release-key.keystore
+-alias alias_name -keyalg RSA -keysize 2048 -validity 10000
+</pre>
+  <p>This example prompts you for passwords for the keystore and key, and to provide the
+  Distinguished Name fields for your key. It then generates the keystore as a file called
+  <code>my-release-key.keystore</code>. The keystore contains a single key, valid for 10000 days.
+  The alias is a name that you will use later when signing your app.</p>
+</li>
+<li style="margin-top:18px">
+  <p>Compile your app in release mode to obtain an unsigned APK.</p>
+</li>
+<li style="margin-top:18px">
+  <p>Sign your app with your private key using
+  <code><a href="http://docs.oracle.com/javase/6/docs/technotes/tools/windows/jarsigner.html">jarsigner</a></code>:
+  </p>
+<pre>
+$ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1
+-keystore my-release-key.keystore my_application.apk alias_name
+</pre>
+  <p>This example prompts you for passwords for the keystore and key. It then modifies the APK
+  in-place to sign it. Note that you can sign an APK multiple times with different keys.</p>
+</li>
+<li style="margin-top:18px">
+  <p>Verify that your APK is signed. For example:</p>
+<pre>
+$ jarsigner -verify -verbose -certs my_application.apk
+</pre>
+</li>
+<li style="margin-top:18px">
+  <p>Align the final APK package using
+  <code><a href="{@docRoot}tools/help/zipalign.html">zipalign</a></code>.</p>
+<pre>
+$ zipalign -v 4 your_project_name-unaligned.apk your_project_name.apk
+</pre>
+  <p><code>zipalign</code> ensures that all uncompressed data starts with a particular byte
+  alignment relative to the start of the file, which reduces the amount of RAM consumed by an
+  app.</p>
+</li>
+</ol>
diff --git a/docs/html/training/articles/security-gms-provider.jd b/docs/html/training/articles/security-gms-provider.jd
new file mode 100644
index 0000000..0d3cf1e
--- /dev/null
+++ b/docs/html/training/articles/security-gms-provider.jd
@@ -0,0 +1,298 @@
+page.title=Updating Your Security Provider to Protect Against SSL Exploits
+page.tags="network","certificates"
+
+page.article=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>In this document</h2>
+<ol class="nolist">
+  <li><a href="#patching">Patching the Security Provider with
+      ProviderInstaller</a></li>
+  <li><a href="#example_sync">Patching Synchronously</a></li>
+  <li><a href="#example_async">Patching Asynchronously</a></li>
+
+</ol>
+
+
+<h2>See also</h2>
+<ul>
+  <li><a href="{@docRoot}google/play-services/">Google Play Services</a></li>
+  <li><a href="https://www.openssl.org/news/secadv_20140605.txt">OpenSSL
+   Security Advisory [05 Jun 2014]: SSL/TLS MITM vulnerability
+   (CVE-2014-0224)</a></li>
+  <li><a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-0224">
+    Vulnerability Summary for CVE-2014-0224</a></li>
+</ul>
+</div>
+</div>
+
+
+<p> Android relies on a security {@link java.security.Provider Provider} to
+provide secure network communications. However, from time to time,
+vulnerabilities are found in the default security provider. To protect against
+these vulnerabilities, <a href="{@docRoot}google/play-services/">Google Play
+services</a> provides a way to automatically update a device's security provider
+to protect against known exploits. By calling Google Play services methods, your
+app can ensure that it's running on a device that has the latest updates to
+protect against known exploits.</p>
+
+<p>For example, a vulnerability was discovered in OpenSSL
+(<a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-0224">CVE-2014-0224</a>)
+that can leave apps open to a "man-in-the-middle" attack that decrypts
+secure traffic without either side knowing. With Google Play services version
+5.0, a fix is available, but apps must ensure that this fix is installed. By
+using the Google Play services methods, your app can ensure that it's running
+on a device that's secured against that attack.</p>
+
+<p class="caution"><strong>Caution: </strong>Updating a device's security {@link
+java.security.Provider Provider} does <em>not</em> update {@link
+android.net.SSLCertificateSocketFactory
+android.net.SSLCertificateSocketFactory}. Rather than using this class, we
+encourage app developers to use high-level methods for interacting with
+cryptography. Most apps can use APIs like {@link
+javax.net.ssl.HttpsURLConnection}, {@link org.apache.http.client.HttpClient},
+and {@link android.net.http.AndroidHttpClient} without needing to set a custom
+{@link javax.net.ssl.TrustManager} or create an {@link
+android.net.SSLCertificateSocketFactory}.</p>
+
+<h2 id="patching">Patching the Security Provider with ProviderInstaller</h2>
+
+<p>To update a device's security provider, use the
+<a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html">{@code ProviderInstaller}</a>
+class. You can verify that the security provider is up-to-date (and update it,
+if necessary) by calling
+that class's <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>
+(or <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html#installIfNeededAsync(android.content.Context, com.google.android.gms.security.ProviderInstaller.ProviderInstallListener)">{@code installIfNeededAsync()}</a>)
+method.</p>
+
+<p>When you call <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>, the
+<a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html">{@code ProviderInstaller}</a>
+does the following:</p>
+
+<ul>
+  <li>If the device's {@link java.security.Provider Provider} is successfully
+    updated (or is already up-to-date), the method returns normally.</li>
+  <li>If the device's Google Play services library is out of date, the method
+    throws
+    <a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesRepairableException.html">{@code GooglePlayServicesRepairableException}</a>.
+    The app can then catch this exception and show
+    the user an appropriate dialog box to update Google Play services.</li>
+    <li>If a non-recoverable error occurs, the method throws
+    <a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesNotAvailableException.html">{@code GooglePlayServicesNotAvailableException}</a>
+    to indicate that it is unable to update the {@link java.security.Provider
+    Provider}. The app can then catch the exception and choose an appropriate
+    course of action, such as displaying the standard
+    <a href="{@docRoot}reference/com/google/android/gms/common/SupportErrorDialogFragment.html">fix-it flow diagram</a>.</li>
+</ul>
+
+<p>The
+<a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html#installIfNeededAsync(android.content.Context, com.google.android.gms.security.ProviderInstaller.ProviderInstallListener)">{@code installIfNeededAsync()}</a>
+method behaves similarly, except that instead of
+throwing exceptions, it calls the appropriate callback method to indicate
+success or failure.</p>
+
+<p>If <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>
+needs to install a new {@link java.security.Provider Provider}, this can take
+anywhere from 30-50 milliseconds (on more recent devices) to 350 ms (on older
+devices). If the security provider is already up-to-date, the method takes a
+negligible amount of time. To avoid affecting user experience:</p>
+
+<ul>
+  <li>Call
+  <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>
+  from background networking threads immediately when the threads are loaded,
+  instead of waiting for the thread to try to use the network. (There's no harm
+  in calling the method multiple times, since it returns immediately if the
+  security provider doesn't need updating.)</li>
+
+  <li>If user experience will be affected by the thread blocking--for example,
+  if the call is from an activity in the UI thread--call the asynchronous
+  version of the method,
+  <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html#installIfNeededAsync(android.content.Context, com.google.android.gms.security.ProviderInstaller.ProviderInstallListener)">{@code installIfNeededAsync()}</a>.
+  (Of course, if you do this, you need to wait for the operation to finish
+  before you attempt any secure communications. The
+  <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html">{@code ProviderInstaller}</a>
+  calls your listener's <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.ProviderInstallListener.html#onProviderInstalled()">{@code onProviderInstalled()}</a>
+  method to signal success.)</li>
+</ul>
+
+<p class="warning"><strong>Warning:</strong> If the
+<a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html">{@code ProviderInstaller}</a>
+is unable to install an updated {@link java.security.Provider Provider},
+your device's security provider might be vulnerable  to known exploits. Your app
+should behave as if all HTTP communication is unencrypted.</p>
+
+<p>Once the {@link java.security.Provider Provider} is updated, all calls to
+security APIs (including SSL APIs) are routed through it.
+(However, this does not apply to  {@link android.net.SSLCertificateSocketFactory
+android.net.SSLCertificateSocketFactory}, which remains vulnerable to such
+exploits as
+<a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-0224">CVE-2014-0224</a>.)</p>
+
+<h2 id="example_sync">Patching Synchronously</h2>
+
+<p>The simplest way to patch the security provider is to call the synchronous
+method <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>.
+This is appropriate if user experience won't be affected by the thread blocking
+while it waits for the operation to finish.</p>
+
+<p>For example, here's an implementation of a <a href="{@docRoot}training/sync-adapters">sync adapter</a> that updates the security provider. Since a sync
+adapter runs in the background, it's okay if the thread blocks while waiting
+for the security provider to be updated. The sync adapter calls
+<a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a> to
+update the security provider. If the method returns normally, the sync adapter
+knows the security provider is up-to-date. If the method throws an exception,
+the sync adapter can take appropriate action (such as prompting the user to
+update Google Play services).</p>
+
+<pre>/**
+ * Sample sync adapter using {&#64;link ProviderInstaller}.
+ */
+public class SyncAdapter extends AbstractThreadedSyncAdapter {
+
+  ...
+
+  // This is called each time a sync is attempted; this is okay, since the
+  // overhead is negligible if the security provider is up-to-date.
+  &#64;Override
+  public void onPerformSync(Account account, Bundle extras, String authority,
+      ContentProviderClient provider, SyncResult syncResult) {
+    try {
+      ProviderInstaller.installIfNeeded(getContext());
+    } catch (GooglePlayServicesRepairableException e) {
+
+      // Indicates that Google Play services is out of date, disabled, etc.
+
+      // Prompt the user to install/update/enable Google Play services.
+      GooglePlayServicesUtil.showErrorNotification(
+          e.getConnectionStatusCode(), getContext());
+
+      // Notify the SyncManager that a soft error occurred.
+      syncResult.stats.numIOExceptions++;
+      return;
+
+    } catch (GooglePlayServicesNotAvailableException e) {
+      // Indicates a non-recoverable error; the ProviderInstaller is not able
+      // to install an up-to-date Provider.
+
+      // Notify the SyncManager that a hard error occurred.
+      syncResult.stats.numAuthExceptions++;
+      return;
+    }
+
+    // If this is reached, you know that the provider was already up-to-date,
+    // or was successfully updated.
+  }
+}</pre>
+
+<h2 id="example_async">Patching Asynchronously</h2>
+
+<p>Updating the security provider can take as much as 350 milliseconds (on
+older devices). If you're doing the update on a thread that directly affects
+user experience, such as the UI thread, you don't want to make a synchronous
+call to update the provider, since that can result in the app or device
+freezing until the operation finishes. Instead, you should use the asynchronous
+method
+<a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html#installIfNeededAsync(android.content.Context, com.google.android.gms.security.ProviderInstaller.ProviderInstallListener)">{@code installIfNeededAsync()}</a>.
+That method indicates its success or failure by calling callbacks.</p>
+
+<p>For example, here's some code that updates the security provider in an
+activity in the UI thread. The activity calls <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html#installIfNeededAsync(android.content.Context, com.google.android.gms.security.ProviderInstaller.ProviderInstallListener)">{@code installIfNeededAsync()}</a>
+to update the provider, and designates itself as the listener to receive success
+or failure notifications. If the security provider is up-to-date or is
+successfully updated, the activity's
+<a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.ProviderInstallListener.html#onProviderInstalled()">{@code onProviderInstalled()}</a>
+method is called, and the activity knows communication is secure. If the
+provider cannot be updated, the activity's
+<a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.ProviderInstallListener.html#onProviderInstallFailed(int, android.content.Intent)">{@code onProviderInstallFailed()}</a>
+method is called, and the activity can take appropriate action (such as
+prompting the user to update Google Play services).</p>
+
+<pre>/**
+ * Sample activity using {&#64;link ProviderInstaller}.
+ */
+public class MainActivity extends Activity
+    implements ProviderInstaller.ProviderInstallListener {
+
+  private static final int ERROR_DIALOG_REQUEST_CODE = 1;
+
+  private boolean mRetryProviderInstall;
+
+  //Update the security provider when the activity is created.
+  &#64;Override
+  protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    ProviderInstaller.installIfNeededAsync(this, this);
+  }
+
+  /**
+   * This method is only called if the provider is successfully updated
+   * (or is already up-to-date).
+   */
+  &#64;Override
+  protected void onProviderInstalled() {
+    // Provider is up-to-date, app can make secure network calls.
+  }
+
+  /**
+   * This method is called if updating fails; the error code indicates
+   * whether the error is recoverable.
+   */
+  &#64;Override
+  protected void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {
+    if (GooglePlayServicesUtil.isUserRecoverableError(errorCode)) {
+      // Recoverable error. Show a dialog prompting the user to
+      // install/update/enable Google Play services.
+      GooglePlayServicesUtil.showErrorDialogFragment(
+          errorCode,
+          this,
+          ERROR_DIALOG_REQUEST_CODE,
+          new DialogInterface.OnCancelListener() {
+            &#64;Override
+            public void onCancel(DialogInterface dialog) {
+              // The user chose not to take the recovery action
+              onProviderInstallerNotAvailable();
+            }
+          });
+    } else {
+      // Google Play services is not available.
+      onProviderInstallerNotAvailable();
+    }
+  }
+
+  &#64;Override
+  protected void onActivityResult(int requestCode, int resultCode,
+      Intent data) {
+    super.onActivityResult(requestCode, resultCode, data);
+    if (requestCode == ERROR_DIALOG_REQUEST_CODE) {
+      // Adding a fragment via GooglePlayServicesUtil.showErrorDialogFragment
+      // before the instance state is restored throws an error. So instead,
+      // set a flag here, which will cause the fragment to delay until
+      // onPostResume.
+      mRetryProviderInstall = true;
+    }
+  }
+
+  /**
+   * On resume, check to see if we flagged that we need to reinstall the
+   * provider.
+   */
+  &#64;Override
+  protected void onPostResume() {
+    super.onPostResult();
+    if (mRetryProviderInstall) {
+      // We can now safely retry installation.
+      ProviderInstall.installIfNeededAsync(this, this);
+    }
+    mRetryProviderInstall = false;
+  }
+
+  private void onProviderInstallerNotAvailable() {
+    // This is reached if the provider cannot be updated for some reason.
+    // App should consider all HTTP communication to be vulnerable, and take
+    // appropriate action.
+  }
+}
+</pre>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 4407d30..4dd57ab 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -1487,6 +1487,14 @@
           >Security with HTTPS and SSL</a>
       </li>
 
+      <li>
+        <a href="<?cs var:toroot ?>training/articles/security-gms-provider.html"
+           description=
+           "How to use and update Google Play services security provider, to
+           protect against SSL exploits."
+          >Updating Your Security Provider to Protect Against SSL Exploits</a>
+      </li>
+
       <li class="nav-section">
         <div class="nav-section-header">
           <a href="<?cs var:toroot ?>training/enterprise/index.html"
diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java
index 9d015f7..ade14c6 100644
--- a/graphics/java/android/graphics/RadialGradient.java
+++ b/graphics/java/android/graphics/RadialGradient.java
@@ -16,6 +16,9 @@
 
 package android.graphics;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
 public class RadialGradient extends Shader {
 
     private static final int TYPE_COLORS_AND_POSITIONS = 1;
@@ -32,63 +35,64 @@
     private float mRadius;
     private int[] mColors;
     private float[] mPositions;
-    private int mColor0;
-    private int mColor1;
+    private int mCenterColor;
+    private int mEdgeColor;
 
     private TileMode mTileMode;
 
     /** Create a shader that draws a radial gradient given the center and radius.
-        @param x        The x-coordinate of the center of the radius
-        @param y        The y-coordinate of the center of the radius
-        @param radius   Must be positive. The radius of the circle for this gradient
+        @param centerX  The x-coordinate of the center of the radius
+        @param centerY  The y-coordinate of the center of the radius
+        @param radius   Must be positive. The radius of the circle for this gradient.
         @param colors   The colors to be distributed between the center and edge of the circle
-        @param positions May be NULL. The relative position of
-                        each corresponding color in the colors array. If this is NULL,
-                        the the colors are distributed evenly between the center and edge of the circle.
-        @param  tile    The Shader tiling mode
+        @param stops    May be <code>null</code>. Valid values are between <code>0.0f</code> and
+                        <code>1.0f</code>. The relative position of each corresponding color in
+                        the colors array. If <code>null</code>, colors are distributed evenly
+                        between the center and edge of the circle.
+        @param tileMode The Shader tiling mode
     */
-    public RadialGradient(float x, float y, float radius,
-                          int colors[], float positions[], TileMode tile) {
+    public RadialGradient(float centerX, float centerY, float radius,
+               @NonNull int colors[], @Nullable float stops[], @NonNull TileMode tileMode) {
         if (radius <= 0) {
             throw new IllegalArgumentException("radius must be > 0");
         }
         if (colors.length < 2) {
             throw new IllegalArgumentException("needs >= 2 number of colors");
         }
-        if (positions != null && colors.length != positions.length) {
+        if (stops != null && colors.length != stops.length) {
             throw new IllegalArgumentException("color and position arrays must be of equal length");
         }
         mType = TYPE_COLORS_AND_POSITIONS;
-        mX = x;
-        mY = y;
+        mX = centerX;
+        mY = centerY;
         mRadius = radius;
         mColors = colors;
-        mPositions = positions;
-        mTileMode = tile;
-        init(nativeCreate1(x, y, radius, colors, positions, tile.nativeInt));
+        mPositions = stops;
+        mTileMode = tileMode;
+        init(nativeCreate1(centerX, centerY, radius, colors, stops, tileMode.nativeInt));
     }
 
     /** Create a shader that draws a radial gradient given the center and radius.
-        @param x        The x-coordinate of the center of the radius
-        @param y        The y-coordinate of the center of the radius
-        @param radius   Must be positive. The radius of the circle for this gradient
-        @param color0   The color at the center of the circle.
-        @param color1   The color at the edge of the circle.
-        @param tile     The Shader tiling mode
+        @param centerX     The x-coordinate of the center of the radius
+        @param centerY     The y-coordinate of the center of the radius
+        @param radius      Must be positive. The radius of the circle for this gradient
+        @param centerColor The color at the center of the circle.
+        @param edgeColor   The color at the edge of the circle.
+        @param tileMode    The Shader tiling mode
     */
-    public RadialGradient(float x, float y, float radius,
-                          int color0, int color1, TileMode tile) {
+    public RadialGradient(float centerX, float centerY, float radius,
+            int centerColor, int edgeColor, @NonNull TileMode tileMode) {
         if (radius <= 0) {
             throw new IllegalArgumentException("radius must be > 0");
         }
         mType = TYPE_COLOR_CENTER_AND_COLOR_EDGE;
-        mX = x;
-        mY = y;
+        mX = centerX;
+        mY = centerY;
         mRadius = radius;
-        mColor0 = color0;
-        mColor1 = color1;
-        mTileMode = tile;
-        init(nativeCreate2(x, y, radius, color0, color1, tile.nativeInt));
+        mCenterColor = centerColor;
+        mEdgeColor = edgeColor;
+        mTileMode = tileMode;
+        init(nativeCreate2(centerX, centerY, radius, centerColor, edgeColor, tileMode.nativeInt));
     }
 
     /**
@@ -103,7 +107,7 @@
                         mPositions != null ? mPositions.clone() : null, mTileMode);
                 break;
             case TYPE_COLOR_CENTER_AND_COLOR_EDGE:
-                copy = new RadialGradient(mX, mY, mRadius, mColor0, mColor1, mTileMode);
+                copy = new RadialGradient(mX, mY, mRadius, mCenterColor, mEdgeColor, mTileMode);
                 break;
             default:
                 throw new IllegalArgumentException("RadialGradient should be created with either " +
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 0fd4423..e3c03a9 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -171,8 +171,13 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, Mode tintMode) {
-        mState.mDrawable.setTint(tint, tintMode);
+    public void setTintList(ColorStateList tint) {
+        mState.mDrawable.setTintList(tint);
+    }
+
+    @Override
+    public void setTintMode(Mode tintMode) {
+        mState.mDrawable.setTintMode(tintMode);
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 54683aa..00c92fa 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -312,9 +312,7 @@
         final int size = animators.size();
         for (int i = 0; i < size; i++) {
             final Animator animator = animators.get(i);
-            if (animator.isPaused()) {
-                animator.resume();
-            } else if (!animator.isRunning()) {
+            if (!animator.isRunning()) {
                 animator.start();
             }
         }
@@ -327,7 +325,7 @@
         final int size = animators.size();
         for (int i = 0; i < size; i++) {
             final Animator animator = animators.get(i);
-            animator.pause();
+            animator.end();
         }
     }
 
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 525e01d..f5e63ae 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -623,12 +623,16 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
-        final BitmapState state = mBitmapState;
-        state.mTint = tint;
-        state.mTintMode = tintMode;
+    public void setTintList(ColorStateList tint) {
+        mBitmapState.mTint = tint;
+        mTintFilter = updateTintFilter(mTintFilter, tint, mBitmapState.mTintMode);
+        invalidateSelf();
+    }
 
-        mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+    @Override
+    public void setTintMode(PorterDuff.Mode tintMode) {
+        mBitmapState.mTintMode = tintMode;
+        mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, tintMode);
         invalidateSelf();
     }
 
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 174de3a..f116376 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -174,8 +174,13 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, Mode tintMode) {
-        mClipState.mDrawable.setTint(tint, tintMode);
+    public void setTintList(ColorStateList tint) {
+        mClipState.mDrawable.setTintList(tint);
+    }
+
+    @Override
+    public void setTintMode(Mode tintMode) {
+        mClipState.mDrawable.setTintMode(tintMode);
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 4f050e0..9e42a89 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -167,15 +167,17 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, Mode tintMode) {
-        final ColorState state = mColorState;
-        if (state.mTint != tint || state.mTintMode != tintMode) {
-            state.mTint = tint;
-            state.mTintMode = tintMode;
+    public void setTintList(ColorStateList tint) {
+        mColorState.mTint = tint;
+        mTintFilter = updateTintFilter(mTintFilter, tint, mColorState.mTintMode);
+        invalidateSelf();
+    }
 
-            mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
-            invalidateSelf();
-        }
+    @Override
+    public void setTintMode(Mode tintMode) {
+        mColorState.mTintMode = tintMode;
+        mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, tintMode);
+        invalidateSelf();
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index df9f3c3..5a3e3a3 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -478,10 +478,48 @@
      * @param tint Color state list to use for tinting this drawable, or null to
      *            clear the tint
      * @param tintMode A Porter-Duff blending mode
+     * @hide TODO: Was in L-preview, remove this API for release
      */
     public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {}
 
     /**
+     * Specifies a tint for this drawable.
+     * <p>
+     * Setting a color filter via {@link #setColorFilter(ColorFilter)} overrides
+     * tint.
+     *
+     * @param tint Color to use for tinting this drawable
+     * @see #setTintMode(PorterDuff.Mode)
+     */
+    public void setTint(int tint) {
+        setTintList(ColorStateList.valueOf(tint));
+    }
+
+    /**
+     * Specifies a tint for this drawable as a color state list.
+     * <p>
+     * Setting a color filter via {@link #setColorFilter(ColorFilter)} overrides
+     * tint.
+     *
+     * @param tint Color state list to use for tinting this drawable, or null to
+     *            clear the tint
+     * @see #setTintMode(PorterDuff.Mode)
+     */
+    public void setTintList(ColorStateList tint) {}
+
+    /**
+     * Specifies a tint blending mode for this drawable.
+     * <p>
+     * Setting a color filter via {@link #setColorFilter(ColorFilter)} overrides
+     * tint.
+     *
+     * @param tintMode Color state list to use for tinting this drawable, or null to
+     *            clear the tint
+     * @param tintMode A Porter-Duff blending mode
+     */
+    public void setTintMode(PorterDuff.Mode tintMode) {}
+
+    /**
      * Returns the current color filter, or {@code null} if none set.
      *
      * @return the current color filter, or {@code null} if none set
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 55bc35e..0b052f4 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -176,15 +176,29 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, Mode tintMode) {
-        mDrawableContainerState.mHasTint = (tint != null && tintMode != null);
+    public void setTintList(ColorStateList tint) {
+        mDrawableContainerState.mHasTint = tint != null
+                && mDrawableContainerState.mTintMode != null;
 
-        if (mDrawableContainerState.mTint != tint || mDrawableContainerState.mTintMode != tintMode) {
+        if (mDrawableContainerState.mTint != tint) {
             mDrawableContainerState.mTint = tint;
+
+            if (mCurrDrawable != null) {
+                mCurrDrawable.mutate().setTintList(tint);
+            }
+        }
+    }
+
+    @Override
+    public void setTintMode(Mode tintMode) {
+        mDrawableContainerState.mHasTint = mDrawableContainerState.mTint != null
+                && tintMode != null;
+
+        if (mDrawableContainerState.mTintMode != tintMode) {
             mDrawableContainerState.mTintMode = tintMode;
 
             if (mCurrDrawable != null) {
-                mCurrDrawable.mutate().setTint(tint, tintMode);
+                mCurrDrawable.mutate().setTintMode(tintMode);
             }
         }
     }
@@ -437,7 +451,8 @@
                 if (mDrawableContainerState.mHasColorFilter) {
                     d.setColorFilter(mDrawableContainerState.mColorFilter);
                 } else if (mDrawableContainerState.mHasTint) {
-                    d.setTint(mDrawableContainerState.mTint, mDrawableContainerState.mTintMode);
+                    d.setTintList(mDrawableContainerState.mTint);
+                    d.setTintMode(mDrawableContainerState.mTintMode);
                 }
                 d.setVisible(isVisible(), true);
                 d.setDither(mDrawableContainerState.mDither);
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index f6ccbf5..ee5fe2e 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -260,8 +260,13 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, Mode tintMode) {
-        mInsetState.mDrawable.setTint(tint, tintMode);
+    public void setTintList(ColorStateList tint) {
+        mInsetState.mDrawable.setTintList(tint);
+    }
+
+    @Override
+    public void setTintMode(Mode tintMode) {
+        mInsetState.mDrawable.setTintMode(tintMode);
     }
 
     /** {@hide} */
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index d094ce4..43bc89a 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -698,11 +698,20 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, Mode tintMode) {
+    public void setTintList(ColorStateList tint) {
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setTint(tint, tintMode);
+            array[i].mDrawable.setTintList(tint);
+        }
+    }
+
+    @Override
+    public void setTintMode(Mode tintMode) {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            array[i].mDrawable.setTintMode(tintMode);
         }
     }
 
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 758d42a..6ebb8b5 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -346,12 +346,16 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
-        final NinePatchState state = mNinePatchState;
-        state.mTint = tint;
-        state.mTintMode = tintMode;
+    public void setTintList(ColorStateList tint) {
+        mNinePatchState.mTint = tint;
+        mTintFilter = updateTintFilter(mTintFilter, tint, mNinePatchState.mTintMode);
+        invalidateSelf();
+    }
 
-        mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+    @Override
+    public void setTintMode(PorterDuff.Mode tintMode) {
+        mNinePatchState.mTintMode = tintMode;
+        mTintFilter = updateTintFilter(mTintFilter, mNinePatchState.mTint, tintMode);
         invalidateSelf();
     }
 
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 6f21f2e..be2241b 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -276,7 +276,7 @@
     public void getBounds(Rect bounds) {
         final int outerX = (int) mOuterX;
         final int outerY = (int) mOuterY;
-        final int r = (int) mOuterRadius;
+        final int r = (int) mOuterRadius + 1;
         bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
     }
 
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index d404ccd..93df648 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -264,7 +264,7 @@
     public void getBounds(Rect bounds) {
         final int outerX = (int) mOuterX;
         final int outerY = (int) mOuterY;
-        final int r = (int) mOuterRadius;
+        final int r = (int) mOuterRadius + 1;
         bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
     }
 
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 8f8fa98..983eb3b 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -139,8 +139,13 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, Mode tintMode) {
-        mState.mDrawable.setTint(tint, tintMode);
+    public void setTintList(ColorStateList tint) {
+        mState.mDrawable.setTintList(tint);
+    }
+
+    @Override
+    public void setTintMode(Mode tintMode) {
+        mState.mDrawable.setTintMode(tintMode);
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 46c92fe..a954474 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -190,8 +190,13 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, Mode tintMode) {
-        mScaleState.mDrawable.setTint(tint, tintMode);
+    public void setTintList(ColorStateList tint) {
+        mScaleState.mDrawable.setTintList(tint);
+    }
+
+    @Override
+    public void setTintMode(Mode tintMode) {
+        mScaleState.mDrawable.setTintMode(tintMode);
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 394f584..6f18635 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -285,12 +285,16 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
-        final ShapeState state = mShapeState;
-        state.mTint = tint;
-        state.mTintMode = tintMode;
+    public void setTintList(ColorStateList tint) {
+        mShapeState.mTint = tint;
+        mTintFilter = updateTintFilter(mTintFilter, tint, mShapeState.mTintMode);
+        invalidateSelf();
+    }
 
-        mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+    @Override
+    public void setTintMode(PorterDuff.Mode tintMode) {
+        mShapeState.mTintMode = tintMode;
+        mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, tintMode);
         invalidateSelf();
     }
 
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index d5ffa58..813797f 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -307,14 +307,23 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, Mode tintMode) {
+    public void setTintList(ColorStateList tint) {
         final VectorDrawableState state = mVectorState;
-        if (state.mTint != tint || state.mTintMode != tintMode) {
+        if (state.mTint != tint) {
             state.mTint = tint;
-            state.mTintMode = tintMode;
+            mTintFilter = updateTintFilter(mTintFilter, tint, state.mTintMode);
+            state.mVPathRenderer.setColorFilter(mTintFilter);
+            invalidateSelf();
+        }
+    }
 
-            mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
-            mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
+    @Override
+    public void setTintMode(Mode tintMode) {
+        final VectorDrawableState state = mVectorState;
+        if (state.mTintMode != tintMode) {
+            state.mTintMode = tintMode;
+            mTintFilter = updateTintFilter(mTintFilter, state.mTint, tintMode);
+            state.mVPathRenderer.setColorFilter(mTintFilter);
             invalidateSelf();
         }
     }
@@ -883,7 +892,7 @@
                         strokePaint.setStrokeCap(fullPath.mStrokeLineCap);
                     }
 
-                    strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit * minScale);
+                    strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
 
                     strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, stackedAlpha));
                     strokePaint.setStrokeWidth(fullPath.mStrokeWidth * minScale);
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 45aa745..51e47e6 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -116,10 +116,15 @@
 
 private:
     static int startReg(JNIEnv* env);
+    void addOption(const char* optionString, void* extra_info = NULL);
     bool parseRuntimeOption(const char* property,
                             char* buffer,
                             const char* runtimeArg,
                             const char* defaultArg = "");
+    bool parseCompilerOption(const char* property,
+                             char* buffer,
+                             const char* compilerArg,
+                             const char* quotingArg);
     bool parseCompilerRuntimeOption(const char* property,
                                     char* buffer,
                                     const char* runtimeArg,
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 777a35a..6883cc5 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -639,9 +639,10 @@
 
 class DrawBitmapOp : public DrawBoundedOp {
 public:
-    DrawBitmapOp(const SkBitmap* bitmap, float left, float top, const SkPaint* paint)
-            : DrawBoundedOp(left, top, left + bitmap->width(), top + bitmap->height(), paint),
-            mBitmap(bitmap), mAtlas(Caches::getInstance().assetAtlas) {
+    DrawBitmapOp(const SkBitmap* bitmap, const SkPaint* paint)
+            : DrawBoundedOp(0, 0, bitmap->width(), bitmap->height(), paint)
+            , mBitmap(bitmap)
+            , mAtlas(Caches::getInstance().assetAtlas) {
         mEntry = mAtlas.getEntry(bitmap);
         if (mEntry) {
             mEntryGenerationId = mAtlas.getGenerationId();
@@ -650,8 +651,7 @@
     }
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
-                getPaint(renderer));
+        return renderer.drawBitmap(mBitmap, getPaint(renderer));
     }
 
     AssetAtlas::Entry* getAtlasEntry() {
@@ -745,35 +745,6 @@
     UvMapper mUvMapper;
 };
 
-class DrawBitmapMatrixOp : public DrawBoundedOp {
-public:
-    DrawBitmapMatrixOp(const SkBitmap* bitmap, const SkMatrix& matrix, const SkPaint* paint)
-            : DrawBoundedOp(paint), mBitmap(bitmap), mMatrix(matrix) {
-        mLocalBounds.set(0, 0, bitmap->width(), bitmap->height());
-        const mat4 transform(matrix);
-        transform.mapRect(mLocalBounds);
-    }
-
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("Draw bitmap %p matrix " SK_MATRIX_STRING, mBitmap, SK_MATRIX_ARGS(&mMatrix));
-    }
-
-    virtual const char* name() { return "DrawBitmapMatrix"; }
-
-    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
-        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
-    }
-
-private:
-    const SkBitmap* mBitmap;
-    const SkMatrix mMatrix;
-};
-
 class DrawBitmapRectOp : public DrawBoundedOp {
 public:
     DrawBitmapRectOp(const SkBitmap* bitmap,
@@ -807,12 +778,11 @@
 
 class DrawBitmapDataOp : public DrawBitmapOp {
 public:
-    DrawBitmapDataOp(const SkBitmap* bitmap, float left, float top, const SkPaint* paint)
-            : DrawBitmapOp(bitmap, left, top, paint) {}
+    DrawBitmapDataOp(const SkBitmap* bitmap, const SkPaint* paint)
+            : DrawBitmapOp(bitmap, paint) {}
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
-                mLocalBounds.top, getPaint(renderer));
+        return renderer.drawBitmapData(mBitmap, getPaint(renderer));
     }
 
     virtual void output(int level, uint32_t logFlags) const {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 5286ef8..b210e64 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -194,51 +194,42 @@
     return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, float left, float top,
-        const SkPaint* paint) {
+status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
     bitmap = refBitmap(bitmap);
     paint = refPaint(paint);
 
-    addDrawOp(new (alloc()) DrawBitmapOp(bitmap, left, top, paint));
-    return DrawGlInfo::kStatusDone;
-}
-
-status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
-        const SkPaint* paint) {
-    bitmap = refBitmap(bitmap);
-    paint = refPaint(paint);
-
-    addDrawOp(new (alloc()) DrawBitmapMatrixOp(bitmap, matrix, paint));
+    addDrawOp(new (alloc()) DrawBitmapOp(bitmap, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
         float srcRight, float srcBottom, float dstLeft, float dstTop,
         float dstRight, float dstBottom, const SkPaint* paint) {
-    bitmap = refBitmap(bitmap);
-    paint = refPaint(paint);
-
-    if (srcLeft == 0 && srcTop == 0 &&
-            srcRight == bitmap->width() && srcBottom == bitmap->height() &&
-            (srcBottom - srcTop == dstBottom - dstTop) &&
-            (srcRight - srcLeft == dstRight - dstLeft)) {
+    if (srcLeft == 0 && srcTop == 0
+            && srcRight == bitmap->width() && srcBottom == bitmap->height()
+            && (srcBottom - srcTop == dstBottom - dstTop)
+            && (srcRight - srcLeft == dstRight - dstLeft)) {
         // transform simple rect to rect drawing case into position bitmap ops, since they merge
-        addDrawOp(new (alloc()) DrawBitmapOp(bitmap, dstLeft, dstTop, paint));
-        return DrawGlInfo::kStatusDone;
-    }
+        save(SkCanvas::kMatrix_SaveFlag);
+        translate(dstLeft, dstTop);
+        drawBitmap(bitmap, paint);
+        restore();
+    } else {
+        bitmap = refBitmap(bitmap);
+        paint = refPaint(paint);
 
-    addDrawOp(new (alloc()) DrawBitmapRectOp(bitmap,
-                    srcLeft, srcTop, srcRight, srcBottom,
-                    dstLeft, dstTop, dstRight, dstBottom, paint));
+        addDrawOp(new (alloc()) DrawBitmapRectOp(bitmap,
+                srcLeft, srcTop, srcRight, srcBottom,
+                dstLeft, dstTop, dstRight, dstBottom, paint));
+    }
     return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawBitmapData(const SkBitmap* bitmap, float left, float top,
-        const SkPaint* paint) {
+status_t DisplayListRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
     bitmap = refBitmapData(bitmap);
     paint = refPaint(paint);
 
-    addDrawOp(new (alloc()) DrawBitmapDataOp(bitmap, left, top, paint));
+    addDrawOp(new (alloc()) DrawBitmapDataOp(bitmap, paint));
     return DrawGlInfo::kStatusDone;
 }
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index d1d8572..1b3a48a 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -105,15 +105,11 @@
     virtual status_t drawColor(int color, SkXfermode::Mode mode);
 
     // Bitmap-based
-    virtual status_t drawBitmap(const SkBitmap* bitmap, float left, float top,
-            const SkPaint* paint);
-    virtual status_t drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
-            const SkPaint* paint);
+    virtual status_t drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
     virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
             float dstRight, float dstBottom, const SkPaint* paint);
-    virtual status_t drawBitmapData(const SkBitmap* bitmap, float left, float top,
-            const SkPaint* paint);
+    virtual status_t drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint);
     virtual status_t drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
             const float* vertices, const int* colors, const SkPaint* paint);
     virtual status_t drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5fbef2e..e00d2e3 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2034,12 +2034,8 @@
     return DrawGlInfo::kStatusDrew;
 }
 
-status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, float left, float top,
-        const SkPaint* paint) {
-    const float right = left + bitmap->width();
-    const float bottom = top + bitmap->height();
-
-    if (quickRejectSetupScissor(left, top, right, bottom)) {
+status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
+    if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2049,49 +2045,16 @@
     const AutoTexture autoCleanup(texture);
 
     if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlphaBitmap(texture, left, top, paint);
+        drawAlphaBitmap(texture, 0, 0, paint);
     } else {
-        drawTextureRect(left, top, right, bottom, texture, paint);
+        drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
     }
 
     return DrawGlInfo::kStatusDrew;
 }
 
-status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
-        const SkPaint* paint) {
-    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
-    const mat4 transform(matrix);
-    transform.mapRect(r);
-
-    if (quickRejectSetupScissor(r.left, r.top, r.right, r.bottom)) {
-        return DrawGlInfo::kStatusDone;
-    }
-
-    mCaches.activeTexture(0);
-    Texture* texture = getTexture(bitmap);
-    if (!texture) return DrawGlInfo::kStatusDone;
-    const AutoTexture autoCleanup(texture);
-
-    // This could be done in a cheaper way, all we need is pass the matrix
-    // to the vertex shader. The save/restore is a bit overkill.
-    save(SkCanvas::kMatrix_SaveFlag);
-    concatMatrix(matrix);
-    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlphaBitmap(texture, 0.0f, 0.0f, paint);
-    } else {
-        drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
-    }
-    restore();
-
-    return DrawGlInfo::kStatusDrew;
-}
-
-status_t OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, float left, float top,
-        const SkPaint* paint) {
-    const float right = left + bitmap->width();
-    const float bottom = top + bitmap->height();
-
-    if (quickRejectSetupScissor(left, top, right, bottom)) {
+status_t OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
+    if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2100,9 +2063,9 @@
     const AutoTexture autoCleanup(texture);
 
     if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlphaBitmap(texture, left, top, paint);
+        drawAlphaBitmap(texture, 0, 0, paint);
     } else {
-        drawTextureRect(left, top, right, bottom, texture, paint);
+        drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
     }
 
     return DrawGlInfo::kStatusDrew;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3bc591f..fd228db 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -161,17 +161,13 @@
 
     virtual status_t drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1);
     virtual status_t drawLayer(Layer* layer, float x, float y);
-    virtual status_t drawBitmap(const SkBitmap* bitmap, float left, float top,
-            const SkPaint* paint);
+    virtual status_t drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
     status_t drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
             TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint);
-    virtual status_t drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
-            const SkPaint* paint);
     virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
             float dstRight, float dstBottom, const SkPaint* paint);
-    virtual status_t drawBitmapData(const SkBitmap* bitmap, float left, float top,
-            const SkPaint* paint);
+    virtual status_t drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint);
     virtual status_t drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
             const float* vertices, const int* colors, const SkPaint* paint);
     status_t drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 237d500..f48b774 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -94,8 +94,10 @@
 
     properties().debugOutputProperties(level);
     int flags = DisplayListOp::kOpLogFlag_Recurse;
-    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
-        mDisplayListData->displayListOps[i]->output(level, flags);
+    if (mDisplayListData) {
+        for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+            mDisplayListData->displayListOps[i]->output(level, flags);
+        }
     }
 
     ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 40a21e4..f5cd266 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -160,15 +160,11 @@
     virtual status_t drawColor(int color, SkXfermode::Mode mode) = 0;
 
     // Bitmap-based
-    virtual status_t drawBitmap(const SkBitmap* bitmap, float left, float top,
-            const SkPaint* paint) = 0;
-    virtual status_t drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
-            const SkPaint* paint) = 0;
+    virtual status_t drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) = 0;
     virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
             float dstRight, float dstBottom, const SkPaint* paint) = 0;
-    virtual status_t drawBitmapData(const SkBitmap* bitmap, float left, float top,
-            const SkPaint* paint) = 0;
+    virtual status_t drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) = 0;
     virtual status_t drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
             const float* vertices, const int* colors, const SkPaint* paint) = 0;
     virtual status_t drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 3f03093..986e808 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -336,11 +336,14 @@
 }
 
 void RenderProxy::trimMemory(int level) {
-    RenderThread& thread = RenderThread::getInstance();
-    SETUP_TASK(timMemory);
-    args->thread = &thread;
-    args->level = level;
-    thread.queue(task);
+    // Avoid creating a RenderThread to do a trimMemory.
+    if (RenderThread::hasInstance()) {
+        RenderThread& thread = RenderThread::getInstance();
+        SETUP_TASK(timMemory);
+        args->thread = &thread;
+        args->level = level;
+        thread.queue(task);
+    }
 }
 
 CREATE_BRIDGE0(fence) {
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 46fc66b..ce9a742 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -152,6 +152,12 @@
      */
     public final static int FLAG_SCO = 0x1 << 2;
 
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Flag requesting the use of an output stream supporting hardware A/V synchronization.
+     */
+    public final static int FLAG_HW_AV_SYNC = 0x1 << 4;
 
     private int mUsage = USAGE_UNKNOWN;
     private int mContentType = CONTENT_TYPE_UNKNOWN;
@@ -196,7 +202,7 @@
      */
     public int getFlags() {
         // only return the flags that are public
-        return (mFlags & (FLAG_AUDIBILITY_ENFORCED));
+        return (mFlags & (FLAG_AUDIBILITY_ENFORCED | FLAG_HW_AV_SYNC));
     }
 
     /**
@@ -340,7 +346,7 @@
          */
         public Builder setFlags(int flags) {
             flags &= (AudioAttributes.FLAG_AUDIBILITY_ENFORCED | AudioAttributes.FLAG_SCO
-                    | AudioAttributes.FLAG_SECURE);
+                    | AudioAttributes.FLAG_SECURE | AudioAttributes.FLAG_HW_AV_SYNC);
             mFlags |= flags;
             return this;
         }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 705d9c0..a41d4da 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -4573,6 +4573,17 @@
                 outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
                 setWiredDeviceConnectionState(outDevice, state, params);
             } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
+                // FIXME Does not yet handle the case where the setting is changed
+                // after device connection.  Ideally we should handle the settings change
+                // in SettingsObserver. Here we should log that a USB device is connected
+                // and disconnected with its address (card , device) and force the
+                // connection or disconnection when the setting changes.
+                int isDisabled = Settings.System.getInt(mContentResolver,
+                        Settings.System.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);
+                if (isDisabled != 0) {
+                    return;
+                }
+
                 state = intent.getIntExtra("state", 0);
 
                 int alsaCard = intent.getIntExtra("card", -1);
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 8e2ca95..e11aab1 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -487,5 +487,10 @@
     public static native int releaseAudioPatch(AudioPatch patch);
     public static native int listAudioPatches(ArrayList<AudioPatch> patches, int[] generation);
     public static native int setAudioPortConfig(AudioPortConfig config);
+
+    // must be kept in sync with value in include/system/audio.h
+    public static final int AUDIO_HW_SYNC_INVALID = 0;
+
+    public static native int getAudioHwSyncForSession(int sessionId);
 }
 
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 6e1b80a..b786f94 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -77,9 +77,9 @@
      * data.</p>
      *
      * @param width
-     *            The width in pixels of the Images that this reader will produce.
+     *            The default width in pixels of the Images that this reader will produce.
      * @param height
-     *            The height in pixels of the Images that this reader will produce.
+     *            The default height in pixels of the Images that this reader will produce.
      * @param format
      *            The format of the Image that this reader will produce. This
      *            must be one of the {@link android.graphics.ImageFormat} or
@@ -130,39 +130,43 @@
     }
 
     /**
-     * The width of each {@link Image}, in pixels.
+     * The default width of {@link Image Images}, in pixels.
      *
-     * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
-     * {@link #acquireNextImage}) will have the same dimensions as specified in
-     * {@link #newInstance}.</p>
+     * <p>The width may be overridden by the producer sending buffers to this
+     * ImageReader's Surface. If so, the actual width of the images can be
+     * found using {@link Image#getWidth}.</p>
      *
-     * @return the width of an Image
+     * @return the expected width of an Image
      */
     public int getWidth() {
         return mWidth;
     }
 
     /**
-     * The height of each {@link Image}, in pixels.
+     * The default height of {@link Image Images}, in pixels.
      *
-     * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
-     * {@link #acquireNextImage}) will have the same dimensions as specified in
-     * {@link #newInstance}.</p>
+     * <p>The height may be overridden by the producer sending buffers to this
+     * ImageReader's Surface. If so, the actual height of the images can be
+     * found using {@link Image#getHeight}.</p>
      *
-     * @return the height of an Image
+     * @return the expected height of an Image
      */
     public int getHeight() {
         return mHeight;
     }
 
     /**
-     * The {@link ImageFormat image format} of each Image.
+     * The default {@link ImageFormat image format} of {@link Image Images}.
      *
-     * <p>ImageReader guarantees that all {@link Image Images} acquired from ImageReader
-     *  (for example, with {@link #acquireNextImage}) will have the same format as specified in
-     * {@link #newInstance}.</p>
+     * <p>Some color formats may be overridden by the producer sending buffers to
+     * this ImageReader's Surface if the default color format allows. ImageReader
+     * guarantees that all {@link Image Images} acquired from ImageReader
+     * (for example, with {@link #acquireNextImage}) will have a "compatible"
+     * format to what was specified in {@link #newInstance}.
+     * As of now, each format is only compatible to itself.
+     * The actual format of the images can be found using {@link Image#getFormat}.</p>
      *
-     * @return the format of an Image
+     * @return the expected format of an Image
      *
      * @see ImageFormat
      */
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 858383e..1c6d81f 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -225,6 +225,17 @@
     }
 
     /**
+     * Gets the service component that the media browser is connected to.
+     */
+    public @NonNull ComponentName getServiceComponent() {
+        if (!isConnected()) {
+            throw new IllegalStateException("getServiceComponent() called while not connected" +
+                    " (state=" + mState + ")");
+        }
+        return mServiceComponent;
+    }
+
+    /**
      * Gets the root Uri.
      * <p>
      * Note that the root uri may become invalid or change when when the
@@ -234,7 +245,7 @@
      * @throws IllegalStateException if not connected.
      */
     public @NonNull Uri getRoot() {
-        if (mState != CONNECT_STATE_CONNECTED) {
+        if (!isConnected()) {
             throw new IllegalStateException("getSessionToken() called while not connected (state="
                     + getStateLabel(mState) + ")");
         }
@@ -247,7 +258,7 @@
      * @throws IllegalStateException if not connected.
      */
     public @Nullable Bundle getExtras() {
-        if (mState != CONNECT_STATE_CONNECTED) {
+        if (!isConnected()) {
             throw new IllegalStateException("getExtras() called while not connected (state="
                     + getStateLabel(mState) + ")");
         }
@@ -266,7 +277,7 @@
      * @throws IllegalStateException if not connected.
      */
      public @NonNull MediaSession.Token getSessionToken() {
-        if (mState != CONNECT_STATE_CONNECTED) {
+        if (!isConnected()) {
             throw new IllegalStateException("getSessionToken() called while not connected (state="
                     + mState + ")");
         }
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index dd84ad32..3d25aa6 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -25,7 +25,7 @@
     boolean canProjectAudio();
     boolean canProjectVideo();
     boolean canProjectSecureVideo();
-    int getVirtualDisplayFlags();
+    int applyVirtualDisplayFlags(int flags);
     void addCallback(IMediaProjectionCallback callback);
     void removeCallback(IMediaProjectionCallback callback);
 }
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 7c03171..861039d 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -93,6 +93,19 @@
     }
 
     /**
+     * @hide
+     */
+    public VirtualDisplay createVirtualDisplay(@NonNull String name,
+            int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
+            @Nullable VirtualDisplay.Callbacks callbacks, @Nullable Handler handler) {
+        DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
+        int flags = isSecure ? DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE : 0;
+        return dm.createVirtualDisplay(this, name, width, height, dpi, surface,
+                    flags | DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR |
+                    DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION, callbacks, handler);
+    }
+
+    /**
      * Creates a {@link android.hardware.display.VirtualDisplay} to capture the
      * contents of the screen.
      *
@@ -105,9 +118,8 @@
      * than 0.
      * @param surface The surface to which the content of the virtual display
      * should be rendered, or null if there is none initially.
-     * @param isSecure Whether the display should be considered a secure
-     * display. This typically requires special permissions not available to
-     * third party applications.
+     * @param flags A combination of virtual display flags. See {@link DisplayManager} for the full
+     * list of flags.
      * @param callbacks Callbacks to call when the virtual display's state
      * changes, or null if none.
      * @param handler The {@link android.os.Handler} on which the callback should be
@@ -118,10 +130,9 @@
      * String, int, int, int, int, Surface, VirtualDisplay.Callbacks, Handler)
      */
     public VirtualDisplay createVirtualDisplay(@NonNull String name,
-            int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
+            int width, int height, int dpi, int flags, @Nullable Surface surface,
             @Nullable VirtualDisplay.Callbacks callbacks, @Nullable Handler handler) {
         DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
-        int flags = isSecure ? DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE : 0;
         return dm.createVirtualDisplay(
                     this, name, width, height, dpi, surface, flags, callbacks, handler);
     }
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 382579c..e3c198e 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -196,6 +196,30 @@
     }
 
     /**
+     * Get the queue title for this session.
+     */
+    public @Nullable CharSequence getQueueTitle() {
+        try {
+            return mSessionBinder.getQueueTitle();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getQueueTitle", e);
+        }
+        return null;
+    }
+
+    /**
+     * Get the extras for this session.
+     */
+    public @Nullable Bundle getExtras() {
+        try {
+            return mSessionBinder.getExtras();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getExtras", e);
+        }
+        return null;
+    }
+
+    /**
      * Get the rating type supported by the session. One of:
      * <ul>
      * <li>{@link Rating#RATING_NONE}</li>
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index d5719c8..20b8e7c 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -82,4 +82,5 @@
     List<TvStreamConfig> getAvailableTvStreamConfigList(in String inputId, int userId);
     boolean captureFrame(in String inputId, in Surface surface, in TvStreamConfig config,
             int userId);
+    boolean isSingleSessionActive(int userId);
 }
diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
index 651669b..c98a48d 100644
--- a/media/java/android/media/tv/ITvInputService.aidl
+++ b/media/java/android/media/tv/ITvInputService.aidl
@@ -16,7 +16,7 @@
 
 package android.media.tv;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.media.tv.ITvInputServiceCallback;
 import android.media.tv.ITvInputSessionCallback;
 import android.media.tv.TvInputHardwareInfo;
@@ -35,6 +35,6 @@
     // For hardware TvInputService
     void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo);
     void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
-    void notifyHdmiCecDeviceAdded(in HdmiCecDeviceInfo cecDeviceInfo);
-    void notifyHdmiCecDeviceRemoved(in HdmiCecDeviceInfo cecDeviceInfo);
+    void notifyHdmiCecDeviceAdded(in HdmiDeviceInfo deviceInfo);
+    void notifyHdmiCecDeviceRemoved(in HdmiDeviceInfo deviceInfo);
 }
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 5a0ea0d..a826957 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentUris;
+import android.media.tv.TvContract.Programs;
 import android.net.Uri;
 import android.provider.BaseColumns;
 import android.util.ArraySet;
@@ -684,10 +685,11 @@
          * The flag indicating whether this TV channel is searchable or not.
          * <p>
          * In some regions, it is not allowed to surface search results for a given channel without
-         * broadcaster's consent. This is used to impose such restriction. A value of 1 indicates
-         * the channel is searchable and can be included in search results, a value of 0 indicates
-         * the channel and its TV programs are hidden from search. If not specified, this value is
-         * set to 1 (searchable) by default.
+         * broadcaster's consent. This is used to impose such restriction. Channels marked with
+         * "not searchable" cannot be used by other services except for the system service that
+         * shows the TV content. A value of 1 indicates the channel is searchable and can be
+         * included in search results, a value of 0 indicates the channel and its TV programs are
+         * hidden from search. If not specified, this value is set to 1 (searchable) by default.
          * </p><p>
          * Type: INTEGER (boolean)
          * </p>
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index bc0538c..8feb7e6 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -29,7 +29,7 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -152,10 +152,10 @@
 
     /**
      * Create a new instance of the TvInputInfo class,
-     * instantiating it from the given Context, ResolveInfo, and HdmiCecDeviceInfo.
+     * instantiating it from the given Context, ResolveInfo, and HdmiDeviceInfo.
      *
      * @param service The ResolveInfo returned from the package manager about this TV input service.
-     * @param cecInfo The HdmiCecDeviceInfo for a HDMI CEC logical device.
+     * @param cecInfo The HdmiDeviceInfo for a HDMI CEC logical device.
      * @param parentId The ID of this TV input's parent input. {@code null} if none exists.
      * @param iconUri The {@link android.net.Uri} to load the icon image.
      *        {@see android.content.ContentResolver#openInputStream}. If it is null, the application
@@ -166,7 +166,7 @@
      */
     @SystemApi
     public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
-            HdmiCecDeviceInfo cecInfo, String parentId, String label, Uri iconUri)
+            HdmiDeviceInfo cecInfo, String parentId, String label, Uri iconUri)
                     throws XmlPullParserException, IOException {
         boolean isConnectedToHdmiSwitch = (cecInfo.getPhysicalAddress() & 0x0FFF) != 0;
         return createTvInputInfo(context, service, generateInputIdForHdmiCec(
@@ -494,14 +494,14 @@
     }
 
     /**
-     * Used to generate an input id from a ComponentName and HdmiCecDeviceInfo.
+     * Used to generate an input id from a ComponentName and HdmiDeviceInfo.
      *
      * @param name the component name for generating an input id.
-     * @param cecInfo HdmiCecDeviceInfo describing this TV input.
+     * @param cecInfo HdmiDeviceInfo describing this TV input.
      * @return the generated input id for the given {@code name} and {@code cecInfo}.
      */
     private static final String generateInputIdForHdmiCec(
-            ComponentName name, HdmiCecDeviceInfo cecInfo) {
+            ComponentName name, HdmiDeviceInfo cecInfo) {
         // Example of the format : "/CEC%04X%02X"
         String format = String.format("%s%s%%0%sX%%0%sX", DELIMITER_INFO_IN_ID, PREFIX_CEC_DEVICE,
                 LENGTH_CEC_PHYSICAL_ADDRESS, LENGTH_CEC_LOGICAL_ADDRESS);
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d556369..6e075b2 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -948,6 +948,20 @@
     }
 
     /**
+     * Returns true if there is only a single TV input session.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isSingleSessionActive() {
+        try {
+            return mService.isSingleSessionActive(mUserId);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
      * The Session provides the per-session functionality of TV inputs.
      * @hide
      */
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index d6d2d48..6a41c61 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -23,7 +23,7 @@
 import android.content.Intent;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -142,13 +142,13 @@
             }
 
             @Override
-            public void notifyHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDeviceInfo) {
+            public void notifyHdmiCecDeviceAdded(HdmiDeviceInfo cecDeviceInfo) {
                 mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_CEC_TV_INPUT,
                         cecDeviceInfo).sendToTarget();
             }
 
             @Override
-            public void notifyHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDeviceInfo) {
+            public void notifyHdmiCecDeviceRemoved(HdmiDeviceInfo cecDeviceInfo) {
                 mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_CEC_TV_INPUT,
                         cecDeviceInfo).sendToTarget();
             }
@@ -206,11 +206,11 @@
      * {@code cecDeviceInfo}; otherwise, return {@code null}. Override to modify default behavior
      * of ignoring all HDMI CEC logical input device.
      *
-     * @param cecDeviceInfo {@link HdmiCecDeviceInfo} object just added.
+     * @param cecDeviceInfo {@link HdmiDeviceInfo} object just added.
      * @hide
      */
     @SystemApi
-    public TvInputInfo onHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDeviceInfo) {
+    public TvInputInfo onHdmiCecDeviceAdded(HdmiDeviceInfo cecDeviceInfo) {
         return null;
     }
 
@@ -219,11 +219,11 @@
      * otherwise, return {@code null}. Override to modify default behavior of ignoring all HDMI CEC
      * logical input device.
      *
-     * @param cecDeviceInfo {@link HdmiCecDeviceInfo} object just removed.
+     * @param cecDeviceInfo {@link HdmiDeviceInfo} object just removed.
      * @hide
      */
     @SystemApi
-    public String onHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDeviceInfo) {
+    public String onHdmiCecDeviceRemoved(HdmiDeviceInfo cecDeviceInfo) {
         return null;
     }
 
@@ -1287,7 +1287,7 @@
                     return;
                 }
                 case DO_ADD_HDMI_CEC_TV_INPUT: {
-                    HdmiCecDeviceInfo cecDeviceInfo = (HdmiCecDeviceInfo) msg.obj;
+                    HdmiDeviceInfo cecDeviceInfo = (HdmiDeviceInfo) msg.obj;
                     TvInputInfo inputInfo = onHdmiCecDeviceAdded(cecDeviceInfo);
                     if (inputInfo != null) {
                         broadcastAddHdmiCecTvInput(cecDeviceInfo.getLogicalAddress(), inputInfo);
@@ -1295,7 +1295,7 @@
                     return;
                 }
                 case DO_REMOVE_HDMI_CEC_TV_INPUT: {
-                    HdmiCecDeviceInfo cecDeviceInfo = (HdmiCecDeviceInfo) msg.obj;
+                    HdmiDeviceInfo cecDeviceInfo = (HdmiDeviceInfo) msg.obj;
                     String inputId = onHdmiCecDeviceRemoved(cecDeviceInfo);
                     if (inputId != null) {
                         broadcastRemoveTvInput(inputId);
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 66daf87..591f543 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -78,6 +78,10 @@
     private static final int ZORDER_MEDIA_OVERLAY = 1;
     private static final int ZORDER_ON_TOP = 2;
 
+    private static final int CAPTION_DEFAULT = 0;
+    private static final int CAPTION_ENABLED = 1;
+    private static final int CAPTION_DISABLED = 2;
+
     private static final Object sMainTvViewLock = new Object();
     private static TvView sMainTvView;
 
@@ -107,6 +111,7 @@
     private int mSurfaceViewRight;
     private int mSurfaceViewTop;
     private int mSurfaceViewBottom;
+    private int mCaptionEnabled;
 
     private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
         @Override
@@ -353,6 +358,7 @@
      * @param enabled {@code true} to enable, {@code false} to disable.
      */
     public void setCaptionEnabled(boolean enabled) {
+        mCaptionEnabled = enabled ? CAPTION_ENABLED : CAPTION_DISABLED;
         if (mSession != null) {
             mSession.setCaptionEnabled(enabled);
         }
@@ -832,6 +838,9 @@
                     }
                 }
                 createSessionOverlayView();
+                if (mCaptionEnabled != CAPTION_DEFAULT) {
+                    mSession.setCaptionEnabled(mCaptionEnabled == CAPTION_ENABLED);
+                }
                 mSession.tune(mChannelUri, mTuneParams);
                 if (mHasStreamVolume) {
                     mSession.setStreamVolume(mStreamVolume);
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index 5f78afe..c5fb167 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -25,7 +25,7 @@
         <activity
             android:name="com.android.captiveportallogin.CaptivePortalLoginActivity"
             android:label="@string/action_bar_label"
-            android:theme="@android:style/Theme.Holo" >
+            android:theme="@style/AppTheme" >
             <intent-filter>
                 <action android:name="android.intent.action.ACTION_SEND"/>
                 <category android:name="android.intent.category.DEFAULT"/>
diff --git a/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml b/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
index d8f2928..a11bed0 100644
--- a/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
+++ b/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
@@ -5,9 +5,16 @@
     android:layout_height="match_parent"
     tools:context="com.android.captiveportallogin.CaptivePortalLoginActivity"
     tools:ignore="MergeRootFrame">
-    <RelativeLayout
+    <LinearLayout
     android:layout_width="match_parent"
-    android:layout_height="match_parent" >
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <ProgressBar
+        android:id="@+id/progress_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="?android:attr/progressBarStyleHorizontal" />
 
     <WebView
         android:id="@+id/webview"
@@ -16,5 +23,5 @@
         android:layout_alignParentBottom="false"
         android:layout_alignParentRight="false" />
 
-</RelativeLayout>
+</LinearLayout>
 </FrameLayout>
diff --git a/packages/CaptivePortalLogin/res/values/styles.xml b/packages/CaptivePortalLogin/res/values/styles.xml
index 6ce89c7..7ccd3d3 100644
--- a/packages/CaptivePortalLogin/res/values/styles.xml
+++ b/packages/CaptivePortalLogin/res/values/styles.xml
@@ -4,7 +4,7 @@
         Base application theme, dependent on API level. This theme is replaced
         by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
     -->
-    <style name="AppBaseTheme" parent="android:Theme.Light">
+    <style name="AppBaseTheme" parent="@android:style/Theme.Material.Settings">
         <!--
             Theme customizations available in newer API levels can go in
             res/values-vXX/styles.xml, while customizations related to
@@ -15,6 +15,8 @@
     <!-- Application theme. -->
     <style name="AppTheme" parent="AppBaseTheme">
         <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+        <!-- Setting's theme's accent color makes ProgressBar useless, reset back. -->
+        <item name="android:colorAccent">@*android:color/material_light_blue_A200</item>
     </style>
 
 </resources>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 09525b2..ae52a1e 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -26,11 +26,13 @@
 import android.provider.Settings.Global;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.View;
 import android.view.Window;
 import android.webkit.WebChromeClient;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
+import android.widget.ProgressBar;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
@@ -66,7 +68,6 @@
             done(true);
         }
 
-        requestWindowFeature(Window.FEATURE_PROGRESS);
         setContentView(R.layout.activity_captive_portal_login);
 
         getActionBar().setDisplayShowHomeEnabled(false);
@@ -164,7 +165,9 @@
     private class MyWebChromeClient extends WebChromeClient {
         @Override
         public void onProgressChanged(WebView view, int newProgress) {
-            setProgress(newProgress*100);
+            ProgressBar myProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
+            myProgressBar.setProgress(newProgress);
+            myProgressBar.setVisibility(newProgress == 100 ? View.GONE : View.VISIBLE);
         }
     }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 9dd6bc2..1835b8e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -57,7 +57,7 @@
     }
 
     public KeyguardSecurityContainer(Context context) {
-        this(null, null, 0);
+        this(context, null, 0);
     }
 
     public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
@@ -240,10 +240,13 @@
 
         boolean showTimeout = false;
         if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
-            // If we reach this code, it means the user has installed a DevicePolicyManager
-            // that requests device wipe after N attempts.  Once we get below the grace
-            // period, we'll post this dialog every time as a clear warning until the
-            // bombshell hits and the device is wiped.
+            // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
+            // N attempts. Once we get below the grace period, we post this dialog every time as a
+            // clear warning until the deletion fires.
+            //
+            // TODO: Show a different dialog depending on whether the device will be completely
+            // wiped (i.e. policy is set for the primary profile of the USER_OWNER) or a single
+            // secondary user or managed profile will be removed.
             if (remainingBeforeWipe > 0) {
                 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
             } else {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 58cbaba..0d79ee2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -229,13 +229,16 @@
     private SparseBooleanArray mUserFingerprintRecognized = new SparseBooleanArray();
 
     @Override
-    public void onTrustChanged(boolean enabled, int userId) {
+    public void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser) {
         mUserHasTrust.put(userId, enabled);
 
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
                 cb.onTrustChanged(userId);
+                if (enabled && initiatedByUser) {
+                    cb.onTrustInitiatedByUser(userId);
+                }
             }
         }
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 4827e79..0acb9d0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -179,6 +179,11 @@
     public void onTrustManagedChanged(int userId) { }
 
     /**
+     * Called when the user has proved to a trust agent that they want to use the device.
+     */
+    public void onTrustInitiatedByUser(int userId) { }
+
+    /**
      * Called when a fingerprint is recognized.
      * @param userId
      */
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index 7d0da14..db319e9 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -16,16 +16,13 @@
 
 <resources>
 
-    <style name="PrintActivity" parent="@android:style/Theme.Material">
+    <style name="PrintActivity" parent="@android:style/Theme.Material.Settings">
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:windowContentOverlay">@null</item>
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
         <item name="android:backgroundDimEnabled">false</item>
-        <item name="android:colorPrimary">@*android:color/material_blue_grey_900</item>
-        <item name="android:colorPrimaryDark">@*android:color/material_blue_grey_950</item>
-        <item name="android:colorAccent">@*android:color/material_dark_teal_A400</item>
     </style>
 
 </resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index a92ab7e..478a5de 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -183,7 +183,7 @@
     <!-- Default for Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE -->
     <integer name="def_wifi_scan_always_available">0</integer>
 
-    <!-- Default for Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1==on -->
+    <!-- Default for Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1==on -->
     <integer name="def_lock_screen_show_notifications">1</integer>
 
     <!-- Default for Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1==on -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 09e6a94..7c92cde 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -70,7 +70,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 105;
+    private static final int DATABASE_VERSION = 106;
 
     private Context mContext;
     private int mUserHandle;
@@ -1558,24 +1558,17 @@
         }
 
         if (upgradeVersion == 98) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
-                db.beginTransaction();
-                SQLiteStatement stmt = null;
-                try {
-                    stmt = db.compileStatement("INSERT OR REPLACE INTO global(name,value)"
-                            + " VALUES(?,?);");
-                    loadIntegerSetting(stmt, Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS,
-                            R.integer.def_lock_screen_show_notifications);
-                    db.setTransactionSuccessful();
-                } finally {
-                    db.endTransaction();
-                    if (stmt != null) stmt.close();
-                }
-            }
+            // no-op; LOCK_SCREEN_SHOW_NOTIFICATIONS now handled in version 106
             upgradeVersion = 99;
         }
 
         if (upgradeVersion == 99) {
+            // no-op; HEADS_UP_NOTIFICATIONS_ENABLED now handled in version 100
+            upgradeVersion = 100;
+        }
+
+        if (upgradeVersion == 100) {
+            // note: LOCK_SCREEN_SHOW_NOTIFICATIONS now handled in version 106
             if (mUserHandle == UserHandle.USER_OWNER) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
@@ -1590,28 +1583,6 @@
                     if (stmt != null) stmt.close();
                 }
             }
-            upgradeVersion = 100;
-        }
-        if (upgradeVersion == 100) {
-           // Catch devices that were initialized to version 100 and missed these in onCreate()
-            if (mUserHandle == UserHandle.USER_OWNER) {
-                db.beginTransaction();
-                SQLiteStatement stmt = null;
-                try {
-                    stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
-                            + " VALUES(?,?);");
-                    loadIntegerSetting(stmt, Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS,
-                            R.integer.def_lock_screen_show_notifications);
-
-                    loadIntegerSetting(stmt, Global.HEADS_UP_NOTIFICATIONS_ENABLED,
-                            R.integer.def_heads_up_enabled);
-
-                    db.setTransactionSuccessful();
-                } finally {
-                    db.endTransaction();
-                    if (stmt != null) stmt.close();
-                }
-            }
             upgradeVersion = 101;
         }
 
@@ -1695,6 +1666,34 @@
             upgradeVersion = 105;
         }
 
+        if (upgradeVersion < 106) {
+            // LOCK_SCREEN_SHOW_NOTIFICATIONS is now per-user.
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+                        + " VALUES(?,?);");
+                loadBooleanSetting(stmt, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+                        R.bool.def_guest_user_enabled);
+                if (mUserHandle == UserHandle.USER_OWNER) {
+                    final int oldShow = getIntValueFromTable(db,
+                            TABLE_GLOBAL, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, -1);
+                    if (oldShow >= 0) {
+                        // overwrite the default with whatever you had
+                        loadSetting(stmt, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, oldShow);
+                        final SQLiteStatement deleteStmt
+                                = db.compileStatement("DELETE FROM global WHERE name=?");
+                        deleteStmt.bindString(1, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
+                        deleteStmt.execute();
+                    }
+                }
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 106;
+        }
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -2260,6 +2259,9 @@
             loadBooleanSetting(stmt, Settings.Secure.WAKE_GESTURE_ENABLED,
                     R.bool.def_wake_gesture_enabled);
 
+            loadIntegerSetting(stmt, Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+                    R.integer.def_lock_screen_show_notifications);
+
         } finally {
             if (stmt != null) stmt.close();
         }
@@ -2420,9 +2422,6 @@
             loadIntegerSetting(stmt, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
                     R.integer.def_wifi_scan_always_available);
 
-            loadIntegerSetting(stmt, Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS,
-                    R.integer.def_lock_screen_show_notifications);
-
             loadIntegerSetting(stmt, Global.HEADS_UP_NOTIFICATIONS_ENABLED,
                     R.integer.def_heads_up_enabled);
 
diff --git a/packages/SystemUI/res/color/qs_user_detail_name.xml b/packages/SystemUI/res/color/qs_user_detail_name.xml
index 8ddb9be..57f7e65 100644
--- a/packages/SystemUI/res/color/qs_user_detail_name.xml
+++ b/packages/SystemUI/res/color/qs_user_detail_name.xml
@@ -17,6 +17,6 @@
   -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_activated="true" android:color="#ffffffff" />
+    <item android:state_activated="true" android:color="@color/current_user_border_color" />
     <item android:color="#66ffffff" /> <!-- 40% white -->
 </selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_account_circle_qs.xml b/packages/SystemUI/res/drawable/ic_account_circle_qs.xml
index 0d5cd2e..d10a96d 100644
--- a/packages/SystemUI/res/drawable/ic_account_circle_qs.xml
+++ b/packages/SystemUI/res/drawable/ic_account_circle_qs.xml
@@ -16,7 +16,19 @@
   ~ limitations under the License
   -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <item android:state_activated="true" android:drawable="@drawable/ic_account_circle" />
-    <item android:drawable="@drawable/ic_account_circle_qs_muted" />
-</selector>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+
+    <group
+            android:scaleX="1.2"
+            android:scaleY="1.2"
+            android:pivotX="12.0"
+            android:pivotY="12.0">
+        <path
+                android:fillColor="@color/qs_user_detail_icon_muted"
+                android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml b/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml
deleted file mode 100644
index 7b8b89f..0000000
--- a/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-  ~ Copyright (C) 2014 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <group
-        android:scaleX="1.2"
-        android:scaleY="1.2"
-        android:pivotX="12.0"
-        android:pivotY="12.0">
-    <path
-        android:fillColor="@color/qs_user_detail_icon_muted"
-        android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
new file mode 100644
index 0000000..f296076
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <group
+            android:scaleX="1.2"
+            android:scaleY="1.2"
+            android:pivotX="12.0"
+            android:pivotY="12.0">
+        <path
+            android:fillColor="@color/qs_user_detail_icon_muted"
+            android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM17.000000,13.000000l-4.000000,0.000000l0.000000,4.000000l-2.000000,0.000000l0.000000,-4.000000L7.000000,13.000000l0.000000,-2.000000l4.000000,0.000000L11.000000,7.000000l2.000000,0.000000l0.000000,4.000000l4.000000,0.000000L17.000000,13.000000z"/>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_settings_24dp.xml b/packages/SystemUI/res/drawable/ic_settings.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_settings_24dp.xml
rename to packages/SystemUI/res/drawable/ic_settings.xml
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
index 0e2b6d6..650ee5d 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -14,6 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<!-- extends FrameLayout -->
 <com.android.systemui.statusbar.policy.HeadsUpNotificationView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_height="match_parent"
@@ -21,11 +22,12 @@
         android:background="@drawable/heads_up_scrim">
 
         <FrameLayout
+                android:layout_width="@dimen/notification_panel_width"
                 android:layout_height="wrap_content"
+                android:layout_gravity="@integer/notification_panel_layout_gravity"
                 android:paddingStart="@dimen/notification_side_padding"
                 android:paddingEnd="@dimen/notification_side_padding"
                 android:elevation="8dp"
-                android:id="@+id/content_holder"
-                style="@style/NotificationsQuickSettings" />
+                android:id="@+id/content_holder" />
 
 </com.android.systemui.statusbar.policy.HeadsUpNotificationView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
index d17390e..2e67376 100644
--- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
@@ -16,7 +16,9 @@
   ~ limitations under the License
   -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!-- LinearLayout -->
+<com.android.systemui.qs.tiles.UserDetailItemView
+        xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:sysui="http://schemas.android.com/apk/res-auto"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -24,17 +26,21 @@
         android:layout_marginEnd="8dp"
         android:gravity="center_vertical"
         android:clickable="true"
-        android:background="@drawable/ripple_drawable">
-    <TextView android:id="@+id/name"
+        android:background="@drawable/ripple_drawable"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        sysui:activatedFontFamily="sans-serif-medium">
+    <TextView android:id="@+id/user_name"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginEnd="16dp"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.UserName"
             />
-    <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/picture"
+    <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture"
             android:layout_width="@dimen/max_avatar_size"
             android:layout_height="@dimen/max_avatar_size"
             android:contentDescription="@null"
             sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness"
+            sysui:framePadding="6dp"
             sysui:activeFrameColor="@color/current_user_border_color" />
-</LinearLayout>
\ No newline at end of file
+</com.android.systemui.qs.tiles.UserDetailItemView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 0e78d66..d65a23e 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -77,30 +77,14 @@
                     />
         </LinearLayout>
 
-        <LinearLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:padding="8dp"
+        <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
+                android:id="@+id/notification_inspect_item"
+                android:layout_width="52dp"
+                android:layout_height="match_parent"
                 android:layout_weight="0"
-                android:orientation="horizontal"
-                android:showDividers="beginning|middle"
-                android:divider="@*android:drawable/list_divider_holo_dark"
-                android:dividerPadding="8dp"
-                >
-            <Button style="@android:style/Widget.Material.Light.Button.Borderless.Small"
-                    android:id="@+id/notification_inspect_item"
-                    android:layout_width="0dp"
-                    android:layout_height="match_parent"
-                    android:layout_weight="1"
-                    android:gravity="start|center_vertical"
-                    android:drawablePadding="8dp"
-                    android:paddingStart="8dp"
-                    android:textColor="@color/notification_guts_btn_color"
-                    android:textSize="14dp"
-                    android:singleLine="true"
-                    android:ellipsize="end"
-                    android:text="@string/status_bar_notification_inspect_item_title"
-                    />
-        </LinearLayout>
+                android:gravity="center"
+                android:contentDescription="@string/status_bar_notification_inspect_item_title"
+                android:src="@drawable/ic_settings"
+                />
     </LinearLayout>
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 403860c..5ceed84 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -25,7 +25,10 @@
         android:orientation="vertical"
         android:gravity="top|center_horizontal"
         android:paddingTop="16dp"
-        android:paddingBottom="20dp">
+        android:paddingBottom="20dp"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        systemui:activatedFontFamily="sans-serif-medium">
 
     <com.android.systemui.statusbar.phone.UserAvatarView
             android:id="@+id/user_picture"
@@ -33,6 +36,7 @@
             android:layout_height="@dimen/max_avatar_size"
             android:layout_marginBottom="12dp"
             systemui:frameWidth="2dp"
+            systemui:framePadding="6dp"
             systemui:activeFrameColor="@color/current_user_border_color"/>
 
     <TextView
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index f8dfd65..4a5fffe 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -18,11 +18,11 @@
     android:layout_width="match_parent" 
     android:layout_height="match_parent"
     android:focusable="true">
-    <com.android.systemui.recents.views.TaskThumbnailView
+    <com.android.systemui.recents.views.TaskViewThumbnail
         android:id="@+id/task_view_thumbnail"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
-    <com.android.systemui.recents.views.TaskBarView
+    <com.android.systemui.recents.views.TaskViewHeader
         android:id="@+id/task_view_bar"
         android:layout_width="match_parent"
         android:layout_height="@dimen/recents_task_bar_height"
@@ -61,7 +61,7 @@
             android:background="@drawable/recents_button_bg"
             android:visibility="invisible"
             android:src="@drawable/recents_dismiss_light" />
-    </com.android.systemui.recents.views.TaskBarView>
+    </com.android.systemui.recents.views.TaskViewHeader>
     <FrameLayout
         android:id="@+id/lock_to_app_fab"
         android:layout_width="48dp"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index fa1077b..4eab9c7 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -50,20 +50,19 @@
         android:visibility="gone"
         />
 
-    <include
-        layout="@layout/keyguard_status_bar"
-        android:visibility="invisible" />
-
     <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
-        style="@style/NotificationsQuickSettings"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="@integer/notification_panel_layout_gravity"
         android:id="@+id/notification_container_parent"
         android:clipToPadding="false"
         android:clipChildren="false">
 
         <com.android.systemui.statusbar.phone.ObservableScrollView
             android:id="@+id/scroll_view"
-            android:layout_width="match_parent"
+            android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
+            android:layout_gravity="@integer/notification_panel_layout_gravity"
             android:scrollbars="none"
             android:overScrollMode="never"
             android:fillViewport="true">
@@ -95,8 +94,9 @@
 
         <com.android.systemui.statusbar.stack.NotificationStackScrollLayout
             android:id="@+id/notification_stack_scroller"
-            android:layout_width="match_parent"
+            android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
+            android:layout_gravity="@integer/notification_panel_layout_gravity"
             android:layout_marginBottom="@dimen/close_handle_underlap"/>
 
         <ViewStub
@@ -107,6 +107,10 @@
             android:layout_gravity="end"
             android:layout="@layout/keyguard_user_switcher" />
 
+        <include
+            layout="@layout/keyguard_status_bar"
+            android:visibility="invisible" />
+
     </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
 
     <include layout="@layout/status_bar_expanded_header" />
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 1afde69..21d8457 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -20,8 +20,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/header"
-    style="@style/StatusBarHeader"
+    android:layout_width="@dimen/notification_panel_width"
     android:layout_height="@dimen/status_bar_header_height"
+    android:layout_gravity="@integer/notification_panel_layout_gravity"
     android:paddingStart="@dimen/notification_side_padding"
     android:paddingEnd="@dimen/notification_side_padding"
     android:baselineAligned="false"
@@ -49,7 +50,7 @@
         android:layout_width="48dp"
         android:layout_height="@dimen/status_bar_header_height"
         android:background="@drawable/ripple_drawable"
-        android:src="@drawable/ic_settings_24dp"
+        android:src="@drawable/ic_settings"
         android:contentDescription="@string/accessibility_desc_quick_settings"/>
 
     <LinearLayout android:id="@+id/system_icons_super_container"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 112f3a9..3765fe8 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -15,8 +15,10 @@
      limitations under the License.
 -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="@dimen/volume_panel_width"
+    android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:layout_marginLeft="@dimen/notification_side_padding"
+    android:layout_marginRight="@dimen/notification_side_padding"
     android:background="@drawable/qs_background_primary"
     android:translationZ="@dimen/volume_panel_z"
     android:layout_marginBottom="@dimen/volume_panel_z">
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 2f73c63..9d5f7bd 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -78,7 +78,7 @@
             android:clickable="true"
             android:contentDescription="@null"
             android:scaleType="center"
-            android:src="@drawable/ic_settings_24dp" />
+            android:src="@drawable/ic_settings" />
     </FrameLayout>
 
     <LinearLayout
@@ -98,4 +98,4 @@
         android:paddingTop="4dp"
         android:paddingBottom="4dp"
         android:textAppearance="@style/TextAppearance.QS.Subhead" />
-</com.android.systemui.volume.ZenModePanel>
\ No newline at end of file
+</com.android.systemui.volume.ZenModePanel>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 0aab723..4c43069 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Vee alles uit"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Begin nou"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Geen kennisgewings nie"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index d554e45..faf8284 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"ሁሉንም አጽዳ"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"አሁን ጀምር"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"ምንም ማሳወቂያ የለም"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 04812e5..66f51d7 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"محو الكل"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"البدء الآن"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"ليس هناك أي اشعارات"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e5ab744..9382e02 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Изчистване на всички"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Стартиране сега"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Няма известия"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 21f58b5..4015eab 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"সবকিছু সাফ করুন"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"এখন শুরু করুন"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"কোনো বিজ্ঞপ্তি নেই"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index c69b68e..ee55940 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Esborra-ho tot"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Comença ara"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Cap notificació"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 1884c3a..5280acd 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Smazat vše"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Spustit"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Žádná oznámení"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 98353a9..9d3416d 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Ryd alt"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start nu"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Ingen underretninger"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index e7e629c..6688c6a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Alle löschen"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Jetzt starten"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Keine Benachrichtigungen"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 5377c95..dee321b 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Διαγραφή όλων"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Έναρξη τώρα"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Δεν υπάρχουν ειδοποιήσεις"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index f7d959d..3fc88e9 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -39,12 +39,9 @@
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
-    <!-- no translation found for battery_saver_confirmation_title (5299585433050361634) -->
-    <skip />
-    <!-- no translation found for battery_saver_confirmation_ok (7507968430447930257) -->
-    <skip />
-    <!-- no translation found for battery_saver_start_action (5576697451677486320) -->
-    <skip />
+    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Turn on battery saver?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Turn on"</string>
+    <string name="battery_saver_start_action" msgid="5576697451677486320">"Turn on battery saver"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string>
@@ -288,10 +285,8 @@
     <item quantity="other" msgid="5408537517529822157">"For %d hours"</item>
   </plurals>
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
-    <!-- no translation found for battery_saver_notification_text (820318788126672692) -->
-    <skip />
-    <!-- no translation found for battery_saver_notification_action_text (109158658238110382) -->
-    <skip />
+    <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
+    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
@@ -299,4 +294,15 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"No notifications"</string>
+    <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
+    <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
+    <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
+    <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
+    <string name="open_app" msgid="4011771120339160755">"Open app"</string>
+    <string name="disconnect_vpn" msgid="1324915059568548655">"Disconnect VPN"</string>
+    <string name="monitoring_description_device_owned" msgid="7801926679066533391">"This device is managed by:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nYour administrator can monitor your network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator."</string>
+    <string name="monitoring_description_vpn" msgid="93140751707065515">"You gave \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" permission to set up a VPN connection.\n\nThis app can monitor your network activity, including emails, apps and secure websites."</string>
+    <string name="monitoring_description_legacy_vpn" msgid="5397847778080663075">"You\'re connected to a VPN (\"<xliff:g id="APPLICATION">%1$s</xliff:g>\").\n\nYour VPN service provider can monitor your network activity including emails, apps and secure websites."</string>
+    <string name="monitoring_description_vpn_device_owned" msgid="696121105616356493">"This device is managed by:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps and secure websites. For more information, contact your administrator.\n\nAlso, you gave \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" permission to set up a VPN connection. This app can monitor network activity too."</string>
+    <string name="monitoring_description_legacy_vpn_device_owned" msgid="649791650224064248">"This device is managed by:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps and secure websites. For more information, contact your administrator.\n\nAlso, you\'re connected to a VPN (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\"). Your VPN service provider can monitor network activity too."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index f7d959d..3fc88e9 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -39,12 +39,9 @@
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
-    <!-- no translation found for battery_saver_confirmation_title (5299585433050361634) -->
-    <skip />
-    <!-- no translation found for battery_saver_confirmation_ok (7507968430447930257) -->
-    <skip />
-    <!-- no translation found for battery_saver_start_action (5576697451677486320) -->
-    <skip />
+    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Turn on battery saver?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Turn on"</string>
+    <string name="battery_saver_start_action" msgid="5576697451677486320">"Turn on battery saver"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string>
@@ -288,10 +285,8 @@
     <item quantity="other" msgid="5408537517529822157">"For %d hours"</item>
   </plurals>
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
-    <!-- no translation found for battery_saver_notification_text (820318788126672692) -->
-    <skip />
-    <!-- no translation found for battery_saver_notification_action_text (109158658238110382) -->
-    <skip />
+    <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
+    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
@@ -299,4 +294,15 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start now"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"No notifications"</string>
+    <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
+    <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
+    <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
+    <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
+    <string name="open_app" msgid="4011771120339160755">"Open app"</string>
+    <string name="disconnect_vpn" msgid="1324915059568548655">"Disconnect VPN"</string>
+    <string name="monitoring_description_device_owned" msgid="7801926679066533391">"This device is managed by:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nYour administrator can monitor your network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator."</string>
+    <string name="monitoring_description_vpn" msgid="93140751707065515">"You gave \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" permission to set up a VPN connection.\n\nThis app can monitor your network activity, including emails, apps and secure websites."</string>
+    <string name="monitoring_description_legacy_vpn" msgid="5397847778080663075">"You\'re connected to a VPN (\"<xliff:g id="APPLICATION">%1$s</xliff:g>\").\n\nYour VPN service provider can monitor your network activity including emails, apps and secure websites."</string>
+    <string name="monitoring_description_vpn_device_owned" msgid="696121105616356493">"This device is managed by:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps and secure websites. For more information, contact your administrator.\n\nAlso, you gave \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" permission to set up a VPN connection. This app can monitor network activity too."</string>
+    <string name="monitoring_description_legacy_vpn_device_owned" msgid="649791650224064248">"This device is managed by:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps and secure websites. For more information, contact your administrator.\n\nAlso, you\'re connected to a VPN (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\"). Your VPN service provider can monitor network activity too."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b19a157..b9f7c8d 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Borrar todo"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Comenzar ahora"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"No hay notificaciones"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 326d2ba..2260d7d 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Borrar todo"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Iniciar ahora"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Ninguna notificación"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 7600e15..8c3ee90 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Tühjenda kõik"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Alusta kohe"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Märguandeid pole"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 1ef6599..4c67086 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Garbitu guztiak"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Hasi"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Ez dago jakinarazpenik"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index c02d1e9..9f39599 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -243,7 +243,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"هشدار <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="7883614615463619450">"هیچ برنامه جدیدی موجود نیست"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
-    <string name="recents_lock_to_app_button_label" msgid="4793991421811647489">"قفل در برنامه"</string>
+    <string name="recents_lock_to_app_button_label" msgid="4793991421811647489">"قفل به برنامه"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"شارژ کامل شد"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"در حال شارژ شدن"</string>
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"پاک کردن همه موارد"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"اکنون شروع شود"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"اعلانی موجود نیست"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index d9e53c5..7bef3aa 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Poista kaikki"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Aloita nyt"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Ei ilmoituksia"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index ea63ccc..cf0095b 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Tout effacer"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Commencer maintenant"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Aucune notification"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 8db8975..41f4df4 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Tout effacer"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Commencer"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Aucune notification"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index b3e88e6..aedbd03 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Eliminar todas"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Iniciar agora"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Non hai notificacións"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 7001f82..5a53ee9 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"सभी साफ करें"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"अब प्रारंभ करें"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"कोई सूचना नहीं"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 4fc775c..43c9207 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Izbriši sve"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Započni sad"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Nema obavijesti"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 6d5a15c..ed26b93 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Az összes törlése"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Indítás most"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Nincs értesítés"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index f4375ce..80d1aa4 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Մաքրել բոլորը"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Մեկնարկել հիմա"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Ծանուցումներ չկան"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 96b1165..1e8d882 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Hapus semua"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Mulai sekarang"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Tidak ada pemberitahuan"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 266af50..153ece3 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Hreinsa allt"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Byrja núna"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Engar tilkynningar"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 7da2268..3828e23 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Cancella tutto"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Avvia adesso"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Nessuna notifica"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index fba167e..1f64088 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"נקה הכל"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"התחל כעת"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"אין הודעות"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 3baf0c8..2307b6e 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"すべて消去"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"今すぐ開始"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"通知はありません"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 13421f9..331c4c8 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"ყველას გასუფთავება"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"დაწყება ახლავე"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"შეტყობინებები არ არის."</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index edbd25f..6991615 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Барлығын тазалау"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Қазір бастау"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Хабарландырулар жоқ"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index ac210d4..d9d8402 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"សម្អាត​ទាំងអស់"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ចាប់ផ្ដើម​ឥឡូវ"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"គ្មាន​ការ​ជូនដំណឹង"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index f86779e..1bd31d2 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸು"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ಈಗ ಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"ಯಾವುದೇ ಅಧಿಸೂಚನೆಗಳಿಲ್ಲ"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index a4e6712..a62d501 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"모두 지우기"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"시작하기"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"알림 없음"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index d726e24..750c1d9 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -325,4 +325,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Бардыгын тазалап салуу"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Азыр баштоо"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Эскертмелер жок"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 5755029..2b1a4dc 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -24,9 +24,6 @@
      value at runtime for some things) -->
     <integer name="status_bar_recents_bg_gradient_degrees">90</integer>
 
-    <!-- The number of columns in the QuickSettings -->
-    <integer name="quick_settings_num_columns">4</integer>
-
     <!-- The maximum number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">2</integer>
 
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 42c4392..9b772bd 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -41,6 +41,7 @@
     <!-- The side padding for the task stack as a percentage of the width. -->
     <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.2229</item>
 
-    <!-- Width of the zen mode interstitial dialog. -->
-    <dimen name="zen_mode_dialog_width">384dp</dimen>
+    <!-- Standard notification width + gravity -->
+    <dimen name="notification_panel_width">@dimen/standard_notification_panel_width</dimen>
+    <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 5950d8d..a433b85 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -39,12 +39,9 @@
     <string name="invalid_charger_title" msgid="3515740382572798460">"ບໍ່​ຮອງຮັບ​ການ​ສາກ​ຜ່ານ USB."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"ໃຊ້​ສະເພາະ​ສາຍ​ສາກ​ທີ່​ມາ​ກັບ​ເຄື່ອງ."</string>
     <string name="battery_low_why" msgid="4553600287639198111">"​ການ​ຕັ້ງ​ຄ່າ"</string>
-    <!-- no translation found for battery_saver_confirmation_title (5299585433050361634) -->
-    <skip />
-    <!-- no translation found for battery_saver_confirmation_ok (7507968430447930257) -->
-    <skip />
-    <!-- no translation found for battery_saver_start_action (5576697451677486320) -->
-    <skip />
+    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ເປີດ​ໃຊ້​ການ​ປະ​ຢັດ​ແບັດ​ເຕີ​ຣີ​ບໍ?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"ເປີດ​ໃຊ້"</string>
+    <string name="battery_saver_start_action" msgid="5576697451677486320">"​ເປີດ​ໃຊ້​ໂຕ​ປະ​ຢັດ​ແບັດ​ເຕີ​ຣີ"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ການຕັ້ງຄ່າ"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ໂໝດເທິງຍົນ"</string>
@@ -288,10 +285,8 @@
     <item quantity="other" msgid="5408537517529822157">"ເປັນ​ເວລາ %d ຊົ່ວ​ໂມງ"</item>
   </plurals>
     <string name="battery_saver_notification_title" msgid="237918726750955859">"ເປີດ​ໃຊ້​ໂຕ​ປະຢັດ​ແບັດເຕີຣີ​ແລ້ວ"</string>
-    <!-- no translation found for battery_saver_notification_text (820318788126672692) -->
-    <skip />
-    <!-- no translation found for battery_saver_notification_action_text (109158658238110382) -->
-    <skip />
+    <string name="battery_saver_notification_text" msgid="820318788126672692">"ຫຼຸດ​ປະ​ສິ​ທິ​ພາບ​ແລະ​ການ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ພື້ນຫຼັງ"</string>
+    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ປິດ​ໂຕ​ປະ​ຢັດ​ແບັດ​ເຕີ​ຣີ"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"​ເນື້ອ​ຫາ​ຖືກ​ເຊື່ອງ​ແລ້ວ"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ​ຈະ​ເລີ່ມ​ບັນ​ທຶກ​ທຸກ​ຢ່າງ​ທີ່​ສະ​ແດງ​ຜົນ​ໃນ​ໜ້າ​ຈໍ​ທ່ານ."</string>
@@ -299,4 +294,15 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"ລຶບລ້າງທັງໝົດ"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ເລີ່ມດຽວນີ້"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"ບໍ່ມີການແຈ້ງເຕືອນ"</string>
+    <string name="device_owned_footer" msgid="3802752663326030053">"ອຸ​ປະ​ກອນ​ອາດ​ມີ​ການ​ເຝົ້າ​ຕິດ​ຕາມ"</string>
+    <string name="vpn_footer" msgid="2388611096129106812">"​ເຄືອ​ຂ່າຍ​ອາດ​ມີ​ການ​ເຝົ້າ​ຕິດ​ຕາມ"</string>
+    <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ການກວດ​ສອບ​ຕິດ​ຕາມ​ອຸ​ປະ​ກອນ"</string>
+    <string name="monitoring_title" msgid="169206259253048106">"ການກວດ​ສອບ​ຕິດ​ຕາມ​ເຄືອ​ຂ່າຍ"</string>
+    <string name="open_app" msgid="4011771120339160755">"ເປີດແອັບຯ"</string>
+    <string name="disconnect_vpn" msgid="1324915059568548655">"ຕັດ​ການ​ເຊື່ອມ​ຕໍ່ VPN"</string>
+    <string name="monitoring_description_device_owned" msgid="7801926679066533391">"ອຸ​ປະ​ກອນ​ນີ້​ຖືກ​ຈັດ​ການ​ໂດຍ:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\n​ຜູ່​ເບິ່ງ​ແຍງ​ລະ​ບົບ​ສາ​ມາດ​ເຝົ້າ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ເຄື​ອ​ຂ່າຍ​ຂອງ​ທ່ານ ຮວມ​ເຖິງ: ອີ​ເມວ, ແອັບຯ ແລະ​ເວັບ​ໄຊ​ທີ່​ເຂົ້າ​ລະ​ຫັດ.\n\nສຳ​ລັບ​ຂໍ້​ມູນ​ເພີ່ມ​ເຕີມ, ໃຫ້​ຕິດ​ຕໍ່​ຜູ່​ເບິ່ງ​ແຍງ​ລະ​ບົບ​ຂອງ​ທ່ານ."</string>
+    <string name="monitoring_description_vpn" msgid="93140751707065515">"​ທ່ານມອບ​ສິດ​ອະ​ນຸ​ຍາດໃຫ້ \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" ເພື່ອ​ຕັ້ງ​ຄ່າ​ການ​ເຊື່ອມ​ຕໍ່ VPN.\n\nແອັບຯ​ນີ້​ສາ​ມາດ​ເຝົ້າ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ​ໄດ້ ຮວມ​ເຖິງ​ອີ​ເມວ, ແອັບຯ ແລະ​ເວັບ​ໄຊ​ທີ່​ເຂົ້າ​ລະ​ຫັດ."</string>
+    <string name="monitoring_description_legacy_vpn" msgid="5397847778080663075">"ທ່ານ​ເຊື່ອມ​ຕໍ່​ຫາ VPN ແລ້ວ (\"<xliff:g id="APPLICATION">%1$s</xliff:g>\").\n\nຜູ່​ໃຫ້​ບໍ​ລິ​ການ VPN ​ຂອງ​ທ່ານ​ສາ​ມາດ​ເຝົ້າ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ​ໄດ້​ ຮວມ​ເຖິງອີ​ເມວ, ແອັບຯ ແລະ​ເວັບ​ໄຊ​ທີ່​ເຂົ້າ​ລະ​ຫັດ."</string>
+    <string name="monitoring_description_vpn_device_owned" msgid="696121105616356493">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຖືກ​ຈັດ​ການ​ໂດຍ:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\n​ຜູ່​ເບິ່ງ​ແຍງ​ລະ​ບົບ​ຂອງ​ທ່ານ​ສາ​ມາດ​ເຝົ້າ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ​ໄດ້ ຮວມ​ເຖິງ​ອີ​ເມວ, ແອັບຯ ແລະ​ເວັບ​ໄຊ​ທີ່​ເຂົ້າ​ລະ​​ຫັດ. ສຳ​ລັບ​ຂໍ້​ມູນ​ເພີ່ມ​ເຕີມ, ໃຫ້​ຕິດ​ຕໍ່​ຜູ່​ເບິ່ງ​ແຍງ​ລະ​ບົບ​ຂອງ​ທ່ານ.\n\nອີກ​ຢ່າງ​ນຶ່ງ, ທ່ານມອບ​ສິດ​ອະ​ນຸ​ຍາດໃຫ້ \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" ເພື່ອ​ຕັ້ງ​ຄ່າ​ການ​ເຊື່ອມ​ຕໍ່ VPN. ແອັບຯ​ນີ້​ສາ​ມາດ​ເຝົ້າ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ​ໄດ້."</string>
+    <string name="monitoring_description_legacy_vpn_device_owned" msgid="649791650224064248">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຖືກ​ຈັດ​ການ​ໂດຍ:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\n​ຜູ່​ເບິ່ງ​ແຍງ​ລະ​ບົບ​ຂອງ​ທ່ານ​ສາ​ມາດ​ເຝົ້າ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ​ໄດ້ ຮວມ​ເຖິງ​ອີ​ເມວ, ແອັບຯ ແລະ​ເວັບ​ໄຊ​ທີ່​ເຂົ້າ​ລະ​​ຫັດ. ສຳ​ລັບ​ຂໍ້​ມູນ​ເພີ່ມ​ເຕີມ, ໃຫ້​ຕິດ​ຕໍ່​ຜູ່​ເບິ່ງ​ແຍງ​ລະ​ບົບ​ຂອງ​ທ່ານ.\n\nນອກ​ຈາກ​ນັ້ນ, ທ່ານ​​ໄດ້​ເຊື່ອມ​ຕໍ່​ຫາ VPN (\"<xliff:g id="APPLICATION">%2$s</xliff:g>\"). ຜູ່​ໃຫ້​ບໍ​ລິ​ການ VPN ຂອງ​ທ່ານ​ສາ​ມາດ​ເຝົ້າ​ຕິດ​ຕາມ​ການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ​ໄດ້​ເຊັ່ນ​ກັນ."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index c39b885..3ea3f0b 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Viską išvalyti"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Pradėti dabar"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Nėra įspėjimų"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 0a52f23..b9a4994 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Dzēst visu"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Sākt tūlīt"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Nav paziņojumu"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 03e665f..82adb40 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Исчисти сè"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Започни сега"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Нема известувања"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index f87238f..06f5190 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"എല്ലാം മായ്‌ക്കുക"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ഇപ്പോൾ ആരംഭിക്കുക"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"അറിയിപ്പുകൾ ഒന്നുമില്ല"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 12c9741..0faf210 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Бүгдийг арилгах"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Одоо эхлүүлэх"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Мэдэгдэл байхгүй"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index d25fc41..d670ab6 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"सर्व साफ करा"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"आता प्रारंभ करा"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"सूचना नाहीत"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 2ac2ba9..93acf79 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Kosongkan semua"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Mulakan sekarang"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Tiada pemberitahuan"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 934946f..52883dd 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -295,4 +295,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"အားလုံး ရှင်းလင်းရန်"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ယခု စတင်ပါ"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"အကြောင်းကြားချက်များ မရှိ"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 697d016..2690ceb 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Fjern alt"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start nå"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Ingen varsler"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index ac0af13..2e45f22 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"सबै हटाउनुहोस्"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"अहिले सुरु गर्नुहोस्"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"कुनै सूचनाहरू छैनन्"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 03088d8..0f59a3f 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Alles wissen"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Nu starten"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Geen meldingen"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 8fa2149..d301248 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Usuń wszystkie"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Rozpocznij teraz"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Brak powiadomień"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 43d715a..c06f267 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Começar agora"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Sem notificações"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 6c384a6..87c501f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Iniciar agora"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Sem notificações"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 0c979ed..a5736af 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -305,4 +305,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Ștergeți toate notificările"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Începeți acum"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Nicio notificare"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 3ee1e47..e8900fe 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Очистить все"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Начать"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Нет уведомлений"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 964f770..6dd4a57 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"සියල්ල හිස් කරන්න"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"දැන් අරඹන්න"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"දැනුම්දීම් නැත"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f618864..516a9ac 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -39,12 +39,9 @@
     <string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjanie prostredníctvom USB nie je podporované."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Používajte iba originálnu nabíjačku."</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Nastavenia"</string>
-    <!-- no translation found for battery_saver_confirmation_title (5299585433050361634) -->
-    <skip />
-    <!-- no translation found for battery_saver_confirmation_ok (7507968430447930257) -->
-    <skip />
-    <!-- no translation found for battery_saver_start_action (5576697451677486320) -->
-    <skip />
+    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Zapnúť šetrič batérie?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Zapnúť"</string>
+    <string name="battery_saver_start_action" msgid="5576697451677486320">"Zapnúť šetrič batérie"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavenia"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Režim V lietadle"</string>
@@ -290,10 +287,8 @@
     <item quantity="other" msgid="5408537517529822157">"Na %d h"</item>
   </plurals>
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Šetrič batérie je zapnutý"</string>
-    <!-- no translation found for battery_saver_notification_text (820318788126672692) -->
-    <skip />
-    <!-- no translation found for battery_saver_notification_action_text (109158658238110382) -->
-    <skip />
+    <string name="battery_saver_notification_text" msgid="820318788126672692">"Obmedzí výkonnosť a prenos údajov na pozadí"</string>
+    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnúť šetrič batérie"</string>
     <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g> %%"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávať všetok obsah zobrazený na vašej obrazovke."</string>
@@ -301,4 +296,15 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Vymazať všetko"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Spustiť"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Žiadne upozornenia"</string>
+    <string name="device_owned_footer" msgid="3802752663326030053">"Zariadenie môže byť sledované"</string>
+    <string name="vpn_footer" msgid="2388611096129106812">"Sieť môže byť sledovaná"</string>
+    <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Sledovanie zariadenia"</string>
+    <string name="monitoring_title" msgid="169206259253048106">"Sledovanie siete"</string>
+    <string name="open_app" msgid="4011771120339160755">"Otvoriť aplikáciu"</string>
+    <string name="disconnect_vpn" msgid="1324915059568548655">"Odpojiť sieť VPN"</string>
+    <string name="monitoring_description_device_owned" msgid="7801926679066533391">"Toto zariadenie spravuje organizácia:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nSprávca môže sledovať vašu aktivitu v sieti vrátane e-mailov, aplikácií a zabezpečených webových stránok.\n\nĎalšie informácie získate od svojho správcu."</string>
+    <string name="monitoring_description_vpn" msgid="93140751707065515">"Aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> ste povolili nastaviť pripojenie VPN.\n\nTáto aplikácia môže sledovať vašu aktivitu v sieti vrátane e-mailov, aplikácií a zabezpečených webových stránok."</string>
+    <string name="monitoring_description_legacy_vpn" msgid="5397847778080663075">"Ste pripojený/-á k sieti VPN (<xliff:g id="APPLICATION">%1$s</xliff:g>).\n\nPoskytovateľ služby VPN môže sledovať vašu aktivitu v sieti vrátane e-mailov, aplikácií a zabezpečených webových stránok."</string>
+    <string name="monitoring_description_vpn_device_owned" msgid="696121105616356493">"Toto zariadenie spravuje organizácia:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nSprávca môže sledovať vašu aktivitu v sieti vrátane e-mailov, aplikácií a zabezpečených webových stránok. Ďalšie informácie získate od svojho správcu.\n\nZároveň ste aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g> povolili nastaviť pripojenie VPN. Táto aplikácia môže tiež sledovať vašu aktivitu v sieti."</string>
+    <string name="monitoring_description_legacy_vpn_device_owned" msgid="649791650224064248">"Toto zariadenie spravuje organizácia:\n<xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nSprávca môže sledovať vašu aktivitu v sieti vrátane e-mailov, aplikácií a zabezpečených webových stránok. Ďalšie informácie získate od svojho správcu.\n\nZároveň ste pripojený/-á aj k sieti VPN (<xliff:g id="APPLICATION">%2$s</xliff:g>). Poskytovateľ služby VPN môže tiež sledovať vašu aktivitu v sieti."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index dc6ec17..d67b646 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Izbriši vse"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Začni zdaj"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Ni obvestil"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e639caf..b1712f9 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Обриши све"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Започни одмах"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Нема обавештења"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 547699f..09efed1 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Rensa alla"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Starta nu"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Inga aviseringar"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 5c6f4ad..f5425bc 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -245,7 +245,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Betri imejaa"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Inachaji"</string>
-    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> hadi ijae"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Imebakisha <xliff:g id="CHARGING_TIME">%s</xliff:g> ijae"</string>
     <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Haichaji"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Huenda mtandao\nunafuatiliwa"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Tafuta"</string>
@@ -267,7 +267,7 @@
     <string name="interruption_level_none" msgid="3831278883136066646">"Hamna"</string>
     <string name="interruption_level_priority" msgid="6517366750688942030">"Kipaumbele"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Zote"</string>
-    <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji ( <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hadi ijae)"</string>
+    <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ijae)"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"Aliyealikwa"</string>
     <string name="guest_new_guest" msgid="4259024453643879653">"+ Aliyealikwa"</string>
     <string name="guest_exit_guest" msgid="1619100760451149682">"Ondoa aliyealikwa"</string>
@@ -297,4 +297,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Futa zote"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Anza sasa"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Hakuna arifa"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 9f4c364..4f6d209 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -20,9 +20,6 @@
 <!-- These resources are around just to allow their values to be customized
      for different hardware and product builds. -->
 <resources>
-    <!-- The number of columns in the QuickSettings -->
-    <integer name="quick_settings_num_columns">4</integer>
-
     <!-- The maximum number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">4</integer>
 
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 1c60c18..7cdc078 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -16,12 +16,9 @@
 */
 -->
 <resources>
-    <!-- The width of the notification panel window: 400 + 16 + 16 (padding in the bg drawable) -->
-    <dimen name="notification_panel_width">432dp</dimen>
-
-    <!-- Gravity for the notification panel -->
-    <!-- 0x31 = top|center_horizontal -->
-    <integer name="notification_panel_layout_gravity">0x31</integer>
+    <!-- Standard notification width + gravity -->
+    <dimen name="notification_panel_width">@dimen/standard_notification_panel_width</dimen>
+    <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
 
     <!-- Diameter of outer shape drawable shown in navbar search-->
     <dimen name="navbar_search_outerring_diameter">430dip</dimen>
@@ -49,9 +46,6 @@
     <!-- The side padding for the task stack as a percentage of the width. -->
     <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.075</item>
 
-    <!-- Width of the zen mode interstitial dialog. -->
-    <dimen name="zen_mode_dialog_width">384dp</dimen>
-
     <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
          max value is used when no notifications are displaying, and the min value is when the
          highest possible number of notifications are showing. -->
@@ -78,10 +72,11 @@
     <!-- Margin on the left side of the carrier text on Keyguard -->
     <dimen name="keyguard_carrier_text_margin">24dp</dimen>
 
-    <!-- end margin for system icons if multi user switch is hidden -->
-    <dimen name="system_icons_switcher_hidden_expanded_margin">20dp</dimen>
-
     <!-- The width/height of the phone/camera/unlock icon on keyguard. -->
     <dimen name="keyguard_affordance_height">80dp</dimen>
     <dimen name="keyguard_affordance_width">120dp</dimen>
+
+    <!-- The width of the region on the left/right edge of the screen for performing the camera/
+     phone hints. -->
+    <dimen name="edge_tap_area_width">80dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index 88372bc..5daf08e 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -19,17 +19,6 @@
         <item name="android:layout_width">480dp</item>
     </style>
 
-    <style name="NotificationsQuickSettings">
-        <item name="android:layout_width">@dimen/notification_panel_width</item>
-        <item name="android:layout_height">match_parent</item>
-        <item name="android:layout_gravity">top|center_horizontal</item>
-    </style>
-
-    <style name="StatusBarHeader">
-        <item name="android:layout_width">@dimen/notification_panel_width</item>
-        <item name="android:layout_gravity">center_horizontal</item>
-    </style>
-
     <style name="SearchPanelCard">
         <item name="android:layout_width">550dp</item>
         <item name="android:layout_height">@dimen/search_panel_card_height</item>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index 7695b12..3cd5f67 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -22,12 +22,8 @@
          be situations where they don't sync up perfectly with PhoneStatusBar. -->
     <!-- ======================================== -->
 
-    <!-- The width of the ticker, including the icon -->
-    <dimen name="notification_ticker_width">360dp</dimen>
     <!-- gap on either side of status bar notification icons -->
     <dimen name="status_bar_icon_padding">1dp</dimen>
-    <!-- The width of the notification panel window -->
-    <dimen name="notification_panel_width">512dp</dimen>
     <!-- The minimum height of the notification panel window -->
     <dimen name="notification_panel_min_height">770dp</dimen>
     <!-- Bottom margin (from display edge) for status bar panels -->
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index fca4882..2d46822 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"எல்லாவற்றையும் அழி"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"இப்போது தொடங்கு"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"அறிவிப்புகள் இல்லை"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index c742810..a41bd75 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"అన్నీ క్లియర్ చేయండి"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ఇప్పుడే ప్రారంభించు"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"నోటిఫికేషన్‌లు లేవు"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 6693e08..ec35d9e 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"ล้างทั้งหมด"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"เริ่มเลย"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"ไม่มีการแจ้งเตือน"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 2045be0..b05dd4a 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"I-clear lahat"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Magsimula ngayon"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Walang mga notification"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 7cbfcc9..110dd05 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Tümü temizle"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Şimdi başla"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Bildirim yok"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 803f381..79193d8 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Очистити все"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Почати зараз"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Сповіщень немає"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index beaa55a..0416be3 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"سبھی کو صاف کریں"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"ابھی شروع کریں"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"کوئی اطلاعات نہیں ہیں"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index d9ad468..62bcb12 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Barchasini tozalash"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Boshlash"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Bildirishnomalar yo‘q"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index c6e8c63..ffc0621 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Xóa tất cả"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Bắt đầu ngay"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Không có thông báo nào"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 3c62aa8..0556c29 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"立即开始"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"没有通知"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 1fd7957..21ee7fb 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"立即開始"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"沒有通知"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 5cfdf54..9a29ed8 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -301,4 +301,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"立即開始"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"沒有通知"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index f71ec15..2397502 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -299,4 +299,26 @@
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Sula konke"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Qala manje"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Azikho izaziso"</string>
+    <!-- no translation found for device_owned_footer (3802752663326030053) -->
+    <skip />
+    <!-- no translation found for vpn_footer (2388611096129106812) -->
+    <skip />
+    <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
+    <skip />
+    <!-- no translation found for monitoring_title (169206259253048106) -->
+    <skip />
+    <!-- no translation found for open_app (4011771120339160755) -->
+    <skip />
+    <!-- no translation found for disconnect_vpn (1324915059568548655) -->
+    <skip />
+    <!-- no translation found for monitoring_description_device_owned (7801926679066533391) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn (93140751707065515) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn (5397847778080663075) -->
+    <skip />
+    <!-- no translation found for monitoring_description_vpn_device_owned (696121105616356493) -->
+    <skip />
+    <!-- no translation found for monitoring_description_legacy_vpn_device_owned (649791650224064248) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index d8d170d..8bd3c39 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -56,9 +56,14 @@
     </attr>
     <declare-styleable name="UserAvatarView">
         <attr name="frameWidth" format="dimension" />
+        <attr name="framePadding" format="dimension" />
         <attr name="activeFrameColor" format="color" />
         <attr name="frameColor" />
     </declare-styleable>
+    <declare-styleable name="UserDetailItemView">
+        <attr name="regularFontFamily" format="string" />
+        <attr name="activatedFontFamily" format="string" />
+    </declare-styleable>
     <declare-styleable name="DateView">
         <attr name="datePattern" format="string" />
     </declare-styleable>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 1cdcc2b..c3ea8f8 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -103,4 +103,6 @@
     <color name="notification_guts_btn_color">#FFFFFFFF</color>
 
     <color name="search_panel_card_color">#ffffff</color>
+
+    <color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index efddc62..4a4fa41 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -136,9 +136,14 @@
     <!-- Height of the status bar header bar when on Keyguard -->
     <dimen name="status_bar_header_height_keyguard">40dp</dimen>
 
+    <!-- Width for the notification panel and related windows -->
+    <dimen name="match_parent">-1px</dimen>
+    <dimen name="standard_notification_panel_width">416dp</dimen><!-- includes notification_side_padding on each side -->
+    <dimen name="notification_panel_width">@dimen/match_parent</dimen>
+
     <!-- Gravity for the notification panel -->
-    <!-- 0x37 = fill_horizontal|top -->
-    <integer name="notification_panel_layout_gravity">0x37</integer>
+    <integer name="standard_notification_panel_layout_gravity">0x31</integer><!-- top|center_horizontal -->
+    <integer name="notification_panel_layout_gravity">0x37</integer><!-- fill_horizontal|top -->
 
     <!-- Height of the carrier/wifi name label -->
     <dimen name="carrier_label_height">24dp</dimen>
@@ -232,6 +237,9 @@
          in dps over one second of time. -->
     <dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen>
 
+    <!-- The min alpha to apply to a task affiliation group color. -->
+    <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
+
     <!-- Space reserved for the cards behind the top card in the top stack -->
     <dimen name="top_stack_peek_amount">12dp</dimen>
 
@@ -269,9 +277,6 @@
     <!-- The height of the speed bump view. -->
     <dimen name="speed_bump_height">16dp</dimen>
 
-    <!-- Width of the zen mode interstitial dialog. -->
-    <dimen name="zen_mode_dialog_width">320dp</dimen>
-
     <!-- Lockscreen affordance drag distance for camera and phone. -->
     <dimen name="affordance_drag_distance">100dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 83a9a81..51633dc 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -454,8 +454,8 @@
     <string name="accessibility_clear_all">Clear all notifications.</string>
 
     <!-- Title shown in notification popup for inspecting the responsible
-         application -->
-    <string name="status_bar_notification_inspect_item_title">App info</string>
+         application [CHAR LIMIT=30] -->
+    <string name="status_bar_notification_inspect_item_title">Settings</string>
 
     <!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is on. [CHAR LIMIT=NONE] -->
     <string name="accessibility_rotation_lock_off">Screen will rotate automatically.</string>
@@ -672,6 +672,13 @@
     <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
 
     <!-- Related to user switcher --><skip/>
+
+    <!-- Label for the adding a new user in the user switcher [CHAR LIMIT=35] -->
+    <string name="user_add_user">Add user</string>
+
+    <!-- Name for a freshly added user [CHAR LIMIT=30] -->
+    <string name="user_new_user_name">New user</string>
+
     <!-- Name for the guest user [CHAR LIMIT=35] -->
     <string name="guest_nickname">Guest</string>
 
@@ -761,13 +768,13 @@
     <string name="disconnect_vpn">Disconnect VPN</string>
 
     <!-- Monitoring dialog device owner body text [CHAR LIMIT=300] -->
-    <string name="monitoring_description_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator can monitor your network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>
+    <string name="monitoring_description_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator can monitor your device and network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>
 
     <!-- Monitoring dialog non-legacy VPN text [CHAR LIMIT=300] -->
-    <string name="monitoring_description_vpn">You gave \"<xliff:g id="application">%1$s</xliff:g>\" permission to set up a VPN connection.\n\nThis app can monitor your network activity, including emails, apps and secure websites.</string>
+    <string name="monitoring_description_vpn">You gave \"<xliff:g id="application">%1$s</xliff:g>\" permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and secure websites.</string>
 
     <!-- Monitoring dialog legacy VPN text [CHAR LIMIT=300] -->
-    <string name="monitoring_description_legacy_vpn">You\'re connected to a VPN (\"<xliff:g id="application">%1$s</xliff:g>\").\n\nYour VPN service provider can monitor your network activity including emails, apps, and secure websites.</string>
+    <string name="monitoring_description_legacy_vpn">You\'re connected to a VPN (\"<xliff:g id="application">%1$s</xliff:g>\").\n\nYour VPN service provider can monitor your device and network activity including emails, apps, and secure websites.</string>
 
     <!-- Monitoring dialog non-legacy VPN with device owner text [CHAR LIMIT=300] -->
     <string name="monitoring_description_vpn_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites. For more information, contact your administrator.\n\nAlso, you gave \"<xliff:g id="application">%2$s</xliff:g>\" permission to set up a VPN connection. This app can monitor network activity too.</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 197c0f1..5db6912 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -103,7 +103,7 @@
     <style name="TextAppearance.StatusBar.Expanded.UserSwitcher">
         <item name="android:textSize">16sp</item>
         <item name="android:textStyle">normal</item>
-        <item name="android:textColor">#ffffff</item>
+        <item name="android:textColor">@color/qs_user_detail_name</item>
     </style>
     <style name="TextAppearance.StatusBar.Expanded.UserSwitcher.UserName" />
 
@@ -254,16 +254,7 @@
         <item name="android:colorControlActivated">@color/system_accent_color</item>
     </style>
 
-    <style name="NotificationsQuickSettings">
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">match_parent</item>
-    </style>
-
-    <style name="StatusBarHeader">
-        <item name="android:layout_width">match_parent</item>
-    </style>
-
-     <style name="QSBorderlessButton">
+    <style name="QSBorderlessButton">
         <item name="android:padding">12dp</item>
         <item name="android:background">@drawable/btn_borderless_rect</item>
         <item name="android:gravity">center</item>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index d765aab..759d540 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -16,11 +16,14 @@
 
 package com.android.systemui.qs.tiles;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.UserAvatarView;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -36,6 +39,8 @@
 
     private UserAvatarView mAvatar;
     private TextView mName;
+    private Typeface mRegularTypeface;
+    private Typeface mActivatedTypeface;
 
     public UserDetailItemView(Context context) {
         this(context, null);
@@ -52,6 +57,21 @@
     public UserDetailItemView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        final TypedArray a = context.obtainStyledAttributes(
+                attrs, R.styleable.UserDetailItemView, defStyleAttr, defStyleRes);
+        final int N = a.getIndexCount();
+        for (int i = 0; i < N; i++) {
+            int attr = a.getIndex(i);
+            switch (attr) {
+                case R.styleable.UserDetailItemView_regularFontFamily:
+                    mRegularTypeface = Typeface.create(a.getString(attr), 0 /* style */);
+                    break;
+                case R.styleable.UserDetailItemView_activatedFontFamily:
+                    mActivatedTypeface = Typeface.create(a.getString(attr), 0 /* style */);
+                    break;
+            }
+        }
+        a.recycle();
     }
 
     public static UserDetailItemView convertOrInflate(Context context, View convertView,
@@ -77,6 +97,23 @@
     protected void onFinishInflate() {
         mAvatar = (UserAvatarView) findViewById(R.id.user_picture);
         mName = (TextView) findViewById(R.id.user_name);
+        if (mRegularTypeface == null) {
+            mRegularTypeface = mName.getTypeface();
+        }
+        if (mActivatedTypeface == null) {
+            mActivatedTypeface = mName.getTypeface();
+        }
+        updateTypeface();
     }
 
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        updateTypeface();
+    }
+
+    private void updateTypeface() {
+        boolean activated = ArrayUtils.contains(getDrawableState(), android.R.attr.state_activated);
+        mName.setTypeface(activated ? mActivatedTypeface : mRegularTypeface);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 67eef56..8cff81a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -83,7 +83,7 @@
                     mContext, convertView, parent);
             String name = getName(mContext, item);
             if (item.picture == null) {
-                v.bind(name, mContext.getDrawable(R.drawable.ic_account_circle_qs));
+                v.bind(name, getDrawable(mContext, item));
             } else {
                 v.bind(name, item.picture);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index cf0a1dc..980a4ae 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -86,6 +86,7 @@
     public int taskBarViewLightTextColor;
     public int taskBarViewDarkTextColor;
     public int taskBarViewHighlightColor;
+    public float taskBarViewAffiliationColorMinAlpha;
 
     /** Task bar size & animations */
     public int taskBarHeight;
@@ -221,6 +222,9 @@
                 res.getColor(R.color.recents_task_bar_dark_text_color);
         taskBarViewHighlightColor =
                 res.getColor(R.color.recents_task_bar_highlight_color);
+        TypedValue affMinAlphaPctValue = new TypedValue();
+        res.getValue(R.dimen.recents_task_affiliation_color_min_alpha_percentage, affMinAlphaPctValue, true);
+        taskBarViewAffiliationColorMinAlpha = affMinAlphaPctValue.getFloat();
 
         // Task bar size & animations
         taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index f30e22a..8716184 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -339,8 +339,9 @@
 
             // Create a new task
             Task task = new Task(t.persistentId, (t.id > -1), t.baseIntent, t.affiliatedTaskId,
-                    activityLabel, activityIcon, activityColor, t.userId, t.firstActiveTime,
-                    t.lastActiveTime, (i == (taskCount - 1)), config.lockToAppEnabled);
+                    t.affiliatedTaskColor, activityLabel, activityIcon, activityColor, t.userId,
+                    t.firstActiveTime, t.lastActiveTime, (i == (taskCount - 1)),
+                    config.lockToAppEnabled);
 
             // Preload the specified number of apps
             if (i >= (taskCount - preloadCount)) {
@@ -381,7 +382,7 @@
         }
 
         // Simulate the groupings that we describe
-        stack.createAffiliatedGroupings();
+        stack.createAffiliatedGroupings(config);
 
         // Start the task loader and add all the tasks we need to load
         mLoader.start(context);
@@ -405,11 +406,11 @@
             ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
             if (info == null) continue;
 
-            stack.addTask(new Task(t.persistentId, true, t.baseIntent, t.affiliatedTaskId, null,
-                    null, 0, 0, t.firstActiveTime, t.lastActiveTime, (i == (taskCount - 1)),
-                    config.lockToAppEnabled));
+            stack.addTask(new Task(t.persistentId, true, t.baseIntent, t.affiliatedTaskId,
+                    t.affiliatedTaskColor, null, null, 0, 0, t.firstActiveTime, t.lastActiveTime,
+                    (i == (taskCount - 1)), config.lockToAppEnabled));
         }
-        stack.createAffiliatedGroupings();
+        stack.createAffiliatedGroupings(config);
         return stack;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 41874fc..f6c3a7e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -77,6 +77,7 @@
     public TaskKey key;
     public TaskGrouping group;
     public int taskAffiliation;
+    public int taskAffiliationColor;
     public boolean isLaunchTarget;
     public Drawable applicationIcon;
     public Drawable activityIcon;
@@ -95,16 +96,19 @@
         // Only used by RecentsService for task rect calculations.
     }
 
-    public Task(int id, boolean isActive, Intent intent, int taskAffiliation, String activityTitle,
-                Drawable activityIcon, int colorPrimary, int userId,
+    public Task(int id, boolean isActive, Intent intent, int taskAffiliation, int taskAffiliationColor,
+                String activityTitle, Drawable activityIcon, int colorPrimary, int userId,
                 long firstActiveTime, long lastActiveTime, boolean lockToThisTask,
                 boolean lockToTaskEnabled) {
+        boolean isInAffiliationGroup = (taskAffiliation != id);
+        boolean hasAffiliationGroupColor = isInAffiliationGroup && (taskAffiliationColor != 0);
         this.key = new TaskKey(id, intent, userId, firstActiveTime, lastActiveTime);
         this.taskAffiliation = taskAffiliation;
+        this.taskAffiliationColor = taskAffiliationColor;
         this.activityLabel = activityTitle;
         this.activityIcon = activityIcon;
-        this.colorPrimary = colorPrimary;
-        this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(colorPrimary,
+        this.colorPrimary = hasAffiliationGroupColor ? taskAffiliationColor : colorPrimary;
+        this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
                 Color.WHITE) > 3f;
         this.isActive = isActive;
         this.lockToThisTask = lockToTaskEnabled && lockToThisTask;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index fd6303f..435eb42 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.recents.model;
 
+import android.graphics.Color;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.NamedCounter;
 
 import java.util.ArrayList;
@@ -320,7 +322,7 @@
     /**
      * Temporary: This method will simulate affiliation groups by
      */
-    public void createAffiliatedGroupings() {
+    public void createAffiliatedGroupings(RecentsConfiguration config) {
         if (Constants.DebugFlags.App.EnableSimulatedTaskGroups) {
             HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>();
             // Sort all tasks by increasing firstActiveTime of the task
@@ -387,6 +389,7 @@
             mTaskList.set(tasks);
         } else {
             // Create the task groups
+            HashMap<Task.TaskKey, Task> tasksMap = new HashMap<Task.TaskKey, Task>();
             ArrayList<Task> tasks = mTaskList.getTasks();
             int taskCount = tasks.size();
             for (int i = 0; i < taskCount; i++) {
@@ -401,6 +404,28 @@
                     addGroup(group);
                 }
                 group.addTask(t);
+                tasksMap.put(t.key, t);
+            }
+            // Update the task colors for each of the groups
+            float minAlpha = config.taskBarViewAffiliationColorMinAlpha;
+            int taskGroupCount = mGroups.size();
+            for (int i = 0; i < taskGroupCount; i++) {
+                TaskGrouping group = mGroups.get(i);
+                taskCount = group.getTaskCount();
+                // Ignore the groups that only have one task
+                if (taskCount <= 1) continue;
+                // Calculate the group color distribution
+                int affiliationColor = tasksMap.get(group.mTaskKeys.get(0)).taskAffiliationColor;
+                float alphaStep = (1f - minAlpha) / taskCount;
+                float alpha = 1f;
+                for (int j = 0; j < taskCount; j++) {
+                    Task t = tasksMap.get(group.mTaskKeys.get(j));
+                    t.colorPrimary = Color.rgb(
+                            (int) (alpha * Color.red(affiliationColor) + (1f - alpha) * 0xFF),
+                            (int) (alpha * Color.green(affiliationColor) + (1f - alpha) * 0xFF),
+                            (int) (alpha * Color.blue(affiliationColor) + (1f - alpha) * 0xFF));
+                    alpha -= alphaStep;
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 57f1274..9e7dbf4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -330,7 +330,7 @@
                         // We can reuse the current task transforms to find the task rects
                         TaskViewTransform transform = mCurrentTaskTransforms.get(mStack.indexOfTask(tv.getTask()));
                         TaskViewTransform nextTransform = mCurrentTaskTransforms.get(mStack.indexOfTask(nextTv.getTask()));
-                        clipBottom = transform.rect.bottom - nextTransform.rect.top - 200;
+                        clipBottom = transform.rect.bottom - nextTransform.rect.top;
                     }
                 }
                 tv.getViewBounds().setClipBottom(clipBottom);
@@ -430,9 +430,8 @@
     public void computeScroll() {
         mStackScroller.computeScroll();
         // Synchronize the views
-        if (synchronizeStackViewsWithModel()) {
-            clipTaskViews();
-        }
+        synchronizeStackViewsWithModel();
+        clipTaskViews();
     }
 
     /** Computes the stack and task rects */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index abf3c50..3b9bcc4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -39,7 +39,7 @@
 
 /* A task view */
 public class TaskView extends FrameLayout implements Task.TaskCallbacks,
-        TaskFooterView.TaskFooterViewCallbacks, View.OnClickListener, View.OnLongClickListener {
+        TaskViewFooter.TaskFooterViewCallbacks, View.OnClickListener, View.OnLongClickListener {
     /** The TaskView callbacks */
     interface TaskViewCallbacks {
         public void onTaskViewAppIconClicked(TaskView tv);
@@ -67,9 +67,9 @@
     AnimateableViewBounds mViewBounds;
     Paint mLayerPaint = new Paint();
 
-    TaskThumbnailView mThumbnailView;
-    TaskBarView mBarView;
-    TaskFooterView mFooterView;
+    TaskViewThumbnail mThumbnailView;
+    TaskViewHeader mBarView;
+    TaskViewFooter mFooterView;
     View mActionButtonView;
     TaskViewCallbacks mCb;
 
@@ -124,8 +124,8 @@
     @Override
     protected void onFinishInflate() {
         // Bind the views
-        mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
-        mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
+        mBarView = (TaskViewHeader) findViewById(R.id.task_view_bar);
+        mThumbnailView = (TaskViewThumbnail) findViewById(R.id.task_view_thumbnail);
         mActionButtonView = findViewById(R.id.lock_to_app_fab);
         if (mFooterView != null) {
             mFooterView.setCallbacks(this);
@@ -712,7 +712,7 @@
         setOnClickListener(enabled ? this : null);
     }
 
-    /**** TaskFooterView.TaskFooterViewCallbacks ****/
+    /**** TaskViewFooter.TaskFooterViewCallbacks ****/
 
     @Override
     public void onTaskFooterHeightChanged(int height, int maxHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java
rename to packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java
index 881bbcf..324169e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java
@@ -24,7 +24,7 @@
 
 
 /** The task footer view */
-public class TaskFooterView extends FrameLayout {
+public class TaskViewFooter extends FrameLayout {
 
     interface TaskFooterViewCallbacks {
         public void onTaskFooterHeightChanged(int height, int maxHeight);
@@ -37,19 +37,19 @@
     int mMaxFooterHeight;
     ObjectAnimator mFooterAnimator;
 
-    public TaskFooterView(Context context) {
+    public TaskViewFooter(Context context) {
         this(context, null);
     }
 
-    public TaskFooterView(Context context, AttributeSet attrs) {
+    public TaskViewFooter(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public TaskFooterView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public TaskViewFooter(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public TaskFooterView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public TaskViewFooter(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         mConfig = RecentsConfiguration.getInstance();
         mMaxFooterHeight = mConfig.taskViewLockToAppButtonHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
rename to packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 90bf12f..03fc16e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -28,7 +28,6 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewPropertyAnimator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -39,7 +38,7 @@
 
 
 /* The task bar view */
-class TaskBarView extends FrameLayout {
+class TaskViewHeader extends FrameLayout {
 
     RecentsConfiguration mConfig;
 
@@ -54,19 +53,19 @@
 
     static Paint sHighlightPaint;
 
-    public TaskBarView(Context context) {
+    public TaskViewHeader(Context context) {
         this(context, null);
     }
 
-    public TaskBarView(Context context, AttributeSet attrs) {
+    public TaskViewHeader(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public TaskBarView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public TaskViewHeader(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public TaskBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public TaskViewHeader(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         mConfig = RecentsConfiguration.getInstance();
         setWillNotDraw(false);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java
rename to packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 1116d51..f836aa3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -25,24 +25,24 @@
 
 
 /** The task thumbnail view */
-public class TaskThumbnailView extends FixedSizeImageView {
+public class TaskViewThumbnail extends FixedSizeImageView {
 
     // Task bar clipping
     Rect mClipRect = new Rect();
 
-    public TaskThumbnailView(Context context) {
+    public TaskViewThumbnail(Context context) {
         this(context, null);
     }
 
-    public TaskThumbnailView(Context context, AttributeSet attrs) {
+    public TaskViewThumbnail(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         setScaleType(ScaleType.FIT_XY);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index c559253..d4c8ce3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -429,6 +429,9 @@
         try {
             panelWidth = r.getDimensionPixelSize(R.dimen.notification_panel_width);
         } catch (Resources.NotFoundException e) {
+        }
+        if (panelWidth <= 0) {
+            // includes notification_panel_width==match_parent (-1)
             panelWidth = mDisplayMetrics.widthPixels;
         }
         mPreviewWidth = panelWidth;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index ebde080..8319f41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -21,6 +21,7 @@
 import android.animation.TimeInterpolator;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.TaskStackBuilder;
@@ -30,6 +31,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
@@ -98,7 +101,7 @@
         RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger,
         NotificationData.Environment {
     public static final String TAG = "StatusBar";
-    public static final boolean DEBUG = false;
+    public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     public static final boolean MULTIUSER_DEBUG = false;
 
     protected static final int MSG_SHOW_RECENT_APPS = 1019;
@@ -220,9 +223,8 @@
             final int mode = Settings.Global.getInt(mContext.getContentResolver(),
                     Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
             setZenMode(mode);
-            final boolean show = Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1) != 0;
-            mShowLockscreenNotifications = show;
+
+            updateLockscreenNotificationSetting();
         }
     };
 
@@ -289,6 +291,9 @@
                 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 updateCurrentProfilesCache();
                 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+
+                updateLockscreenNotificationSetting();
+
                 userSwitched(mCurrentUserId);
             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
                 updateCurrentProfilesCache();
@@ -387,8 +392,9 @@
                 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
                 mSettingsObserver);
         mContext.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
-                mSettingsObserver);
+                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
+                mSettingsObserver,
+                UserHandle.USER_ALL);
 
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
@@ -582,31 +588,12 @@
                entry.expandedBig.findViewById(com.android.internal.R.id.media_action_area) != null;
     }
 
-    private void startApplicationDetailsActivity(String packageName) {
-        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
-                Uri.fromParts("package", packageName, null));
-        intent.setComponent(intent.resolveActivity(mContext.getPackageManager()));
-        TaskStackBuilder.create(mContext).addNextIntentWithParentStack(intent).startActivities(
-                null, UserHandle.CURRENT);
-    }
-
-    private static final int max(int...args) {
-        switch (args.length) {
-            case 0:
-                return 0;
-            case 1:
-                return args[0];
-            case 2:
-                return args[1] > args[0] ? args[1] : args[0];
-            default:
-                int m = args[0];
-                for (int i = 0; i < args.length; i++) {
-                    if (args[i] > m) {
-                        m = args[i];
-                    }
-                }
-                return m;
-        }
+    private void startAppNotificationSettingsActivity(String packageName, int appUid) {
+        Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
+        intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
+        intent.putExtra(Settings.EXTRA_APP_UID, appUid);
+        TaskStackBuilder.create(mContext).addNextIntentWithParentStack(intent)
+                .startActivities(null, new UserHandle(UserHandle.getUserId(appUid)));
     }
 
     protected SwipeHelper.LongPressListener getNotificationLongClicker() {
@@ -615,8 +602,6 @@
             public boolean onLongPress(View v, int x, int y) {
                 dismissPopups();
 
-                final String packageNameF = (String) v.getTag();
-                if (packageNameF == null) return false;
                 if (v.getWindowToken() == null) return false;
 
                 // Assume we are a status_bar_notification_row
@@ -626,14 +611,6 @@
                 // Already showing?
                 if (guts.getVisibility() == View.VISIBLE) return false;
 
-                final View button = guts.findViewById(R.id.notification_inspect_item);
-                button.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        startApplicationDetailsActivity(packageNameF);
-                        animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
-                    }
-                });
-
                 guts.setVisibility(View.VISIBLE);
                 final double horz = Math.max(v.getWidth() - x, x);
                 final double vert = Math.max(v.getHeight() - y, y);
@@ -956,28 +933,10 @@
             return inflateViews(entry, parent, true);
     }
 
-    private Drawable loadPackageIconDrawable(String pkg, int userId) {
-        Drawable icon = null;
-        try {
-            icon = mContext.getPackageManager().getApplicationIcon(pkg);
-        } catch (PackageManager.NameNotFoundException e) {
-        }
-
-        return icon;
-    }
-
-    private CharSequence loadPackageName(String pkg) {
-        final PackageManager pm = mContext.getPackageManager();
-        try {
-            ApplicationInfo info = pm.getApplicationInfo(pkg,
-                    PackageManager.GET_UNINSTALLED_PACKAGES);
-            if (info != null) return pm.getApplicationLabel(info);
-        } catch (PackageManager.NameNotFoundException e) {
-        }
-        return pkg;
-    }
-
     private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent, boolean isHeadsUp) {
+        PackageManager pmUser = getPackageManagerForUser(
+                entry.notification.getUser().getIdentifier());
+
         int maxHeight = mRowMaxHeight;
         StatusBarNotification sbn = entry.notification;
         RemoteViews contentView = sbn.getNotification().contentView;
@@ -1028,12 +987,43 @@
         // the notification inspector (see SwipeHelper.setLongPressListener)
         row.setTag(sbn.getPackageName());
         final View guts = row.findViewById(R.id.notification_guts);
-        final Drawable pkgicon = loadPackageIconDrawable(entry.notification.getPackageName(),
-                entry.notification.getUserId());
-        final String pkgname = loadPackageName(entry.notification.getPackageName()).toString();
+        final String pkg = entry.notification.getPackageName();
+        String appname = pkg;
+        Drawable pkgicon = null;
+        int appUid = -1;
+        try {
+            final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
+                PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
+            if (info != null) {
+                appname = String.valueOf(pmUser.getApplicationLabel(info));
+                pkgicon = pmUser.getApplicationIcon(info);
+                appUid = info.uid;
+            }
+        } catch (NameNotFoundException e) {
+            // app is gone, just show package name and generic icon
+            pkgicon = pmUser.getDefaultActivityIcon();
+        }
         ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
         ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(entry.notification.getPostTime());
-        ((TextView) row.findViewById(R.id.pkgname)).setText(pkgname);
+        ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
+        final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
+        if (appUid >= 0) {
+            final int appUidF = appUid;
+            settingsButton.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View v) {
+                    dismissKeyguardThenExecute(new OnDismissAction() {
+                        public boolean onDismiss() {
+                            startAppNotificationSettingsActivity(pkg, appUidF);
+                            animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+                            visibilityChanged(false);
+                            return DELAY_DISMISS_TO_ACTIVITY_LAUNCH;
+                        }
+                    });
+                }
+            });
+        } else {
+            settingsButton.setVisibility(View.GONE);
+        }
 
         workAroundBadLayerDrawableOpacity(row);
         View vetoButton = updateNotificationVetoButton(row, sbn);
@@ -1105,9 +1095,6 @@
         }
 
         if (publicViewLocal == null) {
-            PackageManager pm = getPackageManagerForUser(
-                    entry.notification.getUser().getIdentifier());
-
             // Add a basic notification template
             publicViewLocal = LayoutInflater.from(mContext).inflate(
                     com.android.internal.R.layout.notification_template_material_base,
@@ -1115,8 +1102,8 @@
 
             final TextView title = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.title);
             try {
-                title.setText(pm.getApplicationLabel(
-                        pm.getApplicationInfo(entry.notification.getPackageName(), 0)));
+                title.setText(pmUser.getApplicationLabel(
+                        pmUser.getApplicationInfo(entry.notification.getPackageName(), 0)));
             } catch (NameNotFoundException e) {
                 title.setText(entry.notification.getPackageName());
             }
@@ -1142,7 +1129,7 @@
 
             if (profileIcon != null) {
                 Drawable profileDrawable
-                        = mUserManager.getBadgeForUser(entry.notification.getUser());
+                        = mUserManager.getBadgeForUser(entry.notification.getUser(), 0);
                 if (profileDrawable != null) {
                     profileIcon.setImageDrawable(profileDrawable);
                     profileIcon.setVisibility(View.VISIBLE);
@@ -1424,6 +1411,19 @@
         updateNotifications();
     }
 
+    // extended in PhoneStatusBar
+    protected void setShowLockscreenNotifications(boolean show) {
+        mShowLockscreenNotifications = show;
+    }
+
+    private void updateLockscreenNotificationSetting() {
+        final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+                1,
+                mCurrentUserId) != 0;
+        setShowLockscreenNotifications(show);
+    }
+
     protected abstract void haltTicker();
     protected abstract void setAreThereNotifications();
     protected abstract void updateNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 19bf121..6779e4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -156,7 +156,6 @@
         drawBackgroundCircle(canvas);
         drawArrow(canvas);
         canvas.save();
-        updateIconColor();
         canvas.scale(mImageScale, mImageScale, getWidth() / 2, getHeight() / 2);
         super.onDraw(canvas);
         canvas.restore();
@@ -267,6 +266,7 @@
         if (!radiusNeedsAnimation) {
             if (mCircleAnimator == null) {
                 mCircleRadius = circleRadius;
+                updateIconColor();
                 invalidate();
                 if (nowHidden) {
                     if (mPreviewView != null) {
@@ -323,6 +323,7 @@
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
                 mCircleRadius = (float) animation.getAnimatedValue();
+                updateIconColor();
                 invalidate();
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 8996197..3b14082 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -82,6 +82,7 @@
 
     public void hide(boolean destroyView) {
         if (mKeyguardView != null) {
+            mKeyguardView.setOnDismissAction(null);
             mKeyguardView.cleanUp();
         }
         if (destroyView) {
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 a3b7c92..e70422b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -32,6 +32,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -43,6 +44,7 @@
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.MirrorView;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
@@ -61,6 +63,7 @@
 
     private KeyguardAffordanceHelper mAfforanceHelper;
     private StatusBarHeaderView mHeader;
+    private KeyguardUserSwitcher mKeyguardUserSwitcher;
     private KeyguardStatusBarView mKeyguardStatusBar;
     private View mQsContainer;
     private QSPanel mQsPanel;
@@ -70,7 +73,7 @@
     private View mReserveNotificationSpace;
     private MirrorView mSystemIconsCopy;
     private View mQsNavbarScrim;
-
+    private View mNotificationContainerParent;
     private NotificationStackScrollLayout mNotificationStackScroller;
     private int mNotificationTopPadding;
     private boolean mAnimateNextTopPaddingChange;
@@ -125,7 +128,6 @@
 
     private Interpolator mFastOutSlowInInterpolator;
     private Interpolator mFastOutLinearInterpolator;
-    private Interpolator mLinearOutSlowInInterpolator;
     private ObjectAnimator mClockAnimator;
     private int mClockAnimationTarget = -1;
     private int mTopPaddingAdjustment;
@@ -180,6 +182,7 @@
         mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
         mScrollView.setListener(this);
         mReserveNotificationSpace = findViewById(R.id.reserve_notification_space);
+        mNotificationContainerParent = findViewById(R.id.notification_container_parent);
         mNotificationStackScroller = (NotificationStackScrollLayout)
                 findViewById(R.id.notification_stack_scroller);
         mNotificationStackScroller.setOnHeightChangedListener(this);
@@ -189,8 +192,6 @@
                 android.R.interpolator.fast_out_slow_in);
         mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(),
                 android.R.interpolator.fast_out_linear_in);
-        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
-                android.R.interpolator.linear_out_slow_in);
         mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
         mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
         mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
@@ -215,6 +216,32 @@
                 getResources().getDimensionPixelSize(R.dimen.notification_scrim_wait_distance);
     }
 
+    public void updateResources() {
+        int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
+        int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mHeader.getLayoutParams();
+        if (lp.width != panelWidth) {
+            lp.width = panelWidth;
+            lp.gravity = panelGravity;
+            mHeader.setLayoutParams(lp);
+            mHeader.post(mUpdateHeader);
+        }
+
+        lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
+        if (lp.width != panelWidth) {
+            lp.width = panelWidth;
+            lp.gravity = panelGravity;
+            mNotificationStackScroller.setLayoutParams(lp);
+        }
+
+        lp = (FrameLayout.LayoutParams) mScrollView.getLayoutParams();
+        if (lp.width != panelWidth) {
+            lp.width = panelWidth;
+            lp.gravity = panelGravity;
+            mScrollView.setLayoutParams(lp);
+        }
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
@@ -341,6 +368,7 @@
         mUnlockIconActive = false;
         mAfforanceHelper.reset(true);
         closeQs();
+        mStatusBar.dismissPopups();
         mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */,
                 true /* cancelAnimators */);
     }
@@ -921,6 +949,9 @@
                 && !mStackScrollerOverscrolling && mQsScrimEnabled
                         ? View.VISIBLE
                         : View.INVISIBLE);
+        if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
+            mKeyguardUserSwitcher.hide();
+        }
     }
 
     private void setQsExpansion(float height) {
@@ -1685,4 +1716,15 @@
             updateQsState();
         }
     }
+
+    public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) {
+        mKeyguardUserSwitcher = keyguardUserSwitcher;
+    }
+
+    private final Runnable mUpdateHeader = new Runnable() {
+        @Override
+        public void run() {
+            mHeader.updateEverything();
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 7c6e47c..57b7401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -35,6 +35,7 @@
     private View mScrollView;
     private View mUserSwitcher;
     private View mStackScroller;
+    private View mKeyguardStatusBar;
     private boolean mInflated;
 
     public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
@@ -46,6 +47,7 @@
         super.onFinishInflate();
         mScrollView = findViewById(R.id.scroll_view);
         mStackScroller = findViewById(R.id.notification_stack_scroller);
+        mKeyguardStatusBar = findViewById(R.id.keyguard_header);
         ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
         userSwitcher.setOnInflateListener(this);
         mUserSwitcher = userSwitcher;
@@ -61,18 +63,30 @@
     @Override
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
         boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
+        boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
 
         // Invert the order of the scroll view and user switcher such that the notifications receive
         // touches first but the panel gets drawn above.
         if (child == mScrollView) {
             return super.drawChild(canvas, mStackScroller, drawingTime);
         } else if (child == mStackScroller) {
-            return super.drawChild(canvas, userSwitcherVisible ? mUserSwitcher : mScrollView,
+            return super.drawChild(canvas,
+                    userSwitcherVisible && statusBarVisible ? mUserSwitcher
+                    : statusBarVisible ? mKeyguardStatusBar
+                    : userSwitcherVisible ? mUserSwitcher
+                    : mScrollView,
                     drawingTime);
         } else if (child == mUserSwitcher) {
-            return super.drawChild(canvas, userSwitcherVisible ? mScrollView : mUserSwitcher,
+            return super.drawChild(canvas,
+                    userSwitcherVisible && statusBarVisible ? mKeyguardStatusBar
+                    : mScrollView,
                     drawingTime);
-        } else {
+        } else if (child == mKeyguardStatusBar) {
+            return super.drawChild(canvas,
+                    userSwitcherVisible && statusBarVisible ? mScrollView
+                    : mScrollView,
+                    drawingTime);
+        }else {
             return super.drawChild(canvas, child, drawingTime);
         }
     }
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 750fb39..1d678af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -799,13 +799,13 @@
 
         mFlashlightController = new FlashlightController(mContext);
         mKeyguardBottomArea.setFlashlightController(mFlashlightController);
-        mUserSwitcherController = new UserSwitcherController(mContext);
         mNextAlarmController = new NextAlarmController(mContext);
         mKeyguardMonitor = new KeyguardMonitor();
+        mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor);
 
         mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
                 (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
-                mKeyguardStatusBar, mUserSwitcherController);
+                mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
 
 
         // Set up the quick settings tile panel
@@ -3030,11 +3030,20 @@
      */
     void updateResources() {
         // Update the quick setting tiles
-        if (mQSPanel != null) mQSPanel.updateResources();
+        if (mQSPanel != null) {
+            mQSPanel.updateResources();
+        }
 
         loadDimens();
         mLinearOutSlowIn = AnimationUtils.loadInterpolator(
                 mContext, android.R.interpolator.linear_out_slow_in);
+
+        if (mNotificationPanel != null) {
+            mNotificationPanel.updateResources();
+        }
+        if (mHeadsUpNotificationView != null) {
+            mHeadsUpNotificationView.updateResources();
+        }
     }
 
     protected void loadDimens() {
@@ -3076,7 +3085,7 @@
 
         mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count);
 
-        if (false) Log.v(TAG, "updateResources");
+        if (DEBUG) Log.v(TAG, "updateResources");
     }
 
     // Visibility reporting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index b3051b4..0c62fd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -243,21 +243,25 @@
         boolean changed = expanded != mExpanded;
         mExpanded = expanded;
         if (changed) {
-            updateHeights();
-            updateVisibilities();
-            updateSystemIconsLayoutParams();
-            updateClickTargets();
-            updateMultiUserSwitch();
-            if (mQSPanel != null) {
-                mQSPanel.setExpanded(expanded);
-            }
-            updateClockScale();
-            updateAvatarScale();
-            updateClockLp();
-            requestCaptureValues();
+            updateEverything();
         }
     }
 
+    public void updateEverything() {
+        updateHeights();
+        updateVisibilities();
+        updateSystemIconsLayoutParams();
+        updateClickTargets();
+        updateMultiUserSwitch();
+        if (mQSPanel != null) {
+            mQSPanel.setExpanded(mExpanded);
+        }
+        updateClockScale();
+        updateAvatarScale();
+        updateClockLp();
+        requestCaptureValues();
+    }
+
     private void updateHeights() {
         int height = mExpanded ? mExpandedHeight : mCollapsedHeight;
         ViewGroup.LayoutParams lp = getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
index 93561aa..101a5f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
@@ -38,6 +38,7 @@
     private int mActiveFrameColor;
     private int mFrameColor;
     private float mFrameWidth;
+    private float mFramePadding;
     private Bitmap mBitmap;
     private Drawable mDrawable;
 
@@ -60,6 +61,9 @@
                 case R.styleable.UserAvatarView_frameWidth:
                     setFrameWidth(a.getDimension(attr, 0));
                     break;
+                case R.styleable.UserAvatarView_framePadding:
+                    setFramePadding(a.getDimension(attr, 0));
+                    break;
                 case R.styleable.UserAvatarView_activeFrameColor:
                     setActiveFrameColor(a.getColor(attr, 0));
                     break;
@@ -115,6 +119,11 @@
         invalidate();
     }
 
+    public void setFramePadding(float framePadding) {
+        mFramePadding = framePadding;
+        invalidate();
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
@@ -131,11 +140,11 @@
             dwidth = mBitmap.getWidth();
             dheight = mBitmap.getHeight();
         } else if (mDrawable != null) {
-            dwidth = mDrawable.getIntrinsicWidth();
-            dheight = mDrawable.getIntrinsicHeight();
-            mDrawable.setBounds(0, 0, dwidth, dheight);
             vwidth -= 2 * (mFrameWidth - 1);
             vheight -= 2 * (mFrameWidth - 1);
+            dwidth = vwidth;
+            dheight = vheight;
+            mDrawable.setBounds(0, 0, dwidth, dheight);
         } else {
             return;
         }
@@ -183,7 +192,8 @@
         if (frameColor != 0) {
             mFramePaint.setColor(frameColor);
             mFramePaint.setStrokeWidth(mFrameWidth);
-            canvas.drawCircle(halfW, halfH, halfSW - mFrameWidth / 2f, mFramePaint);
+            canvas.drawCircle(halfW, halfH, halfSW + (mFramePadding - mFrameWidth) / 2f,
+                    mFramePaint);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 2aceb95..6ae076f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -70,6 +70,15 @@
         if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay);
     }
 
+    public void updateResources() {
+        if (mContentHolder != null) {
+            final LayoutParams lp = (LayoutParams) mContentHolder.getLayoutParams();
+            lp.width = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
+            lp.gravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
+            mContentHolder.setLayoutParams(lp);
+        }
+    }
+
     public void setBar(PhoneStatusBar bar) {
         mBar = bar;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index a0312bc..203196e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.database.DataSetObserver;
-import android.provider.Settings;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -26,7 +25,10 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
+import com.android.systemui.qs.tiles.UserDetailItemView;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.phone.StatusBarHeaderView;
 import com.android.systemui.statusbar.phone.UserAvatarView;
 
 /**
@@ -43,11 +45,14 @@
     private final boolean mSimpleUserSwitcher;
 
     public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
-            KeyguardStatusBarView statusBarView, UserSwitcherController userSwitcherController) {
+            KeyguardStatusBarView statusBarView, NotificationPanelView panelView,
+            UserSwitcherController userSwitcherController) {
         if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON) {
             mUserSwitcher = (ViewGroup) userSwitcher.inflate();
+            mUserSwitcher.setBackground(new KeyguardUserSwitcherScrim(mUserSwitcher));
             mStatusBarView = statusBarView;
             mStatusBarView.setKeyguardUserSwitcher(this);
+            panelView.setKeyguardUserSwitcher(this);
             mAdapter = new Adapter(context, userSwitcherController);
             mAdapter.registerDataSetObserver(mDataSetObserver);
             mSimpleUserSwitcher = userSwitcherController.isSimpleUserSwitcher();
@@ -74,7 +79,7 @@
      * @see android.os.UserManager#isUserSwitcherEnabled()
      */
     private boolean shouldExpandByDefault() {
-        return mSimpleUserSwitcher || mAdapter.getSwitchableUsers() > 1;
+        return mSimpleUserSwitcher;
     }
 
     public void show() {
@@ -86,7 +91,7 @@
     }
 
     public void hide() {
-        if (mUserSwitcher != null) {
+        if (mUserSwitcher != null && mUserSwitcher.getVisibility() == View.VISIBLE) {
             // TODO: animate
             mUserSwitcher.setVisibility(View.GONE);
             mStatusBarView.setKeyguardUserSwitcherShowing(false);
@@ -140,21 +145,19 @@
         public View getView(int position, View convertView, ViewGroup parent) {
             UserSwitcherController.UserRecord item = getItem(position);
 
-            if (convertView == null
+            if (!(convertView instanceof UserDetailItemView)
                     || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) {
                 convertView = LayoutInflater.from(mContext).inflate(
                         R.layout.keyguard_user_switcher_item, parent, false);
                 convertView.setOnClickListener(this);
             }
+            UserDetailItemView v = (UserDetailItemView) convertView;
 
-            TextView nameView = (TextView) convertView.findViewById(R.id.name);
-            UserAvatarView pictureView = (UserAvatarView) convertView.findViewById(R.id.picture);
-
-            nameView.setText(getName(mContext, item));
+            String name = getName(mContext, item);
             if (item.picture == null) {
-                pictureView.setDrawable(mContext.getDrawable(R.drawable.ic_account_circle_qs));
+                v.bind(name, getDrawable(mContext, item));
             } else {
-                pictureView.setBitmap(item.picture);
+                v.bind(name, item.picture);
             }
             convertView.setActivated(item.isCurrent);
             convertView.setTag(item);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
new file mode 100644
index 0000000..3356afd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
@@ -0,0 +1,92 @@
+/*
+ * 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.policy;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.util.LayoutDirection;
+import android.view.View;
+
+import com.android.systemui.R;
+
+/**
+ * Gradient background for the user switcher on Keyguard.
+ */
+public class KeyguardUserSwitcherScrim extends Drawable
+        implements View.OnLayoutChangeListener {
+
+    private static final float OUTER_EXTENT = 2.5f;
+    private static final float INNER_EXTENT = 0.75f;
+
+    private int mDarkColor;
+    private int mTop;
+    private Paint mRadialGradientPaint = new Paint();
+
+    public KeyguardUserSwitcherScrim(View host) {
+        host.addOnLayoutChangeListener(this);
+        mDarkColor = host.getResources().getColor(
+                R.color.keyguard_user_switcher_background_gradient_color);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
+        Rect bounds = getBounds();
+        float width = bounds.width() * OUTER_EXTENT;
+        float height = (mTop + bounds.height()) * OUTER_EXTENT;
+        canvas.translate(0, -mTop);
+        canvas.scale(1, height/width);
+        canvas.drawRect(isLtr ? bounds.right - width : 0, 0,
+                isLtr ? bounds.right : bounds.left + width, width, mRadialGradientPaint);
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+
+    @Override
+    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+            int oldTop, int oldRight, int oldBottom) {
+        if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) {
+            int width = right - left;
+            float radius = width * OUTER_EXTENT;
+            boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
+            mRadialGradientPaint.setShader(
+                    new RadialGradient(isLtr ? width : 0, 0, radius,
+                            new int[] { mDarkColor, Color.TRANSPARENT},
+                            new float[] { Math.max(0f, width * INNER_EXTENT / radius), 1f},
+                            Shader.TileMode.CLAMP));
+            mTop = top;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 6e3656d..c48f3f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -34,6 +34,7 @@
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -68,15 +69,18 @@
     private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
     private final GuestResumeSessionReceiver mGuestResumeSessionReceiver
             = new GuestResumeSessionReceiver();
-    private boolean mSimpleUserSwitcher;
+    private final KeyguardMonitor mKeyguardMonitor;
 
     private ArrayList<UserRecord> mUsers = new ArrayList<>();
     private Dialog mExitGuestDialog;
     private int mLastNonGuestUser = UserHandle.USER_OWNER;
+    private boolean mSimpleUserSwitcher;
+    private boolean mAddUsersWhenLocked;
 
-    public UserSwitcherController(Context context) {
+    public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor) {
         mContext = context;
         mGuestResumeSessionReceiver.register(context);
+        mKeyguardMonitor = keyguardMonitor;
         mUserManager = UserManager.get(context);
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_ADDED);
@@ -87,11 +91,17 @@
         mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter,
                 null /* permission */, null /* scheduler */);
 
-        mSimpleUserSwitcher = Settings.Global.getInt(context.getContentResolver(),
-                SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
+
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
-                mSimpleUserSwitcherObserver);
+                mSettingsObserver);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true,
+                mSettingsObserver);
+        // Fetch initial values.
+        mSettingsObserver.onChange(false);
+
+        keyguardMonitor.addCallback(mCallback);
 
         refreshUsers(UserHandle.USER_NULL);
     }
@@ -116,6 +126,7 @@
             bitmaps.put(r.info.id, r.picture);
         }
 
+        final boolean addUsersWhenLocked = mAddUsersWhenLocked;
         new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() {
             @SuppressWarnings("unchecked")
             @Override
@@ -135,7 +146,8 @@
                     boolean isCurrent = currentId == info.id;
                     if (info.isGuest()) {
                         guestRecord = new UserRecord(info, null /* picture */,
-                                true /* isGuest */, isCurrent);
+                                true /* isGuest */, isCurrent, false /* isAddUser */,
+                                false /* isRestricted */);
                     } else if (info.supportsSwitchTo()) {
                         Bitmap picture = bitmaps.get(info.id);
                         if (picture == null) {
@@ -145,19 +157,40 @@
                             picture = BitmapHelper.createCircularClip(
                                     picture, avatarSize, avatarSize);
                         }
-                        records.add(new UserRecord(info, picture, false /* isGuest */, isCurrent));
+                        records.add(new UserRecord(info, picture, false /* isGuest */, isCurrent,
+                                false /* isAddUser */, false /* isRestricted */));
                     }
                 }
 
+                boolean ownerCanCreateUsers = !mUserManager.hasUserRestriction(
+                        UserManager.DISALLOW_ADD_USER, UserHandle.OWNER);
+                boolean currentUserCanCreateUsers =
+                        (currentId == UserHandle.USER_OWNER) && ownerCanCreateUsers;
+                boolean anyoneCanCreateUsers = ownerCanCreateUsers && addUsersWhenLocked;
+                boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
+                        && guestRecord == null;
+                boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
+                        && records.size() < UserManager.getMaxSupportedUsers();
+                boolean createIsRestricted = !addUsersWhenLocked;
+
                 if (!mSimpleUserSwitcher) {
                     if (guestRecord == null) {
-                        records.add(new UserRecord(null /* info */, null /* picture */,
-                                true /* isGuest */, false /* isCurrent */));
+                        if (canCreateGuest) {
+                            records.add(new UserRecord(null /* info */, null /* picture */,
+                                    true /* isGuest */, false /* isCurrent */,
+                                    false /* isAddUser */, createIsRestricted));
+                        }
                     } else {
                         records.add(guestRecord);
                     }
                 }
 
+                if (canCreateUser) {
+                    records.add(new UserRecord(null /* info */, null /* picture */,
+                            false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
+                            createIsRestricted));
+                }
+
                 return records;
             }
 
@@ -168,7 +201,7 @@
                     notifyAdapters();
                 }
             }
-        }.execute((SparseArray)bitmaps);
+        }.execute((SparseArray) bitmaps);
     }
 
     private void notifyAdapters() {
@@ -190,8 +223,10 @@
         int id;
         if (record.isGuest && record.info == null) {
             // No guest user. Create one.
-            id = mUserManager.createGuest(mContext,
-                    mContext.getResources().getString(R.string.guest_nickname)).id;
+            id = mUserManager.createGuest(mContext, mContext.getString(R.string.guest_nickname)).id;
+        } else if (record.isAddUser) {
+            id = mUserManager.createUser(
+                    mContext.getString(R.string.user_new_user_name), 0 /* flags */).id;
         } else {
             id = record.info.id;
         }
@@ -260,6 +295,11 @@
                     if (shouldBeCurrent && !record.isGuest) {
                         mLastNonGuestUser = record.info.id;
                     }
+                    if (currentId != UserHandle.USER_OWNER && record.isRestricted) {
+                        // Immediately remove restricted records in case the AsyncTask is too slow.
+                        mUsers.remove(i);
+                        i--;
+                    }
                 }
                 notifyAdapters();
             }
@@ -272,10 +312,12 @@
         }
     };
 
-    private final ContentObserver mSimpleUserSwitcherObserver = new ContentObserver(new Handler()) {
+    private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
         public void onChange(boolean selfChange) {
             mSimpleUserSwitcher = Settings.Global.getInt(mContext.getContentResolver(),
                     SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
+            mAddUsersWhenLocked = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
             refreshUsers(UserHandle.USER_NULL);
         };
     };
@@ -301,7 +343,22 @@
 
         @Override
         public int getCount() {
-            return mController.mUsers.size();
+            boolean secureKeyguardShowing = mController.mKeyguardMonitor.isShowing()
+                    && mController.mKeyguardMonitor.isSecure();
+            if (!secureKeyguardShowing) {
+                return mController.mUsers.size();
+            }
+            // The lock screen is secure and showing. Filter out restricted records.
+            final int N = mController.mUsers.size();
+            int count = 0;
+            for (int i = 0; i < N; i++) {
+                if (mController.mUsers.get(i).isRestricted) {
+                    break;
+                } else {
+                    count++;
+                }
+            }
+            return count;
         }
 
         @Override
@@ -326,6 +383,8 @@
                     return context.getString(
                             item.info == null ? R.string.guest_new_guest : R.string.guest_nickname);
                 }
+            } else if (item.isAddUser) {
+                return context.getString(R.string.user_add_user);
             } else {
                 return item.info.name;
             }
@@ -342,6 +401,13 @@
             }
             return result;
         }
+
+        public Drawable getDrawable(Context context, UserRecord item) {
+            if (item.isAddUser) {
+                return context.getDrawable(R.drawable.ic_add_circle_qs);
+            }
+            return context.getDrawable(R.drawable.ic_account_circle_qs);
+        }
     }
 
     public static final class UserRecord {
@@ -349,16 +415,22 @@
         public final Bitmap picture;
         public final boolean isGuest;
         public final boolean isCurrent;
+        public final boolean isAddUser;
+        /** If true, the record is only visible to the owner and only when unlocked. */
+        public final boolean isRestricted;
 
-        public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent) {
+        public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
+                boolean isAddUser, boolean isRestricted) {
             this.info = info;
             this.picture = picture;
             this.isGuest = isGuest;
             this.isCurrent = isCurrent;
+            this.isAddUser = isAddUser;
+            this.isRestricted = isRestricted;
         }
 
         public UserRecord copyWithIsCurrent(boolean _isCurrent) {
-            return new UserRecord(info, picture, isGuest, _isCurrent);
+            return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted);
         }
 
         public String toString() {
@@ -367,17 +439,17 @@
             if (info != null) {
                 sb.append("name=\"" + info.name + "\" id=" + info.id);
             } else {
-                sb.append("<add guest placeholder>");
+                if (isGuest) {
+                    sb.append("<add guest placeholder>");
+                } else if (isAddUser) {
+                    sb.append("<add user placeholder>");
+                }
             }
-            if (isGuest) {
-                sb.append(" <isGuest>");
-            }
-            if (isCurrent) {
-                sb.append(" <isCurrent>");
-            }
-            if (picture != null) {
-                sb.append(" <hasPicture>");
-            }
+            if (isGuest) sb.append(" <isGuest>");
+            if (isAddUser) sb.append(" <isAddUser>");
+            if (isCurrent) sb.append(" <isCurrent>");
+            if (picture != null) sb.append(" <hasPicture>");
+            if (isRestricted) sb.append(" <isRestricted>");
             sb.append(')');
             return sb.toString();
         }
@@ -418,6 +490,13 @@
         }
     };
 
+    private final KeyguardMonitor.Callback mCallback = new KeyguardMonitor.Callback() {
+        @Override
+        public void onKeyguardChanged() {
+            notifyAdapters();
+        }
+    };
+
     private final class ExitGuestDialog extends SystemUIDialog implements
             DialogInterface.OnClickListener {
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index d202036..3a63a79 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -24,6 +24,7 @@
 import android.content.DialogInterface.OnDismissListener;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
@@ -44,7 +45,6 @@
 import android.provider.Settings.Global;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -355,23 +355,8 @@
             }
         };
 
-        // Change some window properties
         final Window window = mDialog.getWindow();
-        final LayoutParams lp = window.getAttributes();
-        lp.token = null;
-        // Offset from the top
-        lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
-        lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
-        lp.format = PixelFormat.TRANSLUCENT;
-        lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
-        lp.gravity = Gravity.TOP;
-        window.setAttributes(lp);
-        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
         window.requestFeature(Window.FEATURE_NO_TITLE);
-        window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
-                | LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                | LayoutParams.FLAG_HARDWARE_ACCELERATED);
         mDialog.setCanceledOnTouchOutside(true);
         mDialog.setContentView(com.android.systemui.R.layout.volume_dialog);
         mDialog.setOnDismissListener(new OnDismissListener() {
@@ -384,9 +369,24 @@
         });
 
         mDialog.create();
-        // temporary workaround, until we support window-level shadows
-        mDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0x00000000));
 
+        final LayoutParams lp = window.getAttributes();
+        lp.token = null;
+        lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
+        lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
+        lp.format = PixelFormat.TRANSLUCENT;
+        lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
+        lp.setTitle(TAG);
+        window.setAttributes(lp);
+
+        updateWidth();
+
+        window.setBackgroundDrawable(new ColorDrawable(0x00000000));
+        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+        window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
+                | LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                | LayoutParams.FLAG_HARDWARE_ACCELERATED);
         mView = window.findViewById(R.id.content);
         mView.setOnTouchListener(new View.OnTouchListener() {
             @Override
@@ -416,6 +416,19 @@
         registerReceiver();
     }
 
+    public void onConfigurationChanged(Configuration newConfig) {
+        updateWidth();
+    }
+
+    private void updateWidth() {
+        final Resources res = mContext.getResources();
+        final LayoutParams lp = mDialog.getWindow().getAttributes();
+        lp.width = res.getDimensionPixelSize(com.android.systemui.R.dimen.notification_panel_width);
+        lp.gravity =
+                res.getInteger(com.android.systemui.R.integer.notification_panel_layout_gravity);
+        mDialog.getWindow().setAttributes(lp);
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("VolumePanel state:");
         pw.print("  mTag="); pw.println(mTag);
@@ -1016,7 +1029,6 @@
             int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
             // when the stream is for remote playback, use -1 to reset the stream type evaluation
             mAudioManager.forceVolumeControlStream(stream);
-
             mDialog.show();
             if (mCallback != null) {
                 mCallback.onVisible(true);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index cc351f9..04a3b88 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -3,6 +3,7 @@
 import android.app.ActivityManagerNative;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.media.AudioManager;
 import android.media.IRemoteVolumeController;
@@ -73,6 +74,14 @@
     }
 
     @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        if (mPanel != null) {
+            mPanel.onConfigurationChanged(newConfig);
+        }
+    }
+
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mPanel != null) {
             mPanel.dump(fd, pw, args);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index ff3cd9d..964acbd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1314,7 +1314,6 @@
             mBackgroundDrawable = drawable;
             if (mDecor != null) {
                 mDecor.setWindowBackground(drawable);
-                mDecor.setClipToOutline(drawable != null && mClipToOutline);
             }
         }
     }
@@ -3389,10 +3388,6 @@
             }
             mDecor.setWindowBackground(background);
 
-            if (background != null) {
-                mDecor.setClipToOutline(mClipToOutline);
-            }
-
             final Drawable frame;
             if (mFrameResource != 0) {
                 frame = getContext().getDrawable(mFrameResource);
@@ -3402,6 +3397,7 @@
             mDecor.setWindowFrame(frame);
 
             mDecor.setElevation(mElevation);
+            mDecor.setClipToOutline(mClipToOutline);
 
             if (mTitle != null) {
                 setTitle(mTitle);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index bdaf9ec..4315e0d 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2732,13 +2732,16 @@
             }
 
             // Take a note we no longer have state for this user.
-            final int index = mLoadedUserIds.indexOfKey(userId);
-            if (index >= 0) {
-                mLoadedUserIds.removeAt(index);
+            final int userIndex = mLoadedUserIds.indexOfKey(userId);
+            if (userIndex >= 0) {
+                mLoadedUserIds.removeAt(userIndex);
             }
 
             // Remove the widget id counter.
-            mNextAppWidgetIds.removeAt(userId);
+            final int nextIdIndex = mNextAppWidgetIds.indexOfKey(userId);
+            if (nextIdIndex >= 0) {
+                mNextAppWidgetIds.removeAt(nextIdIndex);
+            }
         }
     }
 
@@ -3122,9 +3125,13 @@
                 // Apps hosting the AppWidget get to bind to a remote view service in the provider.
                 return true;
             }
-            if (mContext.checkCallingPermission(android.Manifest.permission.BIND_APPWIDGET)
+            final int userId = UserHandle.getUserId(uid);
+            if ((widget.host.getUserId() == userId || (widget.provider != null
+                    && widget.provider.getUserId() == userId))
+                && mContext.checkCallingPermission(android.Manifest.permission.BIND_APPWIDGET)
                     == PackageManager.PERMISSION_GRANTED) {
-                // Apps that can bind have access to all appWidgetIds.
+                // Apps that run in the same user as either the host or the provider and
+                // have the bind widget permission have access to the widget.
                 return true;
             }
             return false;
@@ -3184,14 +3191,7 @@
         }
 
         public boolean isHostInPackageForUid(Host host, int uid, String packageName) {
-            if (UserHandle.getAppId(uid) == Process.myUid()) {
-                // For a host that's in the system process, ignore the user id.
-                return UserHandle.isSameApp(host.id.uid, uid)
-                        && host.id.packageName.equals(packageName);
-            } else {
-                return host.id.uid == uid
-                        && host.id.packageName.equals(packageName);
-            }
+            return host.id.uid == uid && host.id.packageName.equals(packageName);
         }
 
         public boolean isProviderInPackageForUid(Provider provider, int uid,
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c77c5b2..59aef32 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1819,18 +1819,23 @@
         @Override
         public void onServiceConnected(ComponentName component, IBinder service) {
             if (DEBUG) Slog.v(TAG, "Connected to transport " + component);
+            final String name = component.flattenToShortString();
             try {
                 IBackupTransport transport = IBackupTransport.Stub.asInterface(service);
-                registerTransport(transport.name(), component.flattenToShortString(), transport);
+                registerTransport(transport.name(), name, transport);
+                EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 1);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Unable to register transport " + component);
+                EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 0);
             }
         }
 
         @Override
         public void onServiceDisconnected(ComponentName component) {
             if (DEBUG) Slog.v(TAG, "Disconnected from transport " + component);
-            registerTransport(null, component.flattenToShortString(), null);
+            final String name = component.flattenToShortString();
+            EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 0);
+            registerTransport(null, name, null);
         }
     };
 
@@ -3690,6 +3695,9 @@
                         Slog.i(TAG, "Initiating full-data transport backup of "
                                 + currentPackage.packageName);
                     }
+                    EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE,
+                            currentPackage.packageName);
+
                     transportPipes = ParcelFileDescriptor.createPipe();
 
                     // Tell the transport the data's coming
@@ -3780,12 +3788,19 @@
                                     + currentPackage.packageName
                                     + ", skipping");
                         }
+                        EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE,
+                                currentPackage.packageName, "transport rejected");
                         // do nothing, clean up, and continue looping
                     } else if (result != BackupTransport.TRANSPORT_OK) {
                         if (DEBUG) {
                             Slog.i(TAG, "Transport failed; aborting backup: " + result);
+                            EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
                             return;
                         }
+                    } else {
+                        // Success!
+                        EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS,
+                                currentPackage.packageName);
                     }
                     cleanUpPipes(transportPipes);
                     cleanUpPipes(enginePipes);
@@ -7339,6 +7354,9 @@
                 UnifiedRestoreState nextState = UnifiedRestoreState.RUNNING_QUEUE;
                 int status = BackupTransport.TRANSPORT_OK;
 
+                EventLog.writeEvent(EventLogTags.FULL_RESTORE_PACKAGE,
+                        mCurrentPackage.packageName);
+
                 mEngine = new FullRestoreEngine(null, mCurrentPackage, false, false);
                 EngineThread eThread = new EngineThread(mEngine, mEnginePipes[0]);
 
@@ -7390,6 +7408,7 @@
                             // handling will deal properly with that.
                             Slog.e(TAG, "Error " + result + " streaming restore for "
                                     + mCurrentPackage.packageName);
+                            EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
                             status = result;
                         }
                     }
@@ -7399,12 +7418,15 @@
                     // but potentially recoverable; abandon this package's restore but
                     // carry on with the next restore target.
                     Slog.e(TAG, "Unable to route data for restore");
+                    EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
+                            mCurrentPackage.packageName, "I/O error on pipes");
                     status = BackupTransport.AGENT_ERROR;
                 } catch (RemoteException e) {
                     // The transport went away; terminate the whole operation.  Closing
                     // the sockets will wake up the engine and it will then tidy up the
                     // remote end.
                     Slog.e(TAG, "Transport failed during restore");
+                    EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
                     status = BackupTransport.TRANSPORT_ERROR;
                 } finally {
                     // Close the transport pipes and *our* end of the engine pipe,
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index a00fbf3..6761f24 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -55,7 +55,6 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
-import android.net.CaptivePortalTracker;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
@@ -248,12 +247,6 @@
      */
     private NetworkStateTracker mNetTrackers[];
 
-    /*
-     * Handles captive portal check on a network.
-     * Only set if device has {@link PackageManager#FEATURE_WIFI}.
-     */
-    private CaptivePortalTracker mCaptivePortalTracker;
-
     private Context mContext;
     private int mNetworkPreference;
     private int mActiveDefaultNetwork = -1;
@@ -1444,9 +1437,6 @@
                 SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0);
         setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent);
 
-        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
-            mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this);
-        }
         loadGlobalProxy();
 
         synchronized(this) {
@@ -1800,12 +1790,15 @@
                     if (nai == null) {
                         loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED");
                     } else {
-                        if (VDBG) log("Update of Linkproperties for " + nai.name());
+                        if (VDBG) {
+                            log("Update of Linkproperties for " + nai.name() +
+                                    "; created=" + nai.created);
+                        }
                         LinkProperties oldLp = nai.linkProperties;
                         synchronized (nai) {
                             nai.linkProperties = (LinkProperties)msg.obj;
                         }
-                        updateLinkProperties(nai, oldLp);
+                        if (nai.created) updateLinkProperties(nai, oldLp);
                     }
                     break;
                 }
@@ -2042,12 +2035,14 @@
                 log(nai.name() + " got DISCONNECTED, was satisfying " + nai.networkRequests.size());
             }
             // A network agent has disconnected.
-            // Tell netd to clean up the configuration for this network
-            // (routing rules, DNS, etc).
-            try {
-                mNetd.removeNetwork(nai.network.netId);
-            } catch (Exception e) {
-                loge("Exception removing network: " + e);
+            if (nai.created) {
+                // Tell netd to clean up the configuration for this network
+                // (routing rules, DNS, etc).
+                try {
+                    mNetd.removeNetwork(nai.network.netId);
+                } catch (Exception e) {
+                    loge("Exception removing network: " + e);
+                }
             }
             // TODO - if we move the logic to the network agent (have them disconnect
             // because they lost all their requests or because their score isn't good)
@@ -4246,8 +4241,8 @@
 //        for (LinkProperties lp : newLp.getStackedLinks()) {
 //            updateMtu(lp, null);
 //        }
-        updateRoutes(newLp, oldLp, netId);
-        updateDnses(newLp, oldLp, netId);
+        final boolean flushDns = updateRoutes(newLp, oldLp, netId);
+        updateDnses(newLp, oldLp, netId, flushDns);
         updateClat(newLp, oldLp, networkAgent);
     }
 
@@ -4295,7 +4290,11 @@
         }
     }
 
-    private void updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
+    /**
+     * Have netd update routes from oldLp to newLp.
+     * @return true if routes changed between oldLp and newLp
+     */
+    private boolean updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
         CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
         if (oldLp != null) {
             routeDiff = oldLp.compareAllRoutes(newLp);
@@ -4330,8 +4329,9 @@
                 loge("Exception in removeRoute: " + e);
             }
         }
+        return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty();
     }
-    private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
+    private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId, boolean flush) {
         if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
             Collection<InetAddress> dnses = newLp.getDnsServers();
             if (dnses.size() == 0 && mDefaultDns != null) {
@@ -4352,6 +4352,13 @@
                 setDefaultDnsSystemProperties(dnses);
             }
             flushVmDnsCache();
+        } else if (flush) {
+            try {
+                mNetd.flushNetworkDnsCache(netId);
+            } catch (Exception e) {
+                loge("Exception in flushNetworkDnsCache: " + e);
+            }
+            flushVmDnsCache();
         }
     }
 
@@ -4620,13 +4627,9 @@
                     " to " + state);
         }
 
-        if (state == NetworkInfo.State.CONNECTED) {
+        if (state == NetworkInfo.State.CONNECTED && !networkAgent.created) {
             try {
-                // This is likely caused by the fact that this network already
-                // exists. An example is when a network goes from CONNECTED to
-                // CONNECTING and back (like wifi on DHCP renew).
-                // TODO: keep track of which networks we've created, or ask netd
-                // to tell us whether we've already created this network or not.
+                // This should never fail.  Specifying an already in use NetID will cause failure.
                 if (networkAgent.isVPN()) {
                     mNetd.createVirtualNetwork(networkAgent.network.netId,
                             !networkAgent.linkProperties.getDnsServers().isEmpty(),
@@ -4640,7 +4643,7 @@
                         + e.getMessage());
                 return;
             }
-
+            networkAgent.created = true;
             updateLinkProperties(networkAgent, null);
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
             networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 3c50947..5aaeb6a 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -102,6 +102,14 @@
 2833 restore_package (Package|3),(Size|1|2)
 2834 restore_success (Packages|1|1),(Time|1|3)
 
+2840 full_backup_package (Package|3)
+2841 full_backup_agent_failure (Package|3),(Message|3)
+2842 full_backup_transport_failure
+2843 full_backup_success (Package|3)
+2844 full_restore_package (Package|3)
+
+2850 backup_transport_lifecycle (Transport|3),(Bound|1|1)
+
 
 # ---------------------------
 # SystemServer.java
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 362a745..f9b65b8 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1748,6 +1748,16 @@
     }
 
     @Override
+    public void flushNetworkDnsCache(int netId) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("resolver", "flushnet", netId);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
     public void setFirewallEnabled(boolean enabled) {
         enforceSystemUid();
         try {
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index f71a18a..2896f60 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -23,6 +23,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.util.Slog;
 import com.android.internal.R;
@@ -66,8 +67,9 @@
 
     private final Context mContext;
     private final String mDataBlockFile;
-    private final int mAllowedUid;
     private final Object mLock = new Object();
+
+    private int mAllowedAppId = -1;
     /*
      * Separate lock for OEM unlock related operations as they can happen in parallel with regular
      * block operations.
@@ -81,19 +83,22 @@
         mContext = context;
         mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
         mBlockDeviceSize = -1; // Load lazily
-        String allowedPackage = context.getResources()
+        mAllowedAppId = getAllowedAppId(UserHandle.USER_OWNER);
+    }
+
+
+    private int getAllowedAppId(int userHandle) {
+        String allowedPackage = mContext.getResources()
                 .getString(R.string.config_persistentDataPackageName);
         PackageManager pm = mContext.getPackageManager();
         int allowedUid = -1;
         try {
-            allowedUid = pm.getPackageUid(allowedPackage,
-                    Binder.getCallingUserHandle().getIdentifier());
+            allowedUid = pm.getPackageUid(allowedPackage, userHandle);
         } catch (PackageManager.NameNotFoundException e) {
             // not expected
             Slog.e(TAG, "not able to find package " + allowedPackage, e);
         }
-
-        mAllowedUid = allowedUid;
+        return UserHandle.getAppId(allowedUid);
     }
 
     @Override
@@ -108,7 +113,7 @@
     }
 
     private void enforceUid(int callingUid) {
-        if (callingUid != mAllowedUid) {
+        if (UserHandle.getAppId(callingUid) != mAllowedAppId) {
             throw new SecurityException("uid " + callingUid + " not allowed to access PST");
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ae2ef06..c7c7a92 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2200,8 +2200,7 @@
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
         systemDir.mkdirs();
-        mBatteryStatsService = new BatteryStatsService(new File(
-                systemDir, "batterystats.bin").toString(), mHandler);
+        mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
         mBatteryStatsService.getActiveStatistics().readLocked();
         mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
         mOnBattery = DEBUG_POWER ? true
@@ -7471,6 +7470,7 @@
         rti.firstActiveTime = tr.firstActiveTime;
         rti.lastActiveTime = tr.lastActiveTime;
         rti.affiliatedTaskId = tr.mAffiliatedTaskId;
+        rti.affiliatedTaskColor = tr.mAffiliatedTaskColor;
         return rti;
     }
 
@@ -10585,14 +10585,16 @@
     }
 
     void startAppProblemLocked(ProcessRecord app) {
-        if (app.userId == mCurrentUserId) {
-            app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
-                    mContext, app.info.packageName, app.info.flags);
-        } else {
-            // If this app is not running under the current user, then we
-            // can't give it a report button because that would require
-            // launching the report UI under a different user.
-            app.errorReportReceiver = null;
+        // If this app is not running under the current user, then we
+        // can't give it a report button because that would require
+        // launching the report UI under a different user.
+        app.errorReportReceiver = null;
+
+        for (int userId : mCurrentProfileIds) {
+            if (app.userId == userId) {
+                app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
+                        mContext, app.info.packageName, app.info.flags);
+            }
         }
         skipCurrentReceiverLocked(app);
     }
@@ -17244,6 +17246,10 @@
                     Slog.w(TAG, "No user info for user #" + userId);
                     return false;
                 }
+                if (foreground && userInfo.isManagedProfile()) {
+                    Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
+                    return false;
+                }
 
                 if (foreground) {
                     mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3fdeb54..d8da700 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.ServiceManager;
@@ -42,7 +43,10 @@
 import com.android.internal.os.PowerProfile;
 import com.android.server.LocalServices;
 
+import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.List;
 
@@ -62,8 +66,8 @@
     private BluetoothHeadset mBluetoothHeadset;
     PowerManagerInternal mPowerManagerInternal;
 
-    BatteryStatsService(String filename, Handler handler) {
-        mStats = new BatteryStatsImpl(filename, handler);
+    BatteryStatsService(File systemDir, Handler handler) {
+        mStats = new BatteryStatsImpl(systemDir, handler);
     }
     
     public void publish(Context context) {
@@ -117,7 +121,7 @@
     public BatteryStatsImpl getActiveStatistics() {
         return mStats;
     }
-    
+
     public byte[] getStatistics() {
         mContext.enforceCallingPermission(
                 android.Manifest.permission.BATTERY_STATS, null);
@@ -129,7 +133,24 @@
         out.recycle();
         return data;
     }
-    
+
+    public ParcelFileDescriptor getStatisticsStream() {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.BATTERY_STATS, null);
+        //Slog.i("foo", "SENDING BATTERY INFO:");
+        //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
+        Parcel out = Parcel.obtain();
+        mStats.writeToParcel(out, 0);
+        byte[] data = out.marshall();
+        out.recycle();
+        try {
+            return ParcelFileDescriptor.fromData(data, "battery-stats");
+        } catch (IOException e) {
+            Slog.w(TAG, "Unable to create shared memory", e);
+            return null;
+        }
+    }
+
     public long computeBatteryTimeRemaining() {
         synchronized (mStats) {
             long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
@@ -726,7 +747,8 @@
         pw.println("  enable|disable <option>");
         pw.println("    Enable or disable a running option.  Option state is not saved across boots.");
         pw.println("    Options are:");
-        pw.println("      full-wake-history: include wake_lock_in battery history, full wake details.");
+        pw.println("      full-history: include additional detailed events in battery history:");
+        pw.println("          wake_lock_in and proc events");
         pw.println("      no-auto-reset: don't automatically reset stats when unplugged");
     }
 
@@ -737,9 +759,9 @@
             dumpHelp(pw);
             return -1;
         }
-        if ("full-wake-history".equals(args[i])) {
+        if ("full-wake-history".equals(args[i]) || "full-history".equals(args[i])) {
             synchronized (mStats) {
-                mStats.setRecordAllWakeLocksLocked(enable);
+                mStats.setRecordAllHistoryLocked(enable);
             }
         } else if ("no-auto-reset".equals(args[i])) {
             synchronized (mStats) {
@@ -764,7 +786,8 @@
         }
 
         int flags = 0;
-        boolean isCheckin = false;
+        boolean useCheckinFormat = false;
+        boolean isRealCheckin = false;
         boolean noOutput = false;
         boolean writeData = false;
         long historyStart = -1;
@@ -773,7 +796,8 @@
             for (int i=0; i<args.length; i++) {
                 String arg = args[i];
                 if ("--checkin".equals(arg)) {
-                    isCheckin = true;
+                    useCheckinFormat = true;
+                    isRealCheckin = true;
                 } else if ("--history".equals(arg)) {
                     flags |= BatteryStats.DUMP_HISTORY_ONLY;
                 } else if ("--history-start".equals(arg)) {
@@ -787,7 +811,7 @@
                     historyStart = Long.parseLong(args[i]);
                     writeData = true;
                 } else if ("-c".equals(arg)) {
-                    isCheckin = true;
+                    useCheckinFormat = true;
                     flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
                 } else if ("--unplugged".equals(arg)) {
                     flags |= BatteryStats.DUMP_UNPLUGGED_ONLY;
@@ -844,8 +868,35 @@
         if (noOutput) {
             return;
         }
-        if (isCheckin) {
+        if (useCheckinFormat) {
             List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
+            if (isRealCheckin) {
+                // For a real checkin, first we want to prefer to use the last complete checkin
+                // file if there is one.
+                synchronized (mStats.mCheckinFile) {
+                    if (mStats.mCheckinFile.exists()) {
+                        try {
+                            byte[] raw = mStats.mCheckinFile.readFully();
+                            if (raw != null) {
+                                Parcel in = Parcel.obtain();
+                                in.unmarshall(raw, 0, raw.length);
+                                in.setDataPosition(0);
+                                BatteryStatsImpl checkinStats = new BatteryStatsImpl(
+                                        null, mStats.mHandler);
+                                checkinStats.readSummaryFromParcel(in);
+                                in.recycle();
+                                checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
+                                        historyStart);
+                                mStats.mCheckinFile.delete();
+                                return;
+                            }
+                        } catch (IOException e) {
+                            Slog.w(TAG, "Failure reading checkin file "
+                                    + mStats.mCheckinFile.getBaseFile(), e);
+                        }
+                    }
+                }
+            }
             synchronized (mStats) {
                 mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
                 if (writeData) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4a84941..d0ec106 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -68,6 +68,7 @@
     private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
     private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
     private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
+    private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
     private static final String ATTR_CALLING_UID = "calling_uid";
     private static final String ATTR_CALLING_PACKAGE = "calling_package";
     private static final String LAST_ACTIVITY_ICON_SUFFIX = "_last_activity_icon_";
@@ -140,6 +141,7 @@
     CharSequence lastDescription; // Last description captured for this item.
 
     int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
+    int mAffiliatedTaskColor; // color of the parent task affiliation.
     TaskRecord mPrevAffiliate; // previous task in affiliated chain.
     int mPrevAffiliateTaskId = -1; // previous id for persistence.
     TaskRecord mNextAffiliate; // next task in affiliated chain.
@@ -172,7 +174,8 @@
             String _lastDescription, ArrayList<ActivityRecord> activities, long _firstActiveTime,
             long _lastActiveTime, long lastTimeMoved, boolean neverRelinquishIdentity,
             ActivityManager.TaskDescription _lastTaskDescription, int taskAffiliation,
-            int prevTaskId, int nextTaskId, int callingUid, String callingPackage) {
+            int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid,
+            String callingPackage) {
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
@@ -199,6 +202,7 @@
         mNeverRelinquishIdentity = neverRelinquishIdentity;
         lastTaskDescription = _lastTaskDescription;
         mAffiliatedTaskId = taskAffiliation;
+        mAffiliatedTaskColor = taskAffiliationColor;
         mPrevAffiliateTaskId = prevTaskId;
         mNextAffiliateTaskId = nextTaskId;
         mCallingUid = callingUid;
@@ -326,6 +330,7 @@
     void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
         closeRecentsChain();
         mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
+        mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
         // Find the end
         while (taskToAffiliateWith.mNextAffiliate != null) {
             final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate;
@@ -689,11 +694,14 @@
                     }
                     if (colorPrimary == 0) {
                         colorPrimary = r.taskDescription.getPrimaryColor();
-
                     }
                 }
             }
             lastTaskDescription = new ActivityManager.TaskDescription(label, icon, colorPrimary);
+            // Update the task affiliation color if we are the parent of the group
+            if (taskId == mAffiliatedTaskId) {
+                mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
+            }
         }
     }
 
@@ -777,6 +785,7 @@
             saveTaskDescription(lastTaskDescription, String.valueOf(taskId) +
                     LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime, out);
         }
+        out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
         out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
         out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
         out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
@@ -831,6 +840,7 @@
         final int outerDepth = in.getDepth();
         ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription();
         int taskAffiliation = -1;
+        int taskAffiliationColor = 0;
         int prevTaskId = -1;
         int nextTaskId = -1;
         int callingUid = -1;
@@ -877,6 +887,8 @@
                 prevTaskId = Integer.valueOf(attrValue);
             } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) {
                 nextTaskId = Integer.valueOf(attrValue);
+            } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) {
+                taskAffiliationColor = Integer.valueOf(attrValue);
             } else if (ATTR_CALLING_UID.equals(attrName)) {
                 callingUid = Integer.valueOf(attrValue);
             } else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
@@ -921,8 +933,8 @@
                 affinityIntent, affinity, realActivity, origActivity, rootHasReset,
                 autoRemoveRecents, askedCompatMode, taskType, userId, lastDescription, activities,
                 firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
-                taskDescription, taskAffiliation, prevTaskId, nextTaskId, callingUid,
-                callingPackage);
+                taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
+                callingUid, callingPackage);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
             activities.get(activityNdx).task = task;
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 403713d..4eb2ef1 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -46,6 +46,7 @@
     public int currentScore;
     public final NetworkMonitor networkMonitor;
     public final NetworkMisc networkMisc;
+    public boolean created;
 
     // The list of NetworkRequests being satisfied by this Network.
     public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
@@ -66,6 +67,7 @@
         currentScore = score;
         networkMonitor = new NetworkMonitor(context, handler, this);
         networkMisc = misc;
+        created = false;
     }
 
     public void addRequest(NetworkRequest networkRequest) {
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 488c09d..ae5eda3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -26,11 +26,24 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.telephony.CellIdentityCdma;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellIdentityWcdma;
+import android.telephony.CellInfo;
+import android.telephony.CellInfoCdma;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellInfoWcdma;
+import android.telephony.TelephonyManager;
 
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
@@ -38,15 +51,10 @@
 import com.android.server.ConnectivityService;
 import com.android.server.connectivity.NetworkAgentInfo;
 
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
 import java.io.IOException;
-import java.io.OutputStreamWriter;
 import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
 import java.net.URL;
+import java.util.List;
 
 /**
  * {@hide}
@@ -56,6 +64,21 @@
     private static final String TAG = "NetworkMonitor";
     private static final String DEFAULT_SERVER = "clients3.google.com";
     private static final int SOCKET_TIMEOUT_MS = 10000;
+    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
+            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
+    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
+    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
+    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
+    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
+    public static final String EXTRA_CELL_ID = "extra_cellid";
+    public static final String EXTRA_SSID = "extra_ssid";
+    public static final String EXTRA_BSSID = "extra_bssid";
+    /** real time since boot */
+    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
+    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
+
+    private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
+            "android.permission.ACCESS_NETWORK_CONDITIONS";
 
     // Intent broadcast when user selects sign-in notification.
     private static final String ACTION_SIGN_IN_REQUESTED =
@@ -188,6 +211,8 @@
     private final Context mContext;
     private final Handler mConnectivityServiceHandler;
     private final NetworkAgentInfo mNetworkAgentInfo;
+    private final TelephonyManager mTelephonyManager;
+    private final WifiManager mWifiManager;
 
     private String mServer;
     private boolean mIsCaptivePortalCheckEnabled = false;
@@ -209,6 +234,8 @@
         mContext = context;
         mConnectivityServiceHandler = handler;
         mNetworkAgentInfo = networkAgentInfo;
+        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
 
         addState(mDefaultState);
         addState(mOfflineState, mDefaultState);
@@ -608,84 +635,52 @@
     private int isCaptivePortal() {
         if (!mIsCaptivePortalCheckEnabled) return 204;
 
-        String urlString = "http://" + mServer + "/generate_204";
-        if (DBG) {
-            log("Checking " + urlString + " on " + mNetworkAgentInfo.networkInfo.getExtraInfo());
-        }
         HttpURLConnection urlConnection = null;
-        Socket socket = null;
         int httpResponseCode = 599;
         try {
-            URL url = new URL(urlString);
-            // TODO: check that standard HttpURLConnection doesn't choke on
-            // cruel and unusual captive portals, and then replace the
-            // hand-rolled HTTP code in the else branch with this code.
-            if (false) {
-                url = mNetworkAgentInfo.network.getBoundURL(url);
-                urlConnection = (HttpURLConnection) url.openConnection();
-                urlConnection.setInstanceFollowRedirects(false);
-                urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
-                urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
-                urlConnection.setUseCaches(false);
-                urlConnection.getInputStream();
-                httpResponseCode = urlConnection.getResponseCode();
-            } else {
-                // Lookup addresses only on this Network.
-                InetAddress[] hostAddresses = mNetworkAgentInfo.network.getAllByName(url.getHost());
-                // Try all addresses.
-                for (int i = 0; i < hostAddresses.length; i++) {
-                    // Create a new socket for every IP address. See http://b/16664129 .
-                    socket = mNetworkAgentInfo.network.getSocketFactory().createSocket();
-                    socket.setSoTimeout(SOCKET_TIMEOUT_MS);
-                    if (DBG) log("Connecting to " + hostAddresses[i]);
-                    try {
-                        socket.connect(new InetSocketAddress(hostAddresses[i],
-                                url.getDefaultPort()), SOCKET_TIMEOUT_MS);
-                        break;
-                    } catch (IOException e) {
-                        // Ignore exceptions on all but the last.
-                        if (i == (hostAddresses.length - 1)) throw e;
-                    }
-                }
-                if (DBG) log("Requesting " + url.getFile());
-                BufferedReader reader = new BufferedReader(
-                        new InputStreamReader(socket.getInputStream()));
-                OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
-                writer.write("GET " + url.getFile() + " HTTP/1.1\r\nHost: " + url.getHost() +
-                        "\r\nUser-Agent: " + System.getProperty("http.agent") +
-                        "\r\nConnection: close\r\n\r\n");
-                writer.flush();
-                String response = reader.readLine();
-                if (DBG) log("Received \"" + response + "\"");
-                if (response != null && (response.startsWith("HTTP/1.1 ") ||
-                        // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive
-                        // portal.  The only example of this seen so far was a captive portal.  For
-                        // the time being go with prior behavior of assuming it's not a captive
-                        // portal.  If it is considered a captive portal, a different sign-in URL
-                        // is needed (i.e. can't browse a 204).  This could be the result of an HTTP
-                        // proxy server.
-                        response.startsWith("HTTP/1.0 "))) {
-                    // NOTE: We may want to consider an "200" response with "Content-length=0" to
-                    // not be a captive portal. This could be the result of an HTTP proxy server.
-                    // See b/9972012.
-                    httpResponseCode = Integer.parseInt(response.substring(9, 12));
-                } else {
-                    // A response was received but not understood.  The fact that a
-                    // response was sent indicates there's some kind of responsive network
-                    // out there so put up the notification to the user to log into the network
-                    // so the user can have the final say as to whether the network is useful.
-                    httpResponseCode = 399;
-                    while (DBG && response != null && !response.isEmpty()) {
-                        try {
-                            response = reader.readLine();
-                        } catch (IOException e) {
-                            break;
-                        }
-                        log("Received \"" + response + "\"");
-                    }
-                }
+            URL url = new URL("http", mServer, "/generate_204");
+            if (DBG) {
+                log("Checking " + url.toString() + " on " +
+                        mNetworkAgentInfo.networkInfo.getExtraInfo());
             }
-            if (DBG) log("isCaptivePortal: ret=" + httpResponseCode);
+            url = mNetworkAgentInfo.network.getBoundURL(url);
+            urlConnection = (HttpURLConnection) url.openConnection();
+            urlConnection.setInstanceFollowRedirects(false);
+            urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
+            urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
+            urlConnection.setUseCaches(false);
+
+            // Time how long it takes to get a response to our request
+            long requestTimestamp = SystemClock.elapsedRealtime();
+
+            urlConnection.getInputStream();
+
+            // Time how long it takes to get a response to our request
+            long responseTimestamp = SystemClock.elapsedRealtime();
+
+            httpResponseCode = urlConnection.getResponseCode();
+            if (DBG) {
+                log("isCaptivePortal: ret=" + httpResponseCode +
+                        " headers=" + urlConnection.getHeaderFields());
+            }
+            // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive
+            // portal.  The only example of this seen so far was a captive portal.  For
+            // the time being go with prior behavior of assuming it's not a captive
+            // portal.  If it is considered a captive portal, a different sign-in URL
+            // is needed (i.e. can't browse a 204).  This could be the result of an HTTP
+            // proxy server.
+
+            // Consider 200 response with "Content-length=0" to not be a captive portal.
+            // There's no point in considering this a captive portal as the user cannot
+            // sign-in to an empty page.  Probably the result of a broken transparent proxy.
+            // See http://b/9972012.
+            if (httpResponseCode == 200 && urlConnection.getContentLength() == 0) {
+                if (DBG) log("Empty 200 response interpreted as 204 response.");
+                httpResponseCode = 204;
+            }
+
+            sendNetworkConditionsBroadcast(true /* response received */, httpResponseCode == 204,
+                    requestTimestamp, responseTimestamp);
         } catch (IOException e) {
             if (DBG) log("Probably not a portal: exception " + e);
             if (httpResponseCode == 599) {
@@ -695,14 +690,87 @@
             if (urlConnection != null) {
                 urlConnection.disconnect();
             }
-            if (socket != null) {
-                try {
-                    socket.close();
-                } catch (IOException e) {
-                    // Ignore
-                }
-            }
         }
         return httpResponseCode;
     }
+
+    /**
+     * @param responseReceived - whether or not we received a valid HTTP response to our request.
+     * If false, isCaptivePortal and responseTimestampMs are ignored
+     * TODO: This should be moved to the transports.  The latency could be passed to the transports
+     * along with the captive portal result.  Currently the TYPE_MOBILE broadcasts appear unused so
+     * perhaps this could just be added to the WiFi transport only.
+     */
+    private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
+            long requestTimestampMs, long responseTimestampMs) {
+        if (Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0) {
+            if (DBG) log("Don't send network conditions - lacking user consent.");
+            return;
+        }
+
+        Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED);
+        switch (mNetworkAgentInfo.networkInfo.getType()) {
+            case ConnectivityManager.TYPE_WIFI:
+                WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
+                if (currentWifiInfo != null) {
+                    // NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not
+                    // surrounded by double quotation marks (thus violating the Javadoc), but this
+                    // was changed to match the Javadoc in API 17. Since clients may have started
+                    // sanitizing the output of this method since API 17 was released, we should
+                    // not change it here as it would become impossible to tell whether the SSID is
+                    // simply being surrounded by quotes due to the API, or whether those quotes
+                    // are actually part of the SSID.
+                    latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
+                    latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
+                } else {
+                    if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
+                    return;
+                }
+                break;
+            case ConnectivityManager.TYPE_MOBILE:
+                latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType());
+                List<CellInfo> info = mTelephonyManager.getAllCellInfo();
+                if (info == null) return;
+                int numRegisteredCellInfo = 0;
+                for (CellInfo cellInfo : info) {
+                    if (cellInfo.isRegistered()) {
+                        numRegisteredCellInfo++;
+                        if (numRegisteredCellInfo > 1) {
+                            if (DBG) log("more than one registered CellInfo.  Can't " +
+                                    "tell which is active.  Bailing.");
+                            return;
+                        }
+                        if (cellInfo instanceof CellInfoCdma) {
+                            CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
+                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                        } else if (cellInfo instanceof CellInfoGsm) {
+                            CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
+                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                        } else if (cellInfo instanceof CellInfoLte) {
+                            CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
+                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                        } else if (cellInfo instanceof CellInfoWcdma) {
+                            CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
+                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                        } else {
+                            if (DBG) logw("Registered cellinfo is unrecognized");
+                            return;
+                        }
+                    }
+                }
+                break;
+            default:
+                return;
+        }
+        latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkAgentInfo.networkInfo.getType());
+        latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived);
+        latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs);
+
+        if (responseReceived) {
+            latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal);
+            latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs);
+        }
+        mContext.sendBroadcast(latencyBroadcast, PERMISSION_ACCESS_NETWORK_CONDITIONS);
+    }
 }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 2dd150a..e31f177 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1269,28 +1269,26 @@
                         + "greater than 0");
             }
 
+            if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
+                flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+            }
+            if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
+                flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+            }
+
             if (projection != null) {
                 try {
                     if (!getProjectionService().isValidMediaProjection(projection)) {
                         throw new SecurityException("Invalid media projection");
                     }
+                    flags = projection.applyVirtualDisplayFlags(flags);
                 } catch (RemoteException e) {
-                    throw new SecurityException("unable to validate media projection");
-                }
-                flags &= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
-                try {
-                    flags |= projection.getVirtualDisplayFlags();
-                } catch (RemoteException e) {
-                    throw new RuntimeException("unable to retrieve media projection flags");
+                    throw new SecurityException("unable to validate media projection or flags");
                 }
             }
 
-            if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE) != 0) {
-                if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0 ||
-                        (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) {
-                    throw new IllegalArgumentException("screen sharing virtual displays must not "
-                            + "be public or presentation displays");
-                }
+            if (callingUid != Process.SYSTEM_UID &&
+                    (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
                 if (!canProjectVideo(projection)) {
                     throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
                             + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
@@ -1298,16 +1296,6 @@
                             + "display.");
                 }
             }
-
-
-            if (callingUid != Process.SYSTEM_UID &&
-                    (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
-                if (!canProjectVideo(projection)) {
-                    throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
-                            + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
-                            + "MediaProjection token to create a public virtual display.");
-                }
-            }
             if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
                 if (!canProjectSecureVideo(projection)) {
                     throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 0ebd2de..72ac29a 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -262,14 +262,15 @@
                 mInfo.presentationDeadlineNanos = 1000000000L / (int) mInfo.refreshRate; // 1 frame
                 mInfo.flags = 0;
                 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
-                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
-                    if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE) == 0) {
-                        mInfo.flags |=  DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY
-                                | DisplayDeviceInfo.FLAG_NEVER_BLANK;
-                    }
-                } else if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
+                            | DisplayDeviceInfo.FLAG_NEVER_BLANK;
+                }
+                if ((mInfo.flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
+                    mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK;
+                } else {
                     mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
                 }
+
                 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
                     mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
                 }
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 0b9094f..cb92112 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -18,7 +18,7 @@
 
 import android.annotation.Nullable;
 import android.hardware.hdmi.IHdmiControlCallback;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
 import android.os.RemoteException;
 import android.util.Slog;
@@ -66,7 +66,7 @@
             invokeCallback(HdmiControlManager.RESULT_SUCCESS);
             return;
         }
-        HdmiCecDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress);
+        HdmiDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress);
         if (device == null) {
             tv.startNewDeviceAction(newActive);
         }
@@ -101,10 +101,6 @@
         return mSource.getDeviceInfo().getLogicalAddress();
     }
 
-    private final int getSourcePath() {
-        return mSource.getDeviceInfo().getPhysicalAddress();
-    }
-
     private void invokeCallback(int result) {
         if (mCallback == null) {
             return;
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 7552a6a..0b57474 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -16,12 +16,12 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 
 /**
  * Defines constants related to HDMI-CEC protocol internal implementation.
  * If a constant will be used in the public api, it should be located in
- * {@link android.hardware.hdmi.HdmiCec}.
+ * {@link android.hardware.hdmi.HdmiControlManager}.
  */
 final class Constants {
 
@@ -80,7 +80,7 @@
     public static final int ADDR_INVALID = -1;
 
     /** Logical address used to indicate the source comes from internal device. */
-    public static final int ADDR_INTERNAL = HdmiCecDeviceInfo.ADDR_INTERNAL;
+    public static final int ADDR_INTERNAL = HdmiDeviceInfo.ADDR_INTERNAL;
 
     static final int MESSAGE_FEATURE_ABORT = 0x00;
     static final int MESSAGE_IMAGE_VIEW_ON = 0x04;
@@ -178,8 +178,8 @@
     static final int ROUTING_PATH_TOP_MASK = 0xF000;
     static final int ROUTING_PATH_TOP_SHIFT = 12;
 
-    static final int INVALID_PORT_ID = HdmiCecDeviceInfo.PORT_INVALID;
-    static final int INVALID_PHYSICAL_ADDRESS = HdmiCecDeviceInfo.PATH_INVALID;
+    static final int INVALID_PORT_ID = HdmiDeviceInfo.PORT_INVALID;
+    static final int INVALID_PHYSICAL_ADDRESS = HdmiDeviceInfo.PATH_INVALID;
 
     // Send result codes. It should be consistent with hdmi_cec.h's send_message error code.
     static final int SEND_RESULT_SUCCESS = 0;
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index 86e14e1..d67b8f1 100644
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 
 import com.android.internal.util.Preconditions;
@@ -39,7 +39,7 @@
  *   <li>Gather "Vendor id" of all acknowledge devices
  * </ol>
  */
-final class DeviceDiscoveryAction extends FeatureAction {
+final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
     private static final String TAG = "DeviceDiscoveryAction";
 
     // State in which the action is waiting for device polling.
@@ -60,7 +60,7 @@
          *
          * @param deviceInfos a list of all non-local devices. It can be empty list.
          */
-        void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos);
+        void onDeviceDiscoveryDone(List<HdmiDeviceInfo> deviceInfos);
     }
 
     // An internal container used to keep track of device information during
@@ -72,14 +72,14 @@
         private int mPortId = Constants.INVALID_PORT_ID;
         private int mVendorId = Constants.UNKNOWN_VENDOR_ID;
         private String mDisplayName = "";
-        private int mDeviceType = HdmiCecDeviceInfo.DEVICE_INACTIVE;
+        private int mDeviceType = HdmiDeviceInfo.DEVICE_INACTIVE;
 
         private DeviceInfo(int logicalAddress) {
             mLogicalAddress = logicalAddress;
         }
 
-        private HdmiCecDeviceInfo toHdmiCecDeviceInfo() {
-            return new HdmiCecDeviceInfo(mLogicalAddress, mPhysicalAddress, mPortId, mDeviceType,
+        private HdmiDeviceInfo toHdmiDeviceInfo() {
+            return new HdmiDeviceInfo(mLogicalAddress, mPhysicalAddress, mPortId, mDeviceType,
                     mVendorId, mDisplayName);
         }
     }
@@ -314,9 +314,9 @@
 
     private void wrapUpAndFinish() {
         Slog.v(TAG, "---------Wrap up Device Discovery:[" + mDevices.size() + "]---------");
-        ArrayList<HdmiCecDeviceInfo> result = new ArrayList<>();
+        ArrayList<HdmiDeviceInfo> result = new ArrayList<>();
         for (DeviceInfo info : mDevices) {
-            HdmiCecDeviceInfo cecDeviceInfo = info.toHdmiCecDeviceInfo();
+            HdmiDeviceInfo cecDeviceInfo = info.toHdmiDeviceInfo();
             Slog.v(TAG, " DeviceInfo: " + cecDeviceInfo);
             result.add(cecDeviceInfo);
         }
diff --git a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
index 1106810..d965caa 100644
--- a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
@@ -17,20 +17,20 @@
  */
 
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiPlaybackClient;
+import android.hardware.hdmi.HdmiPlaybackClient.DisplayStatusCallback;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.RemoteException;
 import android.util.Slog;
 
 /**
- * Feature action that queries the power status of other device.
- *
- * This action is initiated via {@link HdmiControlManager#queryDisplayStatus()} from
- * the Android system working as playback device to get the power status of TV device.
- *
- * <p>Package-private, accessed by {@link HdmiControlService} only.
+ * Feature action that queries the power status of other device. This action is initiated via
+ * {@link HdmiPlaybackClient#queryDisplayStatus(DisplayStatusCallback)} from the Android system
+ * working as playback device to get the power status of TV device.
+ * <p>
+ * Package-private, accessed by {@link HdmiControlService} only.
  */
-
-final class DevicePowerStatusAction extends FeatureAction {
+final class DevicePowerStatusAction extends HdmiCecFeatureAction {
     private static final String TAG = "DevicePowerStatusAction";
 
     // State in which the action is waiting for <Report Power Status>.
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index 018b34d..ed37ead 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiTvClient;
 import android.hardware.hdmi.IHdmiControlCallback;
@@ -33,7 +33,7 @@
  * for a new active source. It does its best to wake up the target in standby mode
  * before issuing the command &gt;Set Stream path&lt;.
  */
-final class DeviceSelectAction extends FeatureAction {
+final class DeviceSelectAction extends HdmiCecFeatureAction {
     private static final String TAG = "DeviceSelect";
 
     // Time in milliseconds we wait for the device power status to switch to 'Standby'
@@ -67,7 +67,7 @@
     // before we give up and mark the action as failure.
     private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 4;
 
-    private final HdmiCecDeviceInfo mTarget;
+    private final HdmiDeviceInfo mTarget;
     private final IHdmiControlCallback mCallback;
     private final HdmiCecMessage mGivePowerStatus;
 
@@ -81,7 +81,7 @@
      * @param callback callback object
      */
     public DeviceSelectAction(HdmiCecLocalDeviceTv source,
-            HdmiCecDeviceInfo target, IHdmiControlCallback callback) {
+            HdmiDeviceInfo target, IHdmiControlCallback callback) {
         super(source);
         mCallback = callback;
         mTarget = target;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index c33b35f..10e4b6e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -65,16 +65,6 @@
 
     private static final byte[] EMPTY_BODY = EmptyArray.BYTE;
 
-    // A message to pass cec send command to IO looper.
-    private static final int MSG_SEND_CEC_COMMAND = 1;
-    // A message to delegate logical allocation to IO looper.
-    private static final int MSG_ALLOCATE_LOGICAL_ADDRESS = 2;
-
-    // Message types to handle incoming message in main service looper.
-    private final static int MSG_RECEIVE_CEC_COMMAND = 1;
-    // A message to report allocated logical address to main control looper.
-    private final static int MSG_REPORT_LOGICAL_ADDRESS = 2;
-
     private static final int NUM_LOGICAL_ADDRESS = 16;
 
     // Predicate for whether the given logical address is remote device's one or not.
@@ -196,7 +186,15 @@
             int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
             if (curAddress != Constants.ADDR_UNREGISTERED
                     && deviceType == HdmiUtils.getTypeFromAddress(curAddress)) {
-                if (!sendPollMessage(curAddress, curAddress, HdmiConfig.ADDRESS_ALLOCATION_RETRY)) {
+                int failedPollingCount = 0;
+                for (int j = 0; j < HdmiConfig.ADDRESS_ALLOCATION_RETRY; ++j) {
+                    if (!sendPollMessage(curAddress, curAddress, 1)) {
+                        failedPollingCount++;
+                    }
+                }
+
+                // Pick logical address if failed ratio is more than a half of all retries.
+                if (failedPollingCount * 2 >  HdmiConfig.ADDRESS_ALLOCATION_RETRY) {
                     logicalAddress = curAddress;
                     break;
                 }
@@ -206,7 +204,7 @@
         final int assignedAddress = logicalAddress;
         if (callback != null) {
             runOnServiceThread(new Runnable() {
-                    @Override
+                @Override
                 public void run() {
                     callback.onAllocated(deviceType, assignedAddress);
                 }
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
similarity index 82%
rename from services/core/java/com/android/server/hdmi/FeatureAction.java
rename to services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index b7b2f90..f32e660 100644
--- a/services/core/java/com/android/server/hdmi/FeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -29,21 +29,19 @@
 
 /**
  * Encapsulates a sequence of CEC/MHL command exchange for a certain feature.
- *
- * <p>Many CEC/MHL features are accomplished by CEC devices on the bus exchanging
- * more than one command. {@link FeatureAction} represents the life cycle of the communication,
- * manages the state as the process progresses, and if necessary, returns the result
- * to the caller which initiates the action, through the callback given at the creation
- * of the object. All the actual action classes inherit FeatureAction.
- *
- * <p>More than one FeatureAction objects can be up and running simultaneously,
- * maintained by {@link HdmiCecLocalDevice}. Each action is passed a new command
- * arriving from the bus, and either consumes it if the command is what the action expects,
- * or yields it to other action.
- *
- * Declared as package private, accessed by {@link HdmiControlService} only.
+ * <p>
+ * Many CEC/MHL features are accomplished by CEC devices on the bus exchanging more than one
+ * command. {@link HdmiCecFeatureAction} represents the life cycle of the communication, manages the
+ * state as the process progresses, and if necessary, returns the result to the caller which
+ * initiates the action, through the callback given at the creation of the object. All the actual
+ * action classes inherit FeatureAction.
+ * <p>
+ * More than one FeatureAction objects can be up and running simultaneously, maintained by
+ * {@link HdmiCecLocalDevice}. Each action is passed a new command arriving from the bus, and either
+ * consumes it if the command is what the action expects, or yields it to other action. Declared as
+ * package private, accessed by {@link HdmiControlService} only.
  */
-abstract class FeatureAction {
+abstract class HdmiCecFeatureAction {
     private static final String TAG = "FeatureAction";
 
     // Timer handler message used for timeout event
@@ -61,9 +59,9 @@
     // Timer that manages timeout events.
     protected ActionTimer mActionTimer;
 
-    private ArrayList<Pair<FeatureAction, Runnable>> mOnFinishedCallbacks;
+    private ArrayList<Pair<HdmiCecFeatureAction, Runnable>> mOnFinishedCallbacks;
 
-    FeatureAction(HdmiCecLocalDevice source) {
+    HdmiCecFeatureAction(HdmiCecLocalDevice source) {
         mSource = source;
         mService = mSource.getService();
         mActionTimer = createActionTimer(mService.getServiceLooper());
@@ -173,11 +171,11 @@
         mService.sendCecCommand(cmd, callback);
     }
 
-    protected final void addAndStartAction(FeatureAction action) {
+    protected final void addAndStartAction(HdmiCecFeatureAction action) {
         mSource.addAndStartAction(action);
     }
 
-    protected final <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
+    protected final <T extends HdmiCecFeatureAction> List<T> getActions(final Class<T> clazz) {
         return mSource.getActions(clazz);
     }
 
@@ -191,16 +189,16 @@
      *
      * @param action
      */
-    protected final void removeAction(FeatureAction action) {
+    protected final void removeAction(HdmiCecFeatureAction action) {
         mSource.removeAction(action);
     }
 
-    protected final <T extends FeatureAction> void removeAction(final Class<T> clazz) {
+    protected final <T extends HdmiCecFeatureAction> void removeAction(final Class<T> clazz) {
         mSource.removeActionExcept(clazz, null);
     }
 
-    protected final <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
-            final FeatureAction exception) {
+    protected final <T extends HdmiCecFeatureAction> void removeActionExcept(final Class<T> clazz,
+            final HdmiCecFeatureAction exception) {
         mSource.removeActionExcept(clazz, exception);
     }
 
@@ -233,7 +231,7 @@
             removeAction(this);
         }
         if (mOnFinishedCallbacks != null) {
-            for (Pair<FeatureAction, Runnable> actionCallbackPair: mOnFinishedCallbacks) {
+            for (Pair<HdmiCecFeatureAction, Runnable> actionCallbackPair: mOnFinishedCallbacks) {
                 if (actionCallbackPair.first.mState != STATE_NONE) {
                     actionCallbackPair.second.run();
                 }
@@ -269,7 +267,7 @@
                 getSourceAddress(), targetAddress));
     }
 
-    protected final void addOnFinishedCallback(FeatureAction action, Runnable runnable) {
+    protected final void addOnFinishedCallback(HdmiCecFeatureAction action, Runnable runnable) {
         if (mOnFinishedCallbacks == null) {
             mOnFinishedCallbacks = new ArrayList<>();
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index cf16fa3..be4c834 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -47,7 +47,7 @@
     protected final int mDeviceType;
     protected int mAddress;
     protected int mPreferredAddress;
-    protected HdmiCecDeviceInfo mDeviceInfo;
+    protected HdmiDeviceInfo mDeviceInfo;
 
     static class ActiveSource {
         int logicalAddress;
@@ -102,7 +102,7 @@
 
     // A collection of FeatureAction.
     // Note that access to this collection should happen in service thread.
-    private final LinkedList<FeatureAction> mActions = new LinkedList<>();
+    private final LinkedList<HdmiCecFeatureAction> mActions = new LinkedList<>();
 
     private final Handler mHandler = new Handler () {
         @Override
@@ -135,9 +135,9 @@
     // Factory method that returns HdmiCecLocalDevice of corresponding type.
     static HdmiCecLocalDevice create(HdmiControlService service, int deviceType) {
         switch (deviceType) {
-        case HdmiCecDeviceInfo.DEVICE_TV:
+        case HdmiDeviceInfo.DEVICE_TV:
             return new HdmiCecLocalDeviceTv(service);
-        case HdmiCecDeviceInfo.DEVICE_PLAYBACK:
+        case HdmiDeviceInfo.DEVICE_PLAYBACK:
             return new HdmiCecLocalDevicePlayback(service);
         default:
             return null;
@@ -250,7 +250,7 @@
     @ServiceThreadOnly
     private boolean dispatchMessageToAction(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        for (FeatureAction action : mActions) {
+        for (HdmiCecFeatureAction action : mActions) {
             if (action.processCommand(message)) {
                 return true;
             }
@@ -460,13 +460,13 @@
     }
 
     @ServiceThreadOnly
-    HdmiCecDeviceInfo getDeviceInfo() {
+    HdmiDeviceInfo getDeviceInfo() {
         assertRunOnServiceThread();
         return mDeviceInfo;
     }
 
     @ServiceThreadOnly
-    void setDeviceInfo(HdmiCecDeviceInfo info) {
+    void setDeviceInfo(HdmiDeviceInfo info) {
         assertRunOnServiceThread();
         mDeviceInfo = info;
     }
@@ -486,7 +486,7 @@
     }
 
     @ServiceThreadOnly
-    void addAndStartAction(final FeatureAction action) {
+    void addAndStartAction(final HdmiCecFeatureAction action) {
         assertRunOnServiceThread();
         if (mService.isPowerStandbyOrTransient()) {
             Slog.w(TAG, "Skip the action during Standby: " + action);
@@ -498,9 +498,9 @@
 
     // See if we have an action of a given type in progress.
     @ServiceThreadOnly
-    <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
+    <T extends HdmiCecFeatureAction> boolean hasAction(final Class<T> clazz) {
         assertRunOnServiceThread();
-        for (FeatureAction action : mActions) {
+        for (HdmiCecFeatureAction action : mActions) {
             if (action.getClass().equals(clazz)) {
                 return true;
             }
@@ -510,10 +510,10 @@
 
     // Returns all actions matched with given class type.
     @ServiceThreadOnly
-    <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
+    <T extends HdmiCecFeatureAction> List<T> getActions(final Class<T> clazz) {
         assertRunOnServiceThread();
         List<T> actions = Collections.<T>emptyList();
-        for (FeatureAction action : mActions) {
+        for (HdmiCecFeatureAction action : mActions) {
             if (action.getClass().equals(clazz)) {
                 if (actions.isEmpty()) {
                     actions = new ArrayList<T>();
@@ -525,12 +525,12 @@
     }
 
     /**
-     * Remove the given {@link FeatureAction} object from the action queue.
+     * Remove the given {@link HdmiCecFeatureAction} object from the action queue.
      *
-     * @param action {@link FeatureAction} to remove
+     * @param action {@link HdmiCecFeatureAction} to remove
      */
     @ServiceThreadOnly
-    void removeAction(final FeatureAction action) {
+    void removeAction(final HdmiCecFeatureAction action) {
         assertRunOnServiceThread();
         action.finish(false);
         mActions.remove(action);
@@ -539,19 +539,19 @@
 
     // Remove all actions matched with the given Class type.
     @ServiceThreadOnly
-    <T extends FeatureAction> void removeAction(final Class<T> clazz) {
+    <T extends HdmiCecFeatureAction> void removeAction(final Class<T> clazz) {
         assertRunOnServiceThread();
         removeActionExcept(clazz, null);
     }
 
     // Remove all actions matched with the given Class type besides |exception|.
     @ServiceThreadOnly
-    <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
-            final FeatureAction exception) {
+    <T extends HdmiCecFeatureAction> void removeActionExcept(final Class<T> clazz,
+            final HdmiCecFeatureAction exception) {
         assertRunOnServiceThread();
-        Iterator<FeatureAction> iter = mActions.iterator();
+        Iterator<HdmiCecFeatureAction> iter = mActions.iterator();
         while (iter.hasNext()) {
-            FeatureAction action = iter.next();
+            HdmiCecFeatureAction action = iter.next();
             if (action != exception && action.getClass().equals(clazz)) {
                 action.finish(false);
                 iter.remove();
@@ -604,7 +604,7 @@
         setActiveSource(newActive.logicalAddress, newActive.physicalAddress);
     }
 
-    void setActiveSource(HdmiCecDeviceInfo info) {
+    void setActiveSource(HdmiDeviceInfo info) {
         setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress());
     }
 
@@ -698,9 +698,9 @@
 
         // If all actions are not cleared in DEVICE_CLEANUP_TIMEOUT, enforce to finish them.
         // onCleard will be called at the last action's finish method.
-        Iterator<FeatureAction> iter = mActions.iterator();
+        Iterator<HdmiCecFeatureAction> iter = mActions.iterator();
         while (iter.hasNext()) {
-            FeatureAction action = iter.next();
+            HdmiCecFeatureAction action = iter.next();
             action.finish(false);
             iter.remove();
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index b05f1af..ae7fd82 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.RemoteException;
@@ -34,7 +34,7 @@
     private boolean mIsActiveSource = false;
 
     HdmiCecLocalDevicePlayback(HdmiControlService service) {
-        super(service, HdmiCecDeviceInfo.DEVICE_PLAYBACK);
+        super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
     }
 
     @Override
@@ -140,7 +140,7 @@
         if (physicalAddress != mService.getPhysicalAddress()) {
             mIsActiveSource = false;
             if (mService.isPowerOnOrTransient()) {
-                mService.standby();
+                mService.nap();
             }
             return true;
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index aee764b..fb4fa7f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -30,7 +30,7 @@
 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
 
 import android.content.Intent;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiRecordSources;
 import android.hardware.hdmi.HdmiTimerRecordSources;
@@ -41,6 +41,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -52,7 +53,9 @@
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 
@@ -91,15 +94,15 @@
 
     // Copy of mDeviceInfos to guarantee thread-safety.
     @GuardedBy("mLock")
-    private List<HdmiCecDeviceInfo> mSafeAllDeviceInfos = Collections.emptyList();
+    private List<HdmiDeviceInfo> mSafeAllDeviceInfos = Collections.emptyList();
     // All external cec input(source) devices. Does not include system audio device.
     @GuardedBy("mLock")
-    private List<HdmiCecDeviceInfo> mSafeExternalInputs = Collections.emptyList();
+    private List<HdmiDeviceInfo> mSafeExternalInputs = Collections.emptyList();
 
     // Map-like container of all cec devices including local ones.
     // A logical address of device is used as key of container.
     // This is not thread-safe. For external purpose use mSafeDeviceInfos.
-    private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos = new SparseArray<>();
+    private final SparseArray<HdmiDeviceInfo> mDeviceInfos = new SparseArray<>();
 
     // If true, TV going to standby mode puts other devices also to standby.
     private boolean mAutoDeviceOff;
@@ -109,8 +112,12 @@
 
     private final HdmiCecStandbyModeHandler mStandbyHandler;
 
+    // Set of physical addresses of CEC switches on the CEC bus. Managed independently from
+    // other CEC devices since they might not have logical address.
+    private final ArraySet<Integer> mCecSwitches = new ArraySet<Integer>();
+
     HdmiCecLocalDeviceTv(HdmiControlService service) {
-        super(service, HdmiCecDeviceInfo.DEVICE_TV);
+        super(service, HdmiDeviceInfo.DEVICE_TV);
         mPrevPortId = Constants.INVALID_PORT_ID;
         mAutoDeviceOff = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
                 true);
@@ -126,6 +133,7 @@
                 mAddress, mService.getPhysicalAddress(), mDeviceType));
         mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
                 mAddress, mService.getVendorId()));
+        mCecSwitches.add(mService.getPhysicalAddress());  // TV is a CEC switch too.
         launchRoutingControl(reason != HdmiControlService.INITIATED_BY_ENABLE_CEC &&
                 reason != HdmiControlService.INITIATED_BY_BOOT_UP);
         launchDeviceDiscovery();
@@ -179,14 +187,14 @@
             return;
         }
         if (!mService.isControlEnabled()) {
-            HdmiCecDeviceInfo info = getDeviceInfo(targetAddress);
+            HdmiDeviceInfo info = getDeviceInfo(targetAddress);
             if (info != null) {
                 setActiveSource(info);
             }
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
             return;
         }
-        HdmiCecDeviceInfo targetDevice = getDeviceInfo(targetAddress);
+        HdmiDeviceInfo targetDevice = getDeviceInfo(targetAddress);
         if (targetDevice == null) {
             invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
             return;
@@ -271,10 +279,10 @@
         // Show OSD port change banner
         if (notifyInputChange) {
             ActiveSource activeSource = getActiveSource();
-            HdmiCecDeviceInfo info = getDeviceInfo(activeSource.logicalAddress);
+            HdmiDeviceInfo info = getDeviceInfo(activeSource.logicalAddress);
             if (info == null) {
-                info = new HdmiCecDeviceInfo(Constants.ADDR_INVALID, path, portId,
-                        HdmiCecDeviceInfo.DEVICE_RESERVED, 0, null);
+                info = new HdmiDeviceInfo(Constants.ADDR_INVALID, path, portId,
+                        HdmiDeviceInfo.DEVICE_RESERVED, 0, null);
             }
             mService.invokeInputChangeListener(info);
         }
@@ -380,7 +388,7 @@
         if (portId != Constants.INVALID_PORT_ID) {
             // TODO: Do this only if TV is not showing multiview like PIP/PAP.
 
-            HdmiCecDeviceInfo inactiveSource = getDeviceInfo(message.getSource());
+            HdmiDeviceInfo inactiveSource = getDeviceInfo(message.getSource());
             if (inactiveSource == null) {
                 return true;
             }
@@ -426,15 +434,27 @@
     @ServiceThreadOnly
     protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
         assertRunOnServiceThread();
+        int path = HdmiUtils.twoBytesToInt(message.getParams());
+        int address = message.getSource();
+
+        // Build cec switch list with pure CEC switch, AVR.
+        if (address == Constants.ADDR_UNREGISTERED) {
+            int type = message.getParams()[2];
+            if (type == HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH) {
+                mCecSwitches.add(path);
+                updateSafeDeviceInfoList();
+                return true;  // Pure switch does not need further processing. Return here.
+            } else if (type == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
+                mCecSwitches.add(path);
+            }
+        }
+
         // Ignore if [Device Discovery Action] is going on.
         if (hasAction(DeviceDiscoveryAction.class)) {
-            Slog.i(TAG, "Ignore unrecognizable <Report Physical Address> "
-                    + "because Device Discovery Action is on-going:" + message);
+            Slog.i(TAG, "Ignored while Device Discovery Action is in progress: " + message);
             return true;
         }
 
-        int path = HdmiUtils.twoBytesToInt(message.getParams());
-        int address = message.getSource();
         if (!isInDeviceList(path, address)) {
             handleNewDeviceAtTheTailOfActivePath(path);
         }
@@ -552,7 +572,7 @@
     @ServiceThreadOnly
     protected boolean handleSetOsdName(HdmiCecMessage message) {
         int source = message.getSource();
-        HdmiCecDeviceInfo deviceInfo = getDeviceInfo(source);
+        HdmiDeviceInfo deviceInfo = getDeviceInfo(source);
         // If the device is not in device list, ignore it.
         if (deviceInfo == null) {
             Slog.e(TAG, "No source device info for <Set Osd Name>." + message);
@@ -571,7 +591,7 @@
             return true;
         }
 
-        addCecDevice(new HdmiCecDeviceInfo(deviceInfo.getLogicalAddress(),
+        addCecDevice(new HdmiDeviceInfo(deviceInfo.getLogicalAddress(),
                 deviceInfo.getPhysicalAddress(), deviceInfo.getPortId(),
                 deviceInfo.getDeviceType(), deviceInfo.getVendorId(), osdName));
         return true;
@@ -584,8 +604,8 @@
         DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
                 new DeviceDiscoveryCallback() {
                     @Override
-                    public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) {
-                        for (HdmiCecDeviceInfo info : deviceInfos) {
+                    public void onDeviceDiscoveryDone(List<HdmiDeviceInfo> deviceInfos) {
+                        for (HdmiDeviceInfo info : deviceInfos) {
                             addCecDevice(info);
                         }
 
@@ -618,8 +638,8 @@
     @ServiceThreadOnly
     private void clearDeviceInfoList() {
         assertRunOnServiceThread();
-        for (HdmiCecDeviceInfo info : mSafeExternalInputs) {
-            mService.invokeDeviceEventListeners(info, false);
+        for (HdmiDeviceInfo info : mSafeExternalInputs) {
+            invokeDeviceEventListener(info, false);
         }
         mDeviceInfos.clear();
         updateSafeDeviceInfoList();
@@ -634,7 +654,7 @@
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
             return;
         }
-        HdmiCecDeviceInfo avr = getAvrDeviceInfo();
+        HdmiDeviceInfo avr = getAvrDeviceInfo();
         if (avr == null) {
             setSystemAudioMode(false, true);
             invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
@@ -738,7 +758,7 @@
     @ServiceThreadOnly
     private void startArcAction(boolean enabled) {
         assertRunOnServiceThread();
-        HdmiCecDeviceInfo info = getAvrDeviceInfo();
+        HdmiDeviceInfo info = getAvrDeviceInfo();
         if (info == null) {
             return;
         }
@@ -794,7 +814,7 @@
         // Remove existing volume action.
         removeAction(VolumeControlAction.class);
 
-        HdmiCecDeviceInfo avr = getAvrDeviceInfo();
+        HdmiDeviceInfo avr = getAvrDeviceInfo();
         addAndStartAction(VolumeControlAction.ofVolumeChange(this, avr.getLogicalAddress(),
                 cecVolume, delta > 0));
     }
@@ -808,16 +828,10 @@
 
         // Remove existing volume action.
         removeAction(VolumeControlAction.class);
-        HdmiCecDeviceInfo avr = getAvrDeviceInfo();
+        HdmiDeviceInfo avr = getAvrDeviceInfo();
         addAndStartAction(VolumeControlAction.ofMute(this, avr.getLogicalAddress(), mute));
     }
 
-    private boolean isSystemAudioOn() {
-        synchronized (mLock) {
-            return mSystemAudioActivated;
-        }
-    }
-
     @Override
     @ServiceThreadOnly
     protected boolean handleInitiateArc(HdmiCecMessage message) {
@@ -920,19 +934,19 @@
     }
 
     /**
-     * Add a new {@link HdmiCecDeviceInfo}. It returns old device info which has the same
+     * Add a new {@link HdmiDeviceInfo}. It returns old device info which has the same
      * logical address as new device info's.
      *
      * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
      *
-     * @param deviceInfo a new {@link HdmiCecDeviceInfo} to be added.
-     * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo}
+     * @param deviceInfo a new {@link HdmiDeviceInfo} to be added.
+     * @return {@code null} if it is new device. Otherwise, returns old {@HdmiDeviceInfo}
      *         that has the same logical address as new one has.
      */
     @ServiceThreadOnly
-    private HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
+    private HdmiDeviceInfo addDeviceInfo(HdmiDeviceInfo deviceInfo) {
         assertRunOnServiceThread();
-        HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
+        HdmiDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
         if (oldDeviceInfo != null) {
             removeDeviceInfo(deviceInfo.getLogicalAddress());
         }
@@ -943,17 +957,17 @@
 
     /**
      * Remove a device info corresponding to the given {@code logicalAddress}.
-     * It returns removed {@link HdmiCecDeviceInfo} if exists.
+     * It returns removed {@link HdmiDeviceInfo} if exists.
      *
      * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
      *
      * @param logicalAddress logical address of device to be removed
-     * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null}
+     * @return removed {@link HdmiDeviceInfo} it exists. Otherwise, returns {@code null}
      */
     @ServiceThreadOnly
-    private HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) {
+    private HdmiDeviceInfo removeDeviceInfo(int logicalAddress) {
         assertRunOnServiceThread();
-        HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
+        HdmiDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
         if (deviceInfo != null) {
             mDeviceInfos.remove(logicalAddress);
         }
@@ -962,20 +976,21 @@
     }
 
     /**
-     * Return a list of all {@link HdmiCecDeviceInfo}.
+     * Return a list of all {@link HdmiDeviceInfo}.
      *
      * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
-     * This is not thread-safe. For thread safety, call {@link #getSafeDeviceInfoList(boolean)}.
+     * This is not thread-safe. For thread safety, call {@link #getSafeExternalInputs} which
+     * does not include local device.
      */
     @ServiceThreadOnly
-    List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includelLocalDevice) {
+    List<HdmiDeviceInfo> getDeviceInfoList(boolean includelLocalDevice) {
         assertRunOnServiceThread();
         if (includelLocalDevice) {
             return HdmiUtils.sparseArrayToList(mDeviceInfos);
         } else {
-            ArrayList<HdmiCecDeviceInfo> infoList = new ArrayList<>();
+            ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
             for (int i = 0; i < mDeviceInfos.size(); ++i) {
-                HdmiCecDeviceInfo info = mDeviceInfos.valueAt(i);
+                HdmiDeviceInfo info = mDeviceInfos.valueAt(i);
                 if (!isLocalDeviceAddress(info.getLogicalAddress())) {
                     infoList.add(info);
                 }
@@ -987,7 +1002,7 @@
     /**
      * Return external input devices.
      */
-    List<HdmiCecDeviceInfo> getSafeExternalInputs() {
+    List<HdmiDeviceInfo> getSafeExternalInputs() {
         synchronized (mLock) {
             return mSafeExternalInputs;
         }
@@ -996,8 +1011,8 @@
     @ServiceThreadOnly
     private void updateSafeDeviceInfoList() {
         assertRunOnServiceThread();
-        List<HdmiCecDeviceInfo> copiedDevices = HdmiUtils.sparseArrayToList(mDeviceInfos);
-        List<HdmiCecDeviceInfo> externalInputs = getInputDevices();
+        List<HdmiDeviceInfo> copiedDevices = HdmiUtils.sparseArrayToList(mDeviceInfos);
+        List<HdmiDeviceInfo> externalInputs = getInputDevices();
         synchronized (mLock) {
             mSafeAllDeviceInfos = copiedDevices;
             mSafeExternalInputs = externalInputs;
@@ -1010,20 +1025,56 @@
      * <p>Note that this effectively excludes non-source devices like system audio,
      * secondary TV.
      */
-    private List<HdmiCecDeviceInfo> getInputDevices() {
-        ArrayList<HdmiCecDeviceInfo> infoList = new ArrayList<>();
+    private List<HdmiDeviceInfo> getInputDevices() {
+        ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
         for (int i = 0; i < mDeviceInfos.size(); ++i) {
-            HdmiCecDeviceInfo info = mDeviceInfos.valueAt(i);
+            HdmiDeviceInfo info = mDeviceInfos.valueAt(i);
             if (isLocalDeviceAddress(i)) {
                 continue;
             }
-            if (info.isSourceType()) {
+            if (info.isSourceType() && !hideDevicesBehindLegacySwitch(info)) {
                 infoList.add(info);
             }
         }
         return infoList;
     }
 
+    // Check if we are hiding CEC devices connected to a legacy (non-CEC) switch.
+    // Returns true if the policy is set to true, and the device to check does not have
+    // a parent CEC device (which should be the CEC-enabled switch) in the list.
+    private boolean hideDevicesBehindLegacySwitch(HdmiDeviceInfo info) {
+        return HdmiConfig.HIDE_DEVICES_BEHIND_LEGACY_SWITCH
+                && !isConnectedToCecSwitch(info.getPhysicalAddress(), mCecSwitches);
+    }
+
+    private static boolean isConnectedToCecSwitch(int path, Collection<Integer> switches) {
+        for (int switchPath : switches) {
+            if (isParentPath(switchPath, path)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isParentPath(int parentPath, int childPath) {
+        // (A000, AB00) (AB00, ABC0), (ABC0, ABCD)
+        // If child's last non-zero nibble is removed, the result equals to the parent.
+        for (int i = 0; i <= 12; i += 4) {
+            int nibble = (childPath >> i) & 0xF;
+            if (nibble != 0) {
+                int parentNibble = (parentPath >> i) & 0xF;
+                return parentNibble == 0 && (childPath >> i+4) == (parentPath >> i+4);
+            }
+        }
+        return false;
+    }
+
+    private void invokeDeviceEventListener(HdmiDeviceInfo info, boolean activated) {
+        if (!hideDevicesBehindLegacySwitch(info)) {
+            mService.invokeDeviceEventListeners(info, activated);
+        }
+    }
+
     @ServiceThreadOnly
     private boolean isLocalDeviceAddress(int address) {
         assertRunOnServiceThread();
@@ -1036,23 +1087,23 @@
     }
 
     @ServiceThreadOnly
-    HdmiCecDeviceInfo getAvrDeviceInfo() {
+    HdmiDeviceInfo getAvrDeviceInfo() {
         assertRunOnServiceThread();
         return getDeviceInfo(Constants.ADDR_AUDIO_SYSTEM);
     }
 
     /**
-     * Return a {@link HdmiCecDeviceInfo} corresponding to the given {@code logicalAddress}.
+     * Return a {@link HdmiDeviceInfo} corresponding to the given {@code logicalAddress}.
      *
      * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
      * This is not thread-safe. For thread safety, call {@link #getSafeDeviceInfo(int)}.
      *
      * @param logicalAddress logical address to be retrieved
-     * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}.
+     * @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}.
      *         Returns null if no logical address matched
      */
     @ServiceThreadOnly
-    HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
+    HdmiDeviceInfo getDeviceInfo(int logicalAddress) {
         assertRunOnServiceThread();
         return mDeviceInfos.get(logicalAddress);
     }
@@ -1061,7 +1112,7 @@
         return getSafeAvrDeviceInfo() != null;
     }
 
-    HdmiCecDeviceInfo getSafeAvrDeviceInfo() {
+    HdmiDeviceInfo getSafeAvrDeviceInfo() {
         return getSafeDeviceInfo(Constants.ADDR_AUDIO_SYSTEM);
     }
 
@@ -1069,10 +1120,10 @@
      * Thread safe version of {@link #getDeviceInfo(int)}.
      *
      * @param logicalAddress logical address to be retrieved
-     * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}.
+     * @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}.
      *         Returns null if no logical address matched
      */
-    HdmiCecDeviceInfo getSafeDeviceInfo(int logicalAddress) {
+    HdmiDeviceInfo getSafeDeviceInfo(int logicalAddress) {
         synchronized (mLock) {
             return mSafeAllDeviceInfos.get(logicalAddress);
         }
@@ -1085,14 +1136,14 @@
      * @param info device info of a new device.
      */
     @ServiceThreadOnly
-    final void addCecDevice(HdmiCecDeviceInfo info) {
+    final void addCecDevice(HdmiDeviceInfo info) {
         assertRunOnServiceThread();
         addDeviceInfo(info);
         if (info.getLogicalAddress() == mAddress) {
             // The addition of TV device itself should not be notified.
             return;
         }
-        mService.invokeDeviceEventListeners(info, true);
+        invokeDeviceEventListener(info, true);
     }
 
     /**
@@ -1103,10 +1154,10 @@
     @ServiceThreadOnly
     final void removeCecDevice(int address) {
         assertRunOnServiceThread();
-        HdmiCecDeviceInfo info = removeDeviceInfo(address);
+        HdmiDeviceInfo info = removeDeviceInfo(address);
 
         mCecMessageCache.flushMessagesFrom(address);
-        mService.invokeDeviceEventListeners(info, false);
+        invokeDeviceEventListener(info, false);
     }
 
     @ServiceThreadOnly
@@ -1153,17 +1204,17 @@
     }
 
     /**
-     * Returns the {@link HdmiCecDeviceInfo} instance whose physical address matches
+     * Returns the {@link HdmiDeviceInfo} instance whose physical address matches
      * the given routing path. CEC devices use routing path for its physical address to
      * describe the hierarchy of the devices in the network.
      *
      * @param path routing path or physical address
-     * @return {@link HdmiCecDeviceInfo} if the matched info is found; otherwise null
+     * @return {@link HdmiDeviceInfo} if the matched info is found; otherwise null
      */
     @ServiceThreadOnly
-    final HdmiCecDeviceInfo getDeviceInfoByPath(int path) {
+    final HdmiDeviceInfo getDeviceInfoByPath(int path) {
         assertRunOnServiceThread();
-        for (HdmiCecDeviceInfo info : getDeviceInfoList(false)) {
+        for (HdmiDeviceInfo info : getDeviceInfoList(false)) {
             if (info.getPhysicalAddress() == path) {
                 return info;
             }
@@ -1183,7 +1234,7 @@
     @ServiceThreadOnly
     boolean isInDeviceList(int logicalAddress, int physicalAddress) {
         assertRunOnServiceThread();
-        HdmiCecDeviceInfo device = getDeviceInfo(logicalAddress);
+        HdmiDeviceInfo device = getDeviceInfo(logicalAddress);
         if (device == null) {
             return false;
         }
@@ -1195,6 +1246,9 @@
     void onHotplug(int portId, boolean connected) {
         assertRunOnServiceThread();
 
+        if (!connected) {
+            removeCecSwitches(portId);
+        }
         // Tv device will have permanent HotplugDetectionAction.
         List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class);
         if (!hotplugActions.isEmpty()) {
@@ -1205,6 +1259,16 @@
         }
     }
 
+    private void removeCecSwitches(int portId) {
+        Iterator<Integer> it = mCecSwitches.iterator();
+        while (!it.hasNext()) {
+            int path = it.next();
+            if (pathToPortId(path) == portId) {
+                it.remove();
+            }
+        }
+    }
+
     @ServiceThreadOnly
     void setAutoDeviceOff(boolean enabled) {
         assertRunOnServiceThread();
@@ -1268,7 +1332,7 @@
     @ServiceThreadOnly
     private void disableArcIfExist() {
         assertRunOnServiceThread();
-        HdmiCecDeviceInfo avr = getAvrDeviceInfo();
+        HdmiDeviceInfo avr = getAvrDeviceInfo();
         if (avr == null) {
             return;
         }
@@ -1358,10 +1422,10 @@
     }
 
     private boolean checkRecorder(int recorderAddress) {
-        HdmiCecDeviceInfo device = getDeviceInfo(recorderAddress);
+        HdmiDeviceInfo device = getDeviceInfo(recorderAddress);
         return (device != null)
                 && (HdmiUtils.getTypeFromAddress(recorderAddress)
-                        == HdmiCecDeviceInfo.DEVICE_RECORDER);
+                        == HdmiDeviceInfo.DEVICE_RECORDER);
     }
 
     private boolean checkRecordSource(byte[] recordSource) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
index 970568a..433e93f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
@@ -16,9 +16,6 @@
 
 package com.android.server.hdmi;
 
-import android.os.Parcel;
-import android.os.Parcelable;
-
 import libcore.util.EmptyArray;
 
 import java.util.Arrays;
@@ -28,12 +25,9 @@
  * HDMI cable to communicate with one another. A message is defined by its
  * source and destination address, command (or opcode), and optional parameters.
  */
-public final class HdmiCecMessage implements Parcelable {
-
+public final class HdmiCecMessage {
     public static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
 
-    private static final int MAX_MESSAGE_LENGTH = 16;
-
     private final int mSource;
     private final int mDestination;
 
@@ -91,53 +85,6 @@
         return mParams;
     }
 
-    /**
-     * Describe the kinds of special objects contained in this Parcelable's
-     * marshalled representation.
-     */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * Flatten this object in to a Parcel.
-     *
-     * @param dest The Parcel in which the object should be written.
-     * @param flags Additional flags about how the object should be written.
-     *        May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mSource);
-        dest.writeInt(mDestination);
-        dest.writeInt(mOpcode);
-        dest.writeInt(mParams.length);
-        dest.writeByteArray(mParams);
-    }
-
-    public static final Parcelable.Creator<HdmiCecMessage> CREATOR
-            = new Parcelable.Creator<HdmiCecMessage>() {
-        /**
-         * Rebuild a HdmiCecMessage previously stored with writeToParcel().
-         * @param p HdmiCecMessage object to read the Rating from
-         * @return a new HdmiCecMessage created from the data in the parcel
-         */
-        @Override
-        public HdmiCecMessage createFromParcel(Parcel p) {
-            int source = p.readInt();
-            int destination = p.readInt();
-            int opcode = p.readInt();
-            byte[] params = new byte[p.readInt()];
-            p.readByteArray(params);
-            return new HdmiCecMessage(source, destination, opcode, params);
-        }
-        @Override
-        public HdmiCecMessage[] newArray(int size) {
-            return new HdmiCecMessage[size];
-        }
-    };
-
     @Override
     public String toString() {
         StringBuffer s = new StringBuffer();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index d491ac2..4c88ce0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -250,6 +250,9 @@
             return true;
         }
         int path = HdmiUtils.twoBytesToInt(params, offset);
+        if (path != Constants.INVALID_PHYSICAL_ADDRESS && path == mService.getPhysicalAddress()) {
+            return true;
+        }
         int portId = mService.pathToPortId(path);
         if (portId == Constants.INVALID_PORT_ID) {
             return false;
@@ -258,18 +261,19 @@
     }
 
     /**
-     * Check if the given type is valid. A valid type is one of the actual
-     * logical device types defined in the standard ({@link #DEVICE_TV},
-     * {@link #DEVICE_PLAYBACK}, {@link #DEVICE_TUNER}, {@link #DEVICE_RECORDER},
-     * and {@link #DEVICE_AUDIO_SYSTEM}).
+     * Check if the given type is valid. A valid type is one of the actual logical device types
+     * defined in the standard ({@link HdmiDeviceInfo#DEVICE_TV},
+     * {@link HdmiDeviceInfo#DEVICE_PLAYBACK}, {@link HdmiDeviceInfo#DEVICE_TUNER},
+     * {@link HdmiDeviceInfo#DEVICE_RECORDER}, and
+     * {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM}).
      *
      * @param type device type
      * @return true if the given type is valid
      */
     static boolean isValidType(int type) {
-        return (HdmiCecDeviceInfo.DEVICE_TV <= type
-                && type <= HdmiCecDeviceInfo.DEVICE_VIDEO_PROCESSOR)
-                && type != HdmiCecDeviceInfo.DEVICE_RESERVED;
+        return (HdmiDeviceInfo.DEVICE_TV <= type
+                && type <= HdmiDeviceInfo.DEVICE_VIDEO_PROCESSOR)
+                && type != HdmiDeviceInfo.DEVICE_RESERVED;
     }
 
     private class PhysicalAddressValidator implements ParameterValidator {
diff --git a/services/core/java/com/android/server/hdmi/HdmiConfig.java b/services/core/java/com/android/server/hdmi/HdmiConfig.java
index 0793107..046f393 100644
--- a/services/core/java/com/android/server/hdmi/HdmiConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiConfig.java
@@ -34,7 +34,7 @@
     static final int DEVICE_POLLING_RETRY = 1;
 
     // Number of retries for polling each device in periodic check (hotplug detection).
-    static final int HOTPLUG_DETECTION_RETRY = 2;
+    static final int HOTPLUG_DETECTION_RETRY = 1;
 
     // Number of retries for polling each device in address allocation mechanism.
     static final int ADDRESS_ALLOCATION_RETRY = 3;
@@ -46,5 +46,11 @@
     // action. They will have their own retransmission count.
     static final int RETRANSMISSION_COUNT = 1;
 
+    // Do not export the CEC devices connected to a legacy HDMI switch. The usage of legacy
+    // (non-CEC) switches is deprecated. They stop the correct operation of many mandatory
+    // CEC features. If set to true, do not pass the list of CEC devices behind the legacy
+    // switch since they won't be under control from TV.
+    static final boolean HIDE_DEVICES_BEHIND_LEGACY_SWITCH = true;
+
     private HdmiConfig() { /* cannot be instantiated */ }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index edadf6d..cccc44c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -22,7 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiHotplugEvent;
 import android.hardware.hdmi.HdmiPortInfo;
@@ -317,7 +317,7 @@
                     if (logicalAddress == Constants.ADDR_UNREGISTERED) {
                         Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]");
                     } else {
-                        HdmiCecDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType);
+                        HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType);
                         localDevice.setDeviceInfo(deviceInfo);
                         mCecController.addLocalDevice(deviceType, localDevice);
                         mCecController.addLogicalAddress(logicalAddress);
@@ -467,7 +467,7 @@
     }
 
     @ServiceThreadOnly
-    HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
+    HdmiDeviceInfo getDeviceInfo(int logicalAddress) {
         assertRunOnServiceThread();
         HdmiCecLocalDeviceTv tv = tv();
         if (tv == null) {
@@ -517,13 +517,20 @@
     @ServiceThreadOnly
     void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) {
         assertRunOnServiceThread();
-        mCecController.sendCommand(command, callback);
+        if (mMessageValidator.isValid(command)) {
+            mCecController.sendCommand(command, callback);
+        } else {
+            Slog.e(TAG, "Invalid message type:" + command);
+            if (callback != null) {
+                callback.onSendCompleted(Constants.SEND_RESULT_FAILURE);
+            }
+        }
     }
 
     @ServiceThreadOnly
     void sendCecCommand(HdmiCecMessage command) {
         assertRunOnServiceThread();
-        mCecController.sendCommand(command, null);
+        sendCecCommand(command, null);
     }
 
     /**
@@ -646,10 +653,10 @@
         }
     }
 
-    private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) {
+    private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) {
         // TODO: find better name instead of model name.
         String displayName = Build.MODEL;
-        return new HdmiCecDeviceInfo(logicalAddress,
+        return new HdmiDeviceInfo(logicalAddress,
                 getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType,
                 getVendorId(), displayName);
     }
@@ -747,7 +754,7 @@
         }
 
         @Override
-        public HdmiCecDeviceInfo getActiveSource() {
+        public HdmiDeviceInfo getActiveSource() {
             HdmiCecLocalDeviceTv tv = tv();
             if (tv == null) {
                 Slog.w(TAG, "Local tv device not available");
@@ -755,13 +762,13 @@
             }
             ActiveSource activeSource = tv.getActiveSource();
             if (activeSource.isValid()) {
-                return new HdmiCecDeviceInfo(activeSource.logicalAddress,
-                        activeSource.physicalAddress, HdmiCecDeviceInfo.PORT_INVALID,
-                        HdmiCecDeviceInfo.DEVICE_INACTIVE, 0, "");
+                return new HdmiDeviceInfo(activeSource.logicalAddress,
+                        activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID,
+                        HdmiDeviceInfo.DEVICE_INACTIVE, 0, "");
             }
             int activePath = tv.getActivePath();
-            if (activePath != HdmiCecDeviceInfo.PATH_INVALID) {
-                return new HdmiCecDeviceInfo(activePath, tv.getActivePortId());
+            if (activePath != HdmiDeviceInfo.PATH_INVALID) {
+                return new HdmiDeviceInfo(activePath, tv.getActivePortId());
             }
             return null;
         }
@@ -943,7 +950,7 @@
         }
 
         @Override
-        public List<HdmiCecDeviceInfo> getInputDevices() {
+        public List<HdmiDeviceInfo> getInputDevices() {
             enforceAccessPermission();
             // No need to hold the lock for obtaining TV device as the local device instance
             // is preserved while the HDMI control is enabled.
@@ -1212,7 +1219,7 @@
         }
     }
 
-    void invokeDeviceEventListeners(HdmiCecDeviceInfo device, boolean activated) {
+    void invokeDeviceEventListeners(HdmiDeviceInfo device, boolean activated) {
         synchronized (mLock) {
             for (IHdmiDeviceEventListener listener : mDeviceEventListeners) {
                 try {
@@ -1275,7 +1282,7 @@
         }
     }
 
-    void invokeInputChangeListener(HdmiCecDeviceInfo info) {
+    void invokeInputChangeListener(HdmiDeviceInfo info) {
         synchronized (mLock) {
             if (mInputChangeListener != null) {
                 try {
@@ -1384,7 +1391,7 @@
     }
 
     private HdmiCecLocalDeviceTv tv() {
-        return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_TV);
+        return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV);
     }
 
     boolean isTvDevice() {
@@ -1393,7 +1400,7 @@
 
     private HdmiCecLocalDevicePlayback playback() {
         return (HdmiCecLocalDevicePlayback)
-                mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_PLAYBACK);
+                mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK);
     }
 
     AudioManager getAudioManager() {
@@ -1444,6 +1451,11 @@
         // the intent, the sequence will continue at onStandby().
     }
 
+    void nap() {
+        PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
+        pm.nap(SystemClock.uptimeMillis());
+    }
+
     @ServiceThreadOnly
     private void onWakeUp() {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index b92e823..a52e0d2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -30,21 +30,21 @@
 final class HdmiUtils {
 
     private static final int[] ADDRESS_TO_TYPE = {
-        HdmiCecDeviceInfo.DEVICE_TV,  // ADDR_TV
-        HdmiCecDeviceInfo.DEVICE_RECORDER,  // ADDR_RECORDER_1
-        HdmiCecDeviceInfo.DEVICE_RECORDER,  // ADDR_RECORDER_2
-        HdmiCecDeviceInfo.DEVICE_TUNER,  // ADDR_TUNER_1
-        HdmiCecDeviceInfo.DEVICE_PLAYBACK,  // ADDR_PLAYBACK_1
-        HdmiCecDeviceInfo.DEVICE_AUDIO_SYSTEM,  // ADDR_AUDIO_SYSTEM
-        HdmiCecDeviceInfo.DEVICE_TUNER,  // ADDR_TUNER_2
-        HdmiCecDeviceInfo.DEVICE_TUNER,  // ADDR_TUNER_3
-        HdmiCecDeviceInfo.DEVICE_PLAYBACK,  // ADDR_PLAYBACK_2
-        HdmiCecDeviceInfo.DEVICE_RECORDER,  // ADDR_RECORDER_3
-        HdmiCecDeviceInfo.DEVICE_TUNER,  // ADDR_TUNER_4
-        HdmiCecDeviceInfo.DEVICE_PLAYBACK,  // ADDR_PLAYBACK_3
-        HdmiCecDeviceInfo.DEVICE_RESERVED,
-        HdmiCecDeviceInfo.DEVICE_RESERVED,
-        HdmiCecDeviceInfo.DEVICE_TV,  // ADDR_SPECIFIC_USE
+        HdmiDeviceInfo.DEVICE_TV,  // ADDR_TV
+        HdmiDeviceInfo.DEVICE_RECORDER,  // ADDR_RECORDER_1
+        HdmiDeviceInfo.DEVICE_RECORDER,  // ADDR_RECORDER_2
+        HdmiDeviceInfo.DEVICE_TUNER,  // ADDR_TUNER_1
+        HdmiDeviceInfo.DEVICE_PLAYBACK,  // ADDR_PLAYBACK_1
+        HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM,  // ADDR_AUDIO_SYSTEM
+        HdmiDeviceInfo.DEVICE_TUNER,  // ADDR_TUNER_2
+        HdmiDeviceInfo.DEVICE_TUNER,  // ADDR_TUNER_3
+        HdmiDeviceInfo.DEVICE_PLAYBACK,  // ADDR_PLAYBACK_2
+        HdmiDeviceInfo.DEVICE_RECORDER,  // ADDR_RECORDER_3
+        HdmiDeviceInfo.DEVICE_TUNER,  // ADDR_TUNER_4
+        HdmiDeviceInfo.DEVICE_PLAYBACK,  // ADDR_PLAYBACK_3
+        HdmiDeviceInfo.DEVICE_RESERVED,
+        HdmiDeviceInfo.DEVICE_RESERVED,
+        HdmiDeviceInfo.DEVICE_TV,  // ADDR_SPECIFIC_USE
     };
 
     private static final String[] DEFAULT_NAMES = {
@@ -90,7 +90,7 @@
         if (isValidAddress(address)) {
             return ADDRESS_TO_TYPE[address];
         }
-        return HdmiCecDeviceInfo.DEVICE_INACTIVE;
+        return HdmiDeviceInfo.DEVICE_INACTIVE;
     }
 
     /**
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index 813901d..51e68b6 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 
 import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
@@ -33,7 +33,7 @@
  * For other devices, keep 15 secs period.
  */
 // Seq #3
-final class HotplugDetectionAction extends FeatureAction {
+final class HotplugDetectionAction extends HdmiCecFeatureAction {
     private static final String TAG = "HotPlugDetectionAction";
 
     private static final int POLLING_INTERVAL_MS = 5000;
@@ -161,11 +161,11 @@
         }
     }
 
-    private static BitSet infoListToBitSet(List<HdmiCecDeviceInfo> infoList, boolean audioOnly) {
+    private static BitSet infoListToBitSet(List<HdmiDeviceInfo> infoList, boolean audioOnly) {
         BitSet set = new BitSet(NUM_OF_ADDRESS);
-        for (HdmiCecDeviceInfo info : infoList) {
+        for (HdmiDeviceInfo info : infoList) {
             if (audioOnly) {
-                if (info.getDeviceType() == HdmiCecDeviceInfo.DEVICE_AUDIO_SYSTEM) {
+                if (info.getDeviceType() == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
                     set.set(info.getLogicalAddress());
                 }
             } else {
@@ -207,7 +207,7 @@
     }
 
     private void mayChangeRoutingPath(int address) {
-        HdmiCecDeviceInfo info = tv().getDeviceInfo(address);
+        HdmiDeviceInfo info = tv().getDeviceInfo(address);
         if (info != null) {
             tv().handleRemoveActiveRoutingPath(info.getPhysicalAddress());
         }
@@ -236,7 +236,7 @@
     }
 
     private void mayDisableSystemAudioAndARC(int address) {
-        if (HdmiUtils.getTypeFromAddress(address) != HdmiCecDeviceInfo.DEVICE_AUDIO_SYSTEM) {
+        if (HdmiUtils.getTypeFromAddress(address) != HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 907015b..a5fdbea 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 
 import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
@@ -28,12 +28,12 @@
  * connected HDMI-CEC device broadcasts to announce its advent. Additional commands are issued in
  * this action to gather more information on the device such as OSD name and device vendor ID.
  *
- * <p>The result is made in the form of {@link HdmiCecDeviceInfo} object, and passed to service
+ * <p>The result is made in the form of {@link HdmiDeviceInfo} object, and passed to service
  * for the management through its life cycle.
  *
  * <p>Package-private, accessed by {@link HdmiControlService} only.
  */
-final class NewDeviceAction extends FeatureAction {
+final class NewDeviceAction extends HdmiCecFeatureAction {
 
     private static final String TAG = "NewDeviceAction";
 
@@ -152,14 +152,14 @@
         if (mDisplayName == null) {
             mDisplayName = HdmiUtils.getDefaultDeviceName(mDeviceLogicalAddress);
         }
-        tv().addCecDevice(new HdmiCecDeviceInfo(
+        tv().addCecDevice(new HdmiDeviceInfo(
                 mDeviceLogicalAddress, mDevicePhysicalAddress,
                 tv().getPortId(mDevicePhysicalAddress),
                 HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress),
                 mVendorId, mDisplayName));
 
         if (HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress)
-                == HdmiCecDeviceInfo.DEVICE_AUDIO_SYSTEM) {
+                == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
             if (tv().getSystemAudioModeSetting()) {
                 addAndStartAction(new SystemAudioAutoInitiationAction(localDevice(),
                         mDeviceLogicalAddress));
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 6299b99..7db991a 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -17,19 +17,18 @@
 
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
 import android.os.RemoteException;
 import android.util.Slog;
 
 /**
- * Feature action that performs one touch play against TV/Display device.
- *
- * This action is initiated via {@link HdmiControlManager#oneTouchPlay()} from
- * the Android system working as playback device to turn on the TV, and switch the input.
- *
- * <p>Package-private, accessed by {@link HdmiControlService} only.
+ * Feature action that performs one touch play against TV/Display device. This action is initiated
+ * via {@link android.hardware.hdmi.HdmiPlaybackClient#oneTouchPlay(OneTouchPlayCallback)} from the
+ * Android system working as playback device to turn on the TV, and switch the input.
+ * <p>
+ * Package-private, accessed by {@link HdmiControlService} only.
  */
-
-final class OneTouchPlayAction extends FeatureAction {
+final class OneTouchPlayAction extends HdmiCecFeatureAction {
     private static final String TAG = "OneTouchPlayAction";
 
     // State in which the action is waiting for <Report Power Status>. In normal situation
diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
index befc640..39c0d7f 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
@@ -29,7 +29,7 @@
 /**
  * Feature action that performs one touch record.
  */
-public class OneTouchRecordAction extends FeatureAction {
+public class OneTouchRecordAction extends HdmiCecFeatureAction {
     private static final String TAG = "OneTouchRecordAction";
 
     // Timer out for waiting <Record Status> 120s
diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java
index cf44607..9c530a3 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java
@@ -16,14 +16,14 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 
 import android.util.Slog;
 
 /**
  * Base feature action class for &lt;Request ARC Initiation&gt;/&lt;Request ARC Termination&gt;.
  */
-abstract class RequestArcAction extends FeatureAction {
+abstract class RequestArcAction extends HdmiCecFeatureAction {
     private static final String TAG = "RequestArcAction";
 
     // State in which waits for ARC response.
@@ -42,8 +42,8 @@
      */
     RequestArcAction(HdmiCecLocalDevice source, int avrAddress) {
         super(source);
-        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCecDeviceInfo.DEVICE_TV);
-        HdmiUtils.verifyAddressType(avrAddress, HdmiCecDeviceInfo.DEVICE_AUDIO_SYSTEM);
+        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV);
+        HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
         mAvrAddress = avrAddress;
     }
 
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
index f50ae9b..435ab7f 100644
--- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -17,7 +17,7 @@
 package com.android.server.hdmi;
 
 import android.annotation.Nullable;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.RemoteException;
@@ -38,7 +38,7 @@
  * <li> Routing at CEC enable time
  * </ul>
  */
-final class RoutingControlAction extends FeatureAction {
+final class RoutingControlAction extends HdmiCecFeatureAction {
     private static final String TAG = "RoutingControlAction";
 
     // State in which we wait for <Routing Information> to arrive. If timed out, we use the
@@ -155,7 +155,7 @@
         }
         switch (timeoutState) {
             case STATE_WAIT_FOR_ROUTING_INFORMATION:
-                HdmiCecDeviceInfo device = tv().getDeviceInfoByPath(mCurrentRoutingPath);
+                HdmiDeviceInfo device = tv().getDeviceInfoByPath(mCurrentRoutingPath);
                 if (device != null && mQueryDevicePowerStatus) {
                     int deviceLogicalAddress = device.getLogicalAddress();
                     queryDevicePowerStatus(deviceLogicalAddress, new SendMessageCallback() {
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
index ca2826e..9f09eb4 100644
--- a/services/core/java/com/android/server/hdmi/SendKeyAction.java
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -32,7 +32,7 @@
  *
  * <p>Package-private, accessed by {@link HdmiControlService} only.
  */
-final class SendKeyAction extends FeatureAction {
+final class SendKeyAction extends HdmiCecFeatureAction {
     private static final String TAG = "SendKeyAction";
 
     // State in which the action is at work. The state is set in {@link #start()} and
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index e0c1ad5..9f7f98a 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 
 /**
@@ -24,7 +24,7 @@
  * Once TV gets &lt;Initiate ARC&gt;, TV sends &lt;Report ARC Initiated&gt; to AV Receiver.
  * If it fails or it gets &lt;Terminate ARC&gt;, TV just disables ARC.
  */
-final class SetArcTransmissionStateAction extends FeatureAction {
+final class SetArcTransmissionStateAction extends HdmiCecFeatureAction {
     private static final String TAG = "SetArcTransmissionStateAction";
 
     // State in which the action sent <Rerpot Arc Initiated> and
@@ -44,8 +44,8 @@
     SetArcTransmissionStateAction(HdmiCecLocalDevice source, int avrAddress,
             boolean enabled) {
         super(source);
-        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCecDeviceInfo.DEVICE_TV);
-        HdmiUtils.verifyAddressType(avrAddress, HdmiCecDeviceInfo.DEVICE_AUDIO_SYSTEM);
+        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV);
+        HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
         mAvrAddress = avrAddress;
         mEnabled = enabled;
     }
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index 4be036a..7e45a99 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -17,7 +17,7 @@
 package com.android.server.hdmi;
 
 import android.annotation.Nullable;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.RemoteException;
@@ -28,7 +28,7 @@
 /**
  * Base feature action class for SystemAudioActionFromTv and SystemAudioActionFromAvr.
  */
-abstract class SystemAudioAction extends FeatureAction {
+abstract class SystemAudioAction extends HdmiCecFeatureAction {
     private static final String TAG = "SystemAudioAction";
 
     // Transient state to differentiate with STATE_NONE where the on-finished callback
@@ -65,7 +65,7 @@
     SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus,
             IHdmiControlCallback callback) {
         super(source);
-        HdmiUtils.verifyAddressType(avrAddress, HdmiCecDeviceInfo.DEVICE_AUDIO_SYSTEM);
+        HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
         mAvrLogicalAddress = avrAddress;
         mTargetAudioStatus = targetStatus;
         mCallback = callback;
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
index df9bdfc..eb5119b 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.IHdmiControlCallback;
 
@@ -37,7 +37,7 @@
     SystemAudioActionFromAvr(HdmiCecLocalDevice source, int avrAddress,
             boolean targetStatus, IHdmiControlCallback callback) {
         super(source, avrAddress, targetStatus, callback);
-        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCecDeviceInfo.DEVICE_TV);
+        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
index cb3588c..02ecd13 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 
 
@@ -37,7 +37,7 @@
     SystemAudioActionFromTv(HdmiCecLocalDevice sourceAddress, int avrAddress,
             boolean targetStatus, IHdmiControlCallback callback) {
         super(sourceAddress, avrAddress, targetStatus, callback);
-        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCecDeviceInfo.DEVICE_TV);
+        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index 137cada..3653aac 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -22,7 +22,7 @@
  * Action to initiate system audio once AVR is detected on Device discovery action.
  */
 // Seq #27
-final class SystemAudioAutoInitiationAction extends FeatureAction {
+final class SystemAudioAutoInitiationAction extends HdmiCecFeatureAction {
     private final int mAvrAddress;
 
     // State that waits for <System Audio Mode Status> once send
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index 1066204..bfcda50 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -27,7 +27,7 @@
 /**
  * Action to update audio status (volume or mute) of audio amplifier
  */
-final class SystemAudioStatusAction extends FeatureAction {
+final class SystemAudioStatusAction extends HdmiCecFeatureAction {
     private static final String TAG = "SystemAudioStatusAction";
 
     // State that waits for <ReportAudioStatus>.
diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
index 1a179e6..8fc0182 100644
--- a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
+++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
@@ -31,7 +31,7 @@
 /**
  * Feature action that performs timer recording.
  */
-public class TimerRecordingAction extends FeatureAction {
+public class TimerRecordingAction extends HdmiCecFeatureAction {
     private static final String TAG = "TimerRecordingAction";
 
     // Timer out for waiting <Timer Status> 120s.
diff --git a/services/core/java/com/android/server/hdmi/UnmodifiableSparseArray.java b/services/core/java/com/android/server/hdmi/UnmodifiableSparseArray.java
index 5c0a360..7791797 100644
--- a/services/core/java/com/android/server/hdmi/UnmodifiableSparseArray.java
+++ b/services/core/java/com/android/server/hdmi/UnmodifiableSparseArray.java
@@ -59,4 +59,3 @@
         return mArray.toString();
     }
 }
-
diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
index e32b792..01c6f3e 100644
--- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java
+++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
@@ -28,7 +28,7 @@
  * from Audio Receiver(AVR). If TV receives no &lt;Report Audio Status&gt; from AVR, this action
  * will be finished in {@link #IRT_MS} * {@link #VOLUME_CHANGE_TIMEOUT_MAX_COUNT} (ms).
  */
-final class VolumeControlAction extends FeatureAction {
+final class VolumeControlAction extends HdmiCecFeatureAction {
     private static final String TAG = "VolumeControlAction";
 
     private static final int VOLUME_MUTE = 101;
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 9ac90dc..14457ec 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -74,7 +74,7 @@
     static final boolean DEBUG = true;
     /** The number of concurrent jobs we run at one time. */
     private static final int MAX_JOB_CONTEXTS_COUNT = 3;
-    static final String TAG = "JobManagerService";
+    static final String TAG = "JobSchedulerService";
     /** Master list of jobs. */
     final JobStore mJobs;
 
@@ -88,6 +88,11 @@
      */
     static final int MIN_IDLE_COUNT = 1;
     /**
+     * Minimum # of charging jobs that must be ready in order to force the JMS to schedule things
+     * early.
+     */
+    static final int MIN_CHARGING_COUNT = 1;
+    /**
      * Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule
      * things early.
      */
@@ -95,8 +100,9 @@
     /**
      * Minimum # of jobs (with no particular constraints) for which the JMS will be happy running
      * some work early.
+     * This is correlated with the amount of batching we'll be able to do.
      */
-    static final int MIN_READY_JOBS_COUNT = 4;
+    static final int MIN_READY_JOBS_COUNT = 2;
 
     /**
      * Track Services that have currently active or pending jobs. The index is provided by
@@ -546,7 +552,8 @@
          */
         private void maybeQueueReadyJobsForExecutionH() {
             synchronized (mJobs) {
-                int idleCount = 0;
+                int chargingCount = 0;
+                int idleCount =  0;
                 int backoffCount = 0;
                 int connectivityCount = 0;
                 List<JobStatus> runnableJobs = new ArrayList<JobStatus>();
@@ -563,17 +570,34 @@
                         if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) {
                             connectivityCount++;
                         }
+                        if (job.hasChargingConstraint()) {
+                            chargingCount++;
+                        }
                         runnableJobs.add(job);
                     } else if (isReadyToBeCancelledLocked(job)) {
                         stopJobOnServiceContextLocked(job);
                     }
                 }
-                if (backoffCount > 0 || idleCount >= MIN_IDLE_COUNT ||
+                if (backoffCount > 0 ||
+                        idleCount >= MIN_IDLE_COUNT ||
                         connectivityCount >= MIN_CONNECTIVITY_COUNT ||
+                        chargingCount >= MIN_CHARGING_COUNT ||
                         runnableJobs.size() >= MIN_READY_JOBS_COUNT) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "maybeQueueReadyJobsForExecutionH: Running jobs.");
+                    }
                     for (int i=0; i<runnableJobs.size(); i++) {
                         mPendingJobs.add(runnableJobs.get(i));
                     }
+                } else {
+                    if (DEBUG) {
+                        Slog.d(TAG, "maybeQueueReadyJobsForExecutionH: Not running anything.");
+                    }
+                }
+                if (DEBUG) {
+                    Slog.d(TAG, "idle=" + idleCount + " connectivity=" +
+                    connectivityCount + " charging=" + chargingCount + " tot=" +
+                            runnableJobs.size());
                 }
             }
         }
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 2213934..7b71027 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -113,12 +113,13 @@
         public IdlenessTracker() {
             mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
-            Intent intent = new Intent(ACTION_TRIGGER_IDLE);
-            intent.setComponent(new ComponentName(mContext, this.getClass()));
+            Intent intent = new Intent(ACTION_TRIGGER_IDLE)
+                    .setPackage("android")
+                    .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
             mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
 
-            // at boot we presume that the user has just "interacted" with the
-            // device in some meaningful way
+            // At boot we presume that the user has just "interacted" with the
+            // device in some meaningful way.
             mIdle = false;
         }
 
@@ -163,9 +164,11 @@
                 // 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;
+                final long nowElapsed = SystemClock.elapsedRealtime();
+                final long when = nowElapsed + INACTIVITY_IDLE_THRESHOLD;
                 if (DEBUG) {
-                    Slog.v(TAG, "Scheduling idle : " + action + " when=" + when);
+                    Slog.v(TAG, "Scheduling idle : " + action + " now:" + nowElapsed + " when="
+                            + when);
                 }
                 mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                         when, IDLE_WINDOW_SLOP, mIdleTriggerIntent);
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 7b28699..289b5aa 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -103,7 +103,7 @@
             try {
                 hasPermission |= checkPermission(packageName,
                         android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
-                        || mAppOps.checkOpNoThrow(
+                        || mAppOps.noteOpNoThrow(
                                 AppOpsManager.OP_PROJECT_MEDIA, uid, packageName)
                         == AppOpsManager.MODE_ALLOWED;
             } finally {
@@ -196,18 +196,27 @@
         }
 
         @Override // Binder call
-        public int getVirtualDisplayFlags() {
-            switch (mType) {
-                case MediaProjectionManager.TYPE_SCREEN_CAPTURE:
-                    return DisplayManager.VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE;
-                case MediaProjectionManager.TYPE_MIRRORING:
-                    return DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
-                            DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
-                case MediaProjectionManager.TYPE_PRESENTATION:
-                    return DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION |
-                            DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+        public int applyVirtualDisplayFlags(int flags) {
+            if (mType == MediaProjectionManager.TYPE_SCREEN_CAPTURE) {
+                flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+                flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
+                        | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
+                return flags;
+            } else if (mType == MediaProjectionManager.TYPE_MIRRORING) {
+                flags &= ~(DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
+                        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
+                flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
+                        DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
+                return flags;
+            } else if (mType == MediaProjectionManager.TYPE_PRESENTATION) {
+                flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+                flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
+                        DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION |
+                        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+                return flags;
+            } else  {
+                throw new RuntimeException("Unknown MediaProjection type");
             }
-            throw new RuntimeException("Unknown MediaProjection type");
         }
 
         @Override // Binder call
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 8b0a46d..b261ef5 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -212,6 +212,34 @@
         return execute(builder.toString());
     }
 
+    public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
+            String instructionSet) {
+        StringBuilder builder = new StringBuilder("patchoat");
+        builder.append(' ');
+        builder.append(apkPath);
+        builder.append(' ');
+        builder.append(uid);
+        builder.append(isPublic ? " 1" : " 0");
+        builder.append(' ');
+        builder.append(pkgName);
+        builder.append(' ');
+        builder.append(instructionSet);
+        return execute(builder.toString());
+    }
+
+    public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
+        StringBuilder builder = new StringBuilder("patchoat");
+        builder.append(' ');
+        builder.append(apkPath);
+        builder.append(' ');
+        builder.append(uid);
+        builder.append(isPublic ? " 1" : " 0");
+        builder.append(" *");         // No pkgName arg present
+        builder.append(' ');
+        builder.append(instructionSet);
+        return execute(builder.toString());
+    }
+
     public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
         StringBuilder builder = new StringBuilder("dexopt");
         builder.append(' ');
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index c673b98..b4faea1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -38,6 +38,7 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageDeleteObserver2;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
@@ -540,17 +541,17 @@
     }
 
     @Override
-    public void uninstall(String packageName, int flags, IPackageDeleteObserver observer,
+    public void uninstall(String packageName, int flags, IPackageDeleteObserver2 observer,
             int userId) {
         mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall");
 
         // TODO: enforce installer of record or permission
-        mPm.deletePackageAsUser(packageName, observer, userId, flags);
+        mPm.deletePackage(packageName, observer, userId, flags);
     }
 
     @Override
     public void uninstallSplit(String basePackageName, String overlayName, int flags,
-            IPackageDeleteObserver observer, int userId) {
+            IPackageDeleteObserver2 observer, int userId) {
         mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstallSplit");
 
         // TODO: flesh out once PM has split support
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 26019db..5443fbc 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -24,6 +24,7 @@
 import static android.system.OsConstants.O_RDONLY;
 import static android.system.OsConstants.O_WRONLY;
 
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageInstallerSession;
@@ -134,8 +135,8 @@
                     Slog.e(TAG, "Install failed: " + e);
                     destroyInternal();
                     try {
-                        mRemoteObserver.packageInstalled(mPackageName, null, e.error,
-                                e.getMessage());
+                        mRemoteObserver.onPackageInstalled(mPackageName, e.error, e.getMessage(),
+                                null);
                     } catch (RemoteException ignored) {
                     }
                     mCallback.onSessionFinished(PackageInstallerSession.this, false);
@@ -377,11 +378,16 @@
         final IPackageInstallObserver2 remoteObserver = mRemoteObserver;
         final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
             @Override
-            public void packageInstalled(String basePackageName, Bundle extras, int returnCode,
-                    String msg) {
+            public void onUserActionRequired(Intent intent) {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+                    Bundle extras) {
                 destroyInternal();
                 try {
-                    remoteObserver.packageInstalled(basePackageName, extras, returnCode, msg);
+                    remoteObserver.onPackageInstalled(basePackageName, returnCode, msg, extras);
                 } catch (RemoteException ignored) {
                 }
                 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6bedcfb..4bf6636 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -85,6 +85,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.app.PackageDeleteObserver;
 import android.app.admin.IDevicePolicyManager;
 import android.app.backup.IBackupManager;
 import android.content.BroadcastReceiver;
@@ -101,6 +102,7 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageDeleteObserver2;
 import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageManager;
@@ -1063,8 +1065,8 @@
                         if (args.observer != null) {
                             try {
                                 Bundle extras = extrasForInstallResult(res);
-                                args.observer.packageInstalled(res.name, extras, res.returnCode,
-                                        res.returnMsg);
+                                args.observer.onPackageInstalled(res.name, res.returnCode,
+                                        res.returnMsg, extras);
                             } catch (RemoteException e) {
                                 Slog.i(TAG, "Observer no longer exists.");
                             }
@@ -1418,11 +1420,18 @@
                         }
 
                         try {
-                            if (DexFile.isDexOptNeededInternal(lib, null, instructionSet, false)) {
+                            byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,
+                                                                                 instructionSet,
+                                                                                 false);
+                            if (dexoptRequired != DexFile.UP_TO_DATE) {
                                 alreadyDexOpted.add(lib);
 
                                 // The list of "shared libraries" we have at this point is
-                                mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
+                                if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
+                                    mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
+                                } else {
+                                    mInstaller.patchoat(lib, Process.SYSTEM_UID, true, instructionSet);
+                                }
                                 didDexOptLibraryOrTool = true;
                             }
                         } catch (FileNotFoundException e) {
@@ -1469,9 +1478,15 @@
                             continue;
                         }
                         try {
-                            if (DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
+                            byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null,
+                                                                                 instructionSet,
+                                                                                 false);
+                            if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
                                 mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
                                 didDexOptLibraryOrTool = true;
+                            } else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
+                                mInstaller.patchoat(path, Process.SYSTEM_UID, true, instructionSet);
+                                didDexOptLibraryOrTool = true;
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Jar not found: " + path);
@@ -4623,9 +4638,14 @@
                 }
 
                 try {
-                    final boolean isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
+                    // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
+                    // patckage or the one we find does not match the image checksum (i.e. it was
+                    // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
+                    // odex file and it matches the checksum of the image but not its base address,
+                    // meaning we need to move it.
+                    final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
                             pkg.packageName, instructionSet, defer);
-                    if (forceDex || (!defer && isDexOptNeeded)) {
+                    if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
                         Log.i(TAG, "Running dexopt on: " + path + " pkg="
                                 + pkg.applicationInfo.packageName + " isa=" + instructionSet);
                         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
@@ -4641,12 +4661,27 @@
                             performedDexOpt = true;
                             pkg.mDexOptPerformed.add(instructionSet);
                         }
+                    } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
+                        Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
+                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+                        final int ret = mInstaller.patchoat(path, sharedGid, !isForwardLocked(pkg),
+                                pkg.packageName, instructionSet);
+
+                        if (ret < 0) {
+                            // Don't bother running patchoat again if we failed, it will probably
+                            // just result in an error again. Also, don't bother dexopting for other
+                            // paths & ISAs.
+                            return DEX_OPT_FAILED;
+                        } else {
+                            performedDexOpt = true;
+                            pkg.mDexOptPerformed.add(instructionSet);
+                        }
                     }
 
                     // We're deciding to defer a needed dexopt. Don't bother dexopting for other
                     // paths and instruction sets. We'll deal with them all together when we process
                     // our list of deferred dexopts.
-                    if (defer && isDexOptNeeded) {
+                    if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
                         if (mDeferredDexOpt == null) {
                             mDeferredDexOpt = new HashSet<PackageParser.Package>();
                         }
@@ -7723,7 +7758,7 @@
         if (isUserRestricted(UserHandle.getUserId(uid), UserManager.DISALLOW_INSTALL_APPS)) {
             try {
                 if (observer != null) {
-                    observer.packageInstalled("", null, INSTALL_FAILED_USER_RESTRICTED, null);
+                    observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
                 }
             } catch (RemoteException re) {
             }
@@ -10486,9 +10521,15 @@
     }
 
     @Override
-    public void deletePackageAsUser(final String packageName,
-                                    final IPackageDeleteObserver observer,
-                                    final int userId, final int flags) {
+    public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int userId,
+            int flags) {
+        deletePackage(packageName, new LegacyPackageDeleteObserver(observer).getBinder(), userId,
+                flags);
+    }
+
+    @Override
+    public void deletePackage(final String packageName,
+            final IPackageDeleteObserver2 observer, final int userId, final int flags) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.DELETE_PACKAGES, null);
         final int uid = Binder.getCallingUid();
@@ -10499,7 +10540,8 @@
         }
         if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
             try {
-                observer.packageDeleted(packageName, PackageManager.DELETE_FAILED_USER_RESTRICTED);
+                observer.onPackageDeleted(packageName,
+                        PackageManager.DELETE_FAILED_USER_RESTRICTED, null);
             } catch (RemoteException re) {
             }
             return;
@@ -10519,7 +10561,8 @@
         }
         if (uninstallBlocked) {
             try {
-                observer.packageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED);
+                observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED,
+                        null);
             } catch (RemoteException re) {
             }
             return;
@@ -10535,7 +10578,7 @@
                 final int returnCode = deletePackageX(packageName, userId, flags);
                 if (observer != null) {
                     try {
-                        observer.packageDeleted(packageName, returnCode);
+                        observer.onPackageDeleted(packageName, returnCode, null);
                     } catch (RemoteException e) {
                         Log.i(TAG, "Observer no longer exists.");
                     } //end catch
@@ -13407,4 +13450,20 @@
             return false;
         }
     }
+
+    private static class LegacyPackageDeleteObserver extends PackageDeleteObserver {
+        private final IPackageDeleteObserver mLegacy;
+
+        public LegacyPackageDeleteObserver(IPackageDeleteObserver legacy) {
+            mLegacy = legacy;
+        }
+
+        @Override
+        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
+            try {
+                mLegacy.packageDeleted(basePackageName, returnCode);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index ee20b3c..0523af7 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -93,7 +93,6 @@
                     mTrusted = true;
                     mMessage = (CharSequence) msg.obj;
                     boolean initiatedByUser = msg.arg1 != 0;
-                    // TODO: Handle initiatedByUser.
                     long durationMs = msg.getData().getLong(DATA_DURATION);
                     if (durationMs > 0) {
                         mHandler.removeMessages(MSG_TRUST_TIMEOUT);
@@ -102,7 +101,7 @@
                     mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
                             (mMessage != null ? mMessage.toString() : null),
                             durationMs, initiatedByUser);
-                    mTrustManagerService.updateTrust(mUserId);
+                    mTrustManagerService.updateTrust(mUserId, initiatedByUser);
                     break;
                 case MSG_TRUST_TIMEOUT:
                     if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
@@ -115,7 +114,7 @@
                     if (msg.what == MSG_REVOKE_TRUST) {
                         mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName);
                     }
-                    mTrustManagerService.updateTrust(mUserId);
+                    mTrustManagerService.updateTrust(mUserId, false);
                     break;
                 case MSG_RESTART_TIMEOUT:
                     unbind();
@@ -130,7 +129,7 @@
                             if (DEBUG) Log.v(TAG, "Re-enabling agent because it acknowledged "
                                     + "enabled features: " + mName);
                             mTrustDisabledByDpm = false;
-                            mTrustManagerService.updateTrust(mUserId);
+                            mTrustManagerService.updateTrust(mUserId, false);
                         }
                     } else {
                         if (DEBUG) Log.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED "
@@ -144,7 +143,7 @@
                         mMessage = null;
                     }
                     mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
-                    mTrustManagerService.updateTrust(mUserId);
+                    mTrustManagerService.updateTrust(mUserId, false);
                     break;
             }
         }
@@ -282,7 +281,7 @@
         }
         if (mTrustDisabledByDpm != trustDisabled) {
             mTrustDisabledByDpm = trustDisabled;
-            mTrustManagerService.updateTrust(mUserId);
+            mTrustManagerService.updateTrust(mUserId, false);
         }
         return trustDisabled;
     }
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index d3b8d5d..badead6 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -148,13 +148,13 @@
     private void updateTrustAll() {
         List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
         for (UserInfo userInfo : userInfos) {
-            updateTrust(userInfo.id);
+            updateTrust(userInfo.id, false);
         }
     }
 
-    public void updateTrust(int userId) {
+    public void updateTrust(int userId, boolean initiatedByUser) {
         dispatchOnTrustManagedChanged(aggregateIsTrustManaged(userId), userId);
-        dispatchOnTrustChanged(aggregateIsTrusted(userId), userId);
+        dispatchOnTrustChanged(aggregateIsTrusted(userId), userId, initiatedByUser);
     }
 
     void refreshAgentList() {
@@ -272,7 +272,7 @@
             }
         }
         if (trustMayHaveChanged) {
-            updateTrust(userId);
+            updateTrust(userId, false);
         }
         refreshAgentList();
     }
@@ -375,7 +375,7 @@
 
         if (successful && !mUserHasAuthenticatedSinceBoot.get(userId)) {
             mUserHasAuthenticatedSinceBoot.put(userId, true);
-            updateTrust(userId);
+            updateTrust(userId, false);
         }
     }
 
@@ -386,7 +386,7 @@
             updateTrustAll();
         } else {
             mUserHasAuthenticatedSinceBoot.put(userId, false);
-            updateTrust(userId);
+            updateTrust(userId, false);
         }
     }
 
@@ -410,10 +410,11 @@
         }
     }
 
-    private void dispatchOnTrustChanged(boolean enabled, int userId) {
+    private void dispatchOnTrustChanged(boolean enabled, int userId, boolean initiatedByUser) {
+        if (!enabled) initiatedByUser = false;
         for (int i = 0; i < mTrustListeners.size(); i++) {
             try {
-                mTrustListeners.get(i).onTrustChanged(enabled, userId);
+                mTrustListeners.get(i).onTrustChanged(enabled, userId, initiatedByUser);
             } catch (DeadObjectException e) {
                 Slog.d(TAG, "Removing dead TrustListener.");
                 mTrustListeners.remove(i);
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 9252be4..74f725f 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -21,7 +21,7 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiHotplugEvent;
 import android.hardware.hdmi.IHdmiControlService;
 import android.hardware.hdmi.IHdmiDeviceEventListener;
@@ -82,7 +82,7 @@
     private final TvInputHal mHal = new TvInputHal(this);
     private final SparseArray<Connection> mConnections = new SparseArray<>();
     private final List<TvInputHardwareInfo> mHardwareList = new ArrayList<>();
-    private List<HdmiCecDeviceInfo> mHdmiCecDeviceList = new LinkedList<>();
+    private List<HdmiDeviceInfo> mHdmiCecDeviceList = new LinkedList<>();
     /* A map from a device ID to the matching TV input ID. */
     private final SparseArray<String> mHardwareInputIdMap = new SparseArray<>();
     /* A map from a HDMI logical address to the matching TV input ID. */
@@ -164,9 +164,9 @@
             TvInputHardwareInfo info = connection.getHardwareInfoLocked();
             if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) {
                 // Remove HDMI CEC devices linked with this hardware.
-                for (Iterator<HdmiCecDeviceInfo> it = mHdmiCecDeviceList.iterator();
+                for (Iterator<HdmiDeviceInfo> it = mHdmiCecDeviceList.iterator();
                         it.hasNext(); ) {
-                    HdmiCecDeviceInfo deviceInfo = it.next();
+                    HdmiDeviceInfo deviceInfo = it.next();
                     if (deviceInfo.getPortId() == info.getHdmiPortId()) {
                         mHandler.obtainMessage(ListenerHandler.HDMI_CEC_DEVICE_REMOVED, 0, 0,
                                 deviceInfo).sendToTarget();
@@ -220,7 +220,7 @@
         }
     }
 
-    public List<HdmiCecDeviceInfo> getHdmiCecInputDeviceList() {
+    public List<HdmiDeviceInfo> getHdmiCecInputDeviceList() {
         synchronized (mLock) {
             return Collections.unmodifiableList(mHdmiCecDeviceList);
         }
@@ -450,7 +450,7 @@
     private void processPendingHdmiDeviceEventsLocked() {
         for (Iterator<Message> it = mPendingHdmiDeviceEvents.iterator(); it.hasNext(); ) {
             Message msg = it.next();
-            HdmiCecDeviceInfo deviceInfo = (HdmiCecDeviceInfo) msg.obj;
+            HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
             TvInputHardwareInfo hardwareInfo =
                     findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId());
             if (hardwareInfo != null) {
@@ -864,8 +864,8 @@
         public void onStateChanged(String inputId, int state);
         public void onHardwareDeviceAdded(TvInputHardwareInfo info);
         public void onHardwareDeviceRemoved(TvInputHardwareInfo info);
-        public void onHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDevice);
-        public void onHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDevice);
+        public void onHdmiCecDeviceAdded(HdmiDeviceInfo cecDevice);
+        public void onHdmiCecDeviceRemoved(HdmiDeviceInfo cecDevice);
     }
 
     private class ListenerHandler extends Handler {
@@ -895,12 +895,12 @@
                     break;
                 }
                 case HDMI_CEC_DEVICE_ADDED: {
-                    HdmiCecDeviceInfo info = (HdmiCecDeviceInfo) msg.obj;
+                    HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj;
                     mListener.onHdmiCecDeviceAdded(info);
                     break;
                 }
                 case HDMI_CEC_DEVICE_REMOVED: {
-                    HdmiCecDeviceInfo info = (HdmiCecDeviceInfo) msg.obj;
+                    HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj;
                     mListener.onHdmiCecDeviceRemoved(info);
                     break;
                 }
@@ -936,7 +936,7 @@
 
     private final class HdmiDeviceEventListener extends IHdmiDeviceEventListener.Stub {
         @Override
-        public void onStatusChanged(HdmiCecDeviceInfo deviceInfo, boolean activated) {
+        public void onStatusChanged(HdmiDeviceInfo deviceInfo, boolean activated) {
             synchronized (mLock) {
                 if (activated) {
                     if (!mHdmiCecDeviceList.contains(deviceInfo)) {
@@ -966,7 +966,7 @@
 
     private final class HdmiInputChangeListener extends IHdmiInputChangeListener.Stub {
         @Override
-        public void onChanged(HdmiCecDeviceInfo device) throws RemoteException {
+        public void onChanged(HdmiDeviceInfo device) throws RemoteException {
             String inputId;
             synchronized (mLock) {
                 if (device.isCecDevice()) {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 594e9d0..14d1ec4 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -35,10 +35,9 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.Rect;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.media.tv.ITvInputClient;
 import android.media.tv.ITvInputHardware;
 import android.media.tv.ITvInputHardwareCallback;
@@ -283,7 +282,6 @@
         userState.inputMap.clear();
         userState.inputMap = inputMap;
 
-        Resources r = Resources.getSystem();
         userState.ratingSystemXmlUriSet.clear();
         userState.ratingSystemXmlUriSet.add(TvContentRating.SYSTEM_CONTENT_RATING_SYSTEM_XML);
         for (TvInputState state : userState.inputMap.values()) {
@@ -1074,39 +1072,50 @@
             try {
                 synchronized (mLock) {
                     UserState userState = getUserStateLocked(resolvedUserId);
-                    if (sessionToken == userState.mainSessionToken) {
+                    if (userState.mainSessionToken == sessionToken) {
                         return;
                     }
 
-                    SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
-                            resolvedUserId);
-                    ServiceState serviceState = getServiceStateLocked(
-                            sessionState.mInfo.getComponent(), resolvedUserId);
-                    ITvInputSession session = getSessionLocked(sessionState);
+                    SessionState newMainSessionState = getSessionStateLocked(
+                            sessionToken, callingUid, resolvedUserId);
+                    if (newMainSessionState.mHardwareSessionToken != null) {
+                        newMainSessionState = getSessionStateLocked(
+                                newMainSessionState.mHardwareSessionToken,
+                                Process.SYSTEM_UID, resolvedUserId);
+                    }
+                    ServiceState newMainServiceState = getServiceStateLocked(
+                            newMainSessionState.mInfo.getComponent(), resolvedUserId);
+                    ITvInputSession newMainSession = getSessionLocked(newMainSessionState);
 
-                    ServiceState prevMainServiceState = null;
-                    ITvInputSession prevMainSession = null;
+                    ServiceState oldMainServiceState = null;
+                    ITvInputSession oldMainSession = null;
                     if (userState.mainSessionToken != null) {
-                        SessionState prevMainSessionState = getSessionStateLocked(
+                        SessionState oldMainSessionState = getSessionStateLocked(
                                 userState.mainSessionToken, Process.SYSTEM_UID, resolvedUserId);
-                        prevMainServiceState = getServiceStateLocked(
-                                prevMainSessionState.mInfo.getComponent(), resolvedUserId);
-                        prevMainSession = getSessionLocked(prevMainSessionState);
+                        if (oldMainSessionState.mHardwareSessionToken != null) {
+                            oldMainSessionState = getSessionStateLocked(
+                                    oldMainSessionState.mHardwareSessionToken,
+                                    Process.SYSTEM_UID, resolvedUserId);
+                        }
+                        oldMainServiceState = getServiceStateLocked(
+                                oldMainSessionState.mInfo.getComponent(), resolvedUserId);
+                        oldMainSession = getSessionLocked(oldMainSessionState);
                     }
 
                     userState.mainSessionToken = sessionToken;
 
-                    // Inform the new main session first. See {@link TvInputService#onSetMain}.
-                    if (serviceState.mIsHardware) {
+                    // Inform the new main session first.
+                    // See {@link TvInputService#onSetMainSession}.
+                    if (newMainServiceState.mIsHardware) {
                         try {
-                            session.setMainSession(true);
+                            newMainSession.setMainSession(true);
                         } catch (RemoteException e) {
                             Slog.e(TAG, "error in setMainSession", e);
                         }
                     }
-                    if (prevMainSession != null && prevMainServiceState.mIsHardware) {
+                    if (oldMainSession != null && oldMainServiceState.mIsHardware) {
                         try {
-                            prevMainSession.setMainSession(false);
+                            oldMainSession.setMainSession(false);
                         } catch (RemoteException e) {
                             Slog.e(TAG, "error in setMainSession", e);
                         }
@@ -1251,6 +1260,7 @@
                         args.arg1 = sessionState.mLogUri;
                         args.arg2 = ContentUris.parseId(channelUri);
                         args.arg3 = currentTime;
+                        args.arg4 = sessionState;
                         mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget();
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error in tune", e);
@@ -1522,6 +1532,34 @@
         }
 
         @Override
+        public boolean isSingleSessionActive(int userId) throws RemoteException {
+            final long identity = Binder.clearCallingIdentity();
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "isSingleSessionActive");
+            try {
+                synchronized (mLock) {
+                    UserState userState = getUserStateLocked(resolvedUserId);
+                    if (userState.sessionStateMap.size() == 1) {
+                        return true;
+                    }
+                    else if (userState.sessionStateMap.size() == 2) {
+                        SessionState[] sessionStates = userState.sessionStateMap.values().toArray(
+                                new SessionState[0]);
+                        // Check if there is a wrapper input.
+                        if (sessionStates[0].mHardwareSessionToken != null
+                                || sessionStates[1].mHardwareSessionToken != null) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         @SuppressWarnings("resource")
         protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
             final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
@@ -1644,6 +1682,7 @@
                     }
                     pw.decreaseIndent();
 
+                    pw.println("mainSessionToken: " + userState.mainSessionToken);
                     pw.decreaseIndent();
                 }
             }
@@ -1894,9 +1933,9 @@
                         }
                     }
 
-                    List<HdmiCecDeviceInfo> cecDeviceInfoList =
+                    List<HdmiDeviceInfo> cecDeviceInfoList =
                             mTvInputHardwareManager.getHdmiCecInputDeviceList();
-                    for (HdmiCecDeviceInfo cecDeviceInfo : cecDeviceInfoList) {
+                    for (HdmiDeviceInfo cecDeviceInfo : cecDeviceInfoList) {
                         try {
                             serviceState.mService.notifyHdmiCecDeviceAdded(cecDeviceInfo);
                         } catch (RemoteException e) {
@@ -2036,7 +2075,8 @@
                     Uri uri = (Uri) args.arg1;
                     long channelId = (long) args.arg2;
                     long time = (long) args.arg3;
-                    onOpenEntry(uri, channelId, time);
+                    SessionState sessionState = (SessionState) args.arg4;
+                    onOpenEntry(uri, channelId, time, sessionState);
                     args.recycle();
                     return;
                 }
@@ -2045,7 +2085,8 @@
                     Uri uri = (Uri) args.arg1;
                     long channelId = (long) args.arg2;
                     long time = (long) args.arg3;
-                    onUpdateEntry(uri, channelId, time);
+                    SessionState sessionState = (SessionState) args.arg4;
+                    onUpdateEntry(uri, channelId, time, sessionState);
                     args.recycle();
                     return;
                 }
@@ -2064,7 +2105,17 @@
             }
         }
 
-        private void onOpenEntry(Uri uri, long channelId, long watchStarttime) {
+        private void onOpenEntry(Uri logUri, long channelId, long watchStarttime,
+                SessionState sessionState) {
+            if (!isChannelSearchable(channelId)) {
+                // Do not log anything about non-searchable channels.
+                synchronized (mLock) {
+                    sessionState.mLogUri = null;
+                }
+                mContentResolver.delete(logUri, null, null);
+                return;
+            }
+
             String[] projection = {
                     TvContract.Programs.COLUMN_TITLE,
                     TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
@@ -2092,11 +2143,11 @@
                     long endTime = cursor.getLong(2);
                     values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
                     values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, cursor.getString(3));
-                    mContentResolver.update(uri, values, null, null);
+                    mContentResolver.update(logUri, values, null, null);
 
                     // Schedule an update when the current program ends.
                     SomeArgs args = SomeArgs.obtain();
-                    args.arg1 = uri;
+                    args.arg1 = logUri;
                     args.arg2 = channelId;
                     args.arg3 = endTime;
                     Message msg = obtainMessage(LogHandler.MSG_UPDATE_ENTRY, args);
@@ -2109,7 +2160,7 @@
             }
         }
 
-        private void onUpdateEntry(Uri uri, long channelId, long time) {
+        private void onUpdateEntry(Uri uri, long channelId, long time, SessionState sessionState) {
             String[] projection = {
                     TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
                     TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
@@ -2153,7 +2204,7 @@
                 }
             }
             // Re-open the current log entry with the next program information.
-            onOpenEntry(uri, channelId, time);
+            onOpenEntry(uri, channelId, time, sessionState);
         }
 
         private void onCloseEntry(Uri uri, long watchEndTime) {
@@ -2161,6 +2212,26 @@
             values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, watchEndTime);
             mContentResolver.update(uri, values, null, null);
         }
+
+        private boolean isChannelSearchable(long channelId) {
+            String[] projection = { TvContract.Channels.COLUMN_SEARCHABLE };
+            String selection = TvContract.Channels._ID + "=?";
+            String[] selectionArgs = { String.valueOf(channelId) };
+            Cursor cursor = null;
+            try {
+                cursor = mContentResolver.query(TvContract.Channels.CONTENT_URI, projection,
+                        selection, selectionArgs, null);
+                if (cursor != null && cursor.moveToNext()) {
+                    return cursor.getLong(0) == 1 ? true : false;
+                }
+            } finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+            // Unless explicitly specified non-searchable, by default the channel is searchable.
+            return true;
+        }
     }
 
     final class HardwareListener implements TvInputHardwareManager.Listener {
@@ -2204,7 +2275,7 @@
         }
 
         @Override
-        public void onHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDeviceInfo) {
+        public void onHdmiCecDeviceAdded(HdmiDeviceInfo cecDeviceInfo) {
             synchronized (mLock) {
                 UserState userState = getUserStateLocked(mCurrentUserId);
                 // Broadcast the event to all hardware inputs.
@@ -2220,7 +2291,7 @@
         }
 
         @Override
-        public void onHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDeviceInfo) {
+        public void onHdmiCecDeviceRemoved(HdmiDeviceInfo cecDeviceInfo) {
             synchronized (mLock) {
                 UserState userState = getUserStateLocked(mCurrentUserId);
                 // Broadcast the event to all hardware inputs.
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 899a821..fc96991 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2315,30 +2315,39 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            int count = 0;
+            ActiveAdmin admin = (who != null) ? getActiveAdminUncheckedLocked(who, userHandle)
+                    : getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle);
+            return admin != null ? admin.maximumFailedPasswordsForWipe : 0;
+        }
+    }
 
-            if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
-                return admin != null ? admin.maximumFailedPasswordsForWipe : count;
-            }
+    /**
+     * Returns the admin with the strictest policy on maximum failed passwords for this user and all
+     * profiles that are visible from this user. If the policy for the primary and any other profile
+     * are equal, it returns the admin for the primary profile.
+     * Returns {@code null} if none of them have that policy set.
+     */
+    private ActiveAdmin getAdminWithMinimumFailedPasswordsForWipeLocked(int userHandle) {
+        int count = 0;
+        ActiveAdmin strictestAdmin = null;
+        for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
+            DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+            for (ActiveAdmin admin : policy.mAdminList) {
+                if (admin.maximumFailedPasswordsForWipe ==
+                        ActiveAdmin.DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
+                    continue;  // No max number of failed passwords policy set for this profile.
+                }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (count == 0) {
-                        count = admin.maximumFailedPasswordsForWipe;
-                    } else if (admin.maximumFailedPasswordsForWipe != 0
-                            && count > admin.maximumFailedPasswordsForWipe) {
-                        count = admin.maximumFailedPasswordsForWipe;
-                    }
+                // We always favor the primary profile if several profiles have the same value set.
+                if (count == 0 ||
+                        count > admin.maximumFailedPasswordsForWipe ||
+                        (userInfo.isPrimary() && count >= admin.maximumFailedPasswordsForWipe)) {
+                    count = admin.maximumFailedPasswordsForWipe;
+                    strictestAdmin = admin;
                 }
             }
-            return count;
         }
+        return strictestAdmin;
     }
 
     public boolean resetPassword(String password, int flags, int userHandle) {
@@ -2713,7 +2722,9 @@
                 public void run() {
                     try {
                         ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
-                        mUserManager.removeUser(userHandle);
+                        if (!mUserManager.removeUser(userHandle)) {
+                            Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
+                        }
                     } catch (RemoteException re) {
                         // Shouldn't happen
                     }
@@ -2837,9 +2848,15 @@
                 policy.mFailedPasswordAttempts++;
                 saveSettingsLocked(userHandle);
                 if (mHasFeature) {
-                    int max = getMaximumFailedPasswordsForWipe(null, userHandle);
+                    ActiveAdmin strictestAdmin =
+                            getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle);
+                    int max = strictestAdmin != null
+                            ? strictestAdmin.maximumFailedPasswordsForWipe : 0;
                     if (max > 0 && policy.mFailedPasswordAttempts >= max) {
-                        wipeDeviceOrUserLocked(0, userHandle);
+                        // Wipe the user/profile associated with the policy that was violated. This
+                        // is not necessarily calling user: if the policy that fired was from a
+                        // managed profile rather than the main user profile, we wipe former only.
+                        wipeDeviceOrUserLocked(0, strictestAdmin.getUserHandle().getIdentifier());
                     }
                     sendAdminCommandToSelfAndProfilesLocked(
                             DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
@@ -4584,6 +4601,10 @@
             DevicePolicyData policy = getUserData(profileId);
             ActiveAdmin admin = policy.mAdminMap.get(ownerComponent);
 
+            if (admin == null) {
+                return Collections.emptyList();
+            }
+
             if (admin.crossProfileWidgetProviders == null
                     || admin.crossProfileWidgetProviders.isEmpty()) {
                 return Collections.emptyList();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
index b4c221f..f0ecafe 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
@@ -41,12 +41,12 @@
     static final boolean DBG = true;
 
     private static final String NAME = "sound_model.db";
-    private static final int VERSION = 3;
+    private static final int VERSION = 4;
 
     public static interface SoundModelContract {
         public static final String TABLE = "sound_model";
-        public static final String KEY_KEYPHRASE_ID = "keyphrase_id";
         public static final String KEY_MODEL_UUID = "model_uuid";
+        public static final String KEY_KEYPHRASE_ID = "keyphrase_id";
         public static final String KEY_TYPE = "type";
         public static final String KEY_DATA = "data";
         public static final String KEY_RECOGNITION_MODES = "recognition_modes";
@@ -58,8 +58,8 @@
     // Table Create Statement
     private static final String CREATE_TABLE_SOUND_MODEL = "CREATE TABLE "
             + SoundModelContract.TABLE + "("
-            + SoundModelContract.KEY_KEYPHRASE_ID + " INTEGER PRIMARY KEY,"
-            + SoundModelContract.KEY_MODEL_UUID + " TEXT,"
+            + SoundModelContract.KEY_MODEL_UUID + " TEXT PRIMARY KEY,"
+            + SoundModelContract.KEY_KEYPHRASE_ID + " INTEGER,"
             + SoundModelContract.KEY_TYPE + " INTEGER,"
             + SoundModelContract.KEY_DATA + " BLOB,"
             + SoundModelContract.KEY_RECOGNITION_MODES + " INTEGER,"
@@ -122,10 +122,16 @@
     /**
      * Deletes the sound model and associated keyphrases.
      */
-    public boolean deleteKeyphraseSoundModel(int keyphraseId) {
+    public boolean deleteKeyphraseSoundModel(UUID modelUuid) {
+        if (modelUuid == null) {
+            Slog.w(TAG, "Model UUID must be specified for deletion");
+            return false;
+        }
+
         synchronized(this) {
             SQLiteDatabase db = getWritableDatabase();
-            String soundModelClause = SoundModelContract.KEY_KEYPHRASE_ID + "=" + keyphraseId;
+            String soundModelClause = SoundModelContract.KEY_MODEL_UUID + "="
+                    + modelUuid.toString();
 
             try {
                 return db.delete(SoundModelContract.TABLE, soundModelClause, null) != 0;
@@ -151,52 +157,56 @@
 
             try {
                 if (c.moveToFirst()) {
-                    int type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE));
-                    if (type != SoundTrigger.SoundModel.TYPE_KEYPHRASE) {
-                        Slog.w(TAG, "No KeyphraseSoundModel available for the given keyphrase");
-                        return null;
-                    }
-
-                    String modelUuid = c.getString(
-                            c.getColumnIndex(SoundModelContract.KEY_MODEL_UUID));
-                    if (modelUuid == null) {
-                        Slog.w(TAG, "Ignoring sound model since it doesn't specify an ID");
-                        return null;
-                    }
-
-                    byte[] data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
-                    int recognitionModes = c.getInt(
-                            c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES));
-                    int[] users = getArrayForCommaSeparatedString(
-                            c.getString(c.getColumnIndex(SoundModelContract.KEY_USERS)));
-                    String locale = c.getString(c.getColumnIndex(SoundModelContract.KEY_LOCALE));
-                    String text = c.getString(
-                            c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT));
-
-                    // Only add keyphrases meant for the current user.
-                    if (users == null) {
-                        // No users present in the keyphrase.
-                        Slog.w(TAG, "Ignoring keyphrase since it doesn't specify users");
-                        return null;
-                    }
-                    boolean isAvailableForCurrentUser = false;
-                    int currentUser = mUserManager.getUserHandle();
-                    for (int user : users) {
-                        if (currentUser == user) {
-                            isAvailableForCurrentUser = true;
-                            break;
+                    do {
+                        int type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE));
+                        if (type != SoundTrigger.SoundModel.TYPE_KEYPHRASE) {
+                            Slog.w(TAG, "Ignoring sound model since it's type is incorrect");
+                            continue;
                         }
-                    }
-                    if (!isAvailableForCurrentUser) {
-                        Slog.w(TAG, "Ignoring keyphrase since it's not for the current user");
-                        return null;
-                    }
 
-                    Keyphrase[] keyphrases = new Keyphrase[1];
-                    keyphrases[0] = new Keyphrase(
-                            keyphraseId, recognitionModes, locale, text, users);
-                    return new KeyphraseSoundModel(UUID.fromString(modelUuid),
-                            null /* FIXME use vendor UUID */, data, keyphrases);
+                        String modelUuid = c.getString(
+                                c.getColumnIndex(SoundModelContract.KEY_MODEL_UUID));
+                        if (modelUuid == null) {
+                            Slog.w(TAG, "Ignoring sound model since it doesn't specify an ID");
+                            continue;
+                        }
+
+                        byte[] data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
+                        int recognitionModes = c.getInt(
+                                c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES));
+                        int[] users = getArrayForCommaSeparatedString(
+                                c.getString(c.getColumnIndex(SoundModelContract.KEY_USERS)));
+                        String locale = c.getString(
+                                c.getColumnIndex(SoundModelContract.KEY_LOCALE));
+                        String text = c.getString(
+                                c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT));
+
+                        // Only add keyphrases meant for the current user.
+                        if (users == null) {
+                            // No users present in the keyphrase.
+                            Slog.w(TAG, "Ignoring keyphrase since it doesn't specify users");
+                            continue;
+                        }
+
+                        boolean isAvailableForCurrentUser = false;
+                        int currentUser = mUserManager.getUserHandle();
+                        for (int user : users) {
+                            if (currentUser == user) {
+                                isAvailableForCurrentUser = true;
+                                break;
+                            }
+                        }
+                        if (!isAvailableForCurrentUser) {
+                            Slog.w(TAG, "Ignoring keyphrase since it's not for the current user");
+                            continue;
+                        }
+
+                        Keyphrase[] keyphrases = new Keyphrase[1];
+                        keyphrases[0] = new Keyphrase(
+                                keyphraseId, recognitionModes, locale, text, users);
+                        return new KeyphraseSoundModel(UUID.fromString(modelUuid),
+                                null /* FIXME use vendor UUID */, data, keyphrases);
+                    } while (c.moveToNext());
                 }
                 Slog.w(TAG, "No SoundModel available for the given keyphrase");
             } finally {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
index fd36bfc..994f758 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
@@ -28,9 +28,12 @@
 import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
 import android.hardware.soundtrigger.SoundTriggerModule;
 import android.os.RemoteException;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
 import android.util.Slog;
-import android.util.SparseArray;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.UUID;
 
@@ -53,26 +56,37 @@
     public static final int STATUS_ERROR = SoundTrigger.STATUS_ERROR;
     public static final int STATUS_OK = SoundTrigger.STATUS_OK;
 
-    private static final int INVALID_SOUND_MODEL_HANDLE = -1;
+    private static final int INVALID_VALUE = Integer.MIN_VALUE;
 
-    /** The {@link DspInfo} for the system, or null if none exists. */
+    /** The {@link ModuleProperties} for the system, or null if none exists. */
     final ModuleProperties moduleProperties;
 
     /** The properties for the DSP module */
     private final SoundTriggerModule mModule;
+    private final Object mLock = new Object();
+    private final TelephonyManager mTelephonyManager;
+    private final PhoneStateListener mPhoneStateListener;
 
-    // Use a RemoteCallbackList here?
-    private final SparseArray<IRecognitionStatusCallback> mActiveListeners;
-
-    private int mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE;
+    // TODO: Since many layers currently only deal with one recognition
+    // we simplify things by assuming one listener here too.
+    private IRecognitionStatusCallback mActiveListener;
+    private int mKeyphraseId = INVALID_VALUE;
+    private int mCurrentSoundModelHandle = INVALID_VALUE;
     private UUID mCurrentSoundModelUuid = null;
     // FIXME: Ideally this should not be stored if allowMultipleTriggers happens at a lower layer.
     private RecognitionConfig mRecognitionConfig = null;
+    private boolean mRequested = false;
+    private boolean mCallActive = false;
+    // Indicates if the native sound trigger service is disabled or not.
+    // This is an indirect indication of the microphone being open in some other application.
+    private boolean mServiceDisabled = false;
+    private boolean mStarted = false;
 
-    SoundTriggerHelper() {
+    SoundTriggerHelper(TelephonyManager telephonyManager) {
         ArrayList <ModuleProperties> modules = new ArrayList<>();
         int status = SoundTrigger.listModules(modules);
-        mActiveListeners = new SparseArray<>(1);
+        mTelephonyManager = telephonyManager;
+        mPhoneStateListener = new MyCallStateListener();
         if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
             Slog.w(TAG, "listModules status=" + status + ", # of modules=" + modules.size());
             moduleProperties = null;
@@ -85,17 +99,6 @@
     }
 
     /**
-     * @return True, if a recognition for the given {@link Keyphrase} is active.
-     */
-    synchronized boolean isKeyphraseActive(Keyphrase keyphrase) {
-        if (keyphrase == null) {
-            Slog.w(TAG, "isKeyphraseActive requires a non-null keyphrase");
-            return false;
-        }
-        return mActiveListeners.get(keyphrase.id) != null;
-    }
-
-    /**
      * Starts recognition for the given keyphraseId.
      *
      * @param keyphraseId The identifier of the keyphrase for which
@@ -104,85 +107,94 @@
      * @param listener The listener for the recognition events related to the given keyphrase.
      * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
      */
-    synchronized int startRecognition(int keyphraseId,
+    int startRecognition(int keyphraseId,
             KeyphraseSoundModel soundModel,
             IRecognitionStatusCallback listener,
             RecognitionConfig recognitionConfig) {
-        if (DBG) {
-            Slog.d(TAG, "startRecognition for keyphraseId=" + keyphraseId
-                    + " soundModel=" + soundModel + ", listener=" + listener
-                    + ", recognitionConfig=" + recognitionConfig);
-            Slog.d(TAG, "moduleProperties=" + moduleProperties);
-            Slog.d(TAG, "# of current listeners=" + mActiveListeners.size());
-            Slog.d(TAG, "current SoundModel handle=" + mCurrentSoundModelHandle);
-            Slog.d(TAG, "current SoundModel UUID="
-                    + (mCurrentSoundModelUuid == null ? null : mCurrentSoundModelUuid));
-        }
-        if (moduleProperties == null || mModule == null) {
-            Slog.w(TAG, "Attempting startRecognition without the capability");
+        if (soundModel == null || listener == null || recognitionConfig == null) {
             return STATUS_ERROR;
         }
 
-        if (mCurrentSoundModelHandle != INVALID_SOUND_MODEL_HANDLE
-                && !soundModel.uuid.equals(mCurrentSoundModelUuid)) {
-            Slog.w(TAG, "Unloading previous sound model");
-            int status = mModule.unloadSoundModel(mCurrentSoundModelHandle);
-            if (status != SoundTrigger.STATUS_OK) {
-                Slog.w(TAG, "unloadSoundModel call failed with " + status);
-                return status;
+        synchronized (mLock) {
+            if (DBG) {
+                Slog.d(TAG, "startRecognition for keyphraseId=" + keyphraseId
+                        + " soundModel=" + soundModel + ", listener=" + listener.asBinder()
+                        + ", recognitionConfig=" + recognitionConfig);
+                Slog.d(TAG, "moduleProperties=" + moduleProperties);
+                Slog.d(TAG, "current listener="
+                        + (mActiveListener == null ? "null" : mActiveListener.asBinder()));
+                Slog.d(TAG, "current SoundModel handle=" + mCurrentSoundModelHandle);
+                Slog.d(TAG, "current SoundModel UUID="
+                        + (mCurrentSoundModelUuid == null ? null : mCurrentSoundModelUuid));
             }
-            mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE;
-            mCurrentSoundModelUuid = null;
-        }
 
-        // If the previous recognition was by a different listener,
-        // Notify them that it was stopped.
-        IRecognitionStatusCallback oldListener = mActiveListeners.get(keyphraseId);
-        if (oldListener != null && oldListener.asBinder() != listener.asBinder()) {
-            Slog.w(TAG, "Canceling previous recognition");
-            try {
-                oldListener.onError(STATUS_ERROR);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException in onDetectionStopped");
+            if (!mStarted) {
+                // Get the current call state synchronously for the first recognition.
+                mCallActive = mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE;
+                // Register for call state changes when the first call to start recognition occurs.
+                mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
             }
-            mActiveListeners.remove(keyphraseId);
-        }
 
-        // Load the sound model if the current one is null.
-        int soundModelHandle = mCurrentSoundModelHandle;
-        if (mCurrentSoundModelHandle == INVALID_SOUND_MODEL_HANDLE
-                || mCurrentSoundModelUuid == null) {
-            int[] handle = new int[] { INVALID_SOUND_MODEL_HANDLE };
-            int status = mModule.loadSoundModel(soundModel, handle);
-            if (status != SoundTrigger.STATUS_OK) {
-                Slog.w(TAG, "loadSoundModel call failed with " + status);
-                return status;
-            }
-            if (handle[0] == INVALID_SOUND_MODEL_HANDLE) {
-                Slog.w(TAG, "loadSoundModel call returned invalid sound model handle");
+            if (moduleProperties == null || mModule == null) {
+                Slog.w(TAG, "Attempting startRecognition without the capability");
                 return STATUS_ERROR;
             }
-            soundModelHandle = handle[0];
-        } else {
-            if (DBG) Slog.d(TAG, "Reusing previously loaded sound model");
-        }
 
-        // Start the recognition.
-        int status = mModule.startRecognition(soundModelHandle, recognitionConfig);
-        if (status != SoundTrigger.STATUS_OK) {
-            Slog.w(TAG, "startRecognition failed with " + status);
-            return status;
-        }
+            if (mCurrentSoundModelHandle != INVALID_VALUE
+                    && !soundModel.uuid.equals(mCurrentSoundModelUuid)) {
+                Slog.w(TAG, "Unloading previous sound model");
+                int status = mModule.unloadSoundModel(mCurrentSoundModelHandle);
+                if (status != SoundTrigger.STATUS_OK) {
+                    Slog.w(TAG, "unloadSoundModel call failed with " + status);
+                }
+                mCurrentSoundModelHandle = INVALID_VALUE;
+                mCurrentSoundModelUuid = null;
+                mStarted = false;
+            }
 
-        // Everything went well!
-        mCurrentSoundModelHandle = soundModelHandle;
-        mCurrentSoundModelUuid = soundModel.uuid;
-        mRecognitionConfig = recognitionConfig;
-        // Register the new listener. This replaces the old one.
-        // There can only be a maximum of one active listener for a keyphrase
-        // at any given time.
-        mActiveListeners.put(keyphraseId, listener);
-        return STATUS_OK;
+            // If the previous recognition was by a different listener,
+            // Notify them that it was stopped.
+            if (mActiveListener != null && mActiveListener.asBinder() != listener.asBinder()) {
+                Slog.w(TAG, "Canceling previous recognition");
+                try {
+                    mActiveListener.onError(STATUS_ERROR);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "RemoteException in onDetectionStopped");
+                }
+                mActiveListener = null;
+            }
+
+            // Load the sound model if the current one is null.
+            int soundModelHandle = mCurrentSoundModelHandle;
+            if (mCurrentSoundModelHandle == INVALID_VALUE
+                    || mCurrentSoundModelUuid == null) {
+                int[] handle = new int[] { INVALID_VALUE };
+                int status = mModule.loadSoundModel(soundModel, handle);
+                if (status != SoundTrigger.STATUS_OK) {
+                    Slog.w(TAG, "loadSoundModel call failed with " + status);
+                    return status;
+                }
+                if (handle[0] == INVALID_VALUE) {
+                    Slog.w(TAG, "loadSoundModel call returned invalid sound model handle");
+                    return STATUS_ERROR;
+                }
+                soundModelHandle = handle[0];
+            } else {
+                if (DBG) Slog.d(TAG, "Reusing previously loaded sound model");
+            }
+
+            // Start the recognition.
+            mRequested = true;
+            mKeyphraseId = keyphraseId;
+            mCurrentSoundModelHandle = soundModelHandle;
+            mCurrentSoundModelUuid = soundModel.uuid;
+            mRecognitionConfig = recognitionConfig;
+            // Register the new listener. This replaces the old one.
+            // There can only be a maximum of one active listener at any given time.
+            mActiveListener = listener;
+
+            return updateRecognitionLocked(false /* don't notify for synchronous calls */);
+        }
     }
 
     /**
@@ -195,173 +207,325 @@
      *
      * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
      */
-    synchronized int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
-        if (DBG) {
-            Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId
-                    + ", listener=" + listener);
-            Slog.d(TAG, "# of current listeners = " + mActiveListeners.size());
-        }
-
-        if (moduleProperties == null || mModule == null) {
-            Slog.w(TAG, "Attempting stopRecognition without the capability");
-            return STATUS_ERROR;
-        }
-
-        IRecognitionStatusCallback currentListener = mActiveListeners.get(keyphraseId);
+    int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
         if (listener == null) {
-            Slog.w(TAG, "Attempting stopRecognition without a valid listener");
             return STATUS_ERROR;
-        } if (currentListener == null) {
-            // startRecognition hasn't been called or it failed.
-            Slog.w(TAG, "Attempting stopRecognition without a successful startRecognition");
-            return STATUS_ERROR;
-        } else if (currentListener.asBinder() != listener.asBinder()) {
-            // We don't allow a different listener to stop the recognition than the one
-            // that started it.
-            Slog.w(TAG, "Attempting stopRecognition for another recognition");
-            return STATUS_ERROR;
-        } else {
+        }
+
+        synchronized (mLock) {
+            if (DBG) {
+                Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId
+                        + ", listener=" + listener.asBinder());
+                Slog.d(TAG, "current listener="
+                        + (mActiveListener == null ? "null" : mActiveListener.asBinder()));
+            }
+
+            if (moduleProperties == null || mModule == null) {
+                Slog.w(TAG, "Attempting stopRecognition without the capability");
+                return STATUS_ERROR;
+            }
+
+            if (mActiveListener == null) {
+                // startRecognition hasn't been called or it failed.
+                Slog.w(TAG, "Attempting stopRecognition without a successful startRecognition");
+                return STATUS_ERROR;
+            }
+            if (mActiveListener.asBinder() != listener.asBinder()) {
+                // We don't allow a different listener to stop the recognition than the one
+                // that started it.
+                Slog.w(TAG, "Attempting stopRecognition for another recognition");
+                return STATUS_ERROR;
+            }
+
             // Stop recognition if it's the current one, ignore otherwise.
-            int status = mModule.stopRecognition(mCurrentSoundModelHandle);
+            mRequested = false;
+            int status = updateRecognitionLocked(false /* don't notify for synchronous calls */);
             if (status != SoundTrigger.STATUS_OK) {
-                Slog.w(TAG, "stopRecognition call failed with " + status);
                 return status;
             }
+
             status = mModule.unloadSoundModel(mCurrentSoundModelHandle);
             if (status != SoundTrigger.STATUS_OK) {
                 Slog.w(TAG, "unloadSoundModel call failed with " + status);
-                return status;
             }
 
-            mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE;
-            mCurrentSoundModelUuid = null;
-
-            mActiveListeners.remove(keyphraseId);
-            return STATUS_OK;
+            // Clear the internal state once the recognition has been stopped.
+            // Unload sound model call may fail in scenarios, and we'd still want
+            // to reload the sound model.
+            internalClearStateLocked();
+            return status;
         }
     }
 
-    synchronized void stopAllRecognitions() {
-        if (moduleProperties == null || mModule == null) {
-            return;
-        }
+    /**
+     * Stops all recognitions active currently and clears the internal state.
+     */
+    void stopAllRecognitions() {
+        synchronized (mLock) {
+            if (moduleProperties == null || mModule == null) {
+                return;
+            }
 
-        if (mCurrentSoundModelHandle == INVALID_SOUND_MODEL_HANDLE) {
-            return;
-        }
+            if (mCurrentSoundModelHandle == INVALID_VALUE) {
+                return;
+            }
 
-        int status = mModule.stopRecognition(mCurrentSoundModelHandle);
-        if (status != SoundTrigger.STATUS_OK) {
-            Slog.w(TAG, "stopRecognition call failed with " + status);
-        }
-        status = mModule.unloadSoundModel(mCurrentSoundModelHandle);
-        if (status != SoundTrigger.STATUS_OK) {
-            Slog.w(TAG, "unloadSoundModel call failed with " + status);
-        }
+            mRequested = false;
+            int status = updateRecognitionLocked(false /* don't notify for synchronous calls */);
+            status = mModule.unloadSoundModel(mCurrentSoundModelHandle);
+            if (status != SoundTrigger.STATUS_OK) {
+                Slog.w(TAG, "unloadSoundModel call failed with " + status);
+            }
 
-        mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE;
-        mCurrentSoundModelUuid = null;
-
-        mActiveListeners.clear();
+            internalClearStateLocked();
+        }
     }
 
     //---- SoundTrigger.StatusListener methods
     @Override
     public void onRecognition(RecognitionEvent event) {
-        if (event == null) {
+        if (event == null || !(event instanceof KeyphraseRecognitionEvent)) {
             Slog.w(TAG, "Invalid recognition event!");
             return;
         }
 
         if (DBG) Slog.d(TAG, "onRecognition: " + event);
-        switch (event.status) {
-            // Fire aborts/failures to all listeners since it's not tied to a keyphrase.
-            case SoundTrigger.RECOGNITION_STATUS_ABORT: // fall-through
-            case SoundTrigger.RECOGNITION_STATUS_FAILURE:
-                try {
-                    synchronized (this) {
-                        for (int i = 0; i < mActiveListeners.size(); i++) {
-                            mActiveListeners.valueAt(i).onError(STATUS_ERROR);
-                        }
-                    }
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "RemoteException in onDetectionStopped");
-                }
-                break;
-            case SoundTrigger.RECOGNITION_STATUS_SUCCESS:
-                if (!(event instanceof KeyphraseRecognitionEvent)) {
-                    Slog.w(TAG, "Invalid recognition event!");
-                    return;
-                }
-
-                KeyphraseRecognitionExtra[] keyphraseExtras =
-                        ((KeyphraseRecognitionEvent) event).keyphraseExtras;
-                if (keyphraseExtras == null || keyphraseExtras.length == 0) {
-                    Slog.w(TAG, "Invalid keyphrase recognition event!");
-                    return;
-                }
-                // TODO: Handle more than one keyphrase extras.
-                int keyphraseId = keyphraseExtras[0].id;
-                try {
-                    synchronized(this) {
-                        // Check which keyphrase triggered, and fire the appropriate event.
-                        IRecognitionStatusCallback listener = mActiveListeners.get(keyphraseId);
-                        if (listener != null) {
-                            listener.onDetected((KeyphraseRecognitionEvent) event);
-                        } else {
-                            Slog.w(TAG, "received onRecognition event without any listener for it");
-                            return;
-                        }
-
-                        // FIXME: Remove this block if the lower layer supports multiple triggers.
-                        if (mRecognitionConfig != null
-                                && mRecognitionConfig.allowMultipleTriggers) {
-                            int status = mModule.startRecognition(
-                                    mCurrentSoundModelHandle, mRecognitionConfig);
-                            if (status != STATUS_OK) {
-                                Slog.w(TAG, "Error in restarting recognition after a trigger");
-                                listener.onError(status);
-                            }
-                        }
-                    }
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "RemoteException in onDetectionStopped");
-                }
-                break;
+        synchronized (mLock) {
+            if (mActiveListener == null) {
+                Slog.w(TAG, "received onRecognition event without any listener for it");
+                return;
+            }
+            switch (event.status) {
+                // Fire aborts/failures to all listeners since it's not tied to a keyphrase.
+                case SoundTrigger.RECOGNITION_STATUS_ABORT:
+                    onRecognitionAbortLocked();
+                    break;
+                case SoundTrigger.RECOGNITION_STATUS_FAILURE:
+                    onRecognitionFailureLocked();
+                    break;
+                case SoundTrigger.RECOGNITION_STATUS_SUCCESS:
+                    onRecognitionSuccessLocked((KeyphraseRecognitionEvent) event);
+                    break;
+            }
         }
     }
 
+    @Override
     public void onSoundModelUpdate(SoundModelEvent event) {
         if (event == null) {
             Slog.w(TAG, "Invalid sound model event!");
             return;
         }
-
         if (DBG) Slog.d(TAG, "onSoundModelUpdate: " + event);
-
-        //TODO: implement sound model update
+        synchronized (mLock) {
+            onSoundModelUpdatedLocked(event);
+        }
     }
 
+    @Override
     public void onServiceStateChange(int state) {
         if (DBG) Slog.d(TAG, "onServiceStateChange, state: " + state);
-
-        //TODO: implement service state update
+        synchronized (mLock) {
+            onServiceStateChangedLocked(SoundTrigger.SERVICE_STATE_DISABLED == state);
+        }
     }
 
     @Override
     public void onServiceDied() {
-        synchronized (this) {
-            try {
-                for (int i = 0; i < mActiveListeners.size(); i++) {
-                    mActiveListeners.valueAt(i).onError(SoundTrigger.STATUS_DEAD_OBJECT);
-                }
-            } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException in onDetectionStopped");
+        Slog.e(TAG, "onServiceDied!!");
+        synchronized (mLock) {
+            onServiceDiedLocked();
+        }
+    }
+
+    class MyCallStateListener extends PhoneStateListener {
+        @Override
+        public void onCallStateChanged(int state, String arg1) {
+            if (DBG) Slog.d(TAG, "onCallStateChanged: " + state);
+            synchronized (mLock) {
+                onCallStateChangedLocked(TelephonyManager.CALL_STATE_IDLE != state);
             }
-            mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE;
-            mCurrentSoundModelUuid = null;
-            // Remove all listeners.
-            mActiveListeners.clear();
+        }
+    }
+
+    private void onCallStateChangedLocked(boolean callActive) {
+        if (mCallActive == callActive) {
+            // We consider multiple call states as being active
+            // so we check if something really changed or not here.
+            return;
+        }
+        mCallActive = callActive;
+        updateRecognitionLocked(true /* notify */);
+    }
+
+    private void onSoundModelUpdatedLocked(SoundModelEvent event) {
+        // TODO: Handle sound model update here.
+    }
+
+    private void onServiceStateChangedLocked(boolean disabled) {
+        if (disabled == mServiceDisabled) {
+            return;
+        }
+        mServiceDisabled = disabled;
+        updateRecognitionLocked(true /* notify */);
+    }
+
+    private void onRecognitionAbortLocked() {
+        Slog.w(TAG, "Recognition aborted");
+        // No-op
+        // This is handled via service state changes instead.
+    }
+
+    private void onRecognitionFailureLocked() {
+        Slog.w(TAG, "Recognition failure");
+        try {
+            if (mActiveListener != null) {
+                mActiveListener.onError(STATUS_ERROR);
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException in onError", e);
+        } finally {
+            internalClearStateLocked();
+        }
+    }
+
+    private void onRecognitionSuccessLocked(KeyphraseRecognitionEvent event) {
+        Slog.i(TAG, "Recognition success");
+        KeyphraseRecognitionExtra[] keyphraseExtras =
+                ((KeyphraseRecognitionEvent) event).keyphraseExtras;
+        if (keyphraseExtras == null || keyphraseExtras.length == 0) {
+            Slog.w(TAG, "Invalid keyphrase recognition event!");
+            return;
+        }
+        // TODO: Handle more than one keyphrase extras.
+        if (mKeyphraseId != keyphraseExtras[0].id) {
+            Slog.w(TAG, "received onRecognition event for a different keyphrase");
+            return;
+        }
+
+        try {
+            if (mActiveListener != null) {
+                mActiveListener.onDetected((KeyphraseRecognitionEvent) event);
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException in onDetected", e);
+        }
+
+        mStarted = false;
+        mRequested = mRecognitionConfig.allowMultipleTriggers;
+        // TODO: Remove this block if the lower layer supports multiple triggers.
+        if (mRequested) {
+            updateRecognitionLocked(true /* notify */);
+        }
+    }
+
+    private void onServiceDiedLocked() {
+        try {
+            if (mActiveListener != null) {
+                mActiveListener.onError(SoundTrigger.STATUS_DEAD_OBJECT);
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException in onError", e);
+        } finally {
+            internalClearStateLocked();
+        }
+    }
+
+    private int updateRecognitionLocked(boolean notify) {
+        if (mModule == null || moduleProperties == null
+                || mCurrentSoundModelHandle == INVALID_VALUE || mActiveListener == null) {
+            // Nothing to do here.
+            return STATUS_OK;
+        }
+
+        boolean start = mRequested && !mCallActive && !mServiceDisabled;
+        if (start == mStarted) {
+            // No-op.
+            return STATUS_OK;
+        }
+
+        // See if the recognition needs to be started.
+        if (start) {
+            // Start recognition.
+            int status = mModule.startRecognition(mCurrentSoundModelHandle, mRecognitionConfig);
+            if (status != SoundTrigger.STATUS_OK) {
+                Slog.w(TAG, "startRecognition failed with " + status);
+                // Notify of error if needed.
+                if (notify) {
+                    try {
+                        mActiveListener.onError(status);
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "RemoteException in onError", e);
+                    }
+                }
+            } else {
+                mStarted = true;
+                // Notify of resume if needed.
+                if (notify) {
+                    try {
+                        mActiveListener.onRecognitionResumed();
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "RemoteException in onRecognitionResumed", e);
+                    }
+                }
+            }
+            return status;
+        } else {
+            // Stop recognition.
+            int status = mModule.stopRecognition(mCurrentSoundModelHandle);
+            if (status != SoundTrigger.STATUS_OK) {
+                Slog.w(TAG, "stopRecognition call failed with " + status);
+                if (notify) {
+                    try {
+                        mActiveListener.onError(status);
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "RemoteException in onError", e);
+                    }
+                }
+            } else {
+                mStarted = false;
+                // Notify of pause if needed.
+                if (notify) {
+                    try {
+                        mActiveListener.onRecognitionPaused();
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
+                    }
+                }
+            }
+            return status;
+        }
+    }
+
+    private void internalClearStateLocked() {
+        mStarted = false;
+        mRequested = false;
+
+        mKeyphraseId = INVALID_VALUE;
+        mCurrentSoundModelHandle = INVALID_VALUE;
+        mCurrentSoundModelUuid = null;
+        mRecognitionConfig = null;
+        mActiveListener = null;
+
+        // Unregister from call state changes.
+        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        synchronized (mLock) {
+            pw.print("  module properties=");
+            pw.println(moduleProperties == null ? "null" : moduleProperties);
+            pw.print("  keyphrase ID="); pw.println(mKeyphraseId);
+            pw.print("  sound model handle="); pw.println(mCurrentSoundModelHandle);
+            pw.print("  sound model UUID=");
+            pw.println(mCurrentSoundModelUuid == null ? "null" : mCurrentSoundModelUuid);
+            pw.print("  current listener=");
+            pw.println(mActiveListener == null ? "null" : mActiveListener.asBinder());
+
+            pw.print("  requested="); pw.println(mRequested);
+            pw.print("  started="); pw.println(mStarted);
+            pw.print("  call active="); pw.println(mCallActive);
+            pw.print("  service disabled="); pw.println(mServiceDisabled);
         }
     }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 75d41aa..0d24793 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -38,6 +38,7 @@
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionService;
 import android.service.voice.IVoiceInteractionSession;
+import android.telephony.TelephonyManager;
 import android.util.Slog;
 
 import com.android.internal.app.IVoiceInteractionManagerService;
@@ -67,7 +68,8 @@
         mContext = context;
         mResolver = context.getContentResolver();
         mDbHelper = new DatabaseHelper(context);
-        mSoundTriggerHelper = new SoundTriggerHelper();
+        mSoundTriggerHelper = new SoundTriggerHelper(
+                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE));
     }
 
     @Override
@@ -301,19 +303,22 @@
             }
 
             final long caller = Binder.clearCallingIdentity();
+            boolean deleted = false;
             try {
-                if (mDbHelper.deleteKeyphraseSoundModel(keyphraseId)) {
+                KeyphraseSoundModel soundModel = mDbHelper.getKeyphraseSoundModel(keyphraseId);
+                if (soundModel != null) {
+                    deleted = mDbHelper.deleteKeyphraseSoundModel(soundModel.uuid);
+                }
+                return deleted ? SoundTriggerHelper.STATUS_OK : SoundTriggerHelper.STATUS_ERROR;
+            } finally {
+                if (deleted) {
                     synchronized (this) {
                         // Notify the voice interaction service of a change in sound models.
                         if (mImpl != null && mImpl.mService != null) {
                             mImpl.notifySoundModelsChangedLocked();
                         }
                     }
-                    return SoundTriggerHelper.STATUS_OK;
-                } else {
-                    return SoundTriggerHelper.STATUS_ERROR;
                 }
-            } finally {
                 Binder.restoreCallingIdentity(caller);
             }
         }
@@ -427,6 +432,7 @@
                 }
                 mImpl.dumpLocked(fd, pw, args);
             }
+            mSoundTriggerHelper.dump(fd, pw, args);
         }
 
         class SettingsObserver extends ContentObserver {
diff --git a/telecomm/java/android/telecomm/Call.java b/telecomm/java/android/telecomm/Call.java
index 4e9e604..3374d51 100644
--- a/telecomm/java/android/telecomm/Call.java
+++ b/telecomm/java/android/telecomm/Call.java
@@ -249,7 +249,7 @@
         /**
          * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
          *
-         * TODO(ihab): Provide previous state also?
+         * TODO: Provide previous state also?
          *
          * @param call The {@code Call} invoking this method.
          * @param state The new state of the {@code Call}.
@@ -453,7 +453,7 @@
     /**
      * Notifies this {@code Call} that the phone account user interface element was touched.
      *
-     * TODO(ihab): Figure out if and how we can generalize this
+     * TODO: Figure out if and how we can generalize this
      */
     public void phoneAccountClicked() {
         mInCallAdapter.phoneAccountClicked(mTelecommCallId);
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index d347aad..b323646 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -273,7 +273,7 @@
     }
 
     /**
-     * TODO(santoscordon): Needs documentation.
+     * TODO: Needs documentation.
      */
     public final void setParentConnection(Connection parentConnection) {
         Log.d(this, "parenting %s to %s", this, parentConnection);
@@ -458,7 +458,7 @@
     }
 
     /**
-     * TODO(santoscordon): Needs documentation.
+     * TODO: Needs documentation.
      */
     public final void setPostDialWait(String remaining) {
         for (Listener l : mListeners) {
@@ -654,7 +654,7 @@
     public void onSwapWithBackgroundCall() {}
 
     /**
-     * TODO(santoscordon): Needs documentation.
+     * TODO: Needs documentation.
      */
     public void onChildrenChanged(List<Connection> children) {}
 
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 53b304a..5e6bf87 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -647,7 +647,7 @@
             return;
         }
 
-        // TODO(santoscordon): Find existing conference call and invoke split(connection).
+        // TODO: Find existing conference call and invoke split(connection).
     }
 
     private void swapWithBackgroundCall(String callId) {
@@ -880,6 +880,11 @@
         return sNullConnection;
     }
 
+    /**
+     * Abstraction for a class which provides video call functionality. This class contains no base
+     * implementation for its methods. It is expected that subclasses will override these
+     * functions to provide the desired behavior if it is supported.
+     */
     public static abstract class VideoCallProvider {
         private static final int MSG_SET_VIDEO_CALL_LISTENER = 1;
         private static final int MSG_SET_CAMERA = 2;
@@ -1012,38 +1017,48 @@
          *
          * @param cameraId The id of the camera.
          */
-        public abstract void onSetCamera(String cameraId);
+        public void onSetCamera(String cameraId) {
+            // To be implemented by subclass.
+        }
 
         /**
          * Sets the surface to be used for displaying a preview of what the user's camera is
-         * currently capturing.  When video transmission is enabled, this is the video signal which is
-         * sent to the remote device.
+         * currently capturing.  When video transmission is enabled, this is the video signal which
+         * is sent to the remote device.
          *
          * @param surface The surface.
          */
-        public abstract void onSetPreviewSurface(Surface surface);
+        public void onSetPreviewSurface(Surface surface) {
+            // To be implemented by subclass.
+        }
 
         /**
          * Sets the surface to be used for displaying the video received from the remote device.
          *
          * @param surface The surface.
          */
-        public abstract void onSetDisplaySurface(Surface surface);
+        public void onSetDisplaySurface(Surface surface) {
+            // To be implemented by subclass.
+        }
 
         /**
-         * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of the
-         * device is 0 degrees.
+         * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of
+         * the device is 0 degrees.
          *
          * @param rotation The device orientation, in degrees.
          */
-        public abstract void onSetDeviceOrientation(int rotation);
+        public void onSetDeviceOrientation(int rotation) {
+            // To be implemented by subclass.
+        }
 
         /**
          * Sets camera zoom ratio.
          *
          * @param value The camera zoom ratio.
          */
-        public abstract void onSetZoom(float value);
+        public void onSetZoom(float value) {
+            // To be implemented by subclass.
+        }
 
         /**
          * Issues a request to modify the properties of the current session.  The request is sent to
@@ -1054,7 +1069,9 @@
          *
          * @param requestProfile The requested call video properties.
          */
-        public abstract void onSendSessionModifyRequest(VideoCallProfile requestProfile);
+        public void onSendSessionModifyRequest(VideoCallProfile requestProfile) {
+            // To be implemented by subclass.
+        }
 
         /**te
          * Provides a response to a request to change the current call session video
@@ -1066,21 +1083,27 @@
          *
          * @param responseProfile The response call video properties.
          */
-        public abstract void onSendSessionModifyResponse(VideoCallProfile responseProfile);
+        public void onSendSessionModifyResponse(VideoCallProfile responseProfile) {
+            // To be implemented by subclass.
+        }
 
         /**
          * Issues a request to the video provider to retrieve the camera capabilities.
          * Camera capabilities are reported back to the caller via
          * {@link InCallService.VideoCall.Listener#onCameraCapabilitiesChanged(CallCameraCapabilities)}.
          */
-        public abstract void onRequestCameraCapabilities();
+        public void onRequestCameraCapabilities() {
+            // To be implemented by subclass.
+        }
 
         /**
          * Issues a request to the video telephony framework to retrieve the cumulative data usage for
          * the current call.  Data usage is reported back to the caller via
          * {@link InCallService.VideoCall.Listener#onCallDataUsageChanged}.
          */
-        public abstract void onRequestCallDataUsage();
+        public void onRequestCallDataUsage() {
+            // To be implemented by subclass.
+        }
 
         /**
          * Provides the video telephony framework with the URI of an image to be displayed to remote
@@ -1088,7 +1111,9 @@
          *
          * @param uri URI of image to display.
          */
-        public abstract void onSetPauseImage(String uri);
+        public void onSetPauseImage(String uri) {
+            // To be implemented by subclass.
+        }
 
         /**
          * Invokes callback method defined in {@link InCallService.VideoCall.Listener}.
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
index 279e47d..08eb03a 100644
--- a/telecomm/java/android/telecomm/InCallAdapter.java
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -28,8 +28,6 @@
  * given call IDs to execute commands such as {@link #answerCall} for incoming calls or
  * {@link #disconnectCall} for active calls the user would like to end. Some commands are only
  * appropriate for calls in certain states; please consult each method for such limitations.
- * TODO(santoscordon): Needs more/better comments once the API is finalized.
- * TODO(santoscordon): Specify the adapter will stop functioning when there are no more calls.
  */
 public final class InCallAdapter {
     private final IInCallAdapter mAdapter;
@@ -56,8 +54,6 @@
 
     /**
      * Instructs Telecomm to reject the specified call.
-     * TODO(santoscordon): Add reject-with-text-message parameter when that feature
-     * is ported over.
      *
      * @param callId The identifier of the call to reject.
      * @param rejectWithMessage Whether to reject with a text message.
diff --git a/telecomm/java/android/telecomm/InCallService.java b/telecomm/java/android/telecomm/InCallService.java
index 83e2957..a88e1cc 100644
--- a/telecomm/java/android/telecomm/InCallService.java
+++ b/telecomm/java/android/telecomm/InCallService.java
@@ -35,7 +35,7 @@
  * This service is implemented by any app that wishes to provide the user-interface for managing
  * phone calls. Telecomm binds to this service while there exists a live (active or incoming) call,
  * and uses it to notify the in-call app of any live and and recently disconnected calls.
- * TODO(santoscordon): What happens if two or more apps on a given device implement this interface?
+ * TODO: What happens if two or more apps on a given device implement this interface?
  */
 public abstract class InCallService extends Service {
     private static final int MSG_SET_IN_CALL_ADAPTER = 1;
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable26.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable26.xml
new file mode 100644
index 0000000..29cff52
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable26.xml
@@ -0,0 +1,45 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:translateX="50"
+        android:translateY="50" >
+        <path
+            android:name="twoLines"
+            android:pathData="M 100,20 l 0 80 l -30 -80"
+            android:strokeColor="#FF00FF00"
+            android:strokeLineCap="butt"
+            android:strokeLineJoin="miter"
+            android:strokeMiterLimit="5"
+            android:strokeWidth="20" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable27.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable27.xml
new file mode 100644
index 0000000..b0f0cee
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable27.xml
@@ -0,0 +1,45 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:translateX="50"
+        android:translateY="50" >
+        <path
+            android:name="twoLines"
+            android:pathData="M 100,20 l 0 80 l -30 -80"
+            android:strokeColor="#FF00FF00"
+            android:strokeLineCap="round"
+            android:strokeLineJoin="round"
+            android:strokeMiterLimit="10"
+            android:strokeWidth="20" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable28.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable28.xml
new file mode 100644
index 0000000..cd7bb16
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable28.xml
@@ -0,0 +1,45 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:translateX="50"
+        android:translateY="50" >
+        <path
+            android:name="twoLines"
+            android:pathData="M 100,20 l 0 80 l -30 -80"
+            android:strokeColor="#FF00FF00"
+            android:strokeLineCap="square"
+            android:strokeLineJoin="bevel"
+            android:strokeMiterLimit="10"
+            android:strokeWidth="20" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index e8b6952..37e0435 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -53,6 +53,9 @@
             R.drawable.vector_drawable23,
             R.drawable.vector_drawable24,
             R.drawable.vector_drawable25,
+            R.drawable.vector_drawable26,
+            R.drawable.vector_drawable27,
+            R.drawable.vector_drawable28,
     };
 
     @Override
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index 02610f8..77c0c32 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -20,7 +20,7 @@
 import android.os.Bundle;
 import android.service.voice.AlwaysOnHotwordDetector;
 import android.service.voice.AlwaysOnHotwordDetector.Callback;
-import android.service.voice.AlwaysOnHotwordDetector.TriggerAudio;
+import android.service.voice.AlwaysOnHotwordDetector.EventPayload;
 import android.service.voice.VoiceInteractionService;
 import android.util.Log;
 
@@ -37,7 +37,7 @@
         }
 
         @Override
-        public void onDetected(TriggerAudio triggerAudio) {
+        public void onDetected(EventPayload eventPayload) {
             Log.i(TAG, "onDetected");
         }
 
@@ -45,6 +45,16 @@
         public void onError() {
             Log.i(TAG, "onError");
         }
+
+        @Override
+        public void onRecognitionPaused() {
+            Log.i(TAG, "onRecognitionPaused");
+        }
+
+        @Override
+        public void onRecognitionResumed() {
+            Log.i(TAG, "onRecognitionResumed");
+        }
     };
 
     private AlwaysOnHotwordDetector mHotwordDetector;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 755a77a..ccbdadd 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -752,6 +752,7 @@
     config.screenWidthDp = 320;
     config.screenHeightDp = 480;
     config.smallestScreenWidthDp = 320;
+    config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
     assets.setConfiguration(config);
 
     const ResTable& res = assets.getResources(false);