Merge "AudioFormat: implement ENCODING_IEC61937" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index ab52161..617aac0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8512,6 +8512,7 @@
     field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
     field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
     field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
     field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
@@ -19221,7 +19222,6 @@
     method public double getElevationUncertaintyInDeg();
     method public byte getLossOfLock();
     method public byte getMultipathIndicator();
-    method public byte getPrn();
     method public double getPseudorangeInMeters();
     method public double getPseudorangeRateCarrierInMetersPerSec();
     method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
@@ -19232,6 +19232,7 @@
     method public long getReceivedGpsTowUncertaintyInNs();
     method public double getSnrInDb();
     method public short getState();
+    method public short getSvid();
     method public short getTimeFromLastBitInMs();
     method public double getTimeOffsetInNs();
     method public boolean hasAzimuthInDeg();
@@ -19291,7 +19292,6 @@
     method public void setElevationUncertaintyInDeg(double);
     method public void setLossOfLock(byte);
     method public void setMultipathIndicator(byte);
-    method public void setPrn(byte);
     method public void setPseudorangeInMeters(double);
     method public void setPseudorangeRateCarrierInMetersPerSec(double);
     method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
@@ -19302,6 +19302,7 @@
     method public void setReceivedGpsTowUncertaintyInNs(long);
     method public void setSnrInDb(double);
     method public void setState(short);
+    method public void setSvid(short);
     method public void setTimeFromLastBitInMs(short);
     method public void setTimeOffsetInNs(double);
     method public void setUsedInFix(boolean);
@@ -19356,17 +19357,17 @@
     method public int describeContents();
     method public byte[] getData();
     method public short getMessageId();
-    method public byte getPrn();
     method public short getStatus();
     method public short getSubmessageId();
+    method public short getSvid();
     method public byte getType();
     method public void reset();
     method public void set(android.location.GnssNavigationMessage);
     method public void setData(byte[]);
     method public void setMessageId(short);
-    method public void setPrn(byte);
     method public void setStatus(short);
     method public void setSubmessageId(short);
+    method public void setSvid(short);
     method public void setType(byte);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
@@ -19412,8 +19413,8 @@
     method public int getConstellationType(int);
     method public float getElevation(int);
     method public int getNumSatellites();
-    method public int getPrn(int);
     method public float getSnr(int);
+    method public int getSvid(int);
     method public boolean hasAlmanac(int);
     method public boolean hasEphemeris(int);
     method public boolean usedInFix(int);
@@ -22950,10 +22951,8 @@
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
     field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
-    field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
-    field public static final int RECORDING_ERROR_DISCONNECTED = 2; // 0x2
-    field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 3; // 0x3
-    field public static final int RECORDING_ERROR_RESOURCE_BUSY = 4; // 0x4
+    field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
+    field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
     field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
     field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
     field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
@@ -23053,6 +23052,8 @@
 
   public static abstract class TvRecordingClient.RecordingCallback {
     ctor public TvRecordingClient.RecordingCallback();
+    method public void onConnectionFailed(java.lang.String);
+    method public void onDisconnected(java.lang.String);
     method public void onError(int);
     method public void onRecordingStopped(android.net.Uri);
     method public void onTuned();
@@ -51478,7 +51479,6 @@
     method public static int getLength(java.lang.Object);
     method public static long getLong(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
     method public static short getShort(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static java.lang.Object newArray(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
     method public static java.lang.Object newInstance(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
     method public static java.lang.Object newInstance(java.lang.Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
     method public static void set(java.lang.Object, int, java.lang.Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
@@ -56668,13 +56668,11 @@
     method public static final java.text.DecimalFormatSymbols getInstance(java.util.Locale);
     method public java.lang.String getInternationalCurrencySymbol();
     method public char getMinusSign();
-    method public java.lang.String getMinusSignString();
     method public char getMonetaryDecimalSeparator();
     method public java.lang.String getNaN();
     method public char getPatternSeparator();
     method public char getPerMill();
     method public char getPercent();
-    method public java.lang.String getPercentString();
     method public char getZeroDigit();
     method public void setCurrency(java.util.Currency);
     method public void setCurrencySymbol(java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 8ea1854..ec422c0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8818,6 +8818,7 @@
     field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
     field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
     field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
     field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
@@ -20401,7 +20402,6 @@
     method public double getElevationUncertaintyInDeg();
     method public byte getLossOfLock();
     method public byte getMultipathIndicator();
-    method public byte getPrn();
     method public double getPseudorangeInMeters();
     method public double getPseudorangeRateCarrierInMetersPerSec();
     method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
@@ -20412,6 +20412,7 @@
     method public long getReceivedGpsTowUncertaintyInNs();
     method public double getSnrInDb();
     method public short getState();
+    method public short getSvid();
     method public short getTimeFromLastBitInMs();
     method public double getTimeOffsetInNs();
     method public boolean hasAzimuthInDeg();
@@ -20471,7 +20472,6 @@
     method public void setElevationUncertaintyInDeg(double);
     method public void setLossOfLock(byte);
     method public void setMultipathIndicator(byte);
-    method public void setPrn(byte);
     method public void setPseudorangeInMeters(double);
     method public void setPseudorangeRateCarrierInMetersPerSec(double);
     method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
@@ -20482,6 +20482,7 @@
     method public void setReceivedGpsTowUncertaintyInNs(long);
     method public void setSnrInDb(double);
     method public void setState(short);
+    method public void setSvid(short);
     method public void setTimeFromLastBitInMs(short);
     method public void setTimeOffsetInNs(double);
     method public void setUsedInFix(boolean);
@@ -20536,17 +20537,17 @@
     method public int describeContents();
     method public byte[] getData();
     method public short getMessageId();
-    method public byte getPrn();
     method public short getStatus();
     method public short getSubmessageId();
+    method public short getSvid();
     method public byte getType();
     method public void reset();
     method public void set(android.location.GnssNavigationMessage);
     method public void setData(byte[]);
     method public void setMessageId(short);
-    method public void setPrn(byte);
     method public void setStatus(short);
     method public void setSubmessageId(short);
+    method public void setSvid(short);
     method public void setType(byte);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
@@ -20592,8 +20593,8 @@
     method public int getConstellationType(int);
     method public float getElevation(int);
     method public int getNumSatellites();
-    method public int getPrn(int);
     method public float getSnr(int);
+    method public int getSvid(int);
     method public boolean hasAlmanac(int);
     method public boolean hasEphemeris(int);
     method public boolean usedInFix(int);
@@ -24649,10 +24650,8 @@
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
     field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
-    field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
-    field public static final int RECORDING_ERROR_DISCONNECTED = 2; // 0x2
-    field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 3; // 0x3
-    field public static final int RECORDING_ERROR_RESOURCE_BUSY = 4; // 0x4
+    field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
+    field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
     field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
     field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
     field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
@@ -24811,6 +24810,8 @@
 
   public static abstract class TvRecordingClient.RecordingCallback {
     ctor public TvRecordingClient.RecordingCallback();
+    method public void onConnectionFailed(java.lang.String);
+    method public void onDisconnected(java.lang.String);
     method public void onError(int);
     method public void onEvent(java.lang.String, java.lang.String, android.os.Bundle);
     method public void onRecordingStopped(android.net.Uri);
@@ -54567,7 +54568,6 @@
     method public static int getLength(java.lang.Object);
     method public static long getLong(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
     method public static short getShort(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static java.lang.Object newArray(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
     method public static java.lang.Object newInstance(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
     method public static java.lang.Object newInstance(java.lang.Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
     method public static void set(java.lang.Object, int, java.lang.Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
@@ -59757,13 +59757,11 @@
     method public static final java.text.DecimalFormatSymbols getInstance(java.util.Locale);
     method public java.lang.String getInternationalCurrencySymbol();
     method public char getMinusSign();
-    method public java.lang.String getMinusSignString();
     method public char getMonetaryDecimalSeparator();
     method public java.lang.String getNaN();
     method public char getPatternSeparator();
     method public char getPerMill();
     method public char getPercent();
-    method public java.lang.String getPercentString();
     method public char getZeroDigit();
     method public void setCurrency(java.util.Currency);
     method public void setCurrencySymbol(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index e716292..d202108 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -8517,6 +8517,7 @@
     field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
     field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
     field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
     field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
@@ -19229,7 +19230,6 @@
     method public double getElevationUncertaintyInDeg();
     method public byte getLossOfLock();
     method public byte getMultipathIndicator();
-    method public byte getPrn();
     method public double getPseudorangeInMeters();
     method public double getPseudorangeRateCarrierInMetersPerSec();
     method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
@@ -19240,6 +19240,7 @@
     method public long getReceivedGpsTowUncertaintyInNs();
     method public double getSnrInDb();
     method public short getState();
+    method public short getSvid();
     method public short getTimeFromLastBitInMs();
     method public double getTimeOffsetInNs();
     method public boolean hasAzimuthInDeg();
@@ -19299,7 +19300,6 @@
     method public void setElevationUncertaintyInDeg(double);
     method public void setLossOfLock(byte);
     method public void setMultipathIndicator(byte);
-    method public void setPrn(byte);
     method public void setPseudorangeInMeters(double);
     method public void setPseudorangeRateCarrierInMetersPerSec(double);
     method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
@@ -19310,6 +19310,7 @@
     method public void setReceivedGpsTowUncertaintyInNs(long);
     method public void setSnrInDb(double);
     method public void setState(short);
+    method public void setSvid(short);
     method public void setTimeFromLastBitInMs(short);
     method public void setTimeOffsetInNs(double);
     method public void setUsedInFix(boolean);
@@ -19364,17 +19365,17 @@
     method public int describeContents();
     method public byte[] getData();
     method public short getMessageId();
-    method public byte getPrn();
     method public short getStatus();
     method public short getSubmessageId();
+    method public short getSvid();
     method public byte getType();
     method public void reset();
     method public void set(android.location.GnssNavigationMessage);
     method public void setData(byte[]);
     method public void setMessageId(short);
-    method public void setPrn(byte);
     method public void setStatus(short);
     method public void setSubmessageId(short);
+    method public void setSvid(short);
     method public void setType(byte);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
@@ -19420,8 +19421,8 @@
     method public int getConstellationType(int);
     method public float getElevation(int);
     method public int getNumSatellites();
-    method public int getPrn(int);
     method public float getSnr(int);
+    method public int getSvid(int);
     method public boolean hasAlmanac(int);
     method public boolean hasEphemeris(int);
     method public boolean usedInFix(int);
@@ -22959,10 +22960,8 @@
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
     field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
-    field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
-    field public static final int RECORDING_ERROR_DISCONNECTED = 2; // 0x2
-    field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 3; // 0x3
-    field public static final int RECORDING_ERROR_RESOURCE_BUSY = 4; // 0x4
+    field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
+    field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
     field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
     field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
     field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
@@ -23062,6 +23061,8 @@
 
   public static abstract class TvRecordingClient.RecordingCallback {
     ctor public TvRecordingClient.RecordingCallback();
+    method public void onConnectionFailed(java.lang.String);
+    method public void onDisconnected(java.lang.String);
     method public void onError(int);
     method public void onRecordingStopped(android.net.Uri);
     method public void onTuned();
@@ -51495,7 +51496,6 @@
     method public static int getLength(java.lang.Object);
     method public static long getLong(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
     method public static short getShort(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static java.lang.Object newArray(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
     method public static java.lang.Object newInstance(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
     method public static java.lang.Object newInstance(java.lang.Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
     method public static void set(java.lang.Object, int, java.lang.Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
@@ -56685,13 +56685,11 @@
     method public static final java.text.DecimalFormatSymbols getInstance(java.util.Locale);
     method public java.lang.String getInternationalCurrencySymbol();
     method public char getMinusSign();
-    method public java.lang.String getMinusSignString();
     method public char getMonetaryDecimalSeparator();
     method public java.lang.String getNaN();
     method public char getPatternSeparator();
     method public char getPerMill();
     method public char getPercent();
-    method public java.lang.String getPercentString();
     method public char getZeroDigit();
     method public void setCurrency(java.util.Currency);
     method public void setCurrencySymbol(java.lang.String);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 622012e..ea58e29 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static java.lang.Character.MIN_VALUE;
+
 import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
@@ -26,20 +28,6 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.StyleRes;
-import android.os.PersistableBundle;
-import android.transition.Scene;
-import android.transition.TransitionManager;
-import android.util.ArrayMap;
-import android.util.SuperNotCalledException;
-import android.view.DragEvent;
-import android.view.DropPermissions;
-import android.view.Window.WindowControllerCallback;
-import android.widget.Toolbar;
-
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.app.ToolbarActionBar;
-
 import android.annotation.SystemApi;
 import android.app.admin.DevicePolicyManager;
 import android.app.assist.AssistContent;
@@ -61,7 +49,12 @@
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.ShapeDrawable;
 import android.media.AudioManager;
 import android.media.session.MediaController;
 import android.net.Uri;
@@ -71,6 +64,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.UserHandle;
@@ -78,16 +72,22 @@
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.text.method.TextKeyListener;
+import android.transition.Scene;
+import android.transition.TransitionManager;
+import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SuperNotCalledException;
 import android.view.ActionMode;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.ContextThemeWrapper;
+import android.view.DragEvent;
+import android.view.DropPermissions;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutGroup;
 import android.view.KeyboardShortcutInfo;
@@ -104,11 +104,17 @@
 import android.view.ViewManager;
 import android.view.ViewRootImpl;
 import android.view.Window;
+import android.view.Window.WindowControllerCallback;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView;
+import android.widget.Toolbar;
 
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.ToolbarActionBar;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneWindow;
 
 import java.io.FileDescriptor;
@@ -119,8 +125,6 @@
 import java.util.HashMap;
 import java.util.List;
 
-import static java.lang.Character.MIN_VALUE;
-
 /**
  * An activity is a single, focused thing that the user can do.  Almost all
  * activities interact with the user, so the Activity class takes care of
@@ -3974,17 +3978,52 @@
         // Get the primary color and update the TaskDescription for this activity
         if (theme != null) {
             TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
+            int windowBgResourceId = a.getResourceId(
+                    com.android.internal.R.styleable.Window_windowBackground, 0);
+            int windowBgFallbackResourceId = a.getResourceId(
+                    com.android.internal.R.styleable.Window_windowBackgroundFallback, 0);
             int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
+            int colorBg = tryExtractColorFromDrawable(DecorView.getResizingBackgroundDrawable(this,
+                    windowBgResourceId, windowBgFallbackResourceId));
             a.recycle();
             if (colorPrimary != 0) {
-                ActivityManager.TaskDescription v = new ActivityManager.TaskDescription(null, null,
-                        colorPrimary);
-                setTaskDescription(v);
+                ActivityManager.TaskDescription td = new ActivityManager.TaskDescription();
+                td.setPrimaryColor(colorPrimary);
+                td.setBackgroundColor(colorBg);
+                setTaskDescription(td);
             }
         }
     }
 
     /**
+     * Attempts to extract the color from a given drawable.
+     *
+     * @return the extracted color or 0 if no color could be extracted.
+     */
+    private int tryExtractColorFromDrawable(Drawable drawable) {
+        if (drawable instanceof ColorDrawable) {
+            return ((ColorDrawable) drawable).getColor();
+        } else if (drawable instanceof InsetDrawable) {
+            return tryExtractColorFromDrawable(((InsetDrawable) drawable).getDrawable());
+        } else if (drawable instanceof ShapeDrawable) {
+            Paint p = ((ShapeDrawable) drawable).getPaint();
+            if (p != null) {
+                return p.getColor();
+            }
+        } else if (drawable instanceof LayerDrawable) {
+            LayerDrawable ld = (LayerDrawable) drawable;
+            int numLayers = ld.getNumberOfLayers();
+            for (int i = 0; i < numLayers; i++) {
+                int color = tryExtractColorFromDrawable(ld.getDrawable(i));
+                if (color != 0) {
+                    return color;
+                }
+            }
+        }
+        return 0;
+    }
+
+    /**
      * Requests permissions to be granted to this application. These permissions
      * must be requested in your manifest, they should not be granted to your app,
      * and they should have protection level {@link android.content.pm.PermissionInfo
@@ -5612,8 +5651,8 @@
         if (taskDescription.getIconFilename() == null && taskDescription.getIcon() != null) {
             final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
             final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size, true);
-            td = new ActivityManager.TaskDescription(taskDescription.getLabel(), icon,
-                    taskDescription.getPrimaryColor());
+            td = new ActivityManager.TaskDescription(taskDescription);
+            td.setIcon(icon);
         } else {
             td = taskDescription;
         }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1eb2fe2..dd73261 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -632,6 +632,17 @@
         public static boolean useWindowFrameForBackdrop(int stackId) {
             return stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == PINNED_STACK_ID;
         }
+
+        /**
+         * Returns true if a window from the specified stack with {@param stackId} are normally
+         * fullscreen, i. e. they can become the top opaque fullscreen window, meaning that it
+         * controls system bars, lockscreen occluded/dismissing state, screen rotation animation,
+         * etc.
+         */
+        public static boolean normallyFullscreenWindows(int stackId) {
+            return stackId != PINNED_STACK_ID && stackId != FREEFORM_WORKSPACE_STACK_ID
+                    && stackId != DOCKED_STACK_ID;
+        }
     }
 
     /**
@@ -863,8 +874,10 @@
         public static final String ATTR_TASKDESCRIPTION_PREFIX = "task_description_";
         private static final String ATTR_TASKDESCRIPTIONLABEL =
                 ATTR_TASKDESCRIPTION_PREFIX + "label";
-        private static final String ATTR_TASKDESCRIPTIONCOLOR =
+        private static final String ATTR_TASKDESCRIPTIONCOLOR_PRIMARY =
                 ATTR_TASKDESCRIPTION_PREFIX + "color";
+        private static final String ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND =
+                ATTR_TASKDESCRIPTION_PREFIX + "colorBackground";
         private static final String ATTR_TASKDESCRIPTIONICONFILENAME =
                 ATTR_TASKDESCRIPTION_PREFIX + "icon_filename";
 
@@ -872,28 +885,21 @@
         private Bitmap mIcon;
         private String mIconFilename;
         private int mColorPrimary;
+        private int mColorBackground;
 
         /**
          * Creates the TaskDescription to the specified values.
          *
          * @param label A label and description of the current state of this task.
          * @param icon An icon that represents the current state of this task.
-         * @param colorPrimary A color to override the theme's primary color.  This color must be opaque.
+         * @param colorPrimary A color to override the theme's primary color.  This color must be
+         *                     opaque.
          */
         public TaskDescription(String label, Bitmap icon, int colorPrimary) {
+            this(label, icon, null, colorPrimary, 0);
             if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
                 throw new RuntimeException("A TaskDescription's primary color should be opaque");
             }
-
-            mLabel = label;
-            mIcon = icon;
-            mColorPrimary = colorPrimary;
-        }
-
-        /** @hide */
-        public TaskDescription(String label, int colorPrimary, String iconFilename) {
-            this(label, null, colorPrimary);
-            mIconFilename = iconFilename;
         }
 
         /**
@@ -903,7 +909,7 @@
          * @param icon An icon that represents the current state of this activity.
          */
         public TaskDescription(String label, Bitmap icon) {
-            this(label, icon, 0);
+            this(label, icon, null, 0, 0);
         }
 
         /**
@@ -912,14 +918,24 @@
          * @param label A label and description of the current state of this activity.
          */
         public TaskDescription(String label) {
-            this(label, null, 0);
+            this(label, null, null, 0, 0);
         }
 
         /**
          * Creates an empty TaskDescription.
          */
         public TaskDescription() {
-            this(null, null, 0);
+            this(null, null, null, 0, 0);
+        }
+
+        /** @hide */
+        public TaskDescription(String label, Bitmap icon, String iconFilename, int colorPrimary,
+                int colorBackground) {
+            mLabel = label;
+            mIcon = icon;
+            mIconFilename = iconFilename;
+            mColorPrimary = colorPrimary;
+            mColorBackground = colorBackground;
         }
 
         /**
@@ -928,8 +944,9 @@
         public TaskDescription(TaskDescription td) {
             mLabel = td.mLabel;
             mIcon = td.mIcon;
-            mColorPrimary = td.mColorPrimary;
             mIconFilename = td.mIconFilename;
+            mColorPrimary = td.mColorPrimary;
+            mColorBackground = td.mColorBackground;
         }
 
         private TaskDescription(Parcel source) {
@@ -957,6 +974,18 @@
         }
 
         /**
+         * Sets the background color for this task description.
+         * @hide
+         */
+        public void setBackgroundColor(int backgroundColor) {
+            // Ensure that the given color is valid
+            if ((backgroundColor != 0) && (Color.alpha(backgroundColor) != 255)) {
+                throw new RuntimeException("A TaskDescription's background color should be opaque");
+            }
+            mColorBackground = backgroundColor;
+        }
+
+        /**
          * Sets the icon for this task description.
          * @hide
          */
@@ -1005,8 +1034,8 @@
         public static Bitmap loadTaskDescriptionIcon(String iconFilename, int userId) {
             if (iconFilename != null) {
                 try {
-                    return ActivityManagerNative.getDefault().
-                            getTaskDescriptionIcon(iconFilename, userId);
+                    return ActivityManagerNative.getDefault().getTaskDescriptionIcon(iconFilename,
+                            userId);
                 } catch (RemoteException e) {
                 }
             }
@@ -1020,13 +1049,26 @@
             return mColorPrimary;
         }
 
+        /**
+         * @return The background color.
+         * @hide
+         */
+        public int getBackgroundColor() {
+            return mColorBackground;
+        }
+
         /** @hide */
         public void saveToXml(XmlSerializer out) throws IOException {
             if (mLabel != null) {
                 out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, mLabel);
             }
             if (mColorPrimary != 0) {
-                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(mColorPrimary));
+                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR_PRIMARY,
+                        Integer.toHexString(mColorPrimary));
+            }
+            if (mColorBackground != 0) {
+                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND,
+                        Integer.toHexString(mColorBackground));
             }
             if (mIconFilename != null) {
                 out.attribute(null, ATTR_TASKDESCRIPTIONICONFILENAME, mIconFilename);
@@ -1037,8 +1079,10 @@
         public void restoreFromXml(String attrName, String attrValue) {
             if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
                 setLabel(attrValue);
-            } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
+            } else if (ATTR_TASKDESCRIPTIONCOLOR_PRIMARY.equals(attrName)) {
                 setPrimaryColor((int) Long.parseLong(attrValue, 16));
+            } else if (ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND.equals(attrName)) {
+                setBackgroundColor((int) Long.parseLong(attrValue, 16));
             } else if (ATTR_TASKDESCRIPTIONICONFILENAME.equals(attrName)) {
                 setIconFilename(attrValue);
             }
@@ -1064,6 +1108,7 @@
                 mIcon.writeToParcel(dest, 0);
             }
             dest.writeInt(mColorPrimary);
+            dest.writeInt(mColorBackground);
             if (mIconFilename == null) {
                 dest.writeInt(0);
             } else {
@@ -1076,6 +1121,7 @@
             mLabel = source.readInt() > 0 ? source.readString() : null;
             mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
             mColorPrimary = source.readInt();
+            mColorBackground = source.readInt();
             mIconFilename = source.readInt() > 0 ? source.readString() : null;
         }
 
@@ -1092,7 +1138,8 @@
         @Override
         public String toString() {
             return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
-                    " colorPrimary: " + mColorPrimary;
+                    " IconFilename: " + mIconFilename + " colorPrimary: " + mColorPrimary +
+                    " colorBackground: " + mColorBackground;
         }
     }
 
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 0d35cf0..3c8dfce 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -56,7 +56,7 @@
     void setImportance(String pkg, int uid, in Notification.Topic topic, int importance);
     int getImportance(String pkg, int uid, in Notification.Topic topic);
     int getTopicImportance(String pkg, String topicId);
-    boolean doesAppUseTopics(String pkg, int uid);
+    boolean doesUserUseTopics(String pkg, int uid);
     boolean hasBannedTopics(String pkg, int uid);
 
     // TODO: Remove this when callers have been migrated to the equivalent
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 55c6353..35b7c39 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3358,13 +3358,9 @@
                 return mN.bigContentView;
             } else if (mStyle != null) {
                 result = mStyle.makeBigContentView();
-            } else if (mActions.size() == 0) {
-                return null;
-            }
-            if (result == null) {
-                result = applyStandardTemplateWithActions(getBigBaseLayoutResource());
-            } else {
                 hideLine1Text(result);
+            } else if (mActions.size() != 0) {
+                result = applyStandardTemplateWithActions(getBigBaseLayoutResource());
             }
             adaptNotificationHeaderForBigContentView(result);
             return result;
@@ -3384,11 +3380,15 @@
         }
 
         private void hideLine1Text(RemoteViews result) {
-            result.setViewVisibility(R.id.text_line_1, View.GONE);
+            if (result != null) {
+                result.setViewVisibility(R.id.text_line_1, View.GONE);
+            }
         }
 
         private void adaptNotificationHeaderForBigContentView(RemoteViews result) {
-            result.setBoolean(R.id.notification_header, "setExpanded", true);
+            if (result != null) {
+                result.setBoolean(R.id.notification_header, "setExpanded", true);
+            }
         }
 
         /**
@@ -4326,6 +4326,15 @@
             return makeMediaBigContentView();
         }
 
+        /**
+         * @hide
+         */
+        @Override
+        public RemoteViews makeHeadsUpContentView() {
+            RemoteViews expanded = makeMediaBigContentView();
+            return expanded != null ? expanded : makeMediaContentView();
+        }
+
         /** @hide */
         @Override
         public void addExtras(Bundle extras) {
@@ -4407,6 +4416,13 @@
 
         private RemoteViews makeMediaBigContentView() {
             final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
+            // Dont add an expanded view if there is no more content to be revealed
+            int actionsInCompact = mActionsToShowInCompact == null
+                    ? 0
+                    : Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
+            if (mBuilder.mN.mLargeIcon == null && actionCount <= actionsInCompact) {
+                return null;
+            }
             RemoteViews big = mBuilder.applyStandardTemplate(
                     R.layout.notification_template_material_big_media,
                     false);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 1b2322f..f53170a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1826,9 +1826,23 @@
      * this method; if it has not, a security exception will be thrown.
      */
     public int getCurrentFailedPasswordAttempts() {
+        return getCurrentFailedPasswordAttempts(myUserId());
+    }
+
+    /**
+     * Retrieve the number of times the given user has failed at entering a
+     * password since that last successful password entry.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call this method; if it has
+     * not and it is not the system uid, a security exception will be thrown.
+     *
+     * @hide
+     */
+    public int getCurrentFailedPasswordAttempts(int userHandle) {
         if (mService != null) {
             try {
-                return mService.getCurrentFailedPasswordAttempts(myUserId(), mParentInstance);
+                return mService.getCurrentFailedPasswordAttempts(userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0f6f856..b476a25 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3028,6 +3028,17 @@
             "android.intent.action.MANAGED_PROFILE_REMOVED";
 
     /**
+     * Broadcast sent to the primary user when the credential-encrypted private storage for
+     * an associated managed profile is unlocked. Carries an extra {@link #EXTRA_USER} that
+     * specifies the UserHandle of the profile that was unlocked. Only applications (for example
+     * Launchers) that need to display merged content across both primary and managed profiles
+     * need to worry about this broadcast. This is only sent to registered receivers,
+     * not manifest receivers.
+     */
+    public static final String ACTION_MANAGED_PROFILE_UNLOCKED =
+            "android.intent.action.MANAGED_PROFILE_UNLOCKED";
+
+    /**
      * Broadcast sent to the primary user when an associated managed profile's availability has
      * changed. This includes when the user toggles the profile's quiet mode. Carries an extra
      * {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 8468040..2ca7589 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -1201,7 +1201,7 @@
         final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
                 sourceDocumentUri.getAuthority());
         try {
-            return moveDocument(client, sourceParentDocumentUri, sourceDocumentUri,
+            return moveDocument(client, sourceDocumentUri, sourceParentDocumentUri,
                     targetParentDocumentUri);
         } catch (Exception e) {
             Log.w(TAG, "Failed to move document", e);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7830142..3169bf4 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4660,6 +4660,14 @@
                 "lock_screen_allow_private_notifications";
 
         /**
+         * When set by a user, allows notification remote input atop a securely locked screen
+         * without having to unlock
+         * @hide
+         */
+        public static final String LOCK_SCREEN_ALLOW_REMOTE_INPUT =
+                "lock_screen_allow_remote_input";
+
+        /**
          * Set by the system to track if the user needs to see the call to action for
          * the lockscreen notification policy.
          * @hide
@@ -5139,14 +5147,6 @@
         public static final String TTS_DEFAULT_SYNTH = "tts_default_synth";
 
         /**
-         * Whether text-to-speech higher speech rate is enabled.
-         * 0 = disabled.
-         * 1 = enabled.
-         * @hide
-         */
-        public static final String TTS_DEFAULT_HIGHER_SPEECH_RATE_ENABLED =
-            "tts_default_higher_speech_rate_enabled";
-        /**
          * Default text-to-speech language.
          *
          * @deprecated this setting is no longer in use, as of the Ice Cream
@@ -5907,13 +5907,6 @@
                 "camera_double_tap_power_gesture_disabled";
 
         /**
-         * Name of the package used as WebView provider (if unset the provider is instead determined
-         * by the system).
-         * @hide
-         */
-        public static final String WEBVIEW_PROVIDER = "webview_provider";
-
-        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -5958,7 +5951,6 @@
             ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
             TTS_USE_DEFAULTS,
             TTS_DEFAULT_RATE,
-            TTS_DEFAULT_HIGHER_SPEECH_RATE_ENABLED,
             TTS_DEFAULT_PITCH,
             TTS_DEFAULT_SYNTH,
             TTS_DEFAULT_LANG,
@@ -6940,6 +6932,13 @@
         public static final String WEBVIEW_DATA_REDUCTION_PROXY_KEY =
                 "webview_data_reduction_proxy_key";
 
+        /**
+         * Name of the package used as WebView provider (if unset the provider is instead determined
+         * by the system).
+         * @hide
+         */
+        public static final String WEBVIEW_PROVIDER = "webview_provider";
+
        /**
         * Whether Wifi display is enabled/disabled
         * 0=disabled. 1=enabled.
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index e9d12f5..409994d 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -54,6 +54,9 @@
 
 import java.io.IOException;
 import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -691,6 +694,22 @@
     private static Pattern sBackgroundColorPattern;
     private static Pattern sTextDecorationPattern;
 
+    /**
+     * Name-value mapping of HTML/CSS colors which have different values in {@link Color}.
+     */
+    private static final Map<String, Integer> sColorMap;
+
+    static {
+        sColorMap = new HashMap<>();
+        sColorMap.put("darkgray", 0xFFA9A9A9);
+        sColorMap.put("gray", 0xFF808080);
+        sColorMap.put("lightgray", 0xFFD3D3D3);
+        sColorMap.put("darkgrey", 0xFFA9A9A9);
+        sColorMap.put("grey", 0xFF808080);
+        sColorMap.put("lightgrey", 0xFFD3D3D3);
+        sColorMap.put("green", 0xFF008000);
+    }
+
     private static Pattern getTextAlignPattern() {
         if (sTextAlignPattern == null) {
             sTextAlignPattern = Pattern.compile("(?:\\s+|\\A)text-align\\s*:\\s*(\\S*)\\b");
@@ -948,7 +967,7 @@
         final int len = text.length();
         if (margin > 0) {
             appendNewlines(text, margin);
-            text.setSpan(new Newline(margin), len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+            start(text, new Newline(margin));
         }
 
         String style = attributes.getValue("", "style");
@@ -957,14 +976,11 @@
             if (m.find()) {
                 String alignment = m.group(1);
                 if (alignment.equalsIgnoreCase("start")) {
-                    text.setSpan(new Alignment(Layout.Alignment.ALIGN_NORMAL),
-                            len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+                    start(text, new Alignment(Layout.Alignment.ALIGN_NORMAL));
                 } else if (alignment.equalsIgnoreCase("center")) {
-                    text.setSpan(new Alignment(Layout.Alignment.ALIGN_CENTER),
-                            len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+                    start(text, new Alignment(Layout.Alignment.ALIGN_CENTER));
                 } else if (alignment.equalsIgnoreCase("end")) {
-                    text.setSpan(new Alignment(Layout.Alignment.ALIGN_OPPOSITE),
-                            len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+                    start(text, new Alignment(Layout.Alignment.ALIGN_OPPOSITE));
                 }
             }
         }
@@ -1053,7 +1069,7 @@
 
     private static void start(Editable text, Object mark) {
         int len = text.length();
-        text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK);
+        text.setSpan(mark, len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
     }
 
     private static void end(Editable text, Class kind, Object repl) {
@@ -1064,25 +1080,22 @@
         }
     }
 
-    private static void startCssStyle(Editable text, Attributes attributes) {
+    private void startCssStyle(Editable text, Attributes attributes) {
         String style = attributes.getValue("", "style");
         if (style != null) {
-            final int len = text.length();
             Matcher m = getForegroundColorPattern().matcher(style);
             if (m.find()) {
-                int c = Color.getHtmlColor(m.group(1));
+                int c = getHtmlColor(m.group(1));
                 if (c != -1) {
-                    text.setSpan(new Foreground(c | 0xFF000000), len, len,
-                            Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+                    start(text, new Foreground(c | 0xFF000000));
                 }
             }
 
             m = getBackgroundColorPattern().matcher(style);
             if (m.find()) {
-                int c = Color.getHtmlColor(m.group(1));
+                int c = getHtmlColor(m.group(1));
                 if (c != -1) {
-                    text.setSpan(new Background(c | 0xFF000000), len, len,
-                            Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+                    start(text, new Background(c | 0xFF000000));
                 }
             }
 
@@ -1090,7 +1103,7 @@
             if (m.find()) {
                 String textDecoration = m.group(1);
                 if (textDecoration.equalsIgnoreCase("line-through")) {
-                    text.setSpan(new Strikethrough(), len, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+                    start(text, new Strikethrough());
                 }
             }
         }
@@ -1134,58 +1147,41 @@
                      Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
     }
 
-    private static void startFont(Editable text, Attributes attributes) {
+    private void startFont(Editable text, Attributes attributes) {
         String color = attributes.getValue("", "color");
         String face = attributes.getValue("", "face");
 
-        int len = text.length();
-        text.setSpan(new Font(color, face), len, len, Spannable.SPAN_MARK_MARK);
+        if (!TextUtils.isEmpty(color)) {
+            int c = getHtmlColor(color);
+            if (c != -1) {
+                start(text, new Foreground(c | 0xFF000000));
+            }
+        }
+
+        if (!TextUtils.isEmpty(face)) {
+            start(text, new Font(face));
+        }
     }
 
     private static void endFont(Editable text) {
-        int len = text.length();
-        Font f = getLast(text, Font.class);
-        int where = text.getSpanStart(f);
-        text.removeSpan(f);
+        Font font = getLast(text, Font.class);
+        if (font != null) {
+            setSpanFromMark(text, font, new TypefaceSpan(font.mFace));
+        }
 
-        if (where != len) {
-            if (!TextUtils.isEmpty(f.mColor)) {
-                if (f.mColor.startsWith("@")) {
-                    Resources res = Resources.getSystem();
-                    String name = f.mColor.substring(1);
-                    int colorRes = res.getIdentifier(name, "color", "android");
-                    if (colorRes != 0) {
-                        ColorStateList colors = res.getColorStateList(colorRes, null);
-                        text.setSpan(new TextAppearanceSpan(null, 0, 0, colors, null),
-                                where, len,
-                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-                    }
-                } else {
-                    int c = Color.getHtmlColor(f.mColor);
-                    if (c != -1) {
-                        text.setSpan(new ForegroundColorSpan(c | 0xFF000000),
-                                where, len,
-                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-                    }
-                }
-            }
-
-            if (f.mFace != null) {
-                text.setSpan(new TypefaceSpan(f.mFace), where, len,
-                             Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-            }
+        Foreground foreground = getLast(text, Foreground.class);
+        if (foreground != null) {
+            setSpanFromMark(text, foreground,
+                    new ForegroundColorSpan(foreground.mForegroundColor));
         }
     }
 
     private static void startA(Editable text, Attributes attributes) {
         String href = attributes.getValue("", "href");
-
-        int len = text.length();
-        text.setSpan(new Href(href), len, len, Spannable.SPAN_MARK_MARK);
+        start(text, new Href(href));
     }
 
     private static void endA(Editable text) {
-        int len = text.length();
         Href h = getLast(text, Href.class);
         if (h != null) {
             if (h.mHref != null) {
@@ -1194,6 +1190,17 @@
         }
     }
 
+    private int getHtmlColor(String color) {
+        if ((mFlags & Html.FROM_HTML_OPTION_USE_CSS_COLORS)
+                == Html.FROM_HTML_OPTION_USE_CSS_COLORS) {
+            Integer i = sColorMap.get(color.toLowerCase(Locale.US));
+            if (i != null) {
+                return i;
+            }
+        }
+        return Color.getHtmlColor(color);
+    }
+
     public void setDocumentLocator(Locator locator) {
     }
 
@@ -1278,11 +1285,9 @@
     private static class Bullet { }
 
     private static class Font {
-        public String mColor;
         public String mFace;
 
-        public Font(String color, String face) {
-            mColor = color;
+        public Font(String face) {
             mFace = face;
         }
     }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a296051..152dd66 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -224,7 +224,7 @@
         mParent.requestTransparentRegion(this);
         mSession = getWindowSession();
         mLayout.token = getWindowToken();
-        mLayout.setTitle("SurfaceView");
+        mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
         mViewVisibility = getVisibility() == VISIBLE;
 
         if (!mGlobalListenersAdded) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2612ab2..bba5a17 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6874,6 +6874,15 @@
      * @param info The info whose drawing order should be populated
      */
     private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) {
+        /*
+         * If the view's bounds haven't been set yet, layout has not completed. In that situation,
+         * drawing order may not be well-defined, and some Views with custom drawing order may
+         * not be initialized sufficiently to respond properly getChildDrawingOrder.
+         */
+        if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) {
+            info.setDrawingOrder(0);
+            return;
+        }
         int drawingOrderInParent = 1;
         // Iterate up the hierarchy if parents are not important for a11y
         View viewAtDrawingLevel = this;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 947906b..609c471 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.app.ActivityManager.StackId;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.CompatibilityInfo;
@@ -388,6 +389,12 @@
          * Check whether the window is currently dimming.
          */
         public boolean isDimming();
+
+        /**
+         * @return the stack id this windows belongs to, or {@link StackId#INVALID_STACK_ID} if
+         *         not attached to any stack.
+         */
+        int getStackId();
     }
 
     /**
@@ -465,6 +472,11 @@
          * @return The content insets of the docked divider window.
          */
         int getDockedDividerInsetsLw();
+
+        /**
+         * Retrieves the {@param outBounds} from the stack with id {@param stackId}.
+         */
+        void getStackBounds(int stackId, Rect outBounds);
     }
 
     public interface PointerEventListener {
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index 3f50fe2..94e8b70 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -97,22 +97,12 @@
      */
     public boolean isEnabled() {
         try {
-            PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
-            int enabled_state = pm.getApplicationEnabledSetting(packageName);
-            switch (enabled_state) {
-                case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
-                    return true;
-                case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
-                    ApplicationInfo applicationInfo = getPackageInfo().applicationInfo;
-                    return applicationInfo.enabled;
-                default:
-                    return false;
-            }
+            // Explicitly fetch up-to-date package info here since the enabled-state of the package
+            // might have changed since we last fetched its package info.
+            updatePackageInfo();
+            return getPackageInfo().applicationInfo.enabled;
         } catch (WebViewPackageNotFoundException e) {
             return false;
-        } catch (IllegalArgumentException e) {
-            // Thrown by PackageManager.getApplicationEnabledSetting if the package does not exist
-            return false;
         }
     }
 
@@ -124,14 +114,18 @@
         return availableByDefault;
     }
 
+    private void updatePackageInfo() {
+        try {
+            PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+            packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new WebViewPackageNotFoundException(e);
+        }
+    }
+
     public PackageInfo getPackageInfo() {
         if (packageInfo == null) {
-            try {
-                PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
-                packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
-            } catch (PackageManager.NameNotFoundException e) {
-                throw new WebViewPackageNotFoundException(e);
-            }
+            updatePackageInfo();
         }
         return packageInfo;
     }
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 45fc6c3..3796df7 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -36,6 +36,8 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.speech.RecognizerIntent;
 import android.text.Editable;
 import android.text.InputType;
@@ -1332,6 +1334,48 @@
         setIconified(false);
     }
 
+    static class SavedState extends BaseSavedState {
+        boolean isIconified;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        public SavedState(Parcel source) {
+            super(source);
+            isIconified = (Boolean) source.readValue(null);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeValue(isIconified);
+        }
+
+        @Override
+        public String toString() {
+            return "SearchView.SavedState{"
+                    + Integer.toHexString(System.identityHashCode(this))
+                    + " isIconified=" + isIconified + "}";
+        }
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        ss.isIconified = isIconified();
+        return ss;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+        updateViewsVisibility(ss.isIconified);
+        requestLayout();
+    }
+
     @Override
     public CharSequence getAccessibilityClassName() {
         return SearchView.class.getName();
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 3402989..8c3c2b5 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -129,6 +129,7 @@
                     if (mServiceConnections.isEmpty()) {
                         mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
                         sendVoiceChoicesIfNeeded();
+                        mChooserListAdapter.setShowServiceTargets(true);
                     }
                     break;
 
@@ -138,6 +139,7 @@
                     }
                     unbindRemainingServices();
                     sendVoiceChoicesIfNeeded();
+                    mChooserListAdapter.setShowServiceTargets(true);
                     break;
 
                 default:
@@ -766,6 +768,7 @@
 
         private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
         private final List<TargetInfo> mCallerTargets = new ArrayList<>();
+        private boolean mShowServiceTargets;
 
         private float mLateFee = 1.f;
 
@@ -866,6 +869,9 @@
         }
 
         public int getServiceTargetCount() {
+            if (!mShowServiceTargets) {
+                return 0;
+            }
             return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS);
         }
 
@@ -955,6 +961,14 @@
             notifyDataSetChanged();
         }
 
+        /**
+         * Set to true to reveal all service targets at once.
+         */
+        public void setShowServiceTargets(boolean show) {
+            mShowServiceTargets = show;
+            notifyDataSetChanged();
+        }
+
         private void insertServiceTarget(ChooserTargetInfo chooserTargetInfo) {
             final float newScore = chooserTargetInfo.getModifiedScore();
             for (int i = 0, N = mServiceTargets.size(); i < N; i++) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 88af920..af3f7ec 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -86,6 +86,7 @@
 import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
@@ -1002,13 +1003,25 @@
                         && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
                         && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
 
+        // If we didn't request fullscreen layout, but we still got it because of the
+        // mForceWindowDrawsStatusBarBackground flag, also consume top inset.
+        boolean consumingStatusBar = (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0
+                && (sysUiVisibility & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
+                && (attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0
+                && (attrs.flags & FLAG_LAYOUT_INSET_DECOR) == 0
+                && mForceWindowDrawsStatusBarBackground
+                && mLastTopInset != 0;
+
+        int consumedTop = consumingStatusBar ? mLastTopInset : 0;
         int consumedRight = consumingNavBar ? mLastRightInset : 0;
         int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
 
         if (mContentRoot != null
                 && mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
             MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
-            if (lp.rightMargin != consumedRight || lp.bottomMargin != consumedBottom) {
+            if (lp.topMargin != consumedTop || lp.rightMargin != consumedRight
+                    || lp.bottomMargin != consumedBottom) {
+                lp.topMargin = consumedTop;
                 lp.rightMargin = consumedRight;
                 lp.bottomMargin = consumedBottom;
                 mContentRoot.setLayoutParams(lp);
@@ -1022,7 +1035,7 @@
             if (insets != null) {
                 insets = insets.replaceSystemWindowInsets(
                         insets.getSystemWindowInsetLeft(),
-                        insets.getSystemWindowInsetTop(),
+                        insets.getSystemWindowInsetTop() - consumedTop,
                         insets.getSystemWindowInsetRight() - consumedRight,
                         insets.getSystemWindowInsetBottom() - consumedBottom);
             }
@@ -1718,8 +1731,13 @@
 
     private void loadBackgroundDrawablesIfNeeded() {
         if (mResizingBackgroundDrawable == null) {
-            mResizingBackgroundDrawable = getResizingBackgroundDrawable(
+            mResizingBackgroundDrawable = getResizingBackgroundDrawable(getContext(),
                     mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource);
+            if (mResizingBackgroundDrawable == null) {
+                // We shouldn't really get here as the background fallback should be always
+                // available since it is defaulted by the system.
+                Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
+            }
         }
         if (mCaptionBackgroundDrawable == null) {
             mCaptionBackgroundDrawable = getContext().getDrawable(
@@ -1817,9 +1835,8 @@
      * Returns the color used to fill areas the app has not rendered content to yet when the
      * user is resizing the window of an activity in multi-window mode.
      */
-    private Drawable getResizingBackgroundDrawable(int backgroundRes, int backgroundFallbackRes) {
-        final Context context = getContext();
-
+    public static Drawable getResizingBackgroundDrawable(Context context, int backgroundRes,
+            int backgroundFallbackRes) {
         if (backgroundRes != 0) {
             final Drawable drawable = context.getDrawable(backgroundRes);
             if (drawable != null) {
@@ -1833,10 +1850,6 @@
                 return fallbackDrawable;
             }
         }
-
-        // We shouldn't really get here as the background fallback should be always available since
-        // it is defaulted by the system.
-        Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
         return null;
     }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 6e374e2..08d4fba 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.statusbar;
 
 import android.content.ComponentName;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
 
@@ -31,7 +32,23 @@
     void animateExpandNotificationsPanel();
     void animateExpandSettingsPanel(String subPanel);
     void animateCollapsePanels();
-    void setSystemUiVisibility(int vis, int mask);
+
+    /**
+     * Notifies the status bar of a System UI visibility flag change.
+     *
+     * @param vis the visibility flags except SYSTEM_UI_FLAG_LIGHT_STATUS_BAR which will be reported
+     *            separately in fullscreenStackVis and dockedStackVis
+     * @param fullscreenStackVis the flags which only apply in the region of the fullscreen stack,
+     *                           which is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+     * @param dockedStackVis the flags that only apply in the region of the docked stack, which is
+     *                       currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+     * @param mask which flags to change
+     * @param fullscreenBounds the current bounds of the fullscreen stack, in screen coordinates
+     * @param dockedBounds the current bounds of the docked stack, in screen coordinates
+     */
+    void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
+            in Rect fullscreenBounds, in Rect dockedBounds);
+
     void topAppWindowChanged(boolean menuVisible);
     void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index bec18ec..8acf5d3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.statusbar;
 
 import android.content.ComponentName;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
 
@@ -37,7 +38,6 @@
     void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription);
     void setIconVisibility(String slot, boolean visible);
     void removeIcon(String slot);
-    void topAppWindowChanged(boolean menuVisible);
     void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher);
     void expandSettingsPanel(String subPanel);
@@ -47,7 +47,8 @@
     // You need the STATUS_BAR_SERVICE permission
     void registerStatusBar(IStatusBar callbacks, out List<String> iconSlots,
             out List<StatusBarIcon> iconList,
-            out int[] switches, out List<IBinder> binders);
+            out int[] switches, out List<IBinder> binders, out Rect fullscreenStackBounds,
+            out Rect dockedStackBounds);
     void onPanelRevealed(boolean clearNotificationEffects, int numItems);
     void onPanelHidden();
     // Mark current notifications as "seen" and stop ringing, vibrating, blinking.
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e239852..cbc735f 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -283,6 +283,15 @@
         getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
     }
 
+    public int getCurrentFailedPasswordAttempts(int userId) {
+        return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
+    }
+
+    public int getMaximumFailedPasswordsForWipe(int userId) {
+        return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
+                null /* componentName */, userId);
+    }
+
     /**
      * Check to see if a pattern matches the saved pattern.
      * If pattern matches, return an opaque attestation that the challenge
diff --git a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
index 0449340..1b40492 100644
--- a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
+++ b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
@@ -16,10 +16,6 @@
 
 package com.android.server.backup;
 
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.app.backup.BackupDataInputStream;
@@ -28,14 +24,21 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.SyncAdapterType;
+import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import java.io.BufferedOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.EOFException;
+import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.security.MessageDigest;
@@ -73,6 +76,8 @@
     private static final String KEY_AUTHORITY_NAME = "name";
     private static final String KEY_AUTHORITY_SYNC_STATE = "syncState";
     private static final String KEY_AUTHORITY_SYNC_ENABLED = "syncEnabled";
+    private static final String STASH_FILE = Environment.getDataDirectory()
+            + "/backup/unadded_account_syncsettings.json";
 
     private Context mContext;
     private AccountManager mAccountManager;
@@ -256,41 +261,99 @@
             }
 
             try {
-                HashSet<Account> currentAccounts = getAccountsHashSet();
-                for (int i = 0; i < accountJSONArray.length(); i++) {
-                    JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
-                    String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
-                    String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
-
-                    Account account = new Account(accountName, accountType);
-
-                    // Check if the account already exists. Accounts that don't exist on the device
-                    // yet won't be restored.
-                    if (currentAccounts.contains(account)) {
-                        restoreExistingAccountSyncSettingsFromJSON(accountJSON);
-                    } else {
-                        // TODO:
-                        // Stash the data to a file that the SyncManager can read from to restore
-                        // settings at a later date.
-                    }
-                }
+                restoreFromJsonArray(accountJSONArray);
             } finally {
                 // Set the master sync preference to the value from the backup set.
                 ContentResolver.setMasterSyncAutomatically(masterSyncEnabled);
             }
-
             Log.i(TAG, "Restore successful.");
         } catch (IOException | JSONException e) {
             Log.e(TAG, "Couldn't restore account sync settings\n" + e);
         }
     }
 
+    private void restoreFromJsonArray(JSONArray accountJSONArray)
+            throws JSONException {
+        HashSet<Account> currentAccounts = getAccounts();
+        JSONArray unaddedAccountsJSONArray = new JSONArray();
+        for (int i = 0; i < accountJSONArray.length(); i++) {
+            JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
+            String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
+            String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
+
+            Account account = null;
+            try {
+                account = new Account(accountName, accountType);
+            } catch (IllegalArgumentException iae) {
+                continue;
+            }
+
+            // Check if the account already exists. Accounts that don't exist on the device
+            // yet won't be restored.
+            if (currentAccounts.contains(account)) {
+                if (DEBUG) Log.i(TAG, "Restoring Sync Settings for" + accountName);
+                restoreExistingAccountSyncSettingsFromJSON(accountJSON);
+            } else {
+                unaddedAccountsJSONArray.put(accountJSON);
+            }
+        }
+
+        if (unaddedAccountsJSONArray.length() > 0) {
+            try (FileOutputStream fOutput = new FileOutputStream(STASH_FILE)) {
+                String jsonString = unaddedAccountsJSONArray.toString();
+                DataOutputStream out = new DataOutputStream(fOutput);
+                out.writeUTF(jsonString);
+            } catch (IOException ioe) {
+                // Error in writing to stash file
+                Log.e(TAG, "unable to write the sync settings to the stash file", ioe);
+            }
+        } else {
+            File stashFile = new File(STASH_FILE);
+            if (stashFile.exists()) stashFile.delete();
+        }
+    }
+
+    /**
+     * Restore SyncSettings for all existing accounts from a stashed backup-set
+     */
+    private void accountAddedInternal() {
+        String jsonString;
+
+        try (FileInputStream fIn = new FileInputStream(new File(STASH_FILE))) {
+            DataInputStream in = new DataInputStream(fIn);
+            jsonString = in.readUTF();
+        } catch (FileNotFoundException fnfe) {
+            // This is expected to happen when there is no accounts info stashed
+            if (DEBUG) Log.d(TAG, "unable to find the stash file", fnfe);
+            return;
+        } catch (IOException ioe) {
+            if (DEBUG) Log.d(TAG, "could not read sync settings from stash file", ioe);
+            return;
+        }
+
+        try {
+            JSONArray unaddedAccountsJSONArray = new JSONArray(jsonString);
+            restoreFromJsonArray(unaddedAccountsJSONArray);
+        } catch (JSONException jse) {
+            // Malformed jsonString
+            Log.e(TAG, "there was an error with the stashed sync settings", jse);
+        }
+    }
+
+    /**
+     * Restore SyncSettings for all existing accounts from a stashed backup-set
+     */
+    public static void accountAdded(Context context) {
+        AccountSyncSettingsBackupHelper helper = new AccountSyncSettingsBackupHelper(context);
+        helper.accountAddedInternal();
+    }
+
     /**
      * Helper method - fetch accounts and return them as a HashSet.
      *
      * @return Accounts in a HashSet.
      */
-    private HashSet<Account> getAccountsHashSet() {
+    private HashSet<Account> getAccounts() {
         Account[] accounts = mAccountManager.getAccounts();
         HashSet<Account> accountHashSet = new HashSet<Account>();
         for (Account account : accounts) {
@@ -359,4 +422,4 @@
     public void writeNewStateDescription(ParcelFileDescriptor newState) {
 
     }
-}
+}
\ No newline at end of file
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 92f7812..8b248b0 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -505,12 +505,6 @@
             bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
 }
 
-// Need to buffer enough input to be able to rewind as much as might be read by a decoder
-// trying to determine the stream's format. Currently the most is 64, read by
-// SkWebpCodec.
-// FIXME: Get this number from SkCodec
-#define BYTES_TO_BUFFER 64
-
 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
         jobject padding, jobject options) {
 
@@ -519,7 +513,7 @@
 
     if (stream.get()) {
         std::unique_ptr<SkStreamRewindable> bufferedStream(
-                SkFrontBufferedStream::Create(stream.release(), BYTES_TO_BUFFER));
+                SkFrontBufferedStream::Create(stream.release(), SkCodec::MinBufferedBytesNeeded()));
         SkASSERT(bufferedStream.get() != NULL);
         bitmap = doDecode(env, bufferedStream.release(), padding, options);
     }
@@ -565,7 +559,7 @@
     // ensures that SkImageDecoder::Factory never rewinds beyond the
     // current position of the file descriptor.
     std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.release(),
-            BYTES_TO_BUFFER));
+            SkCodec::MinBufferedBytesNeeded()));
 
     return doDecode(env, stream.release(), padding, bitmapFactoryOptions);
 }
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 7c8dbe8..2e974a3 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -20,11 +20,13 @@
 #include <core_jni_helpers.h>
 
 #include "SkData.h"
+#include "SkFontMgr.h"
 #include "SkRefCnt.h"
 #include "SkTypeface.h"
 #include "GraphicsJNI.h"
 #include <ScopedPrimitiveArray.h>
 #include <ScopedUtfChars.h>
+#include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_util_AssetManager.h>
 #include <androidfw/AssetManager.h>
 #include "Utils.h"
@@ -33,6 +35,8 @@
 #include <minikin/FontFamily.h>
 #include "MinikinSkia.h"
 
+#include <memory>
+
 namespace android {
 
 static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
@@ -69,13 +73,89 @@
     return addSkTypeface(fontFamily, face);
 }
 
+static struct {
+    jmethodID mGet;
+    jmethodID mSize;
+} gListClassInfo;
+
+static struct {
+    jfieldID mTag;
+    jfieldID mStyleValue;
+} gAxisClassInfo;
+
+static void release_global_ref(const void* /*data*/, void* context) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    bool needToAttach = (env == NULL);
+    if (needToAttach) {
+        JavaVMAttachArgs args;
+        args.version = JNI_VERSION_1_4;
+        args.name = "release_font_data";
+        args.group = NULL;
+        jint result = AndroidRuntime::getJavaVM()->AttachCurrentThread(&env, &args);
+        if (result != JNI_OK) {
+            ALOGE("failed to attach to thread to release global ref.");
+            return;
+        }
+    }
+
+    jobject obj = reinterpret_cast<jobject>(context);
+    env->DeleteGlobalRef(obj);
+
+    if (needToAttach) {
+       AndroidRuntime::getJavaVM()->DetachCurrentThread();
+    }
+}
+
 static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr,
-        jstring path, jint ttcIndex, jint weight, jboolean isItalic) {
-    NPE_CHECK_RETURN_ZERO(env, path);
-    ScopedUtfChars str(env, path);
-    SkTypeface* face = SkTypeface::CreateFromFile(str.c_str(), ttcIndex);
+        jobject font, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) {
+    NPE_CHECK_RETURN_ZERO(env, font);
+
+    // Declare axis native type.
+    std::unique_ptr<SkFontMgr::FontParameters::Axis[]> skiaAxes;
+    int skiaAxesLength = 0;
+    if (listOfAxis) {
+        jint listSize = env->CallIntMethod(listOfAxis, gListClassInfo.mSize);
+
+        skiaAxes.reset(new SkFontMgr::FontParameters::Axis[listSize]);
+        skiaAxesLength = listSize;
+        for (jint i = 0; i < listSize; ++i) {
+            jobject axisObject = env->CallObjectMethod(listOfAxis, gListClassInfo.mGet, i);
+            if (!axisObject) {
+                skiaAxes[i].fTag = 0;
+                skiaAxes[i].fStyleValue = 0;
+                continue;
+            }
+
+            jint tag = env->GetIntField(axisObject, gAxisClassInfo.mTag);
+            jfloat stylevalue = env->GetFloatField(axisObject, gAxisClassInfo.mStyleValue);
+            skiaAxes[i].fTag = tag;
+            skiaAxes[i].fStyleValue = SkFloatToScalar(stylevalue);
+        }
+    }
+
+    void* fontPtr = env->GetDirectBufferAddress(font);
+    if (fontPtr == NULL) {
+        ALOGE("addFont failed to create font, buffer invalid");
+        return false;
+    }
+    jlong fontSize = env->GetDirectBufferCapacity(font);
+    if (fontSize < 0) {
+        ALOGE("addFont failed to create font, buffer size invalid");
+        return false;
+    }
+    jobject fontRef = MakeGlobalRefOrDie(env, font);
+    SkAutoTUnref<SkData> data(SkData::NewWithProc(fontPtr, fontSize,
+            release_global_ref, reinterpret_cast<void*>(fontRef)));
+    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(data));
+
+    SkFontMgr::FontParameters params;
+    params.setCollectionIndex(ttcIndex);
+    params.setAxes(skiaAxes.get(), skiaAxesLength);
+
+    SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
+    SkTypeface* face = fm->createFromStream(fontData.release(), params);
     if (face == NULL) {
-        ALOGE("addFont failed to create font %s", str.c_str());
+        ALOGE("addFont failed to create font, invalid request");
         return false;
     }
     FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
@@ -129,15 +209,26 @@
     { "nCreateFamily",         "(Ljava/lang/String;I)J", (void*)FontFamily_create },
     { "nUnrefFamily",          "(J)V", (void*)FontFamily_unref },
     { "nAddFont",              "(JLjava/lang/String;I)Z", (void*)FontFamily_addFont },
-    { "nAddFontWeightStyle",   "(JLjava/lang/String;IIZ)Z", (void*)FontFamily_addFontWeightStyle },
+    { "nAddFontWeightStyle",   "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z",
+            (void*)FontFamily_addFontWeightStyle },
     { "nAddFontFromAsset",     "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z",
-                                           (void*)FontFamily_addFontFromAsset },
+            (void*)FontFamily_addFontFromAsset },
 };
 
 int register_android_graphics_FontFamily(JNIEnv* env)
 {
-    return RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
-                                NELEM(gFontFamilyMethods));
+    int err = RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
+            NELEM(gFontFamilyMethods));
+
+    jclass listClass = FindClassOrDie(env, "java/util/List");
+    gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;");
+    gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I");
+
+    jclass axisClass = FindClassOrDie(env, "android/graphics/FontListParser$Axis");
+    gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "tag", "I");
+    gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "styleValue", "F");
+
+    return err;
 }
 
 }
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 8e8f6c37..80f8a64 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -128,11 +128,12 @@
     // other fields unused by JNI
 } gAudioMixingRuleFields;
 
-static jclass gAttributeMatchCriterionClass;
+static jclass gAudioMixMatchCriterionClass;
 static struct {
     jfieldID    mAttr;
+    jfieldID    mIntProp;
     jfieldID    mRule;
-} gAttributeMatchCriterionFields;
+} gAudioMixMatchCriterionFields;
 
 static jclass gAudioAttributesClass;
 static struct {
@@ -1563,22 +1564,32 @@
     }
 
     for (jint i = 0; i < numCriteria; i++) {
-        AttributeMatchCriterion nCriterion;
+        AudioMixMatchCriterion nCriterion;
 
         jobject jCriterion = env->GetObjectArrayElement(jCriteria, i);
 
-        nCriterion.mRule = env->GetIntField(jCriterion, gAttributeMatchCriterionFields.mRule);
+        nCriterion.mRule = env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mRule);
 
-        jobject jAttributes = env->GetObjectField(jCriterion, gAttributeMatchCriterionFields.mAttr);
-        if (nCriterion.mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
-                nCriterion.mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
-            nCriterion.mAttr.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
-                                                       gAudioAttributesFields.mUsage);
-        } else {
-            nCriterion.mAttr.mSource = (audio_source_t)env->GetIntField(jAttributes,
-                                                        gAudioAttributesFields.mSource);
+        const uint32_t match_rule = nCriterion.mRule & ~RULE_EXCLUSION_MASK;
+        switch (match_rule) {
+        case RULE_MATCH_UID:
+            nCriterion.mValue.mUid = env->GetIntField(jCriterion,
+                    gAudioMixMatchCriterionFields.mIntProp);
+            break;
+        case RULE_MATCH_ATTRIBUTE_USAGE:
+        case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
+            jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
+            if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
+                nCriterion.mValue.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
+                        gAudioAttributesFields.mUsage);
+            } else {
+                nCriterion.mValue.mSource = (audio_source_t)env->GetIntField(jAttributes,
+                        gAudioAttributesFields.mSource);
+            }
+            env->DeleteLocalRef(jAttributes);
+            }
+            break;
         }
-        env->DeleteLocalRef(jAttributes);
 
         nAudioMix->mCriteria.add(nCriterion);
         env->DeleteLocalRef(jCriterion);
@@ -1833,12 +1844,14 @@
     gAudioMixingRuleFields.mCriteria = GetFieldIDOrDie(env, audioMixingRuleClass, "mCriteria",
                                                        "Ljava/util/ArrayList;");
 
-    jclass attributeMatchCriterionClass =
-                FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AttributeMatchCriterion");
-    gAttributeMatchCriterionClass = MakeGlobalRefOrDie(env, attributeMatchCriterionClass);
-    gAttributeMatchCriterionFields.mAttr = GetFieldIDOrDie(env, attributeMatchCriterionClass, "mAttr",
+    jclass audioMixMatchCriterionClass =
+                FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion");
+    gAudioMixMatchCriterionClass = MakeGlobalRefOrDie(env,audioMixMatchCriterionClass);
+    gAudioMixMatchCriterionFields.mAttr = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mAttr",
                                                        "Landroid/media/AudioAttributes;");
-    gAttributeMatchCriterionFields.mRule = GetFieldIDOrDie(env, attributeMatchCriterionClass, "mRule",
+    gAudioMixMatchCriterionFields.mIntProp = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mIntProp",
+                                                       "I");
+    gAudioMixMatchCriterionFields.mRule = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mRule",
                                                        "I");
 
     jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4e10d39..daa8202 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4204,11 +4204,16 @@
     <string name="new_sms_notification_content">Open SMS app to view</string>
 
     <!-- Notification title shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
-    <string name="user_encrypted_title">Some functions might not be available</string>
+    <string name="user_encrypted_title">Some functionality may be limited</string>
     <!-- Notification message shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
-    <string name="user_encrypted_message">Touch to continue</string>
+    <string name="user_encrypted_message">Tap to unlock</string>
     <!-- Notification detail shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
-    <string name="user_encrypted_detail">User profile locked</string>
+    <string name="user_encrypted_detail">User data locked</string>
+
+    <!-- Notification detail shown when work profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+    <string name="profile_encrypted_detail">Work profile locked</string>
+    <!-- Notification message shown when work profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+    <string name="profile_encrypted_message">Tap to unlock work profile</string>
 
     <!-- Title of notification shown after a MTP device is connected to Android. -->
     <string name="usb_mtp_launch_notification_title">Connected to <xliff:g id="product_name">%1$s</xliff:g></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f75f023..8df6c2e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2522,6 +2522,8 @@
   <java-symbol type="string" name="user_encrypted_title" />
   <java-symbol type="string" name="user_encrypted_message" />
   <java-symbol type="string" name="user_encrypted_detail" />
+  <java-symbol type="string" name="profile_encrypted_detail" />
+  <java-symbol type="string" name="profile_encrypted_message" />
   <java-symbol type="drawable" name="ic_user_secure" />
 
   <java-symbol type="string" name="usb_mtp_launch_notification_title" />
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 6309ed3..f741e3c 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -18,6 +18,9 @@
 
 import android.content.res.AssetManager;
 
+import java.nio.ByteBuffer;
+import java.util.List;
+
 /**
  * A family of typefaces with different styles.
  *
@@ -62,8 +65,9 @@
         return nAddFont(mNativePtr, path, ttcIndex);
     }
 
-    public boolean addFontWeightStyle(String path, int ttcIndex, int weight, boolean style) {
-        return nAddFontWeightStyle(mNativePtr, path, ttcIndex, weight, style);
+    public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontListParser.Axis> axes,
+            int weight, boolean style) {
+        return nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style);
     }
 
     public boolean addFontFromAsset(AssetManager mgr, String path) {
@@ -73,8 +77,9 @@
     private static native long nCreateFamily(String lang, int variant);
     private static native void nUnrefFamily(long nativePtr);
     private static native boolean nAddFont(long nativeFamily, String path, int ttcIndex);
-    private static native boolean nAddFontWeightStyle(long nativeFamily, String path,
-            int ttcIndex, int weight, boolean isItalic);
+    private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
+            int ttcIndex, List<FontListParser.Axis> listOfAxis,
+            int weight, boolean isItalic);
     private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr,
             String path);
 }
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 774f6b8..8f7c6a62 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -25,6 +25,7 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.regex.Pattern;
 
 /**
  * Parser for font config files.
@@ -42,15 +43,26 @@
         public List<Alias> aliases;
     }
 
+    public static class Axis {
+        Axis(int tag, float styleValue) {
+            this.tag = tag;
+            this.styleValue = styleValue;
+        }
+        public final int tag;
+        public final float styleValue;
+    }
+
     public static class Font {
-        Font(String fontName, int ttcIndex, int weight, boolean isItalic) {
+        Font(String fontName, int ttcIndex, List<Axis> axes, int weight, boolean isItalic) {
             this.fontName = fontName;
             this.ttcIndex = ttcIndex;
+            this.axes = axes;
             this.weight = weight;
             this.isItalic = isItalic;
         }
         public String fontName;
         public int ttcIndex;
+        public final List<Axis> axes;
         public int weight;
         public boolean isItalic;
     }
@@ -93,9 +105,10 @@
         parser.require(XmlPullParser.START_TAG, null, "familyset");
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
-            if (parser.getName().equals("family")) {
+            String tag = parser.getName();
+            if (tag.equals("family")) {
                 config.families.add(readFamily(parser));
-            } else if (parser.getName().equals("alias")) {
+            } else if (tag.equals("alias")) {
                 config.aliases.add(readAlias(parser));
             } else {
                 skip(parser);
@@ -114,14 +127,7 @@
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
             if (tag.equals("font")) {
-                String ttcIndexStr = parser.getAttributeValue(null, "index");
-                int ttcIndex = ttcIndexStr == null ? 0 : Integer.parseInt(ttcIndexStr);
-                String weightStr = parser.getAttributeValue(null, "weight");
-                int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
-                boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
-                String filename = parser.nextText();
-                String fullFilename = "/system/fonts/" + filename;
-                fonts.add(new Font(fullFilename, ttcIndex, weight, isItalic));
+                fonts.add(readFont(parser));
             } else {
                 skip(parser);
             }
@@ -129,6 +135,70 @@
         return new Family(name, fonts, lang, variant);
     }
 
+    /** Matches leading and trailing XML whitespace. */
+    private static final Pattern FILENAME_WHITESPACE_PATTERN =
+            Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
+
+    private static Font readFont(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        String indexStr = parser.getAttributeValue(null, "index");
+        int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
+        List<Axis> axes = new ArrayList<Axis>();
+        String weightStr = parser.getAttributeValue(null, "weight");
+        int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
+        boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
+        StringBuilder filename = new StringBuilder();
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() == XmlPullParser.TEXT) {
+                filename.append(parser.getText());
+            }
+            if (parser.getEventType() != XmlPullParser.START_TAG) continue;
+            String tag = parser.getName();
+            if (tag.equals("axis")) {
+                axes.add(readAxis(parser));
+            } else {
+                skip(parser);
+            }
+        }
+        String fullFilename = "/system/fonts/" +
+                FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
+        return new Font(fullFilename, index, axes, weight, isItalic);
+    }
+
+    /** The 'tag' attribute value is read as four character values between 0 and 255 inclusive. */
+    private static final Pattern TAG_PATTERN = Pattern.compile("[\\x00-\\xFF]{4}");
+
+    /** The 'styleValue' attribute has an optional leading '-', followed by '<digits>',
+     *  '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9].
+     */
+    private static final Pattern STYLE_VALUE_PATTERN =
+            Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))");
+
+    private static Axis readAxis(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        int tag = 0;
+        String tagStr = parser.getAttributeValue(null, "tag");
+        if (tagStr != null && TAG_PATTERN.matcher(tagStr).matches()) {
+            tag = tagStr.charAt(0) << 24 +
+                  tagStr.charAt(1) << 16 +
+                  tagStr.charAt(2) <<  8 +
+                  tagStr.charAt(3);
+        } else {
+            throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
+        }
+
+        float styleValue = 0;
+        String styleValueStr = parser.getAttributeValue(null, "stylevalue");
+        if (styleValueStr != null && STYLE_VALUE_PATTERN.matcher(styleValueStr).matches()) {
+            styleValue = Float.parseFloat(styleValueStr);
+        } else {
+            throw new XmlPullParserException("Invalid styleValue attribute value.", parser, null);
+        }
+
+        skip(parser);  // axis tag is empty, ignore any contents and consume end tag
+        return new Axis(tag, styleValue);
+    }
+
     private static Alias readAlias(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         Alias alias = new Alias();
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 1294323..f15aff7 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -17,7 +17,6 @@
 package android.graphics;
 
 import android.content.res.AssetManager;
-import android.graphics.FontListParser.Family;
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.SparseArray;
@@ -28,6 +27,8 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -259,10 +260,26 @@
         mStyle = nativeGetStyle(ni);
     }
 
-    private static FontFamily makeFamilyFromParsed(FontListParser.Family family) {
+    private static FontFamily makeFamilyFromParsed(FontListParser.Family family,
+            Map<String, ByteBuffer> bufferForPath) {
         FontFamily fontFamily = new FontFamily(family.lang, family.variant);
         for (FontListParser.Font font : family.fonts) {
-            fontFamily.addFontWeightStyle(font.fontName, font.ttcIndex, font.weight, font.isItalic);
+            ByteBuffer fontBuffer = bufferForPath.get(font.fontName);
+            if (fontBuffer == null) {
+                try (FileInputStream file = new FileInputStream(font.fontName)) {
+                    FileChannel fileChannel = file.getChannel();
+                    long fontSize = fileChannel.size();
+                    fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
+                    bufferForPath.put(font.fontName, fontBuffer);
+                } catch (IOException e) {
+                    Log.e(TAG, "Error mapping font file " + font.fontName);
+                    continue;
+                }
+            }
+            if (!fontFamily.addFontWeightStyle(fontBuffer, font.ttcIndex, font.axes,
+                    font.weight, font.isItalic)) {
+                Log.e(TAG, "Error creating font " + font.fontName + "#" + font.ttcIndex);
+            }
         }
         return fontFamily;
     }
@@ -280,13 +297,15 @@
             FileInputStream fontsIn = new FileInputStream(configFilename);
             FontListParser.Config fontConfig = FontListParser.parse(fontsIn);
 
+            Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>();
+
             List<FontFamily> familyList = new ArrayList<FontFamily>();
             // Note that the default typeface is always present in the fallback list;
             // this is an enhancement from pre-Minikin behavior.
             for (int i = 0; i < fontConfig.families.size(); i++) {
-                Family f = fontConfig.families.get(i);
+                FontListParser.Family f = fontConfig.families.get(i);
                 if (i == 0 || f.name == null) {
-                    familyList.add(makeFamilyFromParsed(f));
+                    familyList.add(makeFamilyFromParsed(f, bufferForPath));
                 }
             }
             sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
@@ -295,14 +314,14 @@
             Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
             for (int i = 0; i < fontConfig.families.size(); i++) {
                 Typeface typeface;
-                Family f = fontConfig.families.get(i);
+                FontListParser.Family f = fontConfig.families.get(i);
                 if (f.name != null) {
                     if (i == 0) {
                         // The first entry is the default typeface; no sense in
                         // duplicating the corresponding FontFamily.
                         typeface = sDefaultTypeface;
                     } else {
-                        FontFamily fontFamily = makeFamilyFromParsed(f);
+                        FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath);
                         FontFamily[] families = { fontFamily };
                         typeface = Typeface.createFromFamiliesWithDefault(families);
                     }
@@ -324,11 +343,11 @@
             Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
             // TODO: normal in non-Minikin case, remove or make error when Minikin-only
         } catch (FileNotFoundException e) {
-            Log.e(TAG, "Error opening " + configFilename);
+            Log.e(TAG, "Error opening " + configFilename, e);
         } catch (IOException e) {
-            Log.e(TAG, "Error reading " + configFilename);
+            Log.e(TAG, "Error reading " + configFilename, e);
         } catch (XmlPullParserException e) {
-            Log.e(TAG, "XML parse exception for " + configFilename);
+            Log.e(TAG, "XML parse exception for " + configFilename, e);
         }
     }
 
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 1d9fe35..3277c36 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2236,7 +2236,7 @@
     // See if any of the regions is better than the other
     const int region_comparison = localeDataCompareRegions(
             country, o.country,
-            language, localeScript, requested->country);
+            language, requested->localeScript, requested->country);
     if (region_comparison != 0) {
         return (region_comparison > 0);
     }
@@ -2526,17 +2526,34 @@
 
         // For backward compatibility and supporting private-use locales, we
         // fall back to old behavior if we couldn't determine the script for
-        // either of the desired locale or the provided locale.
-        if (localeScript[0] == '\0' || localeScript[1] == '\0') {
+        // either of the desired locale or the provided locale. But if we could determine
+        // the scripts, they should be the same for the locales to match.
+        bool countriesMustMatch = false;
+        char computed_script[4];
+        const char* script;
+        if (settings.localeScript[0] == '\0') { // could not determine the request's script
+            countriesMustMatch = true;
+        } else {
+            if (localeScript[0] == '\0') { // script was not provided, so we try to compute it
+                localeDataComputeScript(computed_script, language, country);
+                if (computed_script[0] == '\0') { // we could not compute the script
+                    countriesMustMatch = true;
+                } else {
+                    script = computed_script;
+                }
+            } else { // script was provided, so just use it
+                script = localeScript;
+            }
+        }
+
+        if (countriesMustMatch) {
             if (country[0] != '\0'
                 && (country[0] != settings.country[0]
                     || country[1] != settings.country[1])) {
                 return false;
             }
         } else {
-            // But if we could determine the scripts, they should be the same
-            // for the locales to match.
-            if (memcmp(localeScript, settings.localeScript, sizeof(localeScript)) != 0) {
+            if (memcmp(script, settings.localeScript, sizeof(settings.localeScript)) != 0) {
                 return false;
             }
         }
diff --git a/libs/androidfw/tests/ConfigLocale_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp
index 7b38640..4b8d65c 100644
--- a/libs/androidfw/tests/ConfigLocale_test.cpp
+++ b/libs/androidfw/tests/ConfigLocale_test.cpp
@@ -371,6 +371,19 @@
     EXPECT_TRUE(supported.match(requested));
 }
 
+TEST(ConfigLocaleTest, match_emptyScript) {
+    ResTable_config supported, requested;
+
+    fillIn("fr", "FR", NULL, NULL, &supported);
+    fillIn("fr", "CA", NULL, NULL, &requested);
+
+    // emulate packages built with older AAPT
+    memset(supported.localeScript, '\0', 4);
+    supported.localeScriptWasProvided = false;
+
+    EXPECT_TRUE(supported.match(requested));
+}
+
 TEST(ConfigLocaleTest, isLocaleBetterThan_basics) {
     ResTable_config config1, config2, request;
 
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 1f242a3..6a565033 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -144,20 +144,8 @@
     external/skia/include/private \
     external/skia/src/core
 
-hwui_shared_libraries := \
-    liblog \
-    libcutils \
-    libutils \
-    libEGL \
-    libGLESv2 \
-    libskia \
-    libui \
-    libgui \
-    libprotobuf-cpp-lite \
-
 ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
     hwui_cflags += -DANDROID_ENABLE_RENDERSCRIPT
-    hwui_shared_libraries += libRS libRScpp
     hwui_c_includes += \
         $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) \
         frameworks/rs/cpp \
@@ -180,12 +168,15 @@
 
 LOCAL_MODULE_CLASS := STATIC_LIBRARIES
 LOCAL_MODULE := libhwui_static
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
 LOCAL_CFLAGS := $(hwui_cflags)
 LOCAL_SRC_FILES := $(hwui_src_files)
 LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(hwui_c_includes) $(call hwui_proto_include)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+        $(LOCAL_PATH) \
+        $(hwui_c_includes) \
+        $(call hwui_proto_include)
 
+include $(LOCAL_PATH)/hwui_static_deps.mk
 include $(BUILD_STATIC_LIBRARY)
 
 # ------------------------
@@ -196,7 +187,6 @@
 
 LOCAL_MODULE_CLASS := STATIC_LIBRARIES
 LOCAL_MODULE := libhwui_static_null_gpu
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
 LOCAL_CFLAGS := \
         $(hwui_cflags) \
         -DHWUI_NULL_GPU
@@ -205,8 +195,12 @@
         debug/nullegl.cpp \
         debug/nullgles.cpp
 LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(hwui_c_includes) $(call hwui_proto_include)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+        $(LOCAL_PATH) \
+        $(hwui_c_includes) \
+        $(call hwui_proto_include)
 
+include $(LOCAL_PATH)/hwui_static_deps.mk
 include $(BUILD_STATIC_LIBRARY)
 
 # ------------------------
@@ -218,8 +212,9 @@
 LOCAL_MODULE_CLASS := SHARED_LIBRARIES
 LOCAL_MODULE := libhwui
 LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
 
+include $(LOCAL_PATH)/hwui_static_deps.mk
 include $(BUILD_SHARED_LIBRARY)
 
 # ------------------------
@@ -230,7 +225,6 @@
 
 LOCAL_MODULE := hwui_unit_tests
 LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
 LOCAL_STATIC_LIBRARIES := libhwui_static_null_gpu
 LOCAL_CFLAGS := \
         $(hwui_cflags) \
@@ -263,6 +257,7 @@
         tests/unit/RecordingCanvasTests.cpp
 endif
 
+include $(LOCAL_PATH)/hwui_static_deps.mk
 include $(BUILD_NATIVE_TEST)
 
 # ------------------------
@@ -278,7 +273,6 @@
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := hwuitest
 LOCAL_MODULE_STEM_64 := hwuitest64
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
 LOCAL_CFLAGS := $(hwui_cflags)
 
 # set to libhwui_static_null_gpu to skip actual GL commands
@@ -289,6 +283,7 @@
     tests/macrobench/TestSceneRunner.cpp \
     tests/macrobench/main.cpp
 
+include $(LOCAL_PATH)/hwui_static_deps.mk
 include $(BUILD_EXECUTABLE)
 
 # ------------------------
@@ -303,7 +298,6 @@
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := hwuimicro
 LOCAL_MODULE_STEM_64 := hwuimicro64
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
 LOCAL_CFLAGS := \
         $(hwui_cflags) \
         -DHWUI_NULL_GPU
@@ -325,6 +319,5 @@
         tests/microbench/FrameBuilderBench.cpp
 endif
 
-LOCAL_CLANG := true # workaround gcc bug
-
+include $(LOCAL_PATH)/hwui_static_deps.mk
 include $(BUILD_EXECUTABLE)
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 11293d6..c8f5e94 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -165,6 +165,10 @@
     generateTexture(colors, positions, info.width, 2, texture);
 
     mSize += size;
+    LOG_ALWAYS_FATAL_IF((int)size != texture->objectSize(),
+            "size != texture->objectSize(), size %" PRIu32 ", objectSize %d"
+            " width = %" PRIu32 " bytesPerPixel() = %zu",
+            size, texture->objectSize(), info.width, bytesPerPixel());
     mCache.put(gradient, texture);
 
     return texture;
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index c09b6dd..4f49a35 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -28,13 +28,19 @@
 
 static int bytesPerPixel(GLint glFormat) {
     switch (glFormat) {
+    // The wrapped-texture case, usually means a SurfaceTexture
+    case 0:
+        return 0;
     case GL_ALPHA:
         return 1;
     case GL_RGB:
         return 3;
     case GL_RGBA:
-    default:
         return 4;
+    case GL_RGBA16F:
+        return 16;
+    default:
+        LOG_ALWAYS_FATAL("UNKNOWN FORMAT %d", glFormat);
     }
 }
 
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
new file mode 100644
index 0000000..7d4ef0f
--- /dev/null
+++ b/libs/hwui/hwui_static_deps.mk
@@ -0,0 +1,28 @@
+###############################################################################
+#
+#
+# This file contains the shared and static dependencies needed by any target
+# that attempts to statically link HWUI (i.e. libhwui_static build target). This
+# file should be included by any target that lists libhwui_static as a
+# dependency.
+#
+# This is a workaround for the fact that the build system does not add these
+# transitive dependencies when it attempts to link libhwui_static into another
+# library.
+#
+###############################################################################
+
+LOCAL_SHARED_LIBRARIES += \
+    liblog \
+    libcutils \
+    libutils \
+    libEGL \
+    libGLESv2 \
+    libskia \
+    libui \
+    libgui \
+    libprotobuf-cpp-lite
+
+ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
+    LOCAL_SHARED_LIBRARIES += libRS libRScpp
+endif
\ No newline at end of file
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index d8f507c..a490685 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -28,7 +28,7 @@
  */
 public final class GnssMeasurement implements Parcelable {
     private int mFlags;
-    private byte mPrn;
+    private short mSvid;
     private double mTimeOffsetInNs;
     private short mState;
     private long mReceivedGpsTowInNs;
@@ -198,7 +198,7 @@
      */
     public void set(GnssMeasurement measurement) {
         mFlags = measurement.mFlags;
-        mPrn = measurement.mPrn;
+        mSvid = measurement.mSvid;
         mTimeOffsetInNs = measurement.mTimeOffsetInNs;
         mState = measurement.mState;
         mReceivedGpsTowInNs = measurement.mReceivedGpsTowInNs;
@@ -248,15 +248,15 @@
      * Gets the Pseudo-random number (PRN).
      * Range: [1, 32]
      */
-    public byte getPrn() {
-        return mPrn;
+    public short getSvid() {
+        return mSvid;
     }
 
     /**
      * Sets the Pseud-random number (PRN).
      */
-    public void setPrn(byte value) {
-        mPrn = value;
+    public void setSvid(short value) {
+        mSvid = value;
     }
 
     /**
@@ -1210,7 +1210,7 @@
             GnssMeasurement gnssMeasurement = new GnssMeasurement();
 
             gnssMeasurement.mFlags = parcel.readInt();
-            gnssMeasurement.mPrn = parcel.readByte();
+            gnssMeasurement.mSvid = (short) parcel.readInt();
             gnssMeasurement.mTimeOffsetInNs = parcel.readDouble();
             gnssMeasurement.mState = (short) parcel.readInt();
             gnssMeasurement.mReceivedGpsTowInNs = parcel.readLong();
@@ -1253,9 +1253,10 @@
         }
     };
 
+    @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mFlags);
-        parcel.writeByte(mPrn);
+        parcel.writeInt(mSvid);
         parcel.writeDouble(mTimeOffsetInNs);
         parcel.writeInt(mState);
         parcel.writeLong(mReceivedGpsTowInNs);
@@ -1301,7 +1302,7 @@
         final String formatWithUncertainty = "   %-29s = %-25s   %-40s = %s\n";
         StringBuilder builder = new StringBuilder("GnssMeasurement:\n");
 
-        builder.append(String.format(format, "Prn", mPrn));
+        builder.append(String.format(format, "Svid", mSvid));
 
         builder.append(String.format(format, "TimeOffsetInNs", mTimeOffsetInNs));
 
@@ -1422,7 +1423,7 @@
 
     private void initialize() {
         mFlags = HAS_NO_FLAGS;
-        setPrn(Byte.MIN_VALUE);
+        setSvid((short) 0);
         setTimeOffsetInNs(Long.MIN_VALUE);
         setState(STATE_UNKNOWN);
         setReceivedGpsTowInNs(Long.MIN_VALUE);
diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java
index 0e011d5..86328eb 100644
--- a/location/java/android/location/GnssNavigationMessage.java
+++ b/location/java/android/location/GnssNavigationMessage.java
@@ -26,7 +26,7 @@
 import java.security.InvalidParameterException;
 
 /**
- * A class containing a GPS satellite Navigation Message.
+ * A class containing a GNSS satellite Navigation Message.
  */
 public final class GnssNavigationMessage implements Parcelable {
 
@@ -84,7 +84,7 @@
     // End enumerations in sync with gps.h
 
     private byte mType;
-    private byte mPrn;
+    private short mSvid;
     private short mMessageId;
     private short mSubmessageId;
     private byte[] mData;
@@ -99,7 +99,7 @@
      */
     public void set(GnssNavigationMessage navigationMessage) {
         mType = navigationMessage.mType;
-        mPrn = navigationMessage.mPrn;
+        mSvid = navigationMessage.mSvid;
         mMessageId = navigationMessage.mMessageId;
         mSubmessageId = navigationMessage.mSubmessageId;
         mData = navigationMessage.mData;
@@ -153,15 +153,15 @@
      * Gets the Pseudo-random number.
      * Range: [1, 32].
      */
-    public byte getPrn() {
-        return mPrn;
+    public short getSvid() {
+        return mSvid;
     }
 
     /**
      * Sets the Pseud-random number.
      */
-    public void setPrn(byte value) {
-        mPrn = value;
+    public void setSvid(short value) {
+        mSvid = value;
     }
 
     /**
@@ -256,7 +256,7 @@
             GnssNavigationMessage navigationMessage = new GnssNavigationMessage();
 
             navigationMessage.setType(parcel.readByte());
-            navigationMessage.setPrn(parcel.readByte());
+            navigationMessage.setSvid((short) parcel.readInt());
             navigationMessage.setMessageId((short) parcel.readInt());
             navigationMessage.setSubmessageId((short) parcel.readInt());
 
@@ -281,9 +281,10 @@
         }
     };
 
+    @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeByte(mType);
-        parcel.writeByte(mPrn);
+        parcel.writeInt(mSvid);
         parcel.writeInt(mMessageId);
         parcel.writeInt(mSubmessageId);
         parcel.writeInt(mData.length);
@@ -302,7 +303,7 @@
         StringBuilder builder = new StringBuilder("GnssNavigationMessage:\n");
 
         builder.append(String.format(format, "Type", getTypeString()));
-        builder.append(String.format(format, "Prn", mPrn));
+        builder.append(String.format(format, "Svid", mSvid));
         builder.append(String.format(format, "Status", getStatusString()));
         builder.append(String.format(format, "MessageId", mMessageId));
         builder.append(String.format(format, "SubmessageId", mSubmessageId));
@@ -321,7 +322,7 @@
 
     private void initialize() {
         mType = MESSAGE_TYPE_UNKNOWN;
-        mPrn = 0;
+        mSvid = 0;
         mMessageId = -1;
         mSubmessageId = -1;
         mData = EMPTY_ARRAY;
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 77e8a5b..906e944 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -47,24 +47,26 @@
     public static final int GNSS_SV_FLAGS_USED_IN_FIX = (1 << 2);
 
     /** @hide */
-    public static final int PRN_SHIFT_WIDTH = 3;
+    public static final int SVID_SHIFT_WIDTH = 7;
+    /** @hide */
+    public static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 3;
+    /** @hide */
+    public static final int CONSTELLATION_TYPE_MASK = 0xf;
 
     /* These package private values are modified by the LocationManager class */
-    /* package */ int[] mPrnWithFlags;
+    /* package */ int[] mSvidWithFlags;
     /* package */ float[] mSnrs;
     /* package */ float[] mElevations;
     /* package */ float[] mAzimuths;
-    /* package */ int[] mConstellationTypes;
     /* package */ int mSvCount;
 
-    GnssStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations, float[] azimuths,
-            int[] constellationTypes) {
+    GnssStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+            float[] azimuths) {
         mSvCount = svCount;
-        mPrnWithFlags = prnWithFlags;
+        mSvidWithFlags = svidWithFlags;
         mSnrs = snrs;
         mElevations = elevations;
         mAzimuths = azimuths;
-        mConstellationTypes = constellationTypes;
     }
 
     /**
@@ -79,15 +81,16 @@
      * @param satIndex the index of the satellite in the list.
      */
     public int getConstellationType(int satIndex) {
-        return mConstellationTypes[satIndex];
+        return (mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
+                & CONSTELLATION_TYPE_MASK;
     }
 
     /**
      * Retrieves the pseudo-random number of the satellite at the specified position.
      * @param satIndex the index of the satellite in the list.
      */
-    public int getPrn(int satIndex) {
-        return mPrnWithFlags[satIndex] >> PRN_SHIFT_WIDTH;
+    public int getSvid(int satIndex) {
+        return mSvidWithFlags[satIndex] >> SVID_SHIFT_WIDTH;
     }
 
     /**
@@ -119,7 +122,7 @@
      * @param satIndex the index of the satellite in the list.
      */
     public boolean hasEphemeris(int satIndex) {
-        return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+        return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
     }
 
     /**
@@ -127,7 +130,7 @@
      * @param satIndex the index of the satellite in the list.
      */
     public boolean hasAlmanac(int satIndex) {
-        return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+        return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
     }
 
     /**
@@ -135,6 +138,6 @@
      * @param satIndex the index of the satellite in the list.
      */
     public boolean usedInFix(int satIndex) {
-        return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_USED_IN_FIX) != 0;
+        return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_USED_IN_FIX) != 0;
     }
 }
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 8d2f781..e41e20c 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -138,15 +138,19 @@
     // For API-compat a public ctor() is not available
     GpsStatus() {}
 
-    private void setStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations,
-            float[] azimuths, int[] constellationTypes) { 
+    private void setStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+            float[] azimuths) {
         clearSatellites();
         for (int i = 0; i < svCount; i++) {
+            final int constellationType =
+                    (svidWithFlags[i] >> GnssStatus.CONSTELLATION_TYPE_SHIFT_WIDTH)
+                    & GnssStatus.CONSTELLATION_TYPE_MASK;
             // Skip all non-GPS satellites.
-            if (constellationTypes[i] != GnssStatus.CONSTELLATION_GPS) {
+            if (constellationType != GnssStatus.CONSTELLATION_GPS) {
+                // TODO: translate the defacto pre-N use of  prn's >32 to new struct
                 continue;
             }
-            int prn = prnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH;
+            int prn = svidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH;
             if (prn > 0 && prn <= NUM_SATELLITES) {
                 GpsSatellite satellite = mSatellites.get(prn);
                 if (satellite == null) {
@@ -159,11 +163,11 @@
                 satellite.mElevation = elevations[i];
                 satellite.mAzimuth = azimuths[i];
                 satellite.mHasEphemeris =
-                        (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+                        (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
                 satellite.mHasAlmanac =
-                        (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+                        (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
                 satellite.mUsedInFix =
-                        (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
+                        (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
             }
         }
     }
@@ -176,8 +180,8 @@
      */
     void setStatus(GnssStatus status, int timeToFirstFix) {
         mTimeToFirstFix = timeToFirstFix;
-        setStatus(status.mSvCount, status.mPrnWithFlags, status.mSnrs, status.mElevations,
-                status.mAzimuths, status.mConstellationTypes);
+        setStatus(status.mSvCount, status.mSvidWithFlags, status.mSnrs, status.mElevations,
+                status.mAzimuths);
     }
 
     void setTimeToFirstFix(int ttff) {
diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
index d1c6a85..8c7d06e 100644
--- a/location/java/android/location/IGnssStatusListener.aidl
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -26,7 +26,7 @@
     void onGnssStarted();
     void onGnssStopped();
     void onFirstFix(int ttff);
-    void onSvStatusChanged(int svCount, in int[] prnWithFlags, in float[] snrs,
-            in float[] elevations, in float[] azimuths, in int[] constellationTypes);
+    void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] snrs,
+            in float[] elevations, in float[] azimuths);
     void onNmeaReceived(long timestamp, String nmea);
 }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 30cf101..23f0710 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1562,10 +1562,9 @@
 
         @Override
         public void onSvStatusChanged(int svCount, int[] prnWithFlags,
-                float[] snrs, float[] elevations, float[] azimuths, int[] constellationTypes) {
+                float[] snrs, float[] elevations, float[] azimuths) {
             if (mGnssCallback != null) {
-                mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths,
-                        constellationTypes);
+                mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths);
 
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index e0fa592f..6fc2f87 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1052,32 +1052,27 @@
         }
     }
 
-// TODO Change getBufferCapacityInFrames() reference below to
-// {@link #getBufferCapacityInFrames()} after @hide is removed.
-// TODO Change setBufferSizeInFrames(int) reference below to
-// {@link #setBufferSizeInFrames(int)} after @hide is removed.
+
     /**
-     *  Returns the effective size of the <code>AudioTrack</code> buffer
+     * Returns the effective size of the <code>AudioTrack</code> buffer
      * that the application writes to.
-     *  <p> This will be less than or equal to the result of
-     * getBufferCapacityInFrames().
-     * It will be equal if setBufferSizeInFrames(int) has never been called.
-     *  <p> If the track is subsequently routed to a different output sink, the buffer
-     *  size and capacity may enlarge to accommodate.
-     *  <p> If the <code>AudioTrack</code> encoding indicates compressed data,
-     *  e.g. {@link AudioFormat#ENCODING_AC3}, then the frame count returned is
-     *  the size of the native <code>AudioTrack</code> buffer in bytes.
-     *  <p> See also {@link AudioManager#getProperty(String)} for key
-     *  {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
-     *  @return current size in frames of the <code>AudioTrack</code> buffer.
-     *  @throws IllegalStateException
+     * <p> This will be less than or equal to the result of
+     * {@link #getBufferCapacityInFrames()}.
+     * It will be equal if {@link #setBufferSizeInFrames(int)} has never been called.
+     * <p> If the track is subsequently routed to a different output sink, the buffer
+     * size and capacity may enlarge to accommodate.
+     * <p> If the <code>AudioTrack</code> encoding indicates compressed data,
+     * e.g. {@link AudioFormat#ENCODING_AC3}, then the frame count returned is
+     * the size of the native <code>AudioTrack</code> buffer in bytes.
+     * <p> See also {@link AudioManager#getProperty(String)} for key
+     * {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
+     * @return current size in frames of the <code>AudioTrack</code> buffer.
+     * @throws IllegalStateException
      */
     public int getBufferSizeInFrames() {
         return native_get_buffer_size_frames();
     }
 
-// TODO Change getBufferCapacityInFrames() reference below to
-// {@link #getBufferCapacityInFrames()} after @hide is removed.
     /**
      * Limits the effective size of the <code>AudioTrack</code> buffer
      * that the application writes to.
@@ -1087,9 +1082,9 @@
      * <p>Changing this limit modifies the latency associated with
      * the buffer for this track. A smaller size will give lower latency
      * but there may be more glitches due to buffer underruns.
-     *  <p>The actual size used may not be equal to this requested size.
+     * <p>The actual size used may not be equal to this requested size.
      * It will be limited to a valid range with a maximum of
-     * getBufferCapacityInFrames().
+     * {@link #getBufferCapacityInFrames()}.
      * It may also be adjusted slightly for internal reasons.
      * If bufferSizeInFrames is less than zero then {@link #ERROR_BAD_VALUE}
      * will be returned.
@@ -1097,9 +1092,9 @@
      * It is not supported for compressed audio tracks.
      *
      * @param bufferSizeInFrames requested buffer size
-     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
-     *    {@link #ERROR_INVALID_OPERATION}
-     *  @throws IllegalStateException
+     * @return the actual buffer size in frames or an error code,
+     *    {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}
+     * @throws IllegalStateException
      */
     public int setBufferSizeInFrames(int bufferSizeInFrames) {
         if (mDataLoadMode == MODE_STATIC || mState == STATE_UNINITIALIZED) {
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 54543ec..e197141 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -42,7 +42,7 @@
 @SystemApi
 public class AudioMixingRule {
 
-    private AudioMixingRule(int mixType, ArrayList<AttributeMatchCriterion> criteria) {
+    private AudioMixingRule(int mixType, ArrayList<AudioMixMatchCriterion> criteria) {
         mCriteria = criteria;
         mTargetMixType = mixType;
     }
@@ -91,21 +91,21 @@
     public static final int RULE_EXCLUDE_UID =
             RULE_EXCLUSION_MASK | RULE_MATCH_UID;
 
-    static final class AttributeMatchCriterion {
+    static final class AudioMixMatchCriterion {
         final AudioAttributes mAttr;
-        final Integer mIntProp;
+        final int mIntProp;
         final int mRule;
 
         /** input parameters must be valid */
-        AttributeMatchCriterion(AudioAttributes attributes, int rule) {
+        AudioMixMatchCriterion(AudioAttributes attributes, int rule) {
             mAttr = attributes;
-            mIntProp = null;
+            mIntProp = Integer.MIN_VALUE;
             mRule = rule;
         }
         /** input parameters must be valid */
-        AttributeMatchCriterion(Integer intProp, int rule) {
+        AudioMixMatchCriterion(Integer intProp, int rule) {
             mAttr = null;
-            mIntProp = intProp;
+            mIntProp = intProp.intValue();
             mRule = rule;
         }
 
@@ -125,10 +125,10 @@
                 dest.writeInt(mAttr.getCapturePreset());
                 break;
             case RULE_MATCH_UID:
-                dest.writeInt(mIntProp.intValue());
+                dest.writeInt(mIntProp);
                 break;
             default:
-                Log.e("AttributeMatchCriterion", "Unknown match rule" + match_rule
+                Log.e("AudioMixMatchCriterion", "Unknown match rule" + match_rule
                         + " when writing to Parcel");
                 dest.writeInt(-1);
             }
@@ -137,8 +137,8 @@
 
     private final int mTargetMixType;
     int getTargetMixType() { return mTargetMixType; }
-    private final ArrayList<AttributeMatchCriterion> mCriteria;
-    ArrayList<AttributeMatchCriterion> getCriteria() { return mCriteria; }
+    private final ArrayList<AudioMixMatchCriterion> mCriteria;
+    ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; }
 
     @Override
     public int hashCode() {
@@ -205,7 +205,7 @@
      */
     @SystemApi
     public static class Builder {
-        private ArrayList<AttributeMatchCriterion> mCriteria;
+        private ArrayList<AudioMixMatchCriterion> mCriteria;
         private int mTargetMixType = AudioMix.MIX_TYPE_INVALID;
 
         /**
@@ -213,7 +213,7 @@
          */
         @SystemApi
         public Builder() {
-            mCriteria = new ArrayList<AttributeMatchCriterion>();
+            mCriteria = new ArrayList<AudioMixMatchCriterion>();
         }
 
         /**
@@ -378,10 +378,10 @@
                 throw new IllegalArgumentException("Incompatible rule for mix");
             }
             synchronized (mCriteria) {
-                Iterator<AttributeMatchCriterion> crIterator = mCriteria.iterator();
+                Iterator<AudioMixMatchCriterion> crIterator = mCriteria.iterator();
                 final int match_rule = rule & ~RULE_EXCLUSION_MASK;
                 while (crIterator.hasNext()) {
-                    final AttributeMatchCriterion criterion = crIterator.next();
+                    final AudioMixMatchCriterion criterion = crIterator.next();
                     switch (match_rule) {
                         case RULE_MATCH_ATTRIBUTE_USAGE:
                             // "usage"-based rule
@@ -413,7 +413,7 @@
                             break;
                         case RULE_MATCH_UID:
                             // "usage"-based rule
-                            if (criterion.mIntProp.intValue() == intProp.intValue()) {
+                            if (criterion.mIntProp == intProp.intValue()) {
                                 if (criterion.mRule == rule) {
                                     // rule already exists, we're done
                                     return this;
@@ -431,10 +431,10 @@
                 switch (match_rule) {
                     case RULE_MATCH_ATTRIBUTE_USAGE:
                     case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
-                        mCriteria.add(new AttributeMatchCriterion(attrToMatch, rule));
+                        mCriteria.add(new AudioMixMatchCriterion(attrToMatch, rule));
                         break;
                     case RULE_MATCH_UID:
-                        mCriteria.add(new AttributeMatchCriterion(intProp, rule));
+                        mCriteria.add(new AudioMixMatchCriterion(intProp, rule));
                         break;
                     default:
                         throw new IllegalStateException("Unreachable code in addRuleInternal()");
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 5ad6126..5d2bac0 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -17,7 +17,7 @@
 package android.media.audiopolicy;
 
 import android.media.AudioFormat;
-import android.media.audiopolicy.AudioMixingRule.AttributeMatchCriterion;
+import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -86,9 +86,9 @@
             dest.writeInt(mix.getFormat().getEncoding());
             dest.writeInt(mix.getFormat().getChannelMask());
             // write mix rules
-            final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria();
+            final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
             dest.writeInt(criteria.size());
-            for (AttributeMatchCriterion criterion : criteria) {
+            for (AudioMixMatchCriterion criterion : criteria) {
                 criterion.writeToParcel(dest);
             }
         }
@@ -150,8 +150,8 @@
             textDump += "  channels=0x";
             textDump += Integer.toHexString(mix.getFormat().getChannelMask()).toUpperCase() +"\n";
             // write mix rules
-            final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria();
-            for (AttributeMatchCriterion criterion : criteria) {
+            final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
+            for (AudioMixMatchCriterion criterion : criteria) {
                 switch(criterion.mRule) {
                     case AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_USAGE:
                         textDump += "  exclude usage ";
@@ -171,11 +171,11 @@
                         break;
                     case AudioMixingRule.RULE_MATCH_UID:
                         textDump += "  match UID ";
-                        textDump += criterion.mIntProp.toString();
+                        textDump += criterion.mIntProp;
                         break;
                     case AudioMixingRule.RULE_EXCLUDE_UID:
                         textDump += "  exclude UID ";
-                        textDump += criterion.mIntProp.toString();
+                        textDump += criterion.mIntProp;
                         break;
                     default:
                         textDump += "invalid rule!";
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 1320e38..00083e6 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -157,35 +157,22 @@
     public static final int RECORDING_ERROR_UNKNOWN = 0;
 
     /**
-     * Error for {@link TvRecordingClient.RecordingCallback#onError(int)}: The recording client has
-     * failed to establish a connection to a recording session.
-     */
-    public static final int RECORDING_ERROR_CONNECTION_FAILED = 1;
-
-    /**
-     * Error for {@link TvRecordingClient.RecordingCallback#onError(int)}: The recording client has
-     * been disconnected from the current recording session.
-     */
-    public static final int RECORDING_ERROR_DISCONNECTED = 2;
-
-    /**
      * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
      * {@link TvRecordingClient.RecordingCallback#onError(int)}: Recording cannot proceed due to
      * insufficient storage space.
      */
-    public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 3;
+    public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1;
 
     /**
      * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
      * {@link TvRecordingClient.RecordingCallback#onError(int)}: Recording cannot proceed because
      * a required recording resource was not able to be allocated.
      */
-    public static final int RECORDING_ERROR_RESOURCE_BUSY = 4;
+    public static final int RECORDING_ERROR_RESOURCE_BUSY = 2;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_CONNECTION_FAILED,
-            RECORDING_ERROR_DISCONNECTED, RECORDING_ERROR_INSUFFICIENT_SPACE,
+    @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_INSUFFICIENT_SPACE,
             RECORDING_ERROR_RESOURCE_BUSY})
     public @interface RecordingError {}
 
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 334c84b..4ebd0fc 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1584,6 +1584,10 @@
          * new data entry in the {@link TvContract.RecordedPrograms} table that describes the newly
          * recorded program.
          *
+         * <p>The recording session must call this method in response to {@link #onStopRecording()}.
+         * The session may call it even before receiving a call to {@link #onStopRecording()} if a
+         * partially recorded program is available when there is an error.
+         *
          * @param recordedProgramUri The URI of the newly recorded program.
          */
         public void notifyRecordingStopped(final Uri recordedProgramUri) {
@@ -1604,8 +1608,14 @@
         }
 
         /**
-         * Informs the application that there is an error. It may be called at any time after this
-         * recording session is created until {@link #onRelease()} is called.
+         * Informs the application that there is an error and this recording session is no longer
+         * able to start or continue recording. It may be called at any time after the recording
+         * session is created until {@link #onRelease()} is called.
+         *
+         * <p>The application may release the current session upon receiving the error code through
+         * {@link TvRecordingClient.RecordingCallback#onError(int)}. The session may call
+         * {@link #notifyRecordingStopped(Uri)} if a partially recorded but still playable program
+         * is available, before calling this method.
          *
          * @param error The error code. Should be one of the followings.
          * <ul>
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index 72606f5..1c920f5 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -68,7 +68,7 @@
 
     /**
      * Tunes to a given channel for TV program recording. The first tune request will create a new
-     * recording session for the corresponding TV input and establish the connection between the
+     * recording session for the corresponding TV input and establish a connection between the
      * application and the session. If recording has already started in the current recording
      * session, this method throws an exception.
      *
@@ -88,7 +88,7 @@
 
     /**
      * Tunes to a given channel for TV program recording. The first tune request will create a new
-     * recording session for the corresponding TV input and establish the connection between the
+     * recording session for the corresponding TV input and establish a connection between the
      * application and the session. If recording has already started in the current recording
      * session, this method throws an exception.
      *
@@ -226,6 +226,23 @@
      */
     public abstract static class RecordingCallback {
         /**
+         * This is called when an error occurred while establishing a connection to the recording
+         * session for the corresponding TV input.
+         *
+         * @param inputId The ID of the TV input bound to the current TvRecordingClient.
+         */
+        public void onConnectionFailed(String inputId) {
+        }
+
+        /**
+         * This is called when the connection to the current recording session is lost.
+         *
+         * @param inputId The ID of the TV input bound to the current TvRecordingClient.
+         */
+        public void onDisconnected(String inputId) {
+        }
+
+        /**
          * This is called when the recording session has been tuned to the given channel and is
          * ready to start recording.
          */
@@ -249,8 +266,6 @@
          * @param error The error code. Should be one of the followings.
          * <ul>
          * <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
-         * <li>{@link TvInputManager#RECORDING_ERROR_CONNECTION_FAILED}
-         * <li>{@link TvInputManager#RECORDING_ERROR_DISCONNECTED}
          * <li>{@link TvInputManager#RECORDING_ERROR_INSUFFICIENT_SPACE}
          * <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY}
          * </ul>
@@ -305,7 +320,9 @@
                 mSession.tune(mChannelUri, mConnectionParams);
             } else {
                 mSessionCallback = null;
-                mCallback.onError(TvInputManager.RECORDING_ERROR_CONNECTION_FAILED);
+                if (mCallback != null) {
+                    mCallback.onConnectionFailed(mInputId);
+                }
             }
         }
 
@@ -331,11 +348,13 @@
                 Log.w(TAG, "onSessionReleased - session not created");
                 return;
             }
-            mSessionCallback = null;
-            mSession = null;
             mIsTuned = false;
             mIsRecordingStarted = false;
-            mCallback.onError(TvInputManager.RECORDING_ERROR_DISCONNECTED);
+            mSessionCallback = null;
+            mSession = null;
+            if (mCallback != null) {
+                mCallback.onDisconnected(mInputId);
+            }
         }
 
         @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
index ff1940a..4cba135 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
@@ -132,7 +132,7 @@
             showBreadcrumb(true);
             mToolbar.setTitle(null);
             mIgnoreNextNavigation = true;
-            mBreadcrumb.setSelection(mBreadcrumbAdapter.getCount() - 1);
+            mBreadcrumb.setSelection(mBreadcrumbAdapter.getCount() - 1, false);
         }
 
         if (DEBUG) Log.d(TAG, "Final toolbar title is: " + mToolbar.getTitle());
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 726538e..f8735b2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -101,7 +101,6 @@
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.services.FileOperationService.OpType;
 import com.android.documentsui.services.FileOperations;
-
 import com.google.common.collect.Lists;
 
 import java.lang.annotation.Retention;
@@ -194,6 +193,11 @@
 
         mRecView.setItemAnimator(new DirectoryItemAnimator(getActivity()));
 
+        // Make the RecyclerView unfocusable. This is needed in order for the focus search code in
+        // FocusManager to work correctly. Setting android:focusable=false in the layout xml doesn't
+        // work, for some reason.
+        mRecView.setFocusable(false);
+
         // TODO: Add a divider between views (which might use RecyclerView.ItemDecoration).
         if (DEBUG_ENABLE_DND) {
             setupDragAndDropOnDirectoryView(mRecView);
@@ -264,7 +268,7 @@
         mSelectionManager.addCallback(selectionListener);
 
         // Make sure this is done after the RecyclerView is set up.
-        mFocusManager = new FocusManager(mRecView, mSelectionManager);
+        mFocusManager = new FocusManager(mRecView);
 
         mModel = new Model();
         mModel.addUpdateListener(mAdapter);
@@ -1262,16 +1266,37 @@
             }
 
             if (mFocusManager.handleKey(doc, keyCode, event)) {
+                // Handle range selection adjustments. Extending the selection will adjust the
+                // bounds of the in-progress range selection. Each time an unshifted navigation
+                // event is received, the range selection is restarted.
+                if (shouldExtendSelection(event)) {
+                    if (!mSelectionManager.isRangeSelectionActive()) {
+                        // Start a range selection if one isn't active
+                        mSelectionManager.startRangeSelection(doc.getAdapterPosition());
+                    }
+                    mSelectionManager.snapRangeSelection(mFocusManager.getFocusPosition());
+                } else {
+                    mSelectionManager.endRangeSelection();
+                }
                 return true;
             }
 
             // Handle enter key events
             if (keyCode == KeyEvent.KEYCODE_ENTER) {
-                return onActivate(doc);
+                if (event.isShiftPressed()) {
+                    return onSelect(doc);
+                } else {
+                    return onActivate(doc);
+                }
             }
 
             return false;
         }
+
+        private boolean shouldExtendSelection(KeyEvent event) {
+            return Events.isNavigationKeyCode(event.getKeyCode()) &&
+                    event.isShiftPressed();
+        }
     }
 
     private final class ModelUpdateListener implements Model.UpdateListener {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
index ad010a6..93ec842 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.dirlist;
 
-import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -32,16 +32,14 @@
 
     private RecyclerView mView;
     private RecyclerView.Adapter<?> mAdapter;
-    private LinearLayoutManager mLayout;
-    private MultiSelectManager mSelectionManager;
+    private GridLayoutManager mLayout;
 
     private int mLastFocusPosition = RecyclerView.NO_POSITION;
 
-    public FocusManager(RecyclerView view, MultiSelectManager selectionManager) {
+    public FocusManager(RecyclerView view) {
         mView = view;
         mAdapter = view.getAdapter();
-        mLayout = (LinearLayoutManager) view.getLayoutManager();
-        mSelectionManager = selectionManager;
+        mLayout = (GridLayoutManager) view.getLayoutManager();
     }
 
     /**
@@ -54,19 +52,24 @@
      * @return Whether the event was handled.
      */
     public boolean handleKey(DocumentHolder doc, int keyCode, KeyEvent event) {
+        boolean extendSelection = false;
+        // Translate space/shift-space into PgDn/PgUp
+        if (keyCode == KeyEvent.KEYCODE_SPACE) {
+            if (event.isShiftPressed()) {
+                keyCode = KeyEvent.KEYCODE_PAGE_UP;
+            } else {
+                keyCode = KeyEvent.KEYCODE_PAGE_DOWN;
+            }
+        } else {
+            extendSelection = event.isShiftPressed();
+        }
+
         if (Events.isNavigationKeyCode(keyCode)) {
             // Find the target item and focus it.
             int endPos = findTargetPosition(doc.itemView, keyCode, event);
 
             if (endPos != RecyclerView.NO_POSITION) {
                 focusItem(endPos);
-                boolean extendSelection = event.isShiftPressed();
-
-                // Handle any necessary adjustments to selection.
-                if (extendSelection) {
-                    int startPos = doc.getAdapterPosition();
-                    mSelectionManager.selectRange(startPos, endPos);
-                }
             }
             // Swallow all navigation keystrokes. Otherwise they go to the app's global
             // key-handler, which will route them back to the DF and cause focus to be reset.
@@ -97,6 +100,13 @@
     }
 
     /**
+     * @return The adapter position of the last focused item.
+     */
+    public int getFocusPosition() {
+        return mLastFocusPosition;
+    }
+
+    /**
      * Finds the destination position where the focus should land for a given navigation event.
      *
      * @param view The view that received the event.
@@ -124,12 +134,27 @@
             case KeyEvent.KEYCODE_DPAD_DOWN:
                 searchDir = View.FOCUS_DOWN;
                 break;
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-                searchDir = View.FOCUS_LEFT;
-                break;
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                searchDir = View.FOCUS_RIGHT;
-                break;
+        }
+
+        if (inGridMode()) {
+            int currentPosition = mView.getChildAdapterPosition(view);
+            // Left and right arrow keys only work in grid mode.
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                    if (currentPosition > 0) {
+                        // Stop backward focus search at the first item, otherwise focus will wrap
+                        // around to the last visible item.
+                        searchDir = View.FOCUS_BACKWARD;
+                    }
+                    break;
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                    if (currentPosition < mAdapter.getItemCount() - 1) {
+                        // Stop forward focus search at the last item, otherwise focus will wrap
+                        // around to the first visible item.
+                        searchDir = View.FOCUS_FORWARD;
+                    }
+                    break;
+            }
         }
 
         if (searchDir != -1) {
@@ -228,4 +253,11 @@
                     });
         }
     }
+
+    /**
+     * @return Whether the layout manager is currently in a grid-configuration.
+     */
+    private boolean inGridMode() {
+        return mLayout.getSpanCount() > 1;
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index d60825b..c8b6f85 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -370,39 +370,41 @@
     }
 
     /**
-     * Handle a range selection event.
-     * <li> If the MSM is currently in single-select mode, only the last item in the range will
-     * actually be selected.
-     * <li>If a range selection is not already active, one will be started, and the given range of
-     * items will be selected.  The given startPos becomes the anchor for the range selection.
-     * <li>If a range selection is already active, the anchor is not changed. The range is extended
-     * from its current anchor to endPos.
+     * Starts a range selection. If a range selection is already active, this will start a new range
+     * selection (which will reset the range anchor).
      *
-     * @param startPos
-     * @param endPos
+     * @param pos The anchor position for the selection range.
      */
-    public void selectRange(int startPos, int endPos) {
-        // In single-select mode, just select the last item in the range.
-        if (mSingleSelect) {
-            attemptSelect(mAdapter.getModelId(endPos));
-            return;
-        }
+    void startRangeSelection(int pos) {
+      attemptSelect(mAdapter.getModelId(pos));
+      setSelectionRangeBegin(pos);
+    }
 
-        // In regular (i.e. multi-select) mode
-        if (!isRangeSelectionActive()) {
-            // If a range selection isn't active, start one up
-            attemptSelect(mAdapter.getModelId(startPos));
-            setSelectionRangeBegin(startPos);
-        }
-        // Extend the range selection
-        mRanger.snapSelection(endPos);
+    /**
+     * Sets the end point for the current range selection, started by a call to
+     * {@link #startRangeSelection(int)}. This function should only be called when a range selection
+     * is active (see {@link #isRangeSelectionActive()}. Items in the range [anchor, end] will be
+     * selected.
+     *
+     * @param pos The new end position for the selection range.
+     */
+    void snapRangeSelection(int pos) {
+        checkNotNull(mRanger);
+        mRanger.snapSelection(pos);
         notifySelectionChanged();
     }
 
     /**
+     * Stops an in-progress range selection.
+     */
+    void endRangeSelection() {
+        mRanger = null;
+    }
+
+    /**
      * @return Whether or not there is a current range selection active.
      */
-    private boolean isRangeSelectionActive() {
+    boolean isRangeSelectionActive() {
         return mRanger != null;
     }
 
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
index d95fb49..9447d9c1 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
@@ -189,6 +189,54 @@
         assertSelection(items.get(20));
     }
 
+    public void testRangeSelection() {
+        mManager.startRangeSelection(15);
+        mManager.snapRangeSelection(19);
+        assertRangeSelection(15, 19);
+    }
+
+    public void testRangeSelection_snapExpand() {
+        mManager.startRangeSelection(15);
+        mManager.snapRangeSelection(19);
+        mManager.snapRangeSelection(27);
+        assertRangeSelection(15, 27);
+    }
+
+    public void testRangeSelection_snapContract() {
+        mManager.startRangeSelection(15);
+        mManager.snapRangeSelection(27);
+        mManager.snapRangeSelection(19);
+        assertRangeSelection(15, 19);
+    }
+
+    public void testRangeSelection_snapInvert() {
+        mManager.startRangeSelection(15);
+        mManager.snapRangeSelection(27);
+        mManager.snapRangeSelection(3);
+        assertRangeSelection(3, 15);
+    }
+
+    public void testRangeSelection_multiple() {
+        mManager.startRangeSelection(15);
+        mManager.snapRangeSelection(27);
+        mManager.endRangeSelection();
+        mManager.startRangeSelection(42);
+        mManager.snapRangeSelection(57);
+        assertSelectionSize(29);
+        assertRangeSelected(15, 27);
+        assertRangeSelected(42, 57);
+
+    }
+
+    public void testRangeSelection_singleSelect() {
+        mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE, null);
+        mManager.addCallback(mCallback);
+        mManager.startRangeSelection(11);
+        mManager.snapRangeSelection(19);
+        assertSelectionSize(1);
+        assertSelection(items.get(19));
+    }
+
     public void testProvisionalSelection() {
         Selection s = mManager.getSelection();
         assertSelection();
diff --git a/packages/MtpDocumentsProvider/res/values/strings.xml b/packages/MtpDocumentsProvider/res/values/strings.xml
index 43a420c..f3a3fcf 100644
--- a/packages/MtpDocumentsProvider/res/values/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values/strings.xml
@@ -25,4 +25,8 @@
     <string name="accessing_notification_title">Accessing files from <xliff:g id="device_model" example="Nexus 9">%1$s</xliff:g></string>
     <!-- Description of notification showing Files app is accessing files in a MTP device. [CHAR LIMIT=60]-->
     <string name="accessing_notification_description">Don\'t disconnect the device</string>
+    <!-- Error message shown in Files app when the connected MTP device is busy. [CHAR LIMIT=150]-->
+    <string name="error_busy_device">The other device is busy. You can\'t transfer files until it\'s available.</string>
+    <!-- Error message shown in Files app when the connected MTP device may be locked. [CHAR LIMIT=150]-->
+    <string name="error_locked_device">No files found. The other device may be locked. If so, unlock it and try again.</string>
 </resources>
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index c456be9..5a11327 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -37,6 +37,7 @@
 import android.provider.DocumentsContract.Root;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
 import java.io.FileNotFoundException;
 import java.util.Objects;
@@ -244,15 +245,16 @@
     }
 
     /**
-     * Returns identifier of single storage if given document points device and it has only one
-     * storage. Otherwise null.
+     * Returns document IDs of storages under the given device document.
      *
-     * @param documentId Document ID that may point a device.
-     * @return Identifier for single storage or null.
+     * @param documentId Document ID that points a device.
+     * @return Storage document IDs.
      * @throws FileNotFoundException The given document ID is not registered in database.
      */
-    @Nullable Identifier getSingleStorageIdentifier(String documentId)
+    String[] getStorageDocumentIds(String documentId)
             throws FileNotFoundException {
+        Preconditions.checkArgument(createIdentifier(documentId).mDocumentType ==
+                DOCUMENT_TYPE_DEVICE);
         // Check if the parent document is device that has single storage.
         try (final Cursor cursor = mDatabase.query(
                 TABLE_DOCUMENTS,
@@ -267,12 +269,11 @@
                 null,
                 null,
                 null)) {
-            if (cursor.getCount() == 1) {
-                cursor.moveToNext();
-                return createIdentifier(cursor.getString(0));
-            } else {
-                return null;
+            final String[] ids = new String[cursor.getCount()];
+            for (int i = 0; cursor.moveToNext(); i++) {
+                ids[i] = cursor.getString(0);
             }
+            return ids;
         }
     }
 
@@ -342,6 +343,26 @@
         }
     }
 
+    String getDeviceDocumentId(int deviceId) throws FileNotFoundException {
+        try (final Cursor cursor = mDatabase.query(
+                TABLE_DOCUMENTS,
+                strings(Document.COLUMN_DOCUMENT_ID),
+                COLUMN_DEVICE_ID + " = ? AND " + COLUMN_DOCUMENT_TYPE + " = ? AND " +
+                COLUMN_ROW_STATE + " != ?",
+                strings(deviceId, DOCUMENT_TYPE_DEVICE, ROW_STATE_DISCONNECTED),
+                null,
+                null,
+                null,
+                "1")) {
+            if (cursor.getCount() > 0) {
+                cursor.moveToNext();
+                return cursor.getString(0);
+            } else {
+                throw new FileNotFoundException("The device ID not found: " + deviceId);
+            }
+        }
+    }
+
     /**
      * Adds new document under the parent.
      * The method does not affect invalidated and pending documents because we know the document is
@@ -557,13 +578,9 @@
 
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            if (oldVersion == 1) {
-                db.execSQL("DROP TABLE " + TABLE_DOCUMENTS);
-                db.execSQL("DROP TABLE " + TABLE_ROOT_EXTRA);
-                onCreate(db);
-                return;
-            }
-            throw new UnsupportedOperationException();
+            db.execSQL("DROP TABLE " + TABLE_DOCUMENTS);
+            db.execSQL("DROP TABLE " + TABLE_ROOT_EXTRA);
+            onCreate(db);
         }
     }
 
@@ -680,7 +697,12 @@
         if (formatCodeMimeType != null) {
             return formatCodeMimeType;
         }
-        return MediaFile.getMimeTypeForFile(info.getName());
+        final String mediaFileMimeType = MediaFile.getMimeTypeForFile(info.getName());
+        if (mediaFileMimeType != null) {
+            return mediaFileMimeType;
+        }
+        // We don't know the file type.
+        return "application/octet-stream";
     }
 
     static String[] strings(Object... args) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
index cb076af..ab356ce 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
@@ -30,7 +30,7 @@
  * Class containing MtpDatabase constants.
  */
 class MtpDatabaseConstants {
-    static final int DATABASE_VERSION = 2;
+    static final int DATABASE_VERSION = 3;
     static final String DATABASE_NAME = "database";
 
     static final int FLAG_DATABASE_IN_MEMORY = 1;
@@ -125,7 +125,7 @@
             COLUMN_PARENT_DOCUMENT_ID + " INTEGER," +
             COLUMN_ROW_STATE + " INTEGER NOT NULL," +
             COLUMN_DOCUMENT_TYPE + " INTEGER NOT NULL," +
-            Document.COLUMN_MIME_TYPE + " TEXT," +
+            Document.COLUMN_MIME_TYPE + " TEXT NOT NULL," +
             Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," +
             Document.COLUMN_SUMMARY + " TEXT," +
             Document.COLUMN_LAST_MODIFIED + " INTEGER," +
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 0338454..a512509 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -20,10 +20,12 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.database.Cursor;
+import android.database.MatrixCursor;
 import android.graphics.Point;
 import android.media.MediaFile;
 import android.mtp.MtpConstants;
 import android.mtp.MtpObjectInfo;
+import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
 import android.os.storage.StorageManager;
@@ -35,6 +37,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.mtp.exceptions.BusyDeviceException;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -163,17 +166,25 @@
         try {
             openDevice(parentIdentifier.mDeviceId);
             if (parentIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) {
-                final Identifier singleStorageIdentifier =
-                        mDatabase.getSingleStorageIdentifier(parentDocumentId);
-                if (singleStorageIdentifier == null) {
+                final String[] storageDocIds = mDatabase.getStorageDocumentIds(parentDocumentId);
+                if (storageDocIds.length == 0) {
+                    // Remote device does not provide storages. Maybe it is locked.
+                    return createErrorCursor(projection, R.string.error_locked_device);
+                } else if (storageDocIds.length > 1) {
                     // Returns storage list from database.
                     return mDatabase.queryChildDocuments(projection, parentDocumentId);
                 }
-                parentIdentifier = singleStorageIdentifier;
+
+                // Exact one storage is found. Skip storage and returns object in the single
+                // storage.
+                parentIdentifier = mDatabase.createIdentifier(storageDocIds[0]);
             }
+
             // Returns object list from document loader.
             return getDocumentLoader(parentIdentifier).queryChildDocuments(
                     projection, parentIdentifier);
+        } catch (BusyDeviceException exception) {
+            return createErrorCursor(projection, R.string.error_busy_device);
         } catch (IOException exception) {
             Log.e(MtpDocumentsProvider.TAG, "queryChildDocuments", exception);
             throw new FileNotFoundException(exception.getMessage());
@@ -350,6 +361,16 @@
     }
 
     /**
+     * Obtains document ID for the given device ID.
+     * @param deviceId
+     * @return document ID
+     * @throws FileNotFoundException device ID has not been build.
+     */
+    public String getDeviceDocumentId(int deviceId) throws FileNotFoundException {
+        return mDatabase.getDeviceDocumentId(deviceId);
+    }
+
+    /**
      * Resumes root scanner to handle the update of device list.
      */
     void resumeRootScanner() {
@@ -442,6 +463,21 @@
         }
     }
 
+    /**
+     * Creates empty cursor with specific error message.
+     *
+     * @param projection Column names.
+     * @param stringResId String resource ID of error message.
+     * @return Empty cursor with error message.
+     */
+    private Cursor createErrorCursor(String[] projection, int stringResId) {
+        final Bundle bundle = new Bundle();
+        bundle.putString(DocumentsContract.EXTRA_ERROR, mResources.getString(stringResId));
+        final Cursor cursor = new MatrixCursor(projection);
+        cursor.setExtras(bundle);
+        return cursor;
+    }
+
     private static class DeviceToolkit {
         public final PipeManager mPipeManager;
         public final DocumentLoader mDocumentLoader;
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 5519efd..0527790 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -33,6 +33,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.mtp.exceptions.BusyDeviceException;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -101,7 +102,8 @@
         }
 
         if (!device.open(connection)) {
-            throw new IOException("Failed to open a MTP device.");
+            // We cannot open connection when another application use the device.
+            throw new BusyDeviceException();
         }
 
         // Handle devices that fail to obtain storages just after opening a MTP session.
@@ -134,7 +136,7 @@
                 try {
                     roots = getRoots(device.getDeviceId());
                 } catch (IOException exp) {
-                    Log.e(MtpDocumentsProvider.TAG, exp.getMessage());
+                    Log.e(MtpDocumentsProvider.TAG, "Failed to open device", exp);
                     // If we failed to fetch roots for the device, we still returns device model
                     // with an empty set of roots so that the device is shown DocumentsUI as long as
                     // the device is physically connected.
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java b/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
index c7206a7..84745b2 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
@@ -17,10 +17,15 @@
 package com.android.mtp;
 
 import android.app.Activity;
-import android.content.ComponentName;
 import android.content.Intent;
+import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
+import android.net.Uri;
 import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.util.Log;
+
+import java.io.IOException;
 
 /**
  * Invisible activity to receive intents.
@@ -33,14 +38,21 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(getIntent().getAction())) {
-            // TODO: To obtain data URI for the attached device, we need to wait until RootScanner
-            // found the device and add it to database. Set correct root URI, and use ACTION_BROWSE
-            // to launch Documents UI.
-            final Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.addCategory(Intent.CATEGORY_LAUNCHER);
-            intent.setComponent(new ComponentName(
-                    "com.android.documentsui", "com.android.documentsui.LauncherActivity"));
-            this.startActivity(intent);
+            final UsbDevice device = getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            try {
+                final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
+                provider.openDevice(device.getDeviceId());
+                final String deviceRootId = provider.getDeviceDocumentId(device.getDeviceId());
+                final Uri uri = DocumentsContract.buildRootUri(
+                        MtpDocumentsProvider.AUTHORITY, deviceRootId);
+
+                final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
+                intent.setData(uri);
+                intent.addCategory(Intent.CATEGORY_DEFAULT);
+                this.startActivity(intent);
+            } catch (IOException exception) {
+                Log.e(MtpDocumentsProvider.TAG, "Failed to open device", exception);
+            }
         }
         finish();
     }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java b/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
new file mode 100644
index 0000000..55f55b0
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp.exceptions;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown when the device is busy and the requested operation cannon be completed.
+ */
+public class BusyDeviceException extends IOException {
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 5b0f557..01fcc55 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -29,6 +29,8 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import com.android.mtp.exceptions.BusyDeviceException;
+
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.Arrays;
@@ -526,6 +528,52 @@
         }
     }
 
+    public void testBusyDevice() throws Exception {
+        mMtpManager = new TestMtpManager(getContext()) {
+            @Override
+            void openDevice(int deviceId) throws IOException {
+                throw new BusyDeviceException();
+            }
+        };
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        mMtpManager.addValidDevice(new MtpDeviceRecord(
+                0, "Device A", false /* unopened */, new MtpRoot[0], null, null));
+
+        mProvider.resumeRootScanner();
+        mResolver.waitForNotification(ROOTS_URI, 1);
+
+        try (final Cursor cursor = mProvider.queryRoots(null)) {
+            assertEquals(1, cursor.getCount());
+        }
+
+        try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {
+            assertEquals(0, cursor.getCount());
+            assertEquals(
+                    "error_busy_device",
+                    cursor.getExtras().getString(DocumentsContract.EXTRA_ERROR));
+        }
+    }
+
+    public void testLockedDevice() throws Exception {
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        mMtpManager.addValidDevice(new MtpDeviceRecord(
+                0, "Device A", false /* unopened */, new MtpRoot[0], null, null));
+
+        mProvider.resumeRootScanner();
+        mResolver.waitForNotification(ROOTS_URI, 1);
+
+        try (final Cursor cursor = mProvider.queryRoots(null)) {
+            assertEquals(1, cursor.getCount());
+        }
+
+        try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {
+            assertEquals(0, cursor.getCount());
+            assertEquals(
+                    "error_locked_device",
+                    cursor.getExtras().getString(DocumentsContract.EXTRA_ERROR));
+        }
+    }
+
     private void setupProvider(int flag) {
         mDatabase = new MtpDatabase(getContext(), flag);
         mProvider = new MtpDocumentsProvider();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
index b23038b..8676b5a 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
@@ -24,6 +24,10 @@
         switch (id) {
             case R.string.root_name:
                 return "%1$s %2$s";
+            case R.string.error_busy_device:
+                return "error_busy_device";
+            case R.string.error_locked_device:
+                return "error_locked_device";
         }
         throw new NotFoundException();
     }
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 8c555a6..bad7e20 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -88,8 +88,8 @@
  * <p>
  * The workflow is:
  * <ol>
- * <li>When {@code dumpstate} starts, it sends a {@code BUGREPORT_STARTED} with its pid and the
- * estimated total effort.
+ * <li>When {@code dumpstate} starts, it sends a {@code BUGREPORT_STARTED} with a sequential id,
+ * its pid, and the estimated total effort.
  * <li>{@link BugreportReceiver} receives the intent and delegates it to this service.
  * <li>Upon start, this service:
  * <ol>
@@ -132,6 +132,7 @@
 
     static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
     static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
+    static final String EXTRA_ID = "android.intent.extra.ID";
     static final String EXTRA_PID = "android.intent.extra.PID";
     static final String EXTRA_MAX = "android.intent.extra.MAX";
     static final String EXTRA_NAME = "android.intent.extra.NAME";
@@ -177,7 +178,7 @@
      */
     private static final String SCREENSHOT_DIR = "bugreports";
 
-    /** Managed dumpstate processes (keyed by pid) */
+    /** Managed dumpstate processes (keyed by id) */
     private final SparseArray<BugreportInfo> mProcesses = new SparseArray<>();
 
     private Context mContext;
@@ -222,7 +223,7 @@
         }
 
         // If service is killed it cannot be recreated because it would not know which
-        // dumpstate PIDs it would have to watch.
+        // dumpstate IDs it would have to watch.
         return START_NOT_STICKY;
     }
 
@@ -299,38 +300,41 @@
             }
             final String action = intent.getAction();
             final int pid = intent.getIntExtra(EXTRA_PID, 0);
+            // TODO: temporarily using pid as id until test cases and dumpstate are changed.
+            final int id = intent.getIntExtra(EXTRA_ID, pid);
             final int max = intent.getIntExtra(EXTRA_MAX, -1);
             final String name = intent.getStringExtra(EXTRA_NAME);
 
-            if (DEBUG) Log.v(TAG, "action: " + action + ", name: " + name + ", pid: " + pid
-                    + ", max: "+ max);
+            if (DEBUG)
+                Log.v(TAG, "action: " + action + ", name: " + name + ", id: " + id + ", pid: "
+                        + pid + ", max: " + max);
             switch (action) {
                 case INTENT_BUGREPORT_STARTED:
-                    if (!startProgress(name, pid, max)) {
+                    if (!startProgress(name, id, pid, max)) {
                         stopSelfWhenDone();
                         return;
                     }
                     poll();
                     break;
                 case INTENT_BUGREPORT_FINISHED:
-                    if (pid == 0) {
+                    if (id == 0) {
                         // Shouldn't happen, unless BUGREPORT_FINISHED is received from a legacy,
                         // out-of-sync dumpstate process.
-                        Log.w(TAG, "Missing " + EXTRA_PID + " on intent " + intent);
+                        Log.w(TAG, "Missing " + EXTRA_ID + " on intent " + intent);
                     }
-                    onBugreportFinished(pid, intent);
+                    onBugreportFinished(id, intent);
                     break;
                 case INTENT_BUGREPORT_INFO_LAUNCH:
-                    launchBugreportInfoDialog(pid);
+                    launchBugreportInfoDialog(id);
                     break;
                 case INTENT_BUGREPORT_SCREENSHOT:
-                    takeScreenshot(pid, true);
+                    takeScreenshot(id, true);
                     break;
                 case INTENT_BUGREPORT_SHARE:
-                    shareBugreport(pid, (BugreportInfo) intent.getParcelableExtra(EXTRA_INFO));
+                    shareBugreport(id, (BugreportInfo) intent.getParcelableExtra(EXTRA_INFO));
                     break;
                 case INTENT_BUGREPORT_CANCEL:
-                    cancel(pid);
+                    cancel(id);
                     break;
                 default:
                     Log.w(TAG, "Unsupported intent: " + action);
@@ -367,10 +371,10 @@
         }
     }
 
-    private BugreportInfo getInfo(int pid) {
-        final BugreportInfo info = mProcesses.get(pid);
+    private BugreportInfo getInfo(int id) {
+        final BugreportInfo info = mProcesses.get(id);
         if (info == null) {
-            Log.w(TAG, "Not monitoring process with PID " + pid);
+            Log.w(TAG, "Not monitoring process with ID " + id);
         }
         return info;
     }
@@ -381,10 +385,14 @@
      *
      * @return whether it succeeded or not.
      */
-    private boolean startProgress(String name, int pid, int max) {
+    private boolean startProgress(String name, int id, int pid, int max) {
         if (name == null) {
             Log.w(TAG, "Missing " + EXTRA_NAME + " on start intent");
         }
+        if (id == -1) {
+            Log.e(TAG, "Missing " + EXTRA_ID + " on start intent");
+            return false;
+        }
         if (pid == -1) {
             Log.e(TAG, "Missing " + EXTRA_PID + " on start intent");
             return false;
@@ -394,14 +402,14 @@
             return false;
         }
 
-        final BugreportInfo info = new BugreportInfo(mContext, pid, name, max);
-        if (mProcesses.indexOfKey(pid) >= 0) {
-            Log.w(TAG, "PID " + pid + " already watched");
+        final BugreportInfo info = new BugreportInfo(mContext, id, pid, name, max);
+        if (mProcesses.indexOfKey(id) >= 0) {
+            Log.w(TAG, "ID " + id + " already watched");
         } else {
-            mProcesses.put(info.pid, info);
+            mProcesses.put(info.id, info);
         }
         // Take initial screenshot.
-        takeScreenshot(pid, false);
+        takeScreenshot(id, false);
         updateProgress(info);
         return true;
     }
@@ -423,22 +431,22 @@
                 com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
         final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
         infoIntent.setAction(INTENT_BUGREPORT_INFO_LAUNCH);
-        infoIntent.putExtra(EXTRA_PID, info.pid);
+        infoIntent.putExtra(EXTRA_ID, info.id);
         final Action infoAction = new Action.Builder(null,
                 mContext.getString(R.string.bugreport_info_action),
-                PendingIntent.getService(mContext, info.pid, infoIntent,
+                PendingIntent.getService(mContext, info.id, infoIntent,
                         PendingIntent.FLAG_UPDATE_CURRENT)).build();
         final Intent screenshotIntent = new Intent(mContext, BugreportProgressService.class);
         screenshotIntent.setAction(INTENT_BUGREPORT_SCREENSHOT);
-        screenshotIntent.putExtra(EXTRA_PID, info.pid);
+        screenshotIntent.putExtra(EXTRA_ID, info.id);
         PendingIntent screenshotPendingIntent = mTakingScreenshot ? null : PendingIntent
-                .getService(mContext, info.pid, screenshotIntent,
+                .getService(mContext, info.id, screenshotIntent,
                         PendingIntent.FLAG_UPDATE_CURRENT);
         final Action screenshotAction = new Action.Builder(null,
                 mContext.getString(R.string.bugreport_screenshot_action),
                 screenshotPendingIntent).build();
 
-        final String title = mContext.getString(R.string.bugreport_in_progress_title, info.pid);
+        final String title = mContext.getString(R.string.bugreport_in_progress_title, info.id);
 
         final String name =
                 info.name != null ? info.name : mContext.getString(R.string.bugreport_unnamed);
@@ -464,8 +472,8 @@
                     + info + ")");
             return;
         }
-        Log.v(TAG, "Sending 'Progress' notification for pid " + info.pid + ": " + percentText);
-        NotificationManager.from(mContext).notify(TAG, info.pid, notification);
+        Log.v(TAG, "Sending 'Progress' notification for id " + info.id + ": " + percentText);
+        NotificationManager.from(mContext).notify(TAG, info.id, notification);
     }
 
     /**
@@ -474,38 +482,38 @@
     private static PendingIntent newCancelIntent(Context context, BugreportInfo info) {
         final Intent intent = new Intent(INTENT_BUGREPORT_CANCEL);
         intent.setClass(context, BugreportProgressService.class);
-        intent.putExtra(EXTRA_PID, info.pid);
-        return PendingIntent.getService(context, info.pid, intent,
+        intent.putExtra(EXTRA_ID, info.id);
+        return PendingIntent.getService(context, info.id, intent,
                 PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
     /**
      * Finalizes the progress on a given bugreport and cancel its notification.
      */
-    private void stopProgress(int pid) {
-        if (mProcesses.indexOfKey(pid) < 0) {
-            Log.w(TAG, "PID not watched: " + pid);
+    private void stopProgress(int id) {
+        if (mProcesses.indexOfKey(id) < 0) {
+            Log.w(TAG, "ID not watched: " + id);
         } else {
-            Log.d(TAG, "Removing PID " + pid);
-            mProcesses.remove(pid);
+            Log.d(TAG, "Removing ID " + id);
+            mProcesses.remove(id);
         }
         stopSelfWhenDone();
-        Log.v(TAG, "stopProgress(" + pid + "): cancel notification");
-        NotificationManager.from(mContext).cancel(TAG, pid);
+        Log.v(TAG, "stopProgress(" + id + "): cancel notification");
+        NotificationManager.from(mContext).cancel(TAG, id);
     }
 
     /**
      * Cancels a bugreport upon user's request.
      */
-    private void cancel(int pid) {
-        Log.v(TAG, "cancel: pid=" + pid);
-        final BugreportInfo info = getInfo(pid);
+    private void cancel(int id) {
+        Log.v(TAG, "cancel: ID=" + id);
+        final BugreportInfo info = getInfo(id);
         if (info != null && !info.finished) {
-            Log.i(TAG, "Cancelling bugreport service (pid=" + pid + ") on user's request");
+            Log.i(TAG, "Cancelling bugreport service (ID=" + id + ") on user's request");
             setSystemProperty(CTL_STOP, BUGREPORT_SERVICE);
             deleteScreenshots(info);
         }
-        stopProgress(pid);
+        stopProgress(id);
     }
 
     /**
@@ -522,14 +530,15 @@
         for (int i = 0; i < total; i++) {
             final BugreportInfo info = mProcesses.valueAt(i);
             if (info == null) {
-                Log.wtf(TAG, "pollProgress(): null info at index " + i + "(pid = "
+                Log.wtf(TAG, "pollProgress(): null info at index " + i + "(ID = "
                         + mProcesses.keyAt(i) + ")");
                 continue;
             }
 
             final int pid = info.pid;
+            final int id = info.id;
             if (info.finished) {
-                if (DEBUG) Log.v(TAG, "Skipping finished process " + pid);
+                if (DEBUG) Log.v(TAG, "Skipping finished process " + pid + "(id: " + id + ")");
                 continue;
             }
             activeProcesses++;
@@ -544,13 +553,13 @@
 
             if (progressChanged || maxChanged) {
                 if (progressChanged) {
-                    if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + " from "
-                            + info.progress + " to " + progress);
+                    if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id
+                            + ") from " + info.progress + " to " + progress);
                     info.progress = progress;
                 }
                 if (maxChanged) {
-                    Log.i(TAG, "Updating max progress for PID " + pid + " from " + info.max
-                            + " to " + max);
+                    Log.i(TAG, "Updating max progress for PID " + pid + "(id: " + id
+                            + ") from " + info.max + " to " + max);
                     info.max = max;
                 }
                 info.lastUpdate = System.currentTimeMillis();
@@ -558,9 +567,9 @@
             } else {
                 long inactiveTime = System.currentTimeMillis() - info.lastUpdate;
                 if (inactiveTime >= INACTIVITY_TIMEOUT) {
-                    Log.w(TAG, "No progress update for process " + pid + " since "
+                    Log.w(TAG, "No progress update for PID " + pid + " since "
                             + info.getFormattedLastUpdate());
-                    stopProgress(info.pid);
+                    stopProgress(info.id);
                 }
             }
         }
@@ -572,19 +581,16 @@
      * Fetches a {@link BugreportInfo} for a given process and launches a dialog where the user can
      * change its values.
      */
-    private void launchBugreportInfoDialog(int pid) {
+    private void launchBugreportInfoDialog(int id) {
         // Copy values so it doesn't lock mProcesses while UI is being updated
         final String name, title, description;
-        final BugreportInfo info = getInfo(pid);
+        final BugreportInfo info = getInfo(id);
         if (info == null) {
             return;
         }
-        name = info.name;
-        title = info.title;
-        description = info.description;
 
         collapseNotificationBar();
-        mInfoDialog.initialize(mContext, pid, name, title, description);
+        mInfoDialog.initialize(mContext, info);
     }
 
     /**
@@ -597,7 +603,7 @@
      * Typical usage is delaying when taken from the notification action, and taking it right away
      * upon receiving a {@link #INTENT_BUGREPORT_STARTED}.
      */
-    private void takeScreenshot(int pid, boolean delayed) {
+    private void takeScreenshot(int id, boolean delayed) {
         setTakingScreenshot(true);
         if (delayed) {
             collapseNotificationBar();
@@ -608,28 +614,28 @@
             // Show a toast just once, otherwise it might be captured in the screenshot.
             Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
 
-            takeScreenshot(pid, SCREENSHOT_DELAY_SECONDS);
+            takeScreenshot(id, SCREENSHOT_DELAY_SECONDS);
         } else {
-            takeScreenshot(pid, 0);
+            takeScreenshot(id, 0);
         }
     }
 
     /**
      * Takes a screenshot after {@code delay} seconds.
      */
-    private void takeScreenshot(int pid, int delay) {
+    private void takeScreenshot(int id, int delay) {
         if (delay > 0) {
-            Log.d(TAG, "Taking screenshot for " + pid + " in " + delay + " seconds");
+            Log.d(TAG, "Taking screenshot for " + id + " in " + delay + " seconds");
             final Message msg = mMainHandler.obtainMessage();
             msg.what = MSG_DELAYED_SCREENSHOT;
-            msg.arg1 = pid;
+            msg.arg1 = id;
             msg.arg2 = delay - 1;
             mMainHandler.sendMessageDelayed(msg, DateUtils.SECOND_IN_MILLIS);
             return;
         }
 
         // It's time to take the screenshot: let the proper thread handle it
-        final BugreportInfo info = getInfo(pid);
+        final BugreportInfo info = getInfo(id);
         if (info == null) {
             return;
         }
@@ -638,7 +644,7 @@
 
         final Message requestMsg = new Message();
         requestMsg.what = MSG_SCREENSHOT_REQUEST;
-        requestMsg.arg1 = pid;
+        requestMsg.arg1 = id;
         requestMsg.obj = screenshotPath;
         mScreenshotHandler.sendMessage(requestMsg);
     }
@@ -715,30 +721,30 @@
      */
     private void stopSelfWhenDone() {
         if (mProcesses.size() > 0) {
-            if (DEBUG) Log.v(TAG, "Staying alive, waiting for pids " + mProcesses);
+            if (DEBUG) Log.d(TAG, "Staying alive, waiting for IDs " + mProcesses);
             return;
         }
-        Log.v(TAG, "No more pids to handle, shutting down");
+        Log.v(TAG, "No more processes to handle, shutting down");
         stopSelf();
     }
 
     /**
      * Handles the BUGREPORT_FINISHED intent sent by {@code dumpstate}.
      */
-    private void onBugreportFinished(int pid, Intent intent) {
+    private void onBugreportFinished(int id, Intent intent) {
         final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
         if (bugreportFile == null) {
             // Should never happen, dumpstate always set the file.
             Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent);
             return;
         }
-        mInfoDialog.onBugreportFinished(pid);
-        BugreportInfo info = getInfo(pid);
+        mInfoDialog.onBugreportFinished(id);
+        BugreportInfo info = getInfo(id);
         if (info == null) {
             // Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED first.
-            Log.v(TAG, "Creating info for untracked pid " + pid);
-            info = new BugreportInfo(mContext, pid);
-            mProcesses.put(pid, info);
+            Log.v(TAG, "Creating info for untracked ID " + id);
+            info = new BugreportInfo(mContext, id);
+            mProcesses.put(id, info);
         }
         info.renameScreenshots(mScreenshotsDir);
         info.bugreportFile = bugreportFile;
@@ -765,7 +771,7 @@
         if (!info.bugreportFile.exists() || !info.bugreportFile.canRead()) {
             Log.e(TAG, "Could not read bugreport file " + info.bugreportFile);
             Toast.makeText(context, R.string.bugreport_unreadable_text, Toast.LENGTH_LONG).show();
-            stopProgress(info.pid);
+            stopProgress(info.id);
             return;
         }
 
@@ -837,12 +843,12 @@
      * Shares the bugreport upon user's request by issuing a {@link Intent#ACTION_SEND_MULTIPLE}
      * intent, but issuing a warning dialog the first time.
      */
-    private void shareBugreport(int pid, BugreportInfo sharedInfo) {
-        BugreportInfo info = getInfo(pid);
+    private void shareBugreport(int id, BugreportInfo sharedInfo) {
+        BugreportInfo info = getInfo(id);
         if (info == null) {
             // Service was terminated but notification persisted
             info = sharedInfo;
-            Log.d(TAG, "shareBugreport(): no info for PID " + pid + " on managed processes ("
+            Log.d(TAG, "shareBugreport(): no info for ID " + id + " on managed processes ("
                     + mProcesses + "), using info from intent instead (" + info + ")");
         }
 
@@ -863,7 +869,7 @@
         mContext.startActivity(notifIntent);
 
         // ... and stop watching this process.
-        stopProgress(pid);
+        stopProgress(id);
     }
 
     /**
@@ -877,16 +883,16 @@
         final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
         shareIntent.setClass(context, BugreportProgressService.class);
         shareIntent.setAction(INTENT_BUGREPORT_SHARE);
-        shareIntent.putExtra(EXTRA_PID, info.pid);
+        shareIntent.putExtra(EXTRA_ID, info.id);
         shareIntent.putExtra(EXTRA_INFO, info);
 
-        final String title = context.getString(R.string.bugreport_finished_title, info.pid);
+        final String title = context.getString(R.string.bugreport_finished_title, info.id);
         final Notification.Builder builder = new Notification.Builder(context)
                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(context.getString(R.string.bugreport_finished_text))
-                .setContentIntent(PendingIntent.getService(context, info.pid, shareIntent,
+                .setContentIntent(PendingIntent.getService(context, info.id, shareIntent,
                         PendingIntent.FLAG_UPDATE_CURRENT))
                 .setDeleteIntent(newCancelIntent(context, info))
                 .setLocalOnly(true)
@@ -897,8 +903,8 @@
             builder.setContentInfo(info.name);
         }
 
-        Log.v(TAG, "Sending 'Share' notification for pid " + info.pid + ": " + title);
-        NotificationManager.from(context).notify(TAG, info.pid, builder.build());
+        Log.v(TAG, "Sending 'Share' notification for ID " + info.id + ": " + title);
+        NotificationManager.from(context).notify(TAG, info.id, builder.build());
     }
 
     /**
@@ -906,7 +912,7 @@
      * finishes - at this point there is nothing to be done other than waiting, hence it has no
      * pending action.
      */
-    private static void sendBugreportBeingUpdatedNotification(Context context, int pid) {
+    private static void sendBugreportBeingUpdatedNotification(Context context, int id) {
         final String title = context.getString(R.string.bugreport_updating_title);
         final Notification.Builder builder = new Notification.Builder(context)
                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
@@ -916,8 +922,8 @@
                 .setLocalOnly(true)
                 .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
-        Log.v(TAG, "Sending 'Updating zip' notification for pid " + pid + ": " + title);
-        NotificationManager.from(context).notify(TAG, pid, builder.build());
+        Log.v(TAG, "Sending 'Updating zip' notification for ID " + id + ": " + title);
+        NotificationManager.from(context).notify(TAG, id, builder.build());
     }
 
     /**
@@ -985,7 +991,7 @@
 
         // It's not possible to add a new entry into an existing file, so we need to create a new
         // zip, copy all entries, then rename it.
-        sendBugreportBeingUpdatedNotification(context, info.pid); // ...and that takes time
+        sendBugreportBeingUpdatedNotification(context, info.id); // ...and that takes time
         final File dir = info.bugreportFile.getParentFile();
         final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName());
         Log.d(TAG, "Writing temporary zip file (" + tmpZip + ") with title and/or description");
@@ -1113,8 +1119,8 @@
     /**
      * Updates the user-provided details of a bugreport.
      */
-    private void updateBugreportInfo(int pid, String name, String title, String description) {
-        final BugreportInfo info = getInfo(pid);
+    private void updateBugreportInfo(int id, String name, String title, String description) {
+        final BugreportInfo info = getInfo(id);
         if (info == null) {
             return;
         }
@@ -1179,6 +1185,7 @@
         private EditText mInfoDescription;
         private AlertDialog mDialog;
         private Button mOkButton;
+        private int mId;
         private int mPid;
 
         /**
@@ -1207,8 +1214,7 @@
         /**
          * Sets its internal state and displays the dialog.
          */
-        private void initialize(Context context, int pid, String name, String title,
-                String description) {
+        private void initialize(Context context, BugreportInfo info) {
             // First initializes singleton.
             if (mDialog == null) {
                 @SuppressLint("InflateParams")
@@ -1232,7 +1238,7 @@
 
                 mDialog = new AlertDialog.Builder(context)
                         .setView(view)
-                        .setTitle(context.getString(R.string.bugreport_info_dialog_title, pid))
+                        .setTitle(context.getString(R.string.bugreport_info_dialog_title, info.id))
                         .setCancelable(false)
                         .setPositiveButton(context.getString(com.android.internal.R.string.ok),
                                 null)
@@ -1258,16 +1264,17 @@
             }
 
             // Then set fields.
-            mSavedName = mTempName = name;
-            mPid = pid;
-            if (!TextUtils.isEmpty(name)) {
-                mInfoName.setText(name);
+            mSavedName = mTempName = info.name;
+            mId = info.id;
+            mPid = info.pid;
+            if (!TextUtils.isEmpty(info.name)) {
+                mInfoName.setText(info.name);
             }
-            if (!TextUtils.isEmpty(title)) {
-                mInfoTitle.setText(title);
+            if (!TextUtils.isEmpty(info.title)) {
+                mInfoTitle.setText(info.title);
             }
-            if (!TextUtils.isEmpty(description)) {
-                mInfoDescription.setText(description);
+            if (!TextUtils.isEmpty(info.description)) {
+                mInfoDescription.setText(info.description);
             }
 
             // And finally display it.
@@ -1290,7 +1297,7 @@
                         final String title = mInfoTitle.getText().toString();
                         final String description = mInfoDescription.getText().toString();
 
-                        updateBugreportInfo(mPid, name, title, description);
+                        updateBugreportInfo(mId, name, title, description);
                         mDialog.dismiss();
                     }
                 });
@@ -1328,7 +1335,7 @@
             // Must update system property for the cases where dumpstate finishes
             // while the user is still entering other fields (like title or
             // description)
-            setBugreportNameProperty(mPid, name);
+            setBugreportNameProperty(mId, name);
         }
 
        /**
@@ -1337,7 +1344,7 @@
          * <p>Once the bugreport is finished dumpstate has already generated the final files, so
          * changing the name would have no effect.
          */
-        private void onBugreportFinished(int pid) {
+        private void onBugreportFinished(int id) {
             if (mInfoName != null) {
                 mInfoName.setEnabled(false);
                 mInfoName.setText(mSavedName);
@@ -1353,6 +1360,11 @@
         private final Context context;
 
         /**
+         * Sequential, user-friendly id used to identify the bugreport.
+         */
+        final int id;
+
+        /**
          * {@code pid} of the {@code dumpstate} process generating the bugreport.
          */
         final int pid;
@@ -1426,8 +1438,9 @@
         /**
          * Constructor for tracked bugreports - typically called upon receiving BUGREPORT_STARTED.
          */
-        BugreportInfo(Context context, int pid, String name, int max) {
+        BugreportInfo(Context context, int id, int pid, String name, int max) {
             this.context = context;
+            this.id = id;
             this.pid = pid;
             this.name = name;
             this.max = max;
@@ -1437,8 +1450,8 @@
          * Constructor for untracked bugreports - typically called upon receiving BUGREPORT_FINISHED
          * without a previous call to BUGREPORT_STARTED.
          */
-        BugreportInfo(Context context, int pid) {
-            this(context, pid, null, 0);
+        BugreportInfo(Context context, int id) {
+            this(context, id, id, null, 0);
             this.finished = true;
         }
 
@@ -1494,7 +1507,7 @@
         @Override
         public String toString() {
             final float percent = ((float) progress * 100 / max);
-            return "pid: " + pid + ", name: " + name + ", finished: " + finished
+            return "id: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
                     + "\n\ttitle: " + title + "\n\tdescription: " + description
                     + "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
                     + "\n\tprogress: " + progress + "/" + max + "(" + percent + ")"
@@ -1506,6 +1519,7 @@
         // Parcelable contract
         protected BugreportInfo(Parcel in) {
             context = null;
+            id = in.readInt();
             pid = in.readInt();
             name = in.readString();
             title = in.readString();
@@ -1527,6 +1541,7 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(id);
             dest.writeInt(pid);
             dest.writeString(name);
             dest.writeString(title);
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a9b8df2..4cd920a 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -52,8 +52,12 @@
     <!-- Tint color for the content on the notification overflow card. -->
     <color name="keyguard_overflow_content_color">#ff686868</color>
 
+    <!-- The disabled recents task bar background color. -->
+    <color name="recents_task_bar_disabled_background_color">#ff676767</color>
     <!-- The default recents task bar background color. -->
     <color name="recents_task_bar_default_background_color">#ffe6e6e6</color>
+    <!-- The default recents task view background color. -->
+    <color name="recents_task_view_default_background_color">#fff3f3f3</color>
     <!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
     <color name="recents_task_bar_light_text_color">#ffeeeeee</color>
     <!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5d4789a..4116962 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -714,6 +714,8 @@
     <string name="recents_search_bar_label">search</string>
     <!-- Recents: Launch error string. [CHAR LIMIT=NONE] -->
     <string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
+    <!-- Recents: Launch disabled string. [CHAR LIMIT=NONE] -->
+    <string name="recents_launch_disabled_message"><xliff:g id="app" example="Calendar">%s</xliff:g> is disabled in safe-mode.</string>
     <!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
     <string name="recents_history_button_label">History</string>
     <!-- Recents: History clear all string. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 454d1ce..4845425 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -62,6 +62,7 @@
             mPlusPaint;
     private float mTextHeight, mWarningTextHeight;
     private int mIconTint = Color.WHITE;
+    private float mOldDarkIntensity = 0f;
 
     private int mHeight;
     private int mWidth;
@@ -295,6 +296,9 @@
     }
 
     public void setDarkIntensity(float darkIntensity) {
+        if (darkIntensity == mOldDarkIntensity) {
+            return;
+        }
         int backgroundColor = getBackgroundColor(darkIntensity);
         int fillColor = getFillColor(darkIntensity);
         mIconTint = fillColor;
@@ -302,6 +306,7 @@
         mBoltPaint.setColor(fillColor);
         mChargeColor = fillColor;
         invalidateSelf();
+        mOldDarkIntensity = darkIntensity;
     }
 
     private int getBackgroundColor(float darkIntensity) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 9da5c2b..e0efaa5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -837,11 +837,13 @@
      * Draws the header of a task used for the window animation into a bitmap.
      */
     private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
         if (toTransform != null && toTask.key != null) {
             Bitmap thumbnail;
             synchronized (mHeaderBarLock) {
                 int toHeaderWidth = (int) toTransform.rect.width();
                 int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+                boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
                 mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(),
                         (int) toTransform.rect.height());
                 thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
@@ -851,7 +853,8 @@
                 } else {
                     Canvas c = new Canvas(thumbnail);
                     c.scale(toTransform.scale, toTransform.scale);
-                    mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */);
+                    mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */,
+                            disabledInSafeMode);
                     mHeaderBar.draw(c);
                     c.setBitmap(null);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
index 244c0df..95aa10f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents.misc;
 
 import android.os.Handler;
+import android.view.ViewDebug;
 
 /**
  * A dozer is a class that fires a trigger after it falls asleep.
@@ -26,8 +27,11 @@
 
     Handler mHandler;
 
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mIsDozing;
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mHasTriggered;
+    @ViewDebug.ExportedProperty(category="recents")
     int mDozeDurationMilliseconds;
     Runnable mOnSleepRunnable;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 22ab794..8b4474f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -112,6 +112,8 @@
     Display mDisplay;
     String mRecentsPackage;
     ComponentName mAssistComponent;
+
+    boolean mIsSafeMode;
     boolean mHasFreeformWorkspaceSupport;
 
     Bitmap mDummyIcon;
@@ -137,6 +139,7 @@
                 mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT) ||
                         Settings.Global.getInt(context.getContentResolver(),
                                 DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+        mIsSafeMode = mPm.isSafeMode();
 
         // Get the dummy thumbnail width/heights
         Resources res = context.getResources();
@@ -187,7 +190,8 @@
                 rti.firstActiveTime = rti.lastActiveTime = i;
                 if (i % 2 == 0) {
                     rti.taskDescription = new ActivityManager.TaskDescription(description,
-                        Bitmap.createBitmap(mDummyIcon),
+                        Bitmap.createBitmap(mDummyIcon), null,
+                        0xFF000000 | (0xFFFFFF & new Random().nextInt()),
                         0xFF000000 | (0xFFFFFF & new Random().nextInt()));
                 } else {
                     rti.taskDescription = new ActivityManager.TaskDescription();
@@ -260,6 +264,13 @@
         return mHasFreeformWorkspaceSupport;
     }
 
+    /**
+     * Returns whether this device is in the safe mode.
+     */
+    public boolean isInSafeMode() {
+        return mIsSafeMode;
+    }
+
     /** Returns whether the recents is currently running */
     public boolean isRecentsTopMost(ActivityManager.RunningTaskInfo topTask,
             MutableBoolean isHomeTopMost) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index c51aa7c..016e6d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -18,6 +18,7 @@
 
 import android.app.ActivityManager;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -188,11 +189,15 @@
                     : null;
             Bitmap thumbnail = loader.getAndUpdateThumbnail(taskKey, false);
             int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
+            int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
+            boolean isSystemApp = (loader.getAndUpdateActivityInfo(taskKey).applicationInfo.flags
+                    & ApplicationInfo.FLAG_SYSTEM) != 0;
 
             // Add the task to the stack
             Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
                     thumbnail, title, contentDescription, dismissDescription, activityColor,
-                    !isStackTask, isLaunchTarget, t.bounds, t.taskDescription);
+                    backgroundColor, !isStackTask, isLaunchTarget, isSystemApp, t.bounds,
+                    t.taskDescription);
 
             allTasks.add(task);
             affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
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 26130ab..5e1af12 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -264,13 +264,16 @@
     private int mNumVisibleThumbnailsLoaded;
 
     int mDefaultTaskBarBackgroundColor;
+    int mDefaultTaskViewBackgroundColor;
     BitmapDrawable mDefaultIcon;
     Bitmap mDefaultThumbnail;
 
     public RecentsTaskLoader(Context context) {
         Resources res = context.getResources();
         mDefaultTaskBarBackgroundColor =
-                res.getColor(R.color.recents_task_bar_default_background_color);
+                context.getColor(R.color.recents_task_bar_default_background_color);
+        mDefaultTaskViewBackgroundColor =
+                context.getColor(R.color.recents_task_view_default_background_color);
         mMaxThumbnailCacheSize = res.getInteger(R.integer.config_recents_max_thumbnail_count);
         mMaxIconCacheSize = res.getInteger(R.integer.config_recents_max_icon_count);
         int iconCacheSize = RecentsDebugFlags.Static.DisableBackgroundCache ? 1 :
@@ -556,10 +559,20 @@
     }
 
     /**
+     * Returns the task's background color if possible.
+     */
+    int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
+        if (td != null && td.getBackgroundColor() != 0) {
+            return td.getBackgroundColor();
+        }
+        return mDefaultTaskViewBackgroundColor;
+    }
+
+    /**
      * Returns the activity info for the given task key, retrieving one from the system if the
      * task key is expired.
      */
-    private ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
+    ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         ComponentName cn = taskKey.getComponent();
         ActivityInfo activityInfo = mActivityInfoCache.get(cn);
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 1c277d5..8ed6dd7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -23,6 +23,7 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.view.ViewDebug;
 
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -48,11 +49,17 @@
 
     /* The Task Key represents the unique primary key for the task */
     public static class TaskKey {
+        @ViewDebug.ExportedProperty(category="recents")
         public final int id;
+        @ViewDebug.ExportedProperty(category="recents")
         public int stackId;
+        @ViewDebug.ExportedProperty(category="recents")
         public final Intent baseIntent;
+        @ViewDebug.ExportedProperty(category="recents")
         public final int userId;
+        @ViewDebug.ExportedProperty(category="recents")
         public long firstActiveTime;
+        @ViewDebug.ExportedProperty(category="recents")
         public long lastActiveTime;
 
         private int mHashCode;
@@ -105,17 +112,21 @@
         }
     }
 
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
     public TaskKey key;
 
     /**
      * The group will be computed separately from the initialization of the task
      */
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="group_")
     public TaskGrouping group;
     /**
      * The affiliationTaskId is the task id of the parent task or itself if it is not affiliated
      * with any task.
      */
+    @ViewDebug.ExportedProperty(category="recents")
     public int affiliationTaskId;
+    @ViewDebug.ExportedProperty(category="recents")
     public int affiliationColor;
 
     /**
@@ -124,15 +135,23 @@
      */
     public Drawable icon;
     public Bitmap thumbnail;
+    @ViewDebug.ExportedProperty(category="recents")
     public String title;
+    @ViewDebug.ExportedProperty(category="recents")
     public String contentDescription;
+    @ViewDebug.ExportedProperty(category="recents")
     public String dismissDescription;
+    @ViewDebug.ExportedProperty(category="recents")
     public int colorPrimary;
+    @ViewDebug.ExportedProperty(category="recents")
+    public int colorBackground;
+    @ViewDebug.ExportedProperty(category="recents")
     public boolean useLightOnPrimaryColor;
 
     /**
      * The bounds of the task, used only if it is a freeform task.
      */
+    @ViewDebug.ExportedProperty(category="recents")
     public Rect bounds;
 
     /**
@@ -143,8 +162,12 @@
     /**
      * The state isLaunchTarget will be set for the correct task upon launching Recents.
      */
+    @ViewDebug.ExportedProperty(category="recents")
     public boolean isLaunchTarget;
+    @ViewDebug.ExportedProperty(category="recents")
     public boolean isHistorical;
+    @ViewDebug.ExportedProperty(category="recents")
+    public boolean isSystemApp;
 
     private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
 
@@ -154,8 +177,8 @@
 
     public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
                 Bitmap thumbnail, String title, String contentDescription,
-                String dismissDescription, int colorPrimary, boolean isHistorical,
-                boolean isLaunchTarget, Rect bounds,
+                String dismissDescription, int colorPrimary, int colorBackground,
+                boolean isHistorical, boolean isLaunchTarget, boolean isSystemApp, Rect bounds,
                 ActivityManager.TaskDescription taskDescription) {
         boolean isInAffiliationGroup = (affiliationTaskId != key.id);
         boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
@@ -168,12 +191,14 @@
         this.contentDescription = contentDescription;
         this.dismissDescription = dismissDescription;
         this.colorPrimary = hasAffiliationGroupColor ? affiliationColor : colorPrimary;
+        this.colorBackground = colorBackground;
         this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
                 Color.WHITE) > 3f;
         this.bounds = bounds;
         this.taskDescription = taskDescription;
         this.isLaunchTarget = isLaunchTarget;
         this.isHistorical = isHistorical;
+        this.isSystemApp = isSystemApp;
     }
 
     /** Copies the other task. */
@@ -188,10 +213,12 @@
         this.contentDescription = o.contentDescription;
         this.dismissDescription = o.dismissDescription;
         this.colorPrimary = o.colorPrimary;
+        this.colorBackground = o.colorBackground;
         this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
         this.bounds = o.bounds;
         this.isLaunchTarget = o.isLaunchTarget;
         this.isHistorical = o.isHistorical;
+        this.isSystemApp = o.isSystemApp;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 5842095..4a65374 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -19,16 +19,22 @@
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.view.View;
+import android.view.ViewDebug;
 import android.view.ViewOutlineProvider;
 
 /* An outline provider that has a clip and outline that can be animated. */
 public class AnimateableViewBounds extends ViewOutlineProvider {
 
     View mSourceView;
+    @ViewDebug.ExportedProperty(category="recents")
     Rect mClipRect = new Rect();
+    @ViewDebug.ExportedProperty(category="recents")
     Rect mClipBounds = new Rect();
+    @ViewDebug.ExportedProperty(category="recents")
     Rect mLastClipBounds = new Rect();
+    @ViewDebug.ExportedProperty(category="recents")
     int mCornerRadius;
+    @ViewDebug.ExportedProperty(category="recents")
     float mAlpha = 1f;
     final float mMinAlpha = 0.25f;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 42aaa97..c4db485 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.recents.views;
 
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -32,6 +34,7 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewDebug;
 import android.view.ViewOutlineProvider;
 import android.view.ViewPropertyAnimator;
 import android.view.WindowInsets;
@@ -79,8 +82,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
 /**
  * This view is the the top level layout that contains TaskStacks (which are laid out according
  * to their SpaceNode bounds.
@@ -103,6 +104,8 @@
 
     private boolean mAwaitingFirstLayout = true;
     private boolean mLastTaskLaunchedWasFreeform;
+
+    @ViewDebug.ExportedProperty(category="recents")
     private Rect mSystemInsets = new Rect();
     private int mDividerSize;
 
@@ -110,6 +113,7 @@
     private Animator mBackgroundScrimAnimator;
 
     private RecentsTransitionHelper mTransitionHelper;
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
     private RecentsViewTouchHandler mTouchHandler;
     private final FlingAnimationUtils mFlingAnimationUtils;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 346ce16..016d937 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -20,6 +20,7 @@
 import android.graphics.Point;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
+import android.view.ViewDebug;
 
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -61,12 +62,18 @@
 
     private RecentsView mRv;
 
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="drag_task")
     private Task mDragTask;
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="drag_task_view_")
     private TaskView mTaskView;
 
+    @ViewDebug.ExportedProperty(category="recents")
     private Point mTaskViewOffset = new Point();
+    @ViewDebug.ExportedProperty(category="recents")
     private Point mDownPos = new Point();
+    @ViewDebug.ExportedProperty(category="recents")
     private boolean mDragRequested;
+    @ViewDebug.ExportedProperty(category="recents")
     private boolean mIsDragging;
     private float mDragSlop;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 19ac1e7..98bc92f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -25,6 +25,7 @@
 import android.util.ArraySet;
 import android.util.FloatProperty;
 import android.util.Property;
+import android.view.ViewDebug;
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -216,15 +217,20 @@
     private TaskStackLayoutAlgorithmCallbacks mCb;
 
     // The task bounds (untransformed) for layout.  This rect is anchored at mTaskRoot.
+    @ViewDebug.ExportedProperty(category="recents")
     public Rect mTaskRect = new Rect();
     // The freeform workspace bounds, inset from the top by the search bar, and is a fixed height
+    @ViewDebug.ExportedProperty(category="recents")
     public Rect mFreeformRect = new Rect();
     // The stack bounds, inset from the top by the search bar, and runs to
     // the bottom of the screen
+    @ViewDebug.ExportedProperty(category="recents")
     public Rect mStackRect = new Rect();
     // This is the current system insets
+    @ViewDebug.ExportedProperty(category="recents")
     public Rect mSystemInsets = new Rect();
     // This is the bounds of the history button above the stack rect
+    @ViewDebug.ExportedProperty(category="recents")
     public Rect mHistoryButtonRect = new Rect();
 
     // The visible ranges when the stack is focused and unfocused
@@ -232,14 +238,17 @@
     private Range mFocusedRange;
 
     // The offset from the top when scrolled to the top of the stack
+    @ViewDebug.ExportedProperty(category="recents")
     private int mFocusedPeekHeight;
 
     // The offset from the top of the stack to the top of the bounds when the stack is scrolled to
     // the end
+    @ViewDebug.ExportedProperty(category="recents")
     private int mStackTopOffset;
 
     // The offset from the bottom of the stack to the bottom of the bounds when the stack is
     // scrolled to the front
+    @ViewDebug.ExportedProperty(category="recents")
     private int mStackBottomOffset;
 
     // The paths defining the motion of the tasks when the stack is focused and unfocused
@@ -250,27 +259,36 @@
 
     // The state of the stack focus (0..1), which controls the transition of the stack from the
     // focused to non-focused state
+    @ViewDebug.ExportedProperty(category="recents")
     private float mFocusState;
 
     // The animator used to reset the focused state
     private ObjectAnimator mFocusStateAnimator;
 
     // The smallest scroll progress, at this value, the back most task will be visible
+    @ViewDebug.ExportedProperty(category="recents")
     float mMinScrollP;
     // The largest scroll progress, at this value, the front most task will be visible above the
     // navigation bar
+    @ViewDebug.ExportedProperty(category="recents")
     float mMaxScrollP;
     // The initial progress that the scroller is set when you first enter recents
+    @ViewDebug.ExportedProperty(category="recents")
     float mInitialScrollP;
     // The task progress for the front-most task in the stack
+    @ViewDebug.ExportedProperty(category="recents")
     float mFrontMostTaskP;
 
     // The last computed task counts
+    @ViewDebug.ExportedProperty(category="recents")
     int mNumStackTasks;
+    @ViewDebug.ExportedProperty(category="recents")
     int mNumFreeformTasks;
 
     // The min/max z translations
+    @ViewDebug.ExportedProperty(category="recents")
     int mMinTranslationZ;
+    @ViewDebug.ExportedProperty(category="recents")
     int mMaxTranslationZ;
 
     // Optimization, allows for quick lookup of task -> index
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 fb3515a..9560eb4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -20,8 +20,6 @@
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.ComponentName;
@@ -40,11 +38,10 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
 
 import com.android.internal.logging.MetricsLogger;
@@ -121,8 +118,11 @@
 
     LayoutInflater mInflater;
     TaskStack mStack;
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="layout_")
     TaskStackLayoutAlgorithm mLayoutAlgorithm;
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="scroller_")
     TaskStackViewScroller mStackScroller;
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
     TaskStackViewTouchHandler mTouchHandler;
     TaskStackAnimationHelper mAnimationHelper;
     GradientDrawable mFreeformWorkspaceBackground;
@@ -134,25 +134,36 @@
     ArraySet<Task.TaskKey> mIgnoreTasks = new ArraySet<>();
     AnimationProps mDeferredTaskViewLayoutAnimation = null;
 
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="doze_")
     DozeTrigger mUIDozeTrigger;
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="focused_task_")
     Task mFocusedTask;
 
     int mTaskCornerRadiusPx;
     private int mDividerSize;
     private int mStartTimerIndicatorDuration;
 
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mTaskViewsClipDirty = true;
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mAwaitingFirstLayout = true;
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mInMeasureLayout = false;
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mEnterAnimationComplete = false;
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mTouchExplorationEnabled;
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mScreenPinningEnabled;
 
     // The stable stack bounds are the full bounds that we were measured with from RecentsView
+    @ViewDebug.ExportedProperty(category="recents")
     private Rect mStableStackBounds = new Rect();
     // The current stack bounds are dynamic and may change as the user drags and drops
+    @ViewDebug.ExportedProperty(category="recents")
     private Rect mStackBounds = new Rect();
 
+    @ViewDebug.ExportedProperty(category="recents")
     private int[] mTmpVisibleRange = new int[2];
     private Rect mTmpRect = new Rect();
     private ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index d1bce55..b54ea1d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -23,6 +23,7 @@
 import android.util.FloatProperty;
 import android.util.Log;
 import android.util.Property;
+import android.view.ViewDebug;
 import android.widget.OverScroller;
 
 import com.android.systemui.Interpolators;
@@ -63,6 +64,7 @@
     TaskStackLayoutAlgorithm mLayoutAlgorithm;
     TaskStackViewScrollerCallbacks mCb;
 
+    @ViewDebug.ExportedProperty(category="recents")
     float mStackScrollP;
     float mFlingDownScrollP;
     int mFlingDownY;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 5d1bb66f..55f9fba 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -28,6 +28,7 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.ViewDebug;
 import android.view.ViewParent;
 import android.view.animation.Animation;
 import android.view.animation.Interpolator;
@@ -69,6 +70,7 @@
     FlingAnimationUtils mFlingAnimUtils;
     ValueAnimator mScrollFlingAnimator;
 
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mIsScrolling;
     float mDownScrollP;
     int mDownX, mDownY;
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 850e36e7..0f485ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -35,8 +35,10 @@
 import android.util.Property;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewDebug;
 import android.view.ViewOutlineProvider;
 import android.view.animation.AccelerateInterpolator;
+import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -105,31 +107,46 @@
                 }
             };
 
+    @ViewDebug.ExportedProperty(category="recents")
     float mTaskProgress;
+    @ViewDebug.ExportedProperty(category="recents")
     float mMaxDimScale;
+    @ViewDebug.ExportedProperty(category="recents")
     int mDimAlpha;
     AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(3f);
     PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
     Paint mDimLayerPaint = new Paint();
     float mActionButtonTranslationZ;
 
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="task_")
     Task mTask;
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mTaskDataLoaded;
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mClipViewInStack = true;
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mTouchExplorationEnabled;
+    @ViewDebug.ExportedProperty(category="recents")
+    boolean mIsDisabledInSafeMode;
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="view_bounds_")
     AnimateableViewBounds mViewBounds;
 
     private AnimatorSet mTransformAnimation;
     private ArrayList<Animator> mTmpAnimators = new ArrayList<>();
 
     View mContent;
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="thumbnail_")
     TaskViewThumbnail mThumbnailView;
+    @ViewDebug.ExportedProperty(deepExport=true, prefix="header_")
     TaskViewHeader mHeaderView;
     View mActionButtonView;
     TaskViewCallbacks mCb;
 
+    @ViewDebug.ExportedProperty(category="recents")
     Point mDownTouchPos = new Point();
 
+    private Toast mDisabledAppToast;
+
     public TaskView(Context context) {
         this(context, null);
     }
@@ -549,15 +566,17 @@
     /**** TaskCallbacks Implementation ****/
 
     public void onTaskBound(Task t) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
         mTask = t;
         mTask.addCallback(this);
+        mIsDisabledInSafeMode = !mTask.isSystemApp && ssp.isInSafeMode();
     }
 
     @Override
     public void onTaskDataLoaded(Task task) {
         // Bind each of the views to the new task data
-        mThumbnailView.rebindToTask(mTask);
-        mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled);
+        mThumbnailView.rebindToTask(mTask, mIsDisabledInSafeMode);
+        mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
         mTaskDataLoaded = true;
     }
 
@@ -572,13 +591,24 @@
 
     @Override
     public void onTaskStackIdChanged() {
-        mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled);
+        mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
     }
 
     /**** View.OnClickListener Implementation ****/
 
     @Override
      public void onClick(final View v) {
+        if (mIsDisabledInSafeMode) {
+            Context context = getContext();
+            String msg = context.getString(R.string.recents_launch_disabled_message, mTask.title);
+            if (mDisabledAppToast != null) {
+                mDisabledAppToast.cancel();
+            }
+            mDisabledAppToast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
+            mDisabledAppToast.show();
+            return;
+        }
+
         boolean screenPinningRequested = false;
         if (v == mActionButtonView) {
             // Reset the translation of the action button before we animate it out
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index c91a833..bb56a52 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -36,6 +36,7 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewAnimationUtils;
+import android.view.ViewDebug;
 import android.view.ViewStub;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -74,6 +75,8 @@
 
         private Paint mHighlightPaint = new Paint();
         private Paint mBackgroundPaint = new Paint();
+        private int mColor;
+        private float mDimAlpha;
 
         public HighlightColorDrawable() {
             mBackgroundPaint.setColor(Color.argb(255, 0, 0, 0));
@@ -83,15 +86,19 @@
         }
 
         public void setColorAndDim(int color, float dimAlpha) {
-            mBackgroundPaint.setColor(color);
+            if (mColor != color || Float.compare(mDimAlpha, dimAlpha) != 0) {
+                mColor = color;
+                mDimAlpha = dimAlpha;
+                mBackgroundPaint.setColor(color);
 
-            ColorUtils.colorToHSL(color, mTmpHSL);
-            // TODO: Consider using the saturation of the color to adjust the lightness as well
-            mTmpHSL[2] = Math.min(1f,
-                    mTmpHSL[2] + HIGHLIGHT_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
-            mHighlightPaint.setColor(ColorUtils.HSLToColor(mTmpHSL));
+                ColorUtils.colorToHSL(color, mTmpHSL);
+                // TODO: Consider using the saturation of the color to adjust the lightness as well
+                mTmpHSL[2] = Math.min(1f,
+                        mTmpHSL[2] + HIGHLIGHT_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
+                mHighlightPaint.setColor(ColorUtils.HSLToColor(mTmpHSL));
 
-            invalidateSelf();
+                invalidateSelf();
+            }
         }
 
         @Override
@@ -121,6 +128,10 @@
         public int getOpacity() {
             return PixelFormat.OPAQUE;
         }
+
+        public int getColor() {
+            return mColor;
+        }
     }
 
     Task mTask;
@@ -139,9 +150,11 @@
     ProgressBar mFocusTimerIndicator;
 
     // Header drawables
+    @ViewDebug.ExportedProperty(category="recents")
     Rect mTaskViewRect = new Rect();
     int mCornerRadius;
     int mHighlightHeight;
+    @ViewDebug.ExportedProperty(category="recents")
     float mDimAlpha;
     Drawable mLightDismissDrawable;
     Drawable mDarkDismissDrawable;
@@ -153,6 +166,7 @@
     Drawable mDarkInfoIcon;
     int mTaskBarViewLightTextColor;
     int mTaskBarViewDarkTextColor;
+    int mDisabledTaskBarBackgroundColor;
     int mMoveTaskTargetStackId = INVALID_STACK_ID;
 
     // Header background
@@ -195,6 +209,8 @@
         mDarkFullscreenIcon = context.getDrawable(R.drawable.recents_move_task_fullscreen_dark);
         mLightInfoIcon = context.getDrawable(R.drawable.recents_info_light);
         mDarkInfoIcon = context.getDrawable(R.drawable.recents_info_dark);
+        mDisabledTaskBarBackgroundColor =
+                context.getColor(R.color.recents_task_bar_disabled_background_color);
 
         // Configure the background and dim
         mBackground = new HighlightColorDrawable();
@@ -331,17 +347,17 @@
      */
     void setDimAlpha(float dimAlpha) {
         mDimAlpha = dimAlpha;
-        updateBackgroundColor(dimAlpha);
+        updateBackgroundColor(mBackground.getColor(), dimAlpha);
     }
 
     /**
      * Updates the background and highlight colors for this header.
      */
-    private void updateBackgroundColor(float dimAlpha) {
+    private void updateBackgroundColor(int color, float dimAlpha) {
         if (mTask != null) {
-            mBackground.setColorAndDim(mTask.colorPrimary, dimAlpha);
+            mBackground.setColorAndDim(color, dimAlpha);
             // TODO: Consider using the saturation of the color to adjust the lightness as well
-            ColorUtils.colorToHSL(mTask.colorPrimary, mTmpHSL);
+            ColorUtils.colorToHSL(color, mTmpHSL);
             mTmpHSL[2] = Math.min(1f, mTmpHSL[2] + OVERLAY_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
             mOverlayBackground.setColorAndDim(ColorUtils.HSLToColor(mTmpHSL), dimAlpha);
             mDimLayerPaint.setAlpha((int) (dimAlpha * 255));
@@ -350,12 +366,15 @@
     }
 
     /** Binds the bar view to the task */
-    public void rebindToTask(Task t, boolean touchExplorationEnabled) {
+    public void rebindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) {
         mTask = t;
 
         // If an activity icon is defined, then we use that as the primary icon to show in the bar,
         // otherwise, we fall back to the application icon
-        updateBackgroundColor(mDimAlpha);
+        int primaryColor = disabledInSafeMode
+                ? mDisabledTaskBarBackgroundColor
+                : t.colorPrimary;
+        updateBackgroundColor(primaryColor, mDimAlpha);
         if (t.icon != null) {
             mIconView.setImageDrawable(t.icon);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index f90951e..0fec9c3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -21,13 +21,17 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.LightingColorFilter;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.graphics.Shader;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewDebug;
 
 import com.android.systemui.R;
 import com.android.systemui.recents.model.Task;
@@ -39,27 +43,40 @@
  */
 public class TaskViewThumbnail extends View {
 
+
+    private static final ColorMatrix TMP_FILTER_COLOR_MATRIX = new ColorMatrix();
+    private static final ColorMatrix TMP_BRIGHTNESS_COLOR_MATRIX = new ColorMatrix();
+
     private Task mTask;
 
     // Drawing
+    @ViewDebug.ExportedProperty(category="recents")
     Rect mThumbnailRect = new Rect();
+    @ViewDebug.ExportedProperty(category="recents")
     Rect mTaskViewRect = new Rect();
     int mCornerRadius;
+    @ViewDebug.ExportedProperty(category="recents")
     float mDimAlpha;
     Matrix mScaleMatrix = new Matrix();
     Paint mDrawPaint = new Paint();
+    Paint mBgFillPaint = new Paint();
     BitmapShader mBitmapShader;
     LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
 
     // Task bar clipping, the top of this thumbnail can be clipped against the opaque header
     // bar that overlaps this thumbnail
     View mTaskBar;
+    @ViewDebug.ExportedProperty(category="recents")
     Rect mClipRect = new Rect();
 
     // Visibility optimization, if the thumbnail height is less than the height of the header
     // bar for the task view, then just mark this thumbnail view as invisible
+    @ViewDebug.ExportedProperty(category="recents")
     boolean mInvisible;
 
+    @ViewDebug.ExportedProperty(category="recents")
+    boolean mDisabledInSafeMode;
+
     public TaskViewThumbnail(Context context) {
         this(context, null);
     }
@@ -79,6 +96,7 @@
         mDrawPaint.setAntiAlias(true);
         mCornerRadius = getResources().getDimensionPixelSize(
                 R.dimen.recents_task_view_rounded_corners_radius);
+        mBgFillPaint.setColor(Color.WHITE);
     }
 
     /**
@@ -100,10 +118,39 @@
         if (mInvisible) {
             return;
         }
-        // Draw the thumbnail with the rounded corners
-        canvas.drawRoundRect(0, 0, mTaskViewRect.width(), mTaskViewRect.height(),
-                mCornerRadius,
-                mCornerRadius, mDrawPaint);
+
+        int thumbnailHeight = (int) (((float) mTaskViewRect.width() / mThumbnailRect.width()) *
+                mThumbnailRect.height());
+        if (thumbnailHeight >= mTaskViewRect.height()) {
+            // The thumbnail fills the full task view bounds, so just draw it
+            canvas.drawRoundRect(0, 0, mTaskViewRect.width(), mTaskViewRect.height(),
+                    mCornerRadius, mCornerRadius, mDrawPaint);
+        } else {
+            int count = 0;
+            if (thumbnailHeight > 0) {
+                // The thumbnail only covers part of the task view bounds, so fill in the
+                // non-thumbnail space with the default background color.  This is the equivalent of
+                // the GL border texture mode.
+                count = canvas.save();
+
+                // Since we only want the top corners to be rounded, draw slightly beyond the
+                // thumbnail height, but clip to the thumbnail height
+                canvas.clipRect(0, 0, mTaskViewRect.width(), thumbnailHeight, Region.Op.REPLACE);
+                canvas.drawRoundRect(0, 0, mTaskViewRect.width(), thumbnailHeight + mCornerRadius,
+                        mCornerRadius, mCornerRadius, mDrawPaint);
+            }
+
+            // In the remaining space, draw the background color
+            canvas.clipRect(0, thumbnailHeight, mTaskViewRect.width(), mTaskViewRect.height(),
+                    Region.Op.REPLACE);
+            canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
+                    mTaskViewRect.width(), mTaskViewRect.height(), mCornerRadius, mCornerRadius,
+                    mBgFillPaint);
+
+            if (thumbnailHeight > 0) {
+                canvas.restoreToCount(count);
+            }
+        }
     }
 
     /** Sets the thumbnail to a given bitmap. */
@@ -128,9 +175,27 @@
         }
         int mul = (int) ((1.0f - mDimAlpha) * 255);
         if (mBitmapShader != null) {
-            mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
-            mDrawPaint.setColorFilter(mLightingColorFilter);
-            mDrawPaint.setColor(0xffffffff);
+            if (mDisabledInSafeMode) {
+                // Brightness: C-new = C-old*(1-amount) + amount
+                TMP_FILTER_COLOR_MATRIX.setSaturation(0);
+                float scale = 1f - mDimAlpha;
+                float[] mat = TMP_BRIGHTNESS_COLOR_MATRIX.getArray();
+                mat[0] = scale;
+                mat[6] = scale;
+                mat[12] = scale;
+                mat[4] = mDimAlpha;
+                mat[9] = mDimAlpha;
+                mat[14] = mDimAlpha;
+                TMP_FILTER_COLOR_MATRIX.preConcat(TMP_BRIGHTNESS_COLOR_MATRIX);
+                ColorMatrixColorFilter filter = new ColorMatrixColorFilter(TMP_FILTER_COLOR_MATRIX);
+                mDrawPaint.setColorFilter(filter);
+                mBgFillPaint.setColorFilter(filter);
+            } else {
+                mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
+                mDrawPaint.setColorFilter(mLightingColorFilter);
+                mDrawPaint.setColor(0xFFffffff);
+                mBgFillPaint.setColorFilter(mLightingColorFilter);
+            }
         } else {
             int grey = mul;
             mDrawPaint.setColorFilter(null);
@@ -196,10 +261,14 @@
     }
 
     /** Binds the thumbnail view to the task */
-    void rebindToTask(Task t) {
+    void rebindToTask(Task t, boolean disabledInSafeMode) {
         mTask = t;
+        mDisabledInSafeMode = disabledInSafeMode;
         if (t.thumbnail != null) {
             setThumbnail(t.thumbnail);
+            if (t.colorBackground != 0) {
+                mBgFillPaint.setColor(t.colorBackground);
+            }
         } else {
             setThumbnail(null);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index c9ebfa0..2bebac2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -38,6 +38,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.os.AsyncTask;
@@ -116,7 +117,7 @@
         ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
         ExpandableNotificationRow.OnExpandClickListener {
     public static final String TAG = "StatusBar";
-    public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    public static final boolean DEBUG = false;
     public static final boolean MULTIUSER_DEBUG = false;
 
     public static final boolean ENABLE_REMOTE_INPUT =
@@ -228,6 +229,7 @@
     protected int mState;
     protected boolean mBouncerShowing;
     protected boolean mShowLockscreenNotifications;
+    protected boolean mAllowLockscreenRemoteInput;
 
     protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
     protected DismissView mDismissView;
@@ -399,11 +401,26 @@
                 }
                 p = p.getParent();
             }
+            ExpandableNotificationRow row = null;
+            while (p != null) {
+                if (p instanceof ExpandableNotificationRow) {
+                    row = (ExpandableNotificationRow) p;
+                    break;
+                }
+                p = p.getParent();
+            }
 
-            if (riv == null) {
+            if (riv == null || row == null) {
                 return false;
             }
 
+            row.setUserExpanded(true);
+
+            if (isLockscreenPublicMode() && !mAllowLockscreenRemoteInput) {
+                onLockedRemoteInput(row, view);
+                return true;
+            }
+
             riv.setVisibility(View.VISIBLE);
             int cx = view.getLeft() + view.getWidth() / 2;
             int cy = view.getTop() + view.getHeight() / 2;
@@ -618,6 +635,10 @@
                 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_REMOTE_INPUT), false,
+                mSettingsObserver,
+                UserHandle.USER_ALL);
 
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
@@ -641,12 +662,15 @@
         // Connect in to the status bar manager service
         mCommandQueue = new CommandQueue(this);
 
-        int[] switches = new int[8];
+        int[] switches = new int[9];
         ArrayList<IBinder> binders = new ArrayList<IBinder>();
         ArrayList<String> iconSlots = new ArrayList<>();
         ArrayList<StatusBarIcon> icons = new ArrayList<>();
+        Rect fullscreenStackBounds = new Rect();
+        Rect dockedStackBounds = new Rect();
         try {
-            mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders);
+            mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
+                    fullscreenStackBounds, dockedStackBounds);
         } catch (RemoteException ex) {
             // If the system process isn't there we're doomed anyway.
         }
@@ -655,7 +679,8 @@
 
         mSettingsObserver.onChange(false); // set up
         disable(switches[0], switches[6], false /* animate */);
-        setSystemUiVisibility(switches[1], 0xffffffff);
+        setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
+                fullscreenStackBounds, dockedStackBounds);
         topAppWindowChanged(switches[2] != 0);
         // StatusBarManagerService has a back up of IME token and it's restored here.
         setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
@@ -1295,6 +1320,8 @@
         }
     }
 
+    protected void onLockedRemoteInput(ExpandableNotificationRow row, View clickedView) {}
+
     @Override
     public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
     }
@@ -1931,6 +1958,10 @@
         mShowLockscreenNotifications = show;
     }
 
+    protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
+        mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
+    }
+
     private void updateLockscreenNotificationSetting() {
         final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
@@ -1940,7 +1971,14 @@
                 null /* admin */, mCurrentUserId);
         final boolean allowedByDpm = (dpmFlags
                 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
+
+        final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
+                0,
+                mCurrentUserId) != 0;
+
         setShowLockscreenNotifications(show && allowedByDpm);
+        setLockScreenAllowRemoteInput(remoteInput);
     }
 
     protected abstract void setAreThereNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 71347c4..3b960ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -17,12 +17,14 @@
 package com.android.systemui.statusbar;
 
 import android.content.ComponentName;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
 import android.util.Pair;
 
+import com.android.internal.os.SomeArgs;
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
 
@@ -94,7 +96,8 @@
         public void animateExpandNotificationsPanel();
         public void animateCollapsePanels(int flags);
         public void animateExpandSettingsPanel(String obj);
-        public void setSystemUiVisibility(int vis, int mask);
+        public void setSystemUiVisibility(int vis, int fullscreenStackVis,
+                int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds);
         public void topAppWindowChanged(boolean visible);
         public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
                 boolean showImeSwitcher);
@@ -169,11 +172,19 @@
         }
     }
 
-    public void setSystemUiVisibility(int vis, int mask) {
+    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
         synchronized (mLock) {
             // Don't coalesce these, since it might have one time flags set such as
             // STATUS_BAR_UNHIDE which might get lost.
-            mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget();
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = vis;
+            args.argi2 = fullscreenStackVis;
+            args.argi3 = dockedStackVis;
+            args.argi4 = mask;
+            args.arg1 = fullscreenStackBounds;
+            args.arg2 = dockedStackBounds;
+            mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, args).sendToTarget();
         }
     }
 
@@ -377,7 +388,10 @@
                     mCallbacks.animateExpandSettingsPanel((String) msg.obj);
                     break;
                 case MSG_SET_SYSTEMUI_VISIBILITY:
-                    mCallbacks.setSystemUiVisibility(msg.arg1, msg.arg2);
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    mCallbacks.setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
+                            args.argi4, (Rect) args.arg1, (Rect) args.arg2);
+                    args.recycle();
                     break;
                 case MSG_TOP_APP_WINDOW_CHANGED:
                     mCallbacks.topAppWindowChanged(msg.arg1 != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 264655c..7422902e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -527,6 +527,8 @@
             mGuts.setVisibility(oldGuts.getVisibility());
             addView(mGuts, index);
         }
+        mPrivateLayout.reInflateViews();
+        mPublicLayout.reInflateViews();
     }
 
     public interface ExpansionLogger {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 76e522e..d5361dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -248,14 +248,16 @@
     public void reset(boolean resetActualHeight) {
         if (mContractedChild != null) {
             mContractedChild.animate().cancel();
+            removeView(mContractedChild);
         }
         if (mExpandedChild != null) {
             mExpandedChild.animate().cancel();
+            removeView(mExpandedChild);
         }
         if (mHeadsUpChild != null) {
             mHeadsUpChild.animate().cancel();
+            removeView(mHeadsUpChild);
         }
-        removeAllViews();
         mContractedChild = null;
         mExpandedChild = null;
         mHeadsUpChild = null;
@@ -494,7 +496,8 @@
                 return VISIBLE_TYPE_EXPANDED;
             }
         } else {
-            if (viewHeight <= mContractedChild.getHeight() || noExpandedChild) {
+            if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
+                    && (!mIsChildInGroup || !mContainingNotification.isExpanded()))) {
                 return VISIBLE_TYPE_CONTRACTED;
             } else {
                 return VISIBLE_TYPE_EXPANDED;
@@ -569,6 +572,9 @@
         if (mIsChildInGroup) {
             mSingleLineView = mHybridViewManager.bindFromNotification(
                     mSingleLineView, mStatusBarNotification.getNotification());
+        } else if (mSingleLineView != null) {
+            removeView(mSingleLineView);
+            mSingleLineView = null;
         }
     }
 
@@ -685,4 +691,12 @@
     public void requestSelectLayout(boolean needsAnimation) {
         selectLayout(needsAnimation, false);
     }
+
+    public void reInflateViews() {
+        if (mIsChildInGroup && mSingleLineView != null) {
+            removeView(mSingleLineView);
+            mSingleLineView = null;
+            updateSingleLineView();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index dd6d6f3..7346bec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -113,15 +113,15 @@
                 ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString(
                 com.android.internal.R.string.default_notification_topic_label))
                 : sbn.getNotification().getTopic();
-        boolean doesAppUseTopics = false;
+        boolean doesUserUseTopics = false;
         try {
-            doesAppUseTopics =
-                    mINotificationManager.doesAppUseTopics(sbn.getPackageName(), sbn.getUid());
+            doesUserUseTopics =
+                    mINotificationManager.doesUserUseTopics(sbn.getPackageName(), sbn.getUid());
         } catch (RemoteException e) {}
-        final boolean appUsesTopics = doesAppUseTopics;
+        final boolean userUsesTopics = doesUserUseTopics;
 
         mApplyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic);
-        if (appUsesTopics) {
+        if (userUsesTopics) {
             mApplyToTopic.setChecked(true);
         }
         final View applyToApp = row.findViewById(R.id.apply_to_app);
@@ -156,7 +156,7 @@
                 updateTitleAndSummary(progress);
                 if (fromUser) {
                     MetricsLogger.action(mContext, MetricsEvent.ACTION_MODIFY_IMPORTANCE_SLIDER);
-                    if (appUsesTopics) {
+                    if (userUsesTopics) {
                         mApplyToTopic.setVisibility(View.VISIBLE);
                         mApplyToTopic.setText(
                                 mContext.getString(R.string.apply_to_topic, mTopic.getLabel()));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 6801e5f..9aa5ea0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -21,6 +21,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.telephony.SubscriptionInfo;
@@ -80,6 +81,7 @@
     private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
     private int mIconTint = Color.WHITE;
     private float mDarkIntensity;
+    private final Rect mTintArea = new Rect();
 
     ViewGroup mEthernetGroup, mWifiGroup;
     View mNoSimsCombo;
@@ -490,23 +492,31 @@
         }
     }
 
-    public void setIconTint(int tint, float darkIntensity) {
-        boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity;
+    public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
+        boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity
+                || !mTintArea.equals(tintArea);
         mIconTint = tint;
         mDarkIntensity = darkIntensity;
+        mTintArea.set(tintArea);
         if (changed && isAttachedToWindow()) {
             applyIconTint();
         }
     }
 
     private void applyIconTint() {
-        setTint(mVpn, mIconTint);
-        setTint(mAirplane, mIconTint);
-        applyDarkIntensity(mDarkIntensity, mNoSims, mNoSimsDark);
-        applyDarkIntensity(mDarkIntensity, mWifi, mWifiDark);
-        applyDarkIntensity(mDarkIntensity, mEthernet, mEthernetDark);
+        setTint(mVpn, StatusBarIconController.getTint(mTintArea, mVpn, mIconTint));
+        setTint(mAirplane, StatusBarIconController.getTint(mTintArea, mAirplane, mIconTint));
+        applyDarkIntensity(
+                StatusBarIconController.getDarkIntensity(mTintArea, mNoSims, mDarkIntensity),
+                mNoSims, mNoSimsDark);
+        applyDarkIntensity(
+                StatusBarIconController.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
+                mWifi, mWifiDark);
+        applyDarkIntensity(
+                StatusBarIconController.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
+                mEthernet, mEthernetDark);
         for (int i = 0; i < mPhoneStates.size(); i++) {
-            mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity);
+            mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity, mTintArea);
         }
     }
 
@@ -613,9 +623,11 @@
             }
         }
 
-        public void setIconTint(int tint, float darkIntensity) {
-            applyDarkIntensity(darkIntensity, mMobile, mMobileDark);
-            setTint(mMobileType, tint);
+        public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
+            applyDarkIntensity(
+                    StatusBarIconController.getDarkIntensity(tintArea, mMobile, darkIntensity),
+                    mMobile, mMobileDark);
+            setTint(mMobileType, StatusBarIconController.getTint(tintArea, mMobileType, tint));
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 60c1911..aa001ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -45,4 +45,10 @@
             mInvertHelper.update(dark);
         }
     }
+
+    @Override
+    public void setVisible(boolean visible) {
+        super.setVisible(visible);
+        mView.setAlpha(visible ? 1.0f : 0.0f);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index a2b4c5d..328f8b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -105,6 +105,7 @@
 
     @Override
     public void setVisible(boolean visible) {
+        mView.animate().cancel();
         mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 5832d86..67d31be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -293,14 +293,19 @@
         mTransformedView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
         mTransformedView.setAlpha(visible ? 1.0f : 0.0f);
         if (visible) {
-            mTransformedView.setTranslationX(0);
-            mTransformedView.setTranslationY(0);
-            mTransformedView.setScaleX(1.0f);
-            mTransformedView.setScaleY(1.0f);
+            resetTransformedView();
         }
     }
 
     public void prepareFadeIn() {
+        resetTransformedView();
+    }
+
+    private void resetTransformedView() {
+        mTransformedView.setTranslationX(0);
+        mTransformedView.setTranslationY(0);
+        mTransformedView.setScaleX(1.0f);
+        mTransformedView.setScaleY(1.0f);
     }
 
     public static TransformState obtain() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
new file mode 100644
index 0000000..f98b9e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import com.android.systemui.statusbar.policy.BatteryController;
+
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+
+/**
+ * Controls how light status bar flag applies to the icons.
+ */
+public class LightStatusBarController {
+
+    private final StatusBarIconController mIconController;
+    private final BatteryController mBatteryController;
+    private FingerprintUnlockController mFingerprintUnlockController;
+
+    private int mFullscreenStackVisibility;
+    private int mDockedStackVisibility;
+    private boolean mFullscreenLight;
+    private boolean mDockedLight;
+
+    private final Rect mLastFullscreenBounds = new Rect();
+    private final Rect mLastDockedBounds = new Rect();
+
+    public LightStatusBarController(StatusBarIconController iconController,
+            BatteryController batteryController) {
+        mIconController = iconController;
+        mBatteryController = batteryController;
+    }
+
+    public void setFingerprintUnlockController(
+            FingerprintUnlockController fingerprintUnlockController) {
+        mFingerprintUnlockController = fingerprintUnlockController;
+    }
+
+    public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis, int mask,
+            Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged,
+            int statusBarMode) {
+        int oldFullscreen = mFullscreenStackVisibility;
+        int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask);
+        int diffFullscreen = newFullscreen ^ oldFullscreen;
+        int oldDocked = mDockedStackVisibility;
+        int newDocked = (oldDocked & ~mask) | (dockedStackVis & mask);
+        int diffDocked = newDocked ^ oldDocked;
+        if ((diffFullscreen & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
+                || (diffDocked & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
+                || sbModeChanged
+                || !mLastFullscreenBounds.equals(fullscreenStackBounds)
+                || !mLastDockedBounds.equals(dockedStackBounds)) {
+
+            mFullscreenLight = isLight(newFullscreen, statusBarMode);
+            mDockedLight = isLight(newDocked, statusBarMode);
+            update(fullscreenStackBounds, dockedStackBounds);
+        }
+        mFullscreenStackVisibility = newFullscreen;
+        mDockedStackVisibility = newDocked;
+        mLastFullscreenBounds.set(fullscreenStackBounds);
+        mLastDockedBounds.set(dockedStackBounds);
+    }
+
+    private boolean isLight(int vis, int statusBarMode) {
+        boolean isTransparentBar = (statusBarMode == MODE_TRANSPARENT
+                || statusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
+        boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
+        boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
+        return allowLight && light;
+    }
+
+    private boolean animateChange() {
+        if (mFingerprintUnlockController == null) {
+            return false;
+        }
+        int unlockMode = mFingerprintUnlockController.getMode();
+        return unlockMode != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+                && unlockMode != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
+    }
+
+    private void update(Rect fullscreenStackBounds, Rect dockedStackBounds) {
+        boolean hasDockedStack = !dockedStackBounds.isEmpty();
+
+        // If both are light or fullscreen is light and there is no docked stack, all icons get
+        // dark.
+        if ((mFullscreenLight && mDockedLight) || (mFullscreenLight && !hasDockedStack)) {
+            mIconController.setIconsDarkArea(null);
+            mIconController.setIconsDark(true, animateChange());
+
+        }
+
+        // If no one is light or the fullscreen is not light and there is no docked stack,
+        // all icons become white.
+        else if ((!mFullscreenLight && !mDockedLight) || (!mFullscreenLight && !hasDockedStack)) {
+            mIconController.setIconsDark(false, animateChange());
+
+        }
+
+        // Not the same for every stack, magic!
+        else {
+            Rect bounds = mFullscreenLight ? fullscreenStackBounds : dockedStackBounds;
+            if (bounds.isEmpty()) {
+                mIconController.setIconsDarkArea(null);
+            } else {
+                mIconController.setIconsDarkArea(bounds);
+            }
+            mIconController.setIconsDark(true, animateChange());
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 03a597c..6e345f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -4,6 +4,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
@@ -32,6 +33,7 @@
     protected View mNotificationIconArea;
     private IconMerger mNotificationIcons;
     private ImageView mMoreIcon;
+    private final Rect mTintArea = new Rect();
 
     public NotificationIconAreaController(Context context, PhoneStatusBar phoneStatusBar) {
         mPhoneStatusBar = phoneStatusBar;
@@ -67,6 +69,20 @@
     }
 
     /**
+     * See {@link StatusBarIconController#setIconsDarkArea}.
+     *
+     * @param tintArea the area in which to tint the icons, specified in screen coordinates
+     */
+    public void setTintArea(Rect tintArea) {
+        if (tintArea == null) {
+            mTintArea.setEmpty();
+        } else {
+            mTintArea.set(tintArea);
+        }
+        applyNotificationIconsTint();
+    }
+
+    /**
      * Sets the color that should be used to tint any icons in the notification area. If this
      * method is not called, the default tint is {@link Color#WHITE}.
      */
@@ -145,7 +161,8 @@
             boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
             boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil);
             if (colorize) {
-                v.setImageTintList(ColorStateList.valueOf(mIconTint));
+                v.setImageTintList(ColorStateList.valueOf(
+                        StatusBarIconController.getTint(mTintArea, v, mIconTint)));
             }
         }
     }
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 14376ac..278dfe6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -69,6 +69,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.Vibrator;
@@ -88,6 +89,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
 import android.view.ViewStub;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -296,6 +298,7 @@
     BrightnessMirrorController mBrightnessMirrorController;
     AccessibilityController mAccessibilityController;
     FingerprintUnlockController mFingerprintUnlockController;
+    LightStatusBarController mLightStatusBarController;
 
     int mNaturalBarHeight = -1;
 
@@ -340,6 +343,9 @@
     private long mKeyguardFadingAwayDelay;
     private long mKeyguardFadingAwayDuration;
 
+    // RemoteInputView to be activated after unlock
+    private View mPendingRemoteInputView;
+
     int mMaxAllowedKeyguardNotifications;
 
     boolean mExpandedVisible;
@@ -361,6 +367,8 @@
 
     // tracking calls to View.setSystemUiVisibility()
     int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
+    private final Rect mLastFullscreenStackBounds = new Rect();
+    private final Rect mLastDockedStackBounds = new Rect();
 
     // last value sent to window manager
     private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
@@ -844,6 +852,8 @@
         mAccessibilityController = new AccessibilityController(mContext);
         mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
         mNextAlarmController = new NextAlarmController(mContext);
+        mLightStatusBarController = new LightStatusBarController(mIconController,
+                mBatteryController);
         mKeyguardMonitor = new KeyguardMonitor(mContext);
         if (UserManager.get(mContext).isUserSwitcherEnabled()) {
             mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
@@ -1089,6 +1099,7 @@
         mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
+        mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
     }
 
     @Override
@@ -1500,8 +1511,8 @@
     }
 
     private void updateNotificationShadeForChildren() {
+        // First let's remove all children which don't belong in the parents
         ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
-        boolean orderChanged = false;
         for (int i = 0; i < mStackScroller.getChildCount(); i++) {
             View view = mStackScroller.getChildAt(i);
             if (!(view instanceof ExpandableNotificationRow)) {
@@ -1513,7 +1524,6 @@
             List<ExpandableNotificationRow> children = parent.getNotificationChildren();
             List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
 
-            // lets first remove all undesired children
             if (children != null) {
                 toRemove.clear();
                 for (ExpandableNotificationRow childRow : children) {
@@ -1526,8 +1536,21 @@
                     mStackScroller.notifyGroupChildRemoved(remove);
                 }
             }
+        }
 
-            // We now add all the children which are not in there already
+        // Let's now add all notification children which are missing
+        boolean orderChanged = false;
+        for (int i = 0; i < mStackScroller.getChildCount(); i++) {
+            View view = mStackScroller.getChildAt(i);
+            if (!(view instanceof ExpandableNotificationRow)) {
+                // We don't care about non-notification views.
+                continue;
+            }
+
+            ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+            List<ExpandableNotificationRow> children = parent.getNotificationChildren();
+            List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
+
             for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
                     childIndex++) {
                 ExpandableNotificationRow childView = orderedChildren.get(childIndex);
@@ -2238,7 +2261,7 @@
 
     @Override
     public void maybeEscalateHeadsUp() {
-        TreeSet<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getSortedEntries();
+        Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries();
         for (HeadsUpManager.HeadsUpEntry entry : entries) {
             final StatusBarNotification sbn = entry.entry.notification;
             final Notification notification = sbn.getNotification();
@@ -2524,7 +2547,8 @@
     }
 
     @Override // CommandQueue
-    public void setSystemUiVisibility(int vis, int mask) {
+    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
         final int oldVal = mSystemUiVisibility;
         final int newVal = (oldVal&~mask) | (vis&mask);
         final int diff = newVal ^ oldVal;
@@ -2533,6 +2557,7 @@
                 Integer.toHexString(vis), Integer.toHexString(mask),
                 Integer.toHexString(oldVal), Integer.toHexString(newVal),
                 Integer.toHexString(diff)));
+        boolean sbModeChanged = false;
         if (diff != 0) {
             // we never set the recents bit via this method, so save the prior state to prevent
             // clobbering the bit below
@@ -2566,7 +2591,7 @@
                     oldVal, newVal, mNavigationBarView.getBarTransitions(),
                     View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
                     View.NAVIGATION_BAR_TRANSPARENT);
-            final boolean sbModeChanged = sbMode != -1;
+            sbModeChanged = sbMode != -1;
             final boolean nbModeChanged = nbMode != -1;
             boolean checkBarModes = false;
             if (sbModeChanged && sbMode != mStatusBarMode) {
@@ -2593,18 +2618,6 @@
                 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
             }
 
-            if ((diff & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 || sbModeChanged) {
-                boolean isTransparentBar = (mStatusBarMode == MODE_TRANSPARENT
-                        || mStatusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
-                boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
-                boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
-                boolean animate = mFingerprintUnlockController == null
-                        || (mFingerprintUnlockController.getMode()
-                                != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
-                        && mFingerprintUnlockController.getMode()
-                                != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK);
-                mIconController.setIconsDark(allowLight && light, animate);
-            }
             // restore the recents bit
             if (wasRecentsVisible) {
                 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
@@ -2613,6 +2626,9 @@
             // send updated sysui visibility to window manager
             notifyUiVisibilityChanged(mSystemUiVisibility);
         }
+
+        mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
+                mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
     }
 
     private int computeBarMode(int oldVis, int newVis, BarTransitions transitions,
@@ -2740,9 +2756,12 @@
     public void setLightsOn(boolean on) {
         Log.v(TAG, "setLightsOn(" + on + ")");
         if (on) {
-            setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
+            setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
+                    mLastFullscreenStackBounds, mLastDockedStackBounds);
         } else {
-            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE);
+            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
+                    View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
+                    mLastDockedStackBounds);
         }
     }
 
@@ -3564,6 +3583,7 @@
             mDraggedDownRow.notifyHeightChanged(false  /* needsAnimation */);
             mDraggedDownRow = null;
         }
+        mPendingRemoteInputView = null;
         mAssistManager.onLockscreenShown();
     }
 
@@ -3680,6 +3700,7 @@
     public boolean hideKeyguard() {
         boolean staying = mLeaveOpenOnKeyguardHide;
         setBarState(StatusBarState.SHADE);
+        View viewToClick = null;
         if (mLeaveOpenOnKeyguardHide) {
             mLeaveOpenOnKeyguardHide = false;
             long delay = calculateGoingToFullShadeDelay();
@@ -3688,6 +3709,8 @@
                 mDraggedDownRow.setUserLocked(false);
                 mDraggedDownRow = null;
             }
+            viewToClick = mPendingRemoteInputView;
+            mPendingRemoteInputView = null;
 
             // Disable layout transitions in navbar for this transition because the load is just
             // too heavy for the CPU and GPU on any device.
@@ -3705,6 +3728,10 @@
         }
         updateKeyguardState(staying, false /* fromShadeLocked */);
 
+        if (viewToClick != null) {
+            viewToClick.callOnClick();
+        }
+
         // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
         // visibilities so next time we open the panel we know the correct height already.
         if (mQSPanel != null) {
@@ -4068,6 +4095,7 @@
             mLeaveOpenOnKeyguardHide = true;
             showBouncer();
             mDraggedDownRow = row;
+            mPendingRemoteInputView = null;
         } else {
             mNotificationPanel.animateToFullShade(0 /* delay */);
             setBarState(StatusBarState.SHADE_LOCKED);
@@ -4076,6 +4104,13 @@
     }
 
     @Override
+    protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
+        mLeaveOpenOnKeyguardHide = true;
+        showBouncer();
+        mPendingRemoteInputView = clicked;
+    }
+
+    @Override
     public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
         mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
         if (mState == StatusBarState.KEYGUARD && nowExpanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 45aae2d..f61f31e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -22,6 +22,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.Handler;
@@ -58,8 +59,8 @@
 public class StatusBarIconController extends StatusBarIconList implements Tunable {
 
     public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
-
     public static final String ICON_BLACKLIST = "icon_blacklist";
+    public static final int DEFAULT_ICON_TINT = Color.WHITE;
 
     private Context mContext;
     private PhoneStatusBar mPhoneStatusBar;
@@ -79,8 +80,11 @@
     private int mIconSize;
     private int mIconHPadding;
 
-    private int mIconTint = Color.WHITE;
+    private int mIconTint = DEFAULT_ICON_TINT;
     private float mDarkIntensity;
+    private final Rect mTintArea = new Rect();
+    private static final Rect sTmpRect = new Rect();
+    private static final int[] sTmpInt2 = new int[2];
 
     private boolean mTransitionPending;
     private boolean mTintChangePending;
@@ -395,6 +399,25 @@
         }
     }
 
+    /**
+     * Sets the dark area so {@link #setIconsDark} only affects the icons in the specified area.
+     *
+     * @param darkArea the area in which icons should change it's tint, in logical screen
+     *                 coordinates
+     */
+    public void setIconsDarkArea(Rect darkArea) {
+        if (darkArea == null && mTintArea.isEmpty()) {
+            return;
+        }
+        if (darkArea == null) {
+            mTintArea.setEmpty();
+        } else {
+            mTintArea.set(darkArea);
+        }
+        applyIconTint();
+        mNotificationIconAreaController.setTintArea(darkArea);
+    }
+
     public void setIconsDark(boolean dark, boolean animate) {
         if (!animate) {
             setIconTintInternal(dark ? 1.0f : 0.0f);
@@ -446,14 +469,60 @@
         mPendingDarkIntensity = darkIntensity;
     }
 
+    /**
+     * @return the tint to apply to {@param view} depending on the desired tint {@param color} and
+     *         the screen {@param tintArea} in which to apply that tint
+     */
+    public static int getTint(Rect tintArea, View view, int color) {
+        if (isInArea(tintArea, view)) {
+            return color;
+        } else {
+            return DEFAULT_ICON_TINT;
+        }
+    }
+
+    /**
+     * @return the dark intensity to apply to {@param view} depending on the desired dark
+     *         {@param intensity} and the screen {@param tintArea} in which to apply that intensity
+     */
+    public static float getDarkIntensity(Rect tintArea, View view, float intensity) {
+        if (isInArea(tintArea, view)) {
+            return intensity;
+        } else {
+            return 0f;
+        }
+    }
+
+    /**
+     * @return true if more than half of the {@param view} area are in {@param area}, false
+     *         otherwise
+     */
+    private static boolean isInArea(Rect area, View view) {
+        if (area.isEmpty()) {
+            return true;
+        }
+        sTmpRect.set(area);
+        view.getLocationOnScreen(sTmpInt2);
+        int left = sTmpInt2[0];
+
+        int intersectStart = Math.max(left, area.left);
+        int intersectEnd = Math.min(left + view.getWidth(), area.right);
+        int intersectAmount = Math.max(0, intersectEnd - intersectStart);
+
+        boolean coversFullStatusBar = area.top <= 0;
+        boolean majorityOfWidth = 2 * intersectAmount > view.getWidth();
+        return majorityOfWidth && coversFullStatusBar;
+    }
+
     private void applyIconTint() {
         for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
             StatusBarIconView v = (StatusBarIconView) mStatusIcons.getChildAt(i);
-            v.setImageTintList(ColorStateList.valueOf(mIconTint));
+            v.setImageTintList(ColorStateList.valueOf(getTint(mTintArea, v, mIconTint)));
         }
-        mSignalCluster.setIconTint(mIconTint, mDarkIntensity);
-        mBatteryMeterView.setDarkIntensity(mDarkIntensity);
-        mClock.setTextColor(mIconTint);
+        mSignalCluster.setIconTint(mIconTint, mDarkIntensity, mTintArea);
+        mBatteryMeterView.setDarkIntensity(
+                isInArea(mTintArea, mBatteryMeterView) ? mDarkIntensity : 0);
+        mClock.setTextColor(getTint(mTintArea, mClock, mIconTint));
     }
 
     public void appTransitionPending() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index f065522..ab81712 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -39,10 +39,10 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Stack;
-import java.util.TreeSet;
 
 /**
  * A manager which handles heads up notifications which is a special mode where
@@ -90,7 +90,6 @@
     private int mSnoozeLengthMs;
     private ContentObserver mSettingsObserver;
     private HashMap<String, HeadsUpEntry> mHeadsUpEntries = new HashMap<>();
-    private TreeSet<HeadsUpEntry> mSortedEntries = new TreeSet<>();
     private HashSet<String> mSwipedOutKeys = new HashSet<>();
     private int mUser;
     private Clock mClock;
@@ -230,7 +229,6 @@
 
     private void removeHeadsUpEntry(NotificationData.Entry entry) {
         HeadsUpEntry remove = mHeadsUpEntries.remove(entry.key);
-        mSortedEntries.remove(remove);
         entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
         entry.row.setHeadsUp(false);
         setEntryPinned(remove, false /* isPinned */);
@@ -345,12 +343,21 @@
         return mHeadsUpEntries.get(key).entry;
     }
 
-    public TreeSet<HeadsUpEntry> getSortedEntries() {
-        return mSortedEntries;
+    public Collection<HeadsUpEntry> getAllEntries() {
+        return mHeadsUpEntries.values();
     }
 
     public HeadsUpEntry getTopEntry() {
-        return mSortedEntries.isEmpty() ? null : mSortedEntries.first();
+        if (mHeadsUpEntries.isEmpty()) {
+            return null;
+        }
+        HeadsUpEntry topEntry = null;
+        for (HeadsUpEntry entry: mHeadsUpEntries.values()) {
+            if (topEntry == null || entry.compareTo(topEntry) == -1) {
+                topEntry = entry;
+            }
+        }
+        return topEntry;
     }
 
     /**
@@ -374,26 +381,18 @@
             return;
         }
         if (mHasPinnedNotification) {
-            int minX = 0;
-            int maxX = 0;
-            int maxY = 0;
-            for (HeadsUpEntry entry : mSortedEntries) {
-                ExpandableNotificationRow row = entry.entry.row;
-                if (row.isPinned()) {
-                    if (row.isChildInGroup()) {
-                        final ExpandableNotificationRow groupSummary
-                                = mGroupManager.getGroupSummary(row.getStatusBarNotification());
-                        if (groupSummary != null) {
-                            row = groupSummary;
-                        }
-                    }
-                    row.getLocationOnScreen(mTmpTwoArray);
-                    minX = mTmpTwoArray[0];
-                    maxX = mTmpTwoArray[0] + row.getWidth();
-                    maxY = row.getIntrinsicHeight();
-                    break;
+            ExpandableNotificationRow topEntry = getTopEntry().entry.row;
+            if (topEntry.isChildInGroup()) {
+                final ExpandableNotificationRow groupSummary
+                        = mGroupManager.getGroupSummary(topEntry.getStatusBarNotification());
+                if (groupSummary != null) {
+                    topEntry = groupSummary;
                 }
             }
+            topEntry.getLocationOnScreen(mTmpTwoArray);
+            int minX = mTmpTwoArray[0];
+            int maxX = mTmpTwoArray[0] + topEntry.getWidth();
+            int maxY = topEntry.getIntrinsicHeight();
 
             info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
             info.touchableRegion.set(minX, 0, maxX, maxY);
@@ -413,7 +412,7 @@
         pw.print("  mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
         pw.print("  now="); pw.println(SystemClock.elapsedRealtime());
         pw.print("  mUser="); pw.println(mUser);
-        for (HeadsUpEntry entry: mSortedEntries) {
+        for (HeadsUpEntry entry: mHeadsUpEntries.values()) {
             pw.print("  HeadsUpEntry="); pw.println(entry.entry);
         }
         int N = mSnoozedPackages.size();
@@ -633,7 +632,6 @@
         }
 
         public void updateEntry(boolean updatePostTime) {
-            mSortedEntries.remove(HeadsUpEntry.this);
             long currentTime = mClock.currentTimeMillis();
             earliestRemovaltime = currentTime + mMinimumDisplayTime;
             if (updatePostTime) {
@@ -648,7 +646,6 @@
                 long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
                 mHandler.postDelayed(mRemoveHeadsUpRunnable, removeDelay);
             }
-            mSortedEntries.add(HeadsUpEntry.this);
         }
 
         private boolean isSticky() {
@@ -658,6 +655,13 @@
 
         @Override
         public int compareTo(HeadsUpEntry o) {
+            boolean isPinned = entry.row.isPinned();
+            boolean otherPinned = o.entry.row.isPinned();
+            if (isPinned && !otherPinned) {
+                return -1;
+            } else if (!isPinned && otherPinned) {
+                return 1;
+            }
             boolean selfFullscreen = hasFullScreenIntent(entry);
             boolean otherFullscreen = hasFullScreenIntent(o.entry);
             if (selfFullscreen && !otherFullscreen) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 784f610..110258c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.tv;
 
 import android.content.ComponentName;
+import android.graphics.Rect;
 import android.os.IBinder;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
@@ -68,7 +69,8 @@
     }
 
     @Override
-    public void setSystemUiVisibility(int vis, int mask) {
+    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
     }
 
     @Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index b79a7ba..ad70853 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -110,9 +110,25 @@
     // The minimal score for accepting a predicted gesture.
     private static final float MIN_PREDICTION_SCORE = 2.0f;
 
+    // Distance a finger must travel before we decide if it is a gesture or not.
     private static final int GESTURE_CONFIRM_MM = 10;
-    private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 1000;
-    private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 500;
+
+    // Time threshold used to determine if an interaction is a gesture or not.
+    // If the first movement of 1cm takes longer than this value, we assume it's
+    // a slow movement, and therefore not a gesture.
+    //
+    // This value was determined by measuring the time for the first 1cm
+    // movement when gesturing, and touch exploring.  Based on user testing,
+    // all gestures started with the initial movement taking less than 100ms.
+    // When touch exploring, the first movement almost always takes longer than
+    // 200ms.  From this data, 150ms seems the best value to decide what
+    // kind of interaction it is.
+    private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
+
+    // Time threshold used to determine if a gesture should be cancelled.  If
+    // the finger pauses for longer than this delay, the ongoing gesture is
+    // cancelled.
+    private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 500;
 
     AccessibilityGestureDetector(Context context, Listener listener) {
         mListener = listener;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 7149065..f8bf59d2 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -87,6 +87,7 @@
 import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.StringBuilderPrinter;
@@ -142,6 +143,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.zip.Deflater;
 import java.util.zip.DeflaterOutputStream;
 import java.util.zip.InflaterInputStream;
@@ -786,8 +788,9 @@
             case MSG_OP_COMPLETE:
             {
                 try {
-                    BackupRestoreTask task = (BackupRestoreTask) msg.obj;
-                    task.operationComplete(msg.arg1);
+                    Pair<BackupRestoreTask, Long> taskWithResult =
+                            (Pair<BackupRestoreTask, Long>) msg.obj;
+                    taskWithResult.first.operationComplete(taskWithResult.second);
                 } catch (ClassCastException e) {
                     Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj);
                 }
@@ -2460,7 +2463,7 @@
         void execute();
 
         // An operation that wanted a callback has completed
-        void operationComplete(int result);
+        void operationComplete(long result);
 
         // An operation that wanted a callback has timed out
         void handleTimeout();
@@ -3095,7 +3098,7 @@
         }
 
         @Override
-        public void operationComplete(int unusedResult) {
+        public void operationComplete(long unusedResult) {
             // The agent reported back to us!
 
             if (mBackupData == null) {
@@ -3494,7 +3497,7 @@
          */
         int preflightFullBackup(PackageInfo pkg, IBackupAgent agent);
 
-        long expectedSize();
+        long getExpectedSizeOrErrorCode();
     };
 
     class FullBackupEngine {
@@ -4532,7 +4535,7 @@
         // a standalone thread.  The  runner owns this half of the pipe, and closes
         // it to indicate EOD to the other end.
         class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight {
-            final AtomicInteger mResult = new AtomicInteger();
+            final AtomicLong mResult = new AtomicLong();
             final CountDownLatch mLatch = new CountDownLatch(1);
             final IBackupTransport mTransport;
 
@@ -4554,7 +4557,11 @@
 
                     // now wait to get our result back
                     mLatch.await();
-                    int totalSize = mResult.get();
+                    long totalSize = mResult.get();
+                    // If preflight timeouted, mResult will contain error code as int.
+                    if (totalSize < 0) {
+                        return (int) totalSize;
+                    }
                     if (MORE_DEBUG) {
                         Slog.v(TAG, "Got preflight response; size=" + totalSize);
                     }
@@ -4581,7 +4588,7 @@
             }
 
             @Override
-            public void operationComplete(int result) {
+            public void operationComplete(long result) {
                 // got the callback, and our preflightFullBackup() method is waiting for the result
                 if (MORE_DEBUG) {
                     Slog.i(TAG, "Preflight op complete, result=" + result);
@@ -4600,7 +4607,7 @@
             }
 
             @Override
-            public long expectedSize() {
+            public long getExpectedSizeOrErrorCode() {
                 try {
                     mLatch.await();
                     return mResult.get();
@@ -4649,7 +4656,7 @@
             }
 
             long expectedSize() {
-                return mPreflight.expectedSize();
+                return mPreflight.getExpectedSizeOrErrorCode();
             }
         }
     }
@@ -8558,7 +8565,7 @@
         }
 
         @Override
-        public void operationComplete(int unusedResult) {
+        public void operationComplete(long unusedResult) {
             if (MORE_DEBUG) {
                 Slog.i(TAG, "operationComplete() during restore: target="
                         + mCurrentPackage.packageName
@@ -9643,9 +9650,8 @@
 
         // The completion callback, if any, is invoked on the handler
         if (op != null && op.callback != null) {
-            Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, op.callback);
-            // NB: this cannot distinguish between results > 2 gig
-            msg.arg1 = (result > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) result;
+            Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(op.callback, result);
+            Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult);
             mBackupHandler.sendMessage(msg);
         }
     }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 4dbb490..c318140 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.ActivityManagerNative;
+import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -34,6 +35,7 @@
 import android.content.res.Resources;
 
 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
+import static android.content.Context.KEYGUARD_SERVICE;
 import static android.content.Context.USER_SERVICE;
 import static android.Manifest.permission.READ_CONTACTS;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -124,7 +126,7 @@
         @Override
         public void onBootPhase(int phase) {
             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
-                mLockSettingsService.maybeShowEncryptionNotification(UserHandle.ALL);
+                mLockSettingsService.maybeShowEncryptionNotifications();
             } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
                 // TODO
             }
@@ -176,22 +178,48 @@
      * If the account is credential-encrypted, show notification requesting the user to unlock
      * the device.
      */
-    private void maybeShowEncryptionNotification(UserHandle userHandle) {
-        if (UserHandle.ALL.equals(userHandle)) {
-            final List<UserInfo> users = mUserManager.getUsers();
-            for (int i = 0; i < users.size(); i++) {
-                UserHandle user = users.get(i).getUserHandle();
-                if (!mUserManager.isUserUnlocked(user)) {
-                    showEncryptionNotification(user);
+    private void maybeShowEncryptionNotifications() {
+        final List<UserInfo> users = mUserManager.getUsers();
+        for (int i = 0; i < users.size(); i++) {
+            UserInfo user = users.get(i);
+            UserHandle userHandle = user.getUserHandle();
+            if (!mUserManager.isUserUnlocked(userHandle)) {
+                if (!user.isManagedProfile()) {
+                    showEncryptionNotification(userHandle);
+                } else {
+                    UserInfo parent = mUserManager.getProfileParent(user.id);
+                    if (parent != null && mUserManager.isUserUnlocked(parent.getUserHandle())) {
+                        // Only show notifications for managed profiles once their parent
+                        // user is unlocked.
+                        showEncryptionNotificationForProfile(userHandle);
+                    }
                 }
             }
-        } else if (!mUserManager.isUserUnlocked(userHandle)){
-            showEncryptionNotification(userHandle);
         }
     }
 
+    private void showEncryptionNotificationForProfile(UserHandle user) {
+        Resources r = mContext.getResources();
+        CharSequence title = r.getText(
+                com.android.internal.R.string.user_encrypted_title);
+        CharSequence message = r.getText(
+                com.android.internal.R.string.profile_encrypted_message);
+        CharSequence detail = r.getText(
+                com.android.internal.R.string.profile_encrypted_detail);
+
+        final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
+        final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, user.getIdentifier());
+        if (unlockIntent == null) {
+            return;
+        }
+        unlockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
+                PendingIntent.FLAG_UPDATE_CURRENT);
+
+        showEncryptionNotification(user, title, message, detail, intent);
+    }
+
     private void showEncryptionNotification(UserHandle user) {
-        if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
         Resources r = mContext.getResources();
         CharSequence title = r.getText(
                 com.android.internal.R.string.user_encrypted_title);
@@ -203,6 +231,12 @@
         PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
                 PendingIntent.FLAG_UPDATE_CURRENT);
 
+        showEncryptionNotification(user, title, message, detail, intent);
+    }
+
+    private void showEncryptionNotification(UserHandle user, CharSequence title, CharSequence message,
+            CharSequence detail, PendingIntent intent) {
+        if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
         Notification notification = new Notification.Builder(mContext)
                 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
                 .setWhen(0)
@@ -230,8 +264,21 @@
         hideEncryptionNotification(new UserHandle(userId));
     }
 
-    public void onUnlockUser(int userHandle) {
-        hideEncryptionNotification(new UserHandle(userHandle));
+    public void onUnlockUser(int userId) {
+        hideEncryptionNotification(new UserHandle(userId));
+
+        // Now we have unlocked the parent user we should show notifications
+        // about any profiles that exist.
+        List<UserInfo> profiles = mUserManager.getProfiles(userId);
+        for (int i = 0; i < profiles.size(); i++) {
+            UserInfo profile = profiles.get(i);
+            if (profile.isManagedProfile()) {
+                UserHandle userHandle = profile.getUserHandle();
+                if (!mUserManager.isUserUnlocked(userHandle)) {
+                    showEncryptionNotificationForProfile(userHandle);
+                }
+            }
+        }
     }
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 95f5734..799d0bd 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -2086,7 +2086,7 @@
             final int oldUidFirewallRule = uidFirewallRules.get(uid, FIREWALL_RULE_DEFAULT);
             if (DBG) {
                 Slog.d(TAG, "oldRule = " + oldUidFirewallRule
-                        + ", newRule=" + rule + " for uid=" + uid);
+                        + ", newRule=" + rule + " for uid=" + uid + " on chain " + chain);
             }
             if (oldUidFirewallRule == rule) {
                 if (DBG) Slog.d(TAG, "!!!!! Skipping change");
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index bef6f0a..1b9d968 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -62,7 +62,7 @@
     static final boolean DEBUG_LRU = DEBUG_ALL || false;
     static final boolean DEBUG_MU = DEBUG_ALL || false;
     static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
-    static final boolean DEBUG_PAUSE = DEBUG_ALL || true;
+    static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
     static final boolean DEBUG_POWER = DEBUG_ALL || false;
     static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
     static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
@@ -85,7 +85,7 @@
     static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false;
     static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
     static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
-    static final boolean DEBUG_VISIBILITY = DEBUG_ALL || true;
+    static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
     static final boolean DEBUG_VISIBLE_BEHIND = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
     static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 75dabc96..1103ea4 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -768,7 +768,6 @@
         r.state = ActivityState.RESUMED;
         if (DEBUG_STATES) Slog.v(TAG_STATES,
                 "Moving to RESUMED: " + r + " (starting new instance)");
-        r.stopped = false;
         mResumedActivity = r;
         r.task.touchActiveTime();
         mRecentTasks.addLocked(r.task);
@@ -1228,9 +1227,11 @@
      * this function updates the rest of our state to match that fact.
      */
     private void completeResumeLocked(ActivityRecord next) {
+        next.visible = true;
         next.idle = false;
         next.results = null;
         next.newIntents = null;
+        next.stopped = false;
 
         if (next.isHomeActivity()) {
             ProcessRecord app = next.task.mActivities.get(0).app;
@@ -1729,6 +1730,8 @@
 
         // This activity is not currently visible, but is running. Tell it to become visible.
         if (r.state == ActivityState.RESUMED || r == starting) {
+            Slog.d(TAG_VISIBILITY, "Not making visible, r=" + r + " state=" + r.state
+                    + " starting=" + starting);
             return;
         }
 
@@ -2291,7 +2294,6 @@
             // From this point on, if something goes wrong there is no way
             // to recover the activity.
             try {
-                next.visible = true;
                 completeResumeLocked(next);
             } catch (Exception e) {
                 // If any exception gets thrown, toss away this
@@ -2302,8 +2304,6 @@
                 if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
                 return true;
             }
-            next.stopped = false;
-
         } else {
             // Whoops, need to restart this activity!
             if (!next.hasBeenLaunched) {
@@ -4283,6 +4283,12 @@
                 // "restart!".
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                         "Config is relaunching resumed " + r);
+
+                if (DEBUG_STATES && !r.visible) {
+                    Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + r
+                            + " called by " + Debug.getCallers(4));
+                }
+
                 relaunchActivityLocked(r, r.configChangeFlags, true, preserveWindow);
             } else {
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -4433,9 +4439,21 @@
         }
 
         if (andResume) {
-            r.results = null;
-            r.newIntents = null;
+            if (DEBUG_STATES) {
+                Slog.d(TAG_STATES, "Resumed after relaunch " + r);
+            }
             r.state = ActivityState.RESUMED;
+            // Relaunch-resume could happen either when the app is already in the front,
+            // or while it's being brought to front. In the latter case, it's marked RESUMED
+            // but not yet visible (or stopped). We need to complete the resume here as the
+            // code in resumeTopActivityInnerLocked to complete the resume might be skipped.
+            if (!r.visible || r.stopped) {
+                mWindowManager.setAppVisibility(r.appToken, true);
+                completeResumeLocked(r);
+            } else {
+                r.results = null;
+                r.newIntents = null;
+            }
         } else {
             mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
             r.state = ActivityState.PAUSED;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e90b5db..93a36eb 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1046,10 +1046,14 @@
     }
 
     ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId) {
+        return resolveIntent(intent, resolvedType, userId, 0);
+    }
+
+    ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
         try {
             return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
-                            PackageManager.MATCH_DEFAULT_ONLY
-                            | ActivityManagerService.STOCK_PM_FLAGS, userId);
+                    PackageManager.MATCH_DEFAULT_ONLY | flags
+                    | ActivityManagerService.STOCK_PM_FLAGS, userId);
         } catch (RemoteException e) {
         }
         return null;
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 1ed749f..9b2bca0 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.server.am;
 
 import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 28be456..cca6fc5 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.server.am;
 
 import static android.app.Activity.RESULT_CANCELED;
@@ -74,7 +90,9 @@
 import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -84,6 +102,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.EventLog;
 import android.util.Slog;
@@ -582,6 +601,22 @@
         intent = new Intent(intent);
 
         ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+        if (rInfo == null) {
+            UserInfo userInfo = mSupervisor.getUserInfo(userId);
+            if (userInfo != null && userInfo.isManagedProfile()) {
+                // Special case for managed profiles, if attempting to launch non-cryto aware
+                // app in a locked managed profile from an unlocked parent allow it to resolve
+                // as user will be sent via confirm credentials to unlock the profile.
+                UserManager userManager = UserManager.get(mService.mContext);
+                UserInfo parent = userManager.getProfileParent(userId);
+                if (parent != null
+                        && userManager.isUserUnlocked(parent.getUserHandle())
+                        && !userManager.isUserUnlocked(userInfo.getUserHandle())) {
+                    rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
+                            PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+                }
+            }
+        }
         // Collect information about the target of the Intent.
         ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
 
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index b45430d..16fd909 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1009,6 +1009,7 @@
             String label = null;
             String iconFilename = null;
             int colorPrimary = 0;
+            int colorBackground = 0;
             for (--activityNdx; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = mActivities.get(activityNdx);
                 if (r.taskDescription != null) {
@@ -1021,9 +1022,13 @@
                     if (colorPrimary == 0) {
                         colorPrimary = r.taskDescription.getPrimaryColor();
                     }
+                    if (colorBackground == 0) {
+                        colorBackground = r.taskDescription.getBackgroundColor();
+                    }
                 }
             }
-            lastTaskDescription = new TaskDescription(label, colorPrimary, iconFilename);
+            lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
+                    colorBackground);
             // Update the task affiliation color if we are the parent of the group
             if (taskId == mAffiliatedTaskId) {
                 mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a355fa4..90ebe18 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -165,15 +165,15 @@
         void register(ContentResolver resolver) {
             resolver.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
             synchronized (mService) {
-                updateCurrentUserSetupCompleteLocked();
+                updateUserSetupCompleteLocked(UserHandle.USER_ALL);
             }
         }
 
         @Override
-        public void onChange(boolean selfChange, Uri uri) {
+        public void onChange(boolean selfChange, Uri uri, int userId) {
             if (mUserSetupComplete.equals(uri)) {
                 synchronized (mService) {
-                    updateCurrentUserSetupCompleteLocked();
+                    updateUserSetupCompleteLocked(userId);
                 }
             }
         }
@@ -297,6 +297,22 @@
                         null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
                         userId);
 
+                if (getUserInfo(userId).isManagedProfile()) {
+                    UserInfo parent = getUserManager().getProfileParent(userId);
+                    if (parent != null) {
+                        final Intent profileUnlockedIntent = new Intent(
+                                Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
+                        unlockedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
+                        unlockedIntent.addFlags(
+                                Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                                | Intent.FLAG_RECEIVER_FOREGROUND);
+                        mService.broadcastIntentLocked(null, null, profileUnlockedIntent,
+                                null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+                                null, false, false, MY_PID, SYSTEM_UID,
+                                parent.id);
+                    }
+                }
+
                 final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                 bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                 bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
@@ -655,7 +671,7 @@
                 final Integer userIdInt = userId;
                 mUserLru.remove(userIdInt);
                 mUserLru.add(userIdInt);
-                updateCurrentUserSetupCompleteLocked();
+                updateUserSetupCompleteLocked(userId);
 
                 if (foreground) {
                     mCurrentUserId = userId;
@@ -870,11 +886,16 @@
         mUserSwitchObservers.finishBroadcast();
     }
 
-    void updateCurrentUserSetupCompleteLocked() {
+    void updateUserSetupCompleteLocked(int userId) {
         final ContentResolver cr = mService.mContext.getContentResolver();
-        final boolean setupComplete =
-                Settings.Secure.getIntForUser(cr, USER_SETUP_COMPLETE, 0, mCurrentUserId) != 0;
-        mSetupCompletedUsers.put(mCurrentUserId, setupComplete);
+        for (int i = mStartedUsers.size() - 1; i >= 0; i--) {
+            int startedUser = mStartedUsers.keyAt(i);
+            if (startedUser == userId || userId == UserHandle.USER_ALL) {
+                final boolean setupComplete =
+                        Settings.Secure.getIntForUser(cr, USER_SETUP_COMPLETE, 0, startedUser) != 0;
+                mSetupCompletedUsers.put(startedUser, setupComplete);
+            }
+        }
     }
 
     boolean isUserSetupCompleteLocked(int userId) {
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 218e529..0d97434 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -62,6 +62,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Messenger;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -70,41 +71,42 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
-import android.os.Messenger;
 import android.provider.Settings;
 import android.text.format.DateUtils;
 import android.text.format.Time;
 import android.util.EventLog;
 import android.util.Log;
-import android.util.Slog;
 import android.util.Pair;
-
+import android.util.Slog;
 import android.util.SparseArray;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
 import com.android.internal.R;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.accounts.AccountManagerService;
+import com.android.server.backup.AccountSyncSettingsBackupHelper;
 import com.android.server.content.SyncStorageEngine.AuthorityInfo;
 import com.android.server.content.SyncStorageEngine.EndPoint;
 import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Random;
-import java.util.List;
-import java.util.Set;
-import java.util.HashSet;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Map;
-import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.Random;
+import java.util.Set;
 
 /**
  * Implementation details:
@@ -451,10 +453,48 @@
                         }
                     }
                 }
+                ensureDefaultPeriodicSyncsH();
             }
         });
     }
 
+    private void ensureDefaultPeriodicSyncsH() {
+
+        long defaultPeriod = SyncStorageEngine.DEFAULT_POLL_FREQUENCY_SECONDS;
+        long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(defaultPeriod);
+
+        List<AuthorityInfo> authorities = mSyncStorageEngine.getAllAuthorities();
+        List<SyncOperation> syncs = getAllPendingSyncsFromCache();
+        for (AuthorityInfo authority: authorities) {
+            boolean foundPeriodicSync = false;
+            for (SyncOperation op: syncs) {
+                if (op.isPeriodic && authority.target.matchesSpec(op.target)) {
+                    foundPeriodicSync = true;
+                    break;
+                }
+            }
+            if (!foundPeriodicSync) {
+                EndPoint target = authority.target;
+                final RegisteredServicesCache.ServiceInfo<SyncAdapterType>
+                        syncAdapterInfo = mSyncAdapters.getServiceInfo(
+                        SyncAdapterType.newKey(
+                                target.provider, target.account.type),
+                        target.userId);
+                if (syncAdapterInfo == null) {
+                    continue;
+                }
+                scheduleSyncOperationH(
+                    new SyncOperation(target, syncAdapterInfo.uid,
+                            syncAdapterInfo.componentName.getPackageName(),
+                            SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_PERIODIC,
+                            new Bundle(), syncAdapterInfo.type.allowParallelSyncs(),
+                            true /* periodic */, SyncOperation.NO_JOB_ID, defaultPeriod * 1000L,
+                            defaultFlex * 1000L)
+                );
+            }
+        }
+    }
+
     private synchronized void verifyJobScheduler() {
         if (mJobScheduler != null) {
             return;
@@ -510,12 +550,12 @@
 
         mSyncStorageEngine.setPeriodicSyncAddedListener(
                 new SyncStorageEngine.PeriodicSyncAddedListener() {
-            @Override
-            public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
-                                            long flex) {
-                updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
-            }
-        });
+                    @Override
+                    public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
+                            long flex) {
+                        updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
+                    }
+                });
 
         mSyncStorageEngine.setOnAuthorityRemovedListener(new SyncStorageEngine.OnAuthorityRemovedListener() {
             @Override
@@ -750,8 +790,8 @@
      * @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
      */
     public void scheduleSync(Account requestedAccount, int userId, int reason,
-                             String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
-                             long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
+            String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
+            long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
         final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
         if (extras == null) {
             extras = new Bundle();
@@ -941,7 +981,7 @@
      * flexMillis will be updated.
      */
     public void updateOrAddPeriodicSync(EndPoint target, long pollFrequency, long flex,
-                                        Bundle extras) {
+            Bundle extras) {
         UpdatePeriodicSyncMessagePayload payload = new UpdatePeriodicSyncMessagePayload(target,
                 pollFrequency, flex, extras);
         mSyncHandler.obtainMessage(SyncHandler.MESSAGE_UPDATE_PERIODIC_SYNC, payload)
@@ -995,7 +1035,7 @@
     }
 
     private void sendSyncFinishedOrCanceledMessage(ActiveSyncContext syncContext,
-                                                   SyncResult syncResult) {
+            SyncResult syncResult) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_SYNC_FINISHED");
         Message msg = mSyncHandler.obtainMessage();
         msg.what = SyncHandler.MESSAGE_SYNC_FINISHED;
@@ -1053,7 +1093,7 @@
         public final SyncResult syncResult;
 
         SyncFinishedOrCancelledMessagePayload(ActiveSyncContext syncContext,
-                                              SyncResult syncResult) {
+                SyncResult syncResult) {
             this.activeSyncContext = syncContext;
             this.syncResult = syncResult;
         }
@@ -1066,7 +1106,7 @@
         public final Bundle extras;
 
         UpdatePeriodicSyncMessagePayload(EndPoint target, long pollFrequency, long flex,
-                                         Bundle extras) {
+                Bundle extras) {
             this.target = target;
             this.pollFrequency = pollFrequency;
             this.flex = flex;
@@ -1297,7 +1337,7 @@
                 JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
 
         JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId,
-                    new ComponentName(mContext, SyncJobService.class))
+                new ComponentName(mContext, SyncJobService.class))
                 .setExtras(syncOperation.toJobInfoExtras())
                 .setRequiredNetworkType(networkType)
                 .setPersisted(true)
@@ -1502,7 +1542,7 @@
          * for this sync. This is used to attribute the wakelock hold to that application.
          */
         public ActiveSyncContext(SyncOperation syncOperation, long historyRowId,
-                                 int syncAdapterUid) {
+                int syncAdapterUid) {
             super();
             mSyncAdapterUid = syncAdapterUid;
             mSyncOperation = syncOperation;
@@ -1731,7 +1771,7 @@
                     new Comparator<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>() {
                         @Override
                         public int compare(RegisteredServicesCache.ServiceInfo<SyncAdapterType> lhs,
-                                           RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
+                                RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
                             return lhs.type.authority.compareTo(rhs.type.authority);
                         }
                     });
@@ -2572,6 +2612,7 @@
         }
 
         private void updateRunningAccountsH(EndPoint syncTargets) {
+            AccountAndUser[] oldAccounts = mRunningAccounts;
             mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Slog.v(TAG, "Accounts list: ");
@@ -2595,6 +2636,17 @@
                 }
             }
 
+            // On account add, check if there are any settings to be restored.
+            for (AccountAndUser aau : mRunningAccounts) {
+                if (!containsAccountAndUser(oldAccounts, aau.account, aau.userId)) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Account " + aau.account + " added, checking sync restore data");
+                    }
+                    AccountSyncSettingsBackupHelper.accountAdded(mContext);
+                    break;
+                }
+            }
+
             List<SyncOperation> ops = getAllPendingSyncsFromCache();
             for (SyncOperation op: ops) {
                 if (!containsAccountAndUser(accounts, op.target.account, op.target.userId)) {
@@ -2618,7 +2670,7 @@
          * @param flexMillis new flex time in milliseconds.
          */
         private void maybeUpdateSyncPeriodH(SyncOperation syncOperation, long pollFrequencyMillis,
-                                            long flexMillis) {
+                long flexMillis) {
             if (!(pollFrequencyMillis == syncOperation.periodMillis
                     && flexMillis == syncOperation.flexMillis)) {
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -2633,7 +2685,7 @@
         }
 
         private void updateOrAddPeriodicSyncH(EndPoint target, long pollFrequency, long flex,
-                                              Bundle extras) {
+                Bundle extras) {
             final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
             verifyJobScheduler();  // Will fill in mScheduledSyncs cache if it is not already filled.
             final long pollFrequencyMillis = pollFrequency * 1000L;
@@ -2821,7 +2873,7 @@
         }
 
         private void runBoundToAdapterH(final ActiveSyncContext activeSyncContext,
-                                        IBinder syncAdapter) {
+                IBinder syncAdapter) {
             final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
             try {
                 activeSyncContext.mIsLinkedToDeath = true;
@@ -2889,7 +2941,7 @@
         }
 
         private void runSyncFinishedOrCanceledH(SyncResult syncResult,
-                                                ActiveSyncContext activeSyncContext) {
+                ActiveSyncContext activeSyncContext) {
             final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
 
             final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
@@ -3023,7 +3075,7 @@
         }
 
         private void installHandleTooManyDeletesNotification(Account account, String authority,
-                                                             long numDeletes, int userId) {
+                long numDeletes, int userId) {
             if (mNotificationMgr == null) return;
 
             final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
@@ -3099,7 +3151,7 @@
         }
 
         public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
-                                  int upstreamActivity, int downstreamActivity, long elapsedTime) {
+                int upstreamActivity, int downstreamActivity, long elapsedTime) {
             EventLog.writeEvent(2720,
                     syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
             mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
@@ -3263,4 +3315,4 @@
             return mContext;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 965054f..cefaa8d 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -80,7 +80,7 @@
     private static final String XML_TAG_LISTEN_FOR_TICKLES = "listenForTickles";
 
     /** Default time for a periodic sync. */
-    private static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
+    static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
 
     /** Percentage of period that is flex by default, if no flexMillis is set. */
     private static final double DEFAULT_FLEX_PERCENT_SYNC = 0.04;
@@ -857,6 +857,16 @@
         }
     }
 
+    List<AuthorityInfo> getAllAuthorities() {
+        List<AuthorityInfo> authorities = new ArrayList<AuthorityInfo>();
+        synchronized (mAuthorities) {
+            for (int i = 0; i < mAuthorities.size(); i++) {
+                authorities.add(mAuthorities.valueAt(i));
+            }
+        }
+        return authorities;
+    }
+
     /**
      * Returns true if there is currently a sync operation being actively processed for the given
      * target.
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index e5e86ac..40283728 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -330,7 +330,7 @@
 
     private void cancelJobImpl(JobStatus cancelled) {
         if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
-        stopTrackingJob(cancelled);
+        stopTrackingJob(cancelled, true /* writeBack */);
         synchronized (mJobs) {
             // Remove from pending queue.
             mPendingJobs.remove(cancelled);
@@ -509,12 +509,12 @@
      * Called when we want to remove a JobStatus object that we've finished executing. Returns the
      * object removed.
      */
-    private boolean stopTrackingJob(JobStatus jobStatus) {
+    private boolean stopTrackingJob(JobStatus jobStatus, boolean writeBack) {
         boolean removed;
         boolean rocking;
         synchronized (mJobs) {
             // Remove from store as well as controllers.
-            removed = mJobs.remove(jobStatus);
+            removed = mJobs.remove(jobStatus, writeBack);
             rocking = mReadyToRock;
         }
         if (removed && rocking) {
@@ -645,7 +645,9 @@
         if (DEBUG) {
             Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
         }
-        if (!stopTrackingJob(jobStatus)) {
+        // Do not write back immediately if this is a periodic job. The job may get lost if system
+        // shuts down before it is added back.
+        if (!stopTrackingJob(jobStatus, !jobStatus.getJob().isPeriodic())) {
             if (DEBUG) {
                 Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
             }
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index f796164..f6a6778 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -159,9 +159,10 @@
 
     /**
      * Remove the provided job. Will also delete the job if it was persisted.
+     * @param writeBack If true, the job will be deleted (if it was persisted) immediately.
      * @return Whether or not the job existed to be removed.
      */
-    public boolean remove(JobStatus jobStatus) {
+    public boolean remove(JobStatus jobStatus, boolean writeBack) {
         boolean removed = mJobSet.remove(jobStatus);
         if (!removed) {
             if (DEBUG) {
@@ -169,7 +170,7 @@
             }
             return false;
         }
-        if (jobStatus.isPersisted()) {
+        if (writeBack && jobStatus.isPersisted()) {
             maybeWriteStatusToDiskAsync();
         }
         return removed;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index ffc52b3..c1eb844 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1557,15 +1557,13 @@
      * called from native code to update SV info
      */
     private void reportSvStatus() {
-        int svCount = native_read_sv_status(mPrnWithFlags, mSnrs, mSvElevations, mSvAzimuths,
-                mConstellationTypes);
+        int svCount = native_read_sv_status(mSvidWithFlags, mSnrs, mSvElevations, mSvAzimuths);
         mListenerHelper.onSvStatusChanged(
                 svCount,
-                mPrnWithFlags,
+                mSvidWithFlags,
                 mSnrs,
                 mSvElevations,
-                mSvAzimuths,
-                mConstellationTypes);
+                mSvAzimuths);
 
         if (VERBOSE) {
             Log.v(TAG, "SV count: " + svCount);
@@ -1573,19 +1571,19 @@
         // Calculate number of sets used in fix.
         int usedInFixCount = 0;
         for (int i = 0; i < svCount; i++) {
-            if ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
+            if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
                 ++usedInFixCount;
             }
             if (VERBOSE) {
-                Log.v(TAG, "prn: " + (mPrnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH) +
+                Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
                         " snr: " + mSnrs[i]/10 +
                         " elev: " + mSvElevations[i] +
                         " azimuth: " + mSvAzimuths[i] +
-                        ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
+                        ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
                                 ? "  " : " E") +
-                        ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
+                        ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
                                 ? "  " : " A") +
-                        ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
+                        ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
                                 ? "" : "U"));
             }
         }
@@ -2398,14 +2396,13 @@
     }
 
     // for GPS SV statistics
-    private static final int MAX_SVS = 512;
+    private static final int MAX_SVS = 64;
 
     // preallocated arrays, to avoid memory allocation in reportStatus()
-    private int mPrnWithFlags[] = new int[MAX_SVS];
+    private int mSvidWithFlags[] = new int[MAX_SVS];
     private float mSnrs[] = new float[MAX_SVS];
     private float mSvElevations[] = new float[MAX_SVS];
     private float mSvAzimuths[] = new float[MAX_SVS];
-    private int mConstellationTypes[] = new int[MAX_SVS];
     private int mSvCount;
     // preallocated to avoid memory allocation in reportNmea()
     private byte[] mNmeaBuffer = new byte[120];
@@ -2426,7 +2423,7 @@
     // returns number of SVs
     // mask[0] is ephemeris mask and mask[1] is almanac mask
     private native int native_read_sv_status(int[] prnWithFlags, float[] snrs, float[] elevations,
-            float[] azimuths, int[] constellationTypes);
+            float[] azimuths);
     private native int native_read_nmea(byte[] buffer, int bufferSize);
     private native void native_inject_location(double latitude, double longitude, float accuracy);
 
diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index 9840c61..0b3111c 100644
--- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -77,8 +77,7 @@
             final int[] prnWithFlags,
             final float[] snrs,
             final float[] elevations,
-            final float[] azimuths,
-            final int[] constellationTypes) {
+            final float[] azimuths) {
         Operation operation = new Operation() {
             @Override
             public void execute(IGnssStatusListener listener) throws RemoteException {
@@ -87,8 +86,7 @@
                         prnWithFlags,
                         snrs,
                         elevations,
-                        azimuths,
-                        constellationTypes);
+                        azimuths);
             }
         };
         foreach(operation);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b2e6adf..426ce41 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -339,6 +339,8 @@
     private final AppOpsManager mAppOps;
 
     private final MyPackageMonitor mPackageMonitor;
+    private final IPackageManager mIPm;
+
 
     // TODO: keep whitelist of system-critical services that should never have
     // rules enforced, such as system, phone, and radio UIDs.
@@ -369,6 +371,7 @@
                 Context.DEVICE_IDLE_CONTROLLER));
         mTime = checkNotNull(time, "missing TrustedTime");
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mIPm = AppGlobals.getPackageManager();
 
         HandlerThread thread = new HandlerThread(TAG);
         thread.start();
@@ -1864,31 +1867,58 @@
     @Override
     public void addRestrictBackgroundWhitelistedUid(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
+        if (!isUidValidForRules(uid)) return;
+        final boolean changed;
         synchronized (mRulesLock) {
+            final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+            if (oldStatus) {
+                if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
+                return;
+            }
+            Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
             mRestrictBackgroundWhitelistUids.append(uid, true);
-            updateRulesForGlobalChangeLocked(true);
+            changed = mRestrictBackground && !oldStatus;
+            if (changed && hasInternetPermissions(uid)) {
+                setUidNetworkRules(uid, false);
+            }
             writePolicyLocked();
         }
-        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0).sendToTarget();
+        if (changed) {
+            mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
+                    .sendToTarget();
+        }
     }
 
     @Override
     public void removeRestrictBackgroundWhitelistedUid(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
+        if (!isUidValidForRules(uid)) return;
+        final boolean changed;
         synchronized (mRulesLock) {
-            removeRestrictBackgroundWhitelistedUidLocked(uid, true);
+            changed = removeRestrictBackgroundWhitelistedUidLocked(uid, true);
         }
-        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0).sendToTarget();
+        if (changed) {
+            mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
+                    .sendToTarget();
+        }
     }
 
-    private void removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean updateNow) {
+    private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean updateNow) {
+        final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+        if (!oldStatus) {
+            if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before");
+            return false;
+        }
+        Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
+        final boolean changed = mRestrictBackground && oldStatus;
         mRestrictBackgroundWhitelistUids.delete(uid);
         if (updateNow) {
-            updateRulesForGlobalChangeLocked(true);
+            if (changed && hasInternetPermissions(uid)) {
+                setUidNetworkRules(uid, true);
+            }
             writePolicyLocked();
         }
+        return changed;
     }
 
     @Override
@@ -2298,13 +2328,19 @@
         uidRules.clear();
 
         // Fully update the app idle firewall chain.
+        final IPackageManager ipm = AppGlobals.getPackageManager();
         final List<UserInfo> users = mUserManager.getUsers();
         for (int ui = users.size() - 1; ui >= 0; ui--) {
             UserInfo user = users.get(ui);
             int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
             for (int uid : idleUids) {
                 if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
-                    uidRules.put(uid, FIREWALL_RULE_DENY);
+                    // quick check: if this uid doesn't have INTERNET permission, it
+                    // doesn't have network access anyway, so it is a waste to mess
+                    // with it here.
+                    if (hasInternetPermissions(uid)) {
+                        uidRules.put(uid, FIREWALL_RULE_DENY);
+                    }
                 }
             }
         }
@@ -2408,22 +2444,27 @@
     }
 
     /**
+     * Checks if an uid has INTERNET permissions.
+     * <p>
+     * Useful for the cases where the lack of network access can simplify the rules.
+     */
+    private boolean hasInternetPermissions(int uid) {
+        try {
+            if (mIPm.checkUidPermission(Manifest.permission.INTERNET, uid)
+                    != PackageManager.PERMISSION_GRANTED) {
+                return false;
+            }
+        } catch (RemoteException e) {
+        }
+        return true;
+    }
+
+    /**
      * Applies network rules to bandwidth and firewall controllers based on uid policy.
      * @param uid The uid for which to apply the latest policy
      */
     void updateRulesForUidLocked(int uid) {
-        if (!isUidValidForRules(uid)) return;
-
-        // quick check: if this uid doesn't have INTERNET permission, it doesn't have
-        // network access anyway, so it is a waste to mess with it here.
-        final IPackageManager ipm = AppGlobals.getPackageManager();
-        try {
-            if (ipm.checkUidPermission(Manifest.permission.INTERNET, uid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                return;
-            }
-        } catch (RemoteException e) {
-        }
+        if (!isUidValidForRules(uid) || !hasInternetPermissions(uid)) return;
 
         final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
         final boolean uidForeground = isUidForegroundLocked(uid);
@@ -2598,7 +2639,6 @@
                         intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                         mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
                     }
-
                     return true;
                 }
                 case MSG_ADVISE_PERSIST_THRESHOLD: {
@@ -2831,13 +2871,5 @@
                 removeRestrictBackgroundWhitelistedUidLocked(uid, true);
             }
         }
-
-        @Override
-        public void onPackageRemovedAllUsers(String packageName, int uid) {
-            if (LOGV) Slog.v(TAG, "onPackageRemovedAllUsers: " + packageName + " ->" + uid);
-            synchronized (mRulesLock) {
-                removeRestrictBackgroundWhitelistedUidLocked(uid, true);
-            }
-        }
     }
 }
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index ce18818..9820a12 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -234,9 +234,13 @@
                 final ConditionRecord r = getRecordLocked(c.id, info.component, true /*create*/);
                 r.info = info;
                 r.condition = c;
-                if (mCallback != null) {
-                    mCallback.onConditionChanged(c.id, c);
-                }
+            }
+        }
+        final int N = conditions.length;
+        for (int i = 0; i < N; i++) {
+            final Condition c = conditions[i];
+            if (mCallback != null) {
+                mCallback.onConditionChanged(c.id, c);
             }
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 36ddbcf..0519cf2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1350,9 +1350,9 @@
         }
 
         @Override
-        public boolean doesAppUseTopics(String pkg, int uid) {
+        public boolean doesUserUseTopics(String pkg, int uid) {
             enforceSystemOrSystemUI("Caller not system or systemui");
-            return mRankingHelper.doesAppUseTopics(pkg, uid);
+            return mRankingHelper.doesUserUseTopics(pkg, uid);
         }
 
         /**
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 17bb907..9773474 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -36,7 +36,7 @@
 
     int getImportance(String packageName, int uid, Notification.Topic topic);
 
-    boolean doesAppUseTopics(String packageName, int uid);
+    boolean doesUserUseTopics(String packageName, int uid);
 
     boolean hasBannedTopics(String packageName, int uid);
 
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 6554bf9..91eab10 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -521,15 +521,14 @@
     }
 
     @Override
-    public boolean doesAppUseTopics(String pkgName, int uid) {
+    public boolean doesUserUseTopics(String pkgName, int uid) {
         final Record r = getOrCreateRecord(pkgName, uid);
-        int numTopics = r.topics.size();
-        if (numTopics == 0
-                || (numTopics == 1 && r.topics.containsKey(Notification.TOPIC_DEFAULT))) {
-            return false;
-        } else {
-            return true;
+        for (Topic topic : r.topics.values()) {
+            if (topic.importance != Ranking.IMPORTANCE_UNSPECIFIED
+                    && r.importance != topic.importance)
+                return true;
         }
+        return false;
     }
 
     private Topic getOrCreateTopic(Record r, Notification.Topic topic) {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index d82bb3d..c6613f5 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -201,8 +201,7 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent,
-                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                        user.getIdentifier());
+                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
                 return new ParceledListSlice<>(apps);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -220,7 +219,7 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 ResolveInfo app = mPm.resolveActivityAsUser(intent,
-                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
                 return app;
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -239,7 +238,7 @@
             try {
                 IPackageManager pm = AppGlobals.getPackageManager();
                 PackageInfo info = pm.getPackageInfo(packageName,
-                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
                 return info != null && info.applicationInfo.enabled;
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -277,7 +276,7 @@
             try {
                 IPackageManager pm = AppGlobals.getPackageManager();
                 ActivityInfo info = pm.getActivityInfo(component,
-                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
                 return info != null;
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -303,7 +302,7 @@
             try {
                 IPackageManager pm = AppGlobals.getPackageManager();
                 ActivityInfo info = pm.getActivityInfo(component,
-                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
                 if (!info.exported) {
                     throw new SecurityException("Cannot launch non-exported components "
                             + component);
@@ -313,7 +312,7 @@
                 // as calling startActivityAsUser ignores the category and just
                 // resolves based on the component if present.
                 List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(launchIntent,
-                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
                 final int size = apps.size();
                 for (int i = 0; i < size; ++i) {
                     ActivityInfo activityInfo = apps.get(i).activityInfo;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8a94ce5..92343d6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13256,16 +13256,19 @@
             // of the package implies that the user actually wants to run that new code,
             // so we enable the package.
             PackageSetting ps = mSettings.mPackages.get(pkgName);
+            final int userId = user.getIdentifier();
             if (ps != null) {
                 if (isSystemApp(newPackage)) {
-                    // NB: implicit assumption that system package upgrades apply to all users
                     if (DEBUG_INSTALL) {
                         Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
                     }
+                    // Enable system package for requested users
                     if (res.origUsers != null) {
-                        for (int userHandle : res.origUsers) {
-                            ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
-                                    userHandle, installerPackageName);
+                        for (int origUserId : res.origUsers) {
+                            if (userId == UserHandle.USER_ALL || userId == origUserId) {
+                                ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
+                                        origUserId, installerPackageName);
+                            }
                         }
                     }
                     // Also convey the prior install/uninstall state
@@ -13283,7 +13286,6 @@
                 }
                 // It's implied that when a user requests installation, they want the app to be
                 // installed and enabled.
-                int userId = user.getIdentifier();
                 if (userId != UserHandle.USER_ALL) {
                     ps.setInstalled(true, userId);
                     ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 22d0994..76d6b28 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1934,13 +1934,18 @@
         if (user == null) {
             return null;
         }
-        setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
-        // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
-        // the putIntForUser() will fail.
-        android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                android.provider.Settings.Secure.LOCATION_MODE,
-                android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id);
-        setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
+            // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
+            // the putIntForUser() will fail.
+            android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    android.provider.Settings.Secure.LOCATION_MODE,
+                    android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id);
+            setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
         return user;
     }
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c046ba6..3a70e67 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -18,6 +18,8 @@
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.content.pm.PackageManager.FEATURE_WATCH;
@@ -32,6 +34,7 @@
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerInternal.SleepToken;
 import android.app.ActivityManagerNative;
@@ -135,6 +138,7 @@
 import com.android.server.LocalServices;
 import com.android.server.policy.keyguard.KeyguardServiceDelegate;
 import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
+import com.android.server.statusbar.StatusBarManagerInternal;
 
 import java.io.File;
 import java.io.FileReader;
@@ -280,6 +284,7 @@
     DreamManagerInternal mDreamManagerInternal;
     PowerManagerInternal mPowerManagerInternal;
     IStatusBarService mStatusBarService;
+    StatusBarManagerInternal mStatusBarManagerInternal;
     boolean mPreloadedRecentApps;
     final Object mServiceAquireLock = new Object();
     Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -488,6 +493,13 @@
     int mResettingSystemUiFlags = 0;
     // Bits that we are currently always keeping cleared.
     int mForceClearedSystemUiFlags = 0;
+    int mLastFullscreenStackSysUiFlags;
+    int mLastDockedStackSysUiFlags;
+    final Rect mNonDockedStackBounds = new Rect();
+    final Rect mDockedStackBounds = new Rect();
+    final Rect mLastNonDockedStackBounds = new Rect();
+    final Rect mLastDockedStackBounds = new Rect();
+
     // What we last reported to system UI about whether the compatibility
     // menu needs to be displayed.
     boolean mLastFocusNeedsMenu = false;
@@ -508,6 +520,8 @@
 
     WindowState mTopFullscreenOpaqueWindowState;
     WindowState mTopFullscreenOpaqueOrDimmingWindowState;
+    WindowState mTopDockedOpaqueWindowState;
+    WindowState mTopDockedOpaqueOrDimmingWindowState;
     HashSet<IApplicationToken> mAppsToBeHidden = new HashSet<IApplicationToken>();
     HashSet<IApplicationToken> mAppsThatDismissKeyguard = new HashSet<IApplicationToken>();
     boolean mTopIsFullscreen;
@@ -844,6 +858,16 @@
         }
     }
 
+    StatusBarManagerInternal getStatusBarManagerInternal() {
+        synchronized (mServiceAquireLock) {
+            if (mStatusBarManagerInternal == null) {
+                mStatusBarManagerInternal =
+                        LocalServices.getService(StatusBarManagerInternal.class);
+            }
+            return mStatusBarManagerInternal;
+        }
+    }
+
     /*
      * We always let the sensor be switched on by default except when
      * the user has explicitly disabled sensor based rotation or when the
@@ -4373,6 +4397,23 @@
                             + mUnrestrictedScreenWidth;
                     pf.bottom = df.bottom = of.bottom = cf.bottom = mUnrestrictedScreenTop
                             + mUnrestrictedScreenHeight;
+                } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
+                    pf.left = df.left = of.left = mRestrictedScreenLeft;
+                    pf.top = df.top = of.top  = mRestrictedScreenTop;
+                    pf.right = df.right = of.right = mRestrictedScreenLeft + mRestrictedScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = mRestrictedScreenTop
+                            + mRestrictedScreenHeight;
+                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+                        cf.left = mDockLeft;
+                        cf.top = mDockTop;
+                        cf.right = mDockRight;
+                        cf.bottom = mDockBottom;
+                    } else {
+                        cf.left = mContentLeft;
+                        cf.top = mContentTop;
+                        cf.right = mContentRight;
+                        cf.bottom = mContentBottom;
+                    }
                 } else {
                     pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
                     pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
@@ -4552,6 +4593,8 @@
     public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
         mTopFullscreenOpaqueWindowState = null;
         mTopFullscreenOpaqueOrDimmingWindowState = null;
+        mTopDockedOpaqueWindowState = null;
+        mTopDockedOpaqueOrDimmingWindowState = null;
         mAppsToBeHidden.clear();
         mAppsThatDismissKeyguard.clear();
         mForceStatusBar = false;
@@ -4597,7 +4640,7 @@
                 && attrs.type < FIRST_SYSTEM_WINDOW;
         final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
         final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
-
+        final int stackId = win.getStackId();
         if (mTopFullscreenOpaqueWindowState == null &&
                 win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
             if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
@@ -4646,9 +4689,7 @@
                 } else {
                     mAppsToBeHidden.add(appToken);
                 }
-                if (attrs.x == 0 && attrs.y == 0
-                        && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
-                        && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
+                if (isFullscreen(attrs) && StackId.normallyFullscreenWindows(stackId)) {
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
                     mTopFullscreenOpaqueWindowState = win;
                     if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
@@ -4692,11 +4733,37 @@
                 mWinShowWhenLocked = win;
             }
         }
-        if (mTopFullscreenOpaqueOrDimmingWindowState == null
-                && win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()
-                && win.isDimming()) {
+
+        // Keep track of the window if it's dimming but not necessarily fullscreen.
+        final boolean reallyVisible = win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw();
+        if (mTopFullscreenOpaqueOrDimmingWindowState == null &&  reallyVisible
+                && win.isDimming() && StackId.normallyFullscreenWindows(stackId)) {
             mTopFullscreenOpaqueOrDimmingWindowState = win;
         }
+
+        // We need to keep track of the top "fullscreen" opaque window for the docked stack
+        // separately, because both the "real fullscreen" opaque window and the one for the docked
+        // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+        if (mTopDockedOpaqueWindowState == null && reallyVisible && appWindow && attached == null
+                && isFullscreen(attrs) && stackId == DOCKED_STACK_ID) {
+            mTopDockedOpaqueWindowState = win;
+            if (mTopDockedOpaqueOrDimmingWindowState == null) {
+                mTopDockedOpaqueOrDimmingWindowState = win;
+            }
+        }
+
+        // Also keep track of any windows that are dimming but not necessarily fullscreen in the
+        // docked stack.
+        if (mTopDockedOpaqueOrDimmingWindowState == null && reallyVisible && win.isDimming()
+                && stackId == DOCKED_STACK_ID) {
+            mTopDockedOpaqueOrDimmingWindowState = win;
+        }
+    }
+
+    private boolean isFullscreen(WindowManager.LayoutParams attrs) {
+        return attrs.x == 0 && attrs.y == 0
+                && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
+                && attrs.height == WindowManager.LayoutParams.MATCH_PARENT;
     }
 
     /** {@inheritDoc} */
@@ -6838,42 +6905,52 @@
             tmpVisibility |= StatusBarManager.DISABLE_RECENT;
         }
 
-        tmpVisibility = updateLightStatusBarLw(tmpVisibility);
+        final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
+                mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
+        final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
+                mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
+        mWindowManagerFuncs.getStackBounds(HOME_STACK_ID, mNonDockedStackBounds);
+        mWindowManagerFuncs.getStackBounds(DOCKED_STACK_ID, mDockedStackBounds);
         final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
         final int diff = visibility ^ mLastSystemUiFlags;
+        final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
+        final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
         final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
-        if (diff == 0 && mLastFocusNeedsMenu == needsMenu
-                && mFocusedApp == win.getAppToken()) {
+        if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
+                && mFocusedApp == win.getAppToken()
+                && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
+                && mLastDockedStackBounds.equals(mDockedStackBounds)) {
             return 0;
         }
         mLastSystemUiFlags = visibility;
+        mLastFullscreenStackSysUiFlags = fullscreenVisibility;
+        mLastDockedStackSysUiFlags = dockedVisibility;
         mLastFocusNeedsMenu = needsMenu;
         mFocusedApp = win.getAppToken();
+        final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
+        final Rect dockedStackBounds = new Rect(mDockedStackBounds);
         mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    try {
-                        IStatusBarService statusbar = getStatusBarService();
-                        if (statusbar != null) {
-                            statusbar.setSystemUiVisibility(visibility, 0xffffffff, win.toString());
-                            statusbar.topAppWindowChanged(needsMenu);
-                        }
-                    } catch (RemoteException e) {
-                        // re-acquire status bar service next time it is needed.
-                        mStatusBarService = null;
+                    StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
+                    if (statusbar != null) {
+                        statusbar.setSystemUiVisibility(visibility, fullscreenVisibility,
+                                dockedVisibility, 0xffffffff, fullscreenStackBounds,
+                                dockedStackBounds, win.toString());
+                        statusbar.topAppWindowChanged(needsMenu);
                     }
                 }
             });
         return diff;
     }
 
-    private int updateLightStatusBarLw(int vis) {
+    private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
         WindowState statusColorWin = isStatusBarKeyguard() && !mHideLockScreen
                 ? mStatusBar
-                : mTopFullscreenOpaqueOrDimmingWindowState;
+                : opaqueOrDimming;
 
         if (statusColorWin != null) {
-            if (statusColorWin == mTopFullscreenOpaqueWindowState) {
+            if (statusColorWin == opaque) {
                 // If the top fullscreen-or-dimming window is also the top fullscreen, respect
                 // its light flag.
                 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 25d646d..cbbcdae 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -16,6 +16,7 @@
 
 package com.android.server.statusbar;
 
+import android.graphics.Rect;
 import android.os.Bundle;
 
 import com.android.server.notification.NotificationDelegate;
@@ -29,4 +30,7 @@
     void showAssistDisclosure();
     void startAssist(Bundle args);
     void onCameraLaunchGestureDetected(int source);
+    void topAppWindowChanged(boolean menuVisible);
+    void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
+            Rect fullscreenBounds, Rect dockedBounds, String cause);
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 90340d5..6eab8d4 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -70,6 +71,10 @@
     private Object mLock = new Object();
     // encompasses lights-out mode and other flags defined on View
     private int mSystemUiVisibility = 0;
+    private int mFullscreenStackSysUiVisibility;
+    private int mDockedStackSysUiVisibility;
+    private final Rect mFullscreenStackBounds = new Rect();
+    private final Rect mDockedStackBounds = new Rect();
     private boolean mMenuVisible = false;
     private int mImeWindowVis = 0;
     private int mImeBackDisposition;
@@ -186,6 +191,19 @@
                 }
             }
         }
+
+        @Override
+        public void topAppWindowChanged(boolean menuVisible) {
+            StatusBarManagerService.this.topAppWindowChanged(menuVisible);
+        }
+
+        @Override
+        public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+                int mask,
+                Rect fullscreenBounds, Rect dockedBounds, String cause) {
+            StatusBarManagerService.this.setSystemUiVisibility(vis, fullscreenStackVis,
+                    dockedStackVis, mask, fullscreenBounds, dockedBounds, cause);
+        }
     };
 
     // ================================================================================
@@ -390,8 +408,7 @@
      * response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set
      * to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}.
      */
-    @Override
-    public void topAppWindowChanged(final boolean menuVisible) {
+    private void topAppWindowChanged(final boolean menuVisible) {
         enforceStatusBar();
 
         if (SPEW) Slog.d(TAG, (menuVisible?"showing":"hiding") + " MENU key");
@@ -399,15 +416,15 @@
         synchronized(mLock) {
             mMenuVisible = menuVisible;
             mHandler.post(new Runnable() {
-                    public void run() {
-                        if (mBar != null) {
-                            try {
-                                mBar.topAppWindowChanged(menuVisible);
-                            } catch (RemoteException ex) {
-                            }
+                public void run() {
+                    if (mBar != null) {
+                        try {
+                            mBar.topAppWindowChanged(menuVisible);
+                        } catch (RemoteException ex) {
                         }
                     }
-                });
+                }
+            });
         }
     }
 
@@ -443,13 +460,19 @@
 
     @Override
     public void setSystemUiVisibility(int vis, int mask, String cause) {
+        setSystemUiVisibility(vis, 0, 0, mask, mFullscreenStackBounds, mDockedStackBounds, cause);
+    }
+
+    private void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
+            Rect fullscreenBounds, Rect dockedBounds, String cause) {
         // also allows calls from window manager which is in this process.
         enforceStatusBarService();
 
         if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");
 
         synchronized (mLock) {
-            updateUiVisibilityLocked(vis, mask);
+            updateUiVisibilityLocked(vis, fullscreenStackVis, dockedStackVis, mask,
+                    fullscreenBounds, dockedBounds);
             disableLocked(
                     mCurrentUserId,
                     vis & StatusBarManager.DISABLE_MASK,
@@ -458,14 +481,25 @@
         }
     }
 
-    private void updateUiVisibilityLocked(final int vis, final int mask) {
-        if (mSystemUiVisibility != vis) {
+    private void updateUiVisibilityLocked(final int vis,
+            final int fullscreenStackVis, final int dockedStackVis, final int mask,
+            final Rect fullscreenBounds, final Rect dockedBounds) {
+        if (mSystemUiVisibility != vis
+                || mFullscreenStackSysUiVisibility != fullscreenStackVis
+                || mDockedStackSysUiVisibility != dockedStackVis
+                || !mFullscreenStackBounds.equals(fullscreenBounds)
+                || !mDockedStackBounds.equals(dockedBounds)) {
             mSystemUiVisibility = vis;
+            mFullscreenStackSysUiVisibility = fullscreenStackVis;
+            mDockedStackSysUiVisibility = dockedStackVis;
+            mFullscreenStackBounds.set(fullscreenBounds);
+            mDockedStackBounds.set(dockedBounds);
             mHandler.post(new Runnable() {
                     public void run() {
                         if (mBar != null) {
                             try {
-                                mBar.setSystemUiVisibility(vis, mask);
+                                mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis,
+                                        mask, fullscreenBounds, dockedBounds);
                             } catch (RemoteException ex) {
                             }
                         }
@@ -617,7 +651,8 @@
     // ================================================================================
     @Override
     public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
-            List<StatusBarIcon> iconList, int switches[], List<IBinder> binders) {
+            List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
+            Rect fullscreenStackBounds, Rect dockedStackBounds) {
         enforceStatusBarService();
 
         Slog.i(TAG, "registerStatusBar bar=" + bar);
@@ -636,7 +671,11 @@
             switches[4] = mImeBackDisposition;
             switches[5] = mShowImeSwitcher ? 1 : 0;
             switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
+            switches[7] = mFullscreenStackSysUiVisibility;
+            switches[8] = mDockedStackSysUiVisibility;
             binders.add(mImeToken);
+            fullscreenStackBounds.set(mFullscreenStackBounds);
+            dockedStackBounds.set(mDockedStackBounds);
         }
     }
 
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 3e8269a..f3b120f 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -31,7 +31,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.provider.Settings.Secure;
+import android.provider.Settings.Global;
 import android.util.AndroidRuntimeException;
 import android.util.Slog;
 import android.webkit.IWebViewUpdateService;
@@ -91,7 +91,7 @@
                     // change provider when the new version of the package is being installed).
                     if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
                         && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
-                        synchronized(this) {
+                        synchronized(WebViewUpdateService.this) {
                             if (mCurrentWebViewPackage == null) return;
 
                             String webViewPackage = "package:" + mCurrentWebViewPackage.packageName;
@@ -268,13 +268,13 @@
     }
 
     private static String getUserChosenWebViewProvider() {
-        return Settings.Secure.getString(AppGlobals.getInitialApplication().getContentResolver(),
-                Settings.Secure.WEBVIEW_PROVIDER);
+        return Settings.Global.getString(AppGlobals.getInitialApplication().getContentResolver(),
+                Settings.Global.WEBVIEW_PROVIDER);
     }
 
     private void updateUserSetting(String newProviderName) {
-        Settings.Secure.putString(getContext().getContentResolver(),
-                Settings.Secure.WEBVIEW_PROVIDER,
+        Settings.Global.putString(getContext().getContentResolver(),
+                Settings.Global.WEBVIEW_PROVIDER,
                 newProviderName == null ? "" : newProviderName);
     }
 
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index d1c0881..0c04d4d 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -24,6 +24,7 @@
 
 import android.content.ClipData;
 import android.content.ClipDescription;
+import android.content.Context;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -33,6 +34,10 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.IUserManager;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DragEvent;
@@ -73,6 +78,8 @@
     IBinder mLocalWin;
     int mPid;
     int mUid;
+    int mSourceUserId;
+    boolean mCrossProfileCopyAllowed;
     ClipData mData;
     ClipDescription mDataDescription;
     int mTouchSource;
@@ -221,6 +228,18 @@
         mNotifiedWindows.clear();
         mDragInProgress = true;
 
+        mSourceUserId = UserHandle.getUserId(mUid);
+
+        final IUserManager userManager =
+                (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
+        try {
+            mCrossProfileCopyAllowed = !userManager.getUserRestrictions(mSourceUserId).getBoolean(
+                    UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
+        } catch (RemoteException e) {
+            Slog.e(TAG_WM, "Remote Exception calling UserManager: " + e);
+            mCrossProfileCopyAllowed = false;
+        }
+
         if (DEBUG_DRAG) {
             Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
         }
@@ -234,7 +253,7 @@
         }
     }
 
-    /* helper - send a caller-provided event, presumed to be DRAG_STARTED, if the
+    /* helper - send a ACTION_DRAG_STARTED event, if the
      * designated window is potentially a drop recipient.  There are race situations
      * around DRAG_ENDED broadcast, so we make sure that once we've declared that
      * the drag has ended, we never send out another DRAG_STARTED for this drag action.
@@ -244,19 +263,7 @@
      */
     private void sendDragStartedLw(WindowState newWin, float touchX, float touchY,
             ClipDescription desc) {
-        // Don't actually send the event if the drag is supposed to be pinned
-        // to the originating window but 'newWin' is not that window.
-        if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
-            final IBinder winBinder = newWin.mClient.asBinder();
-            if (winBinder != mLocalWin) {
-                if (DEBUG_DRAG) {
-                    Slog.d(TAG_WM, "Not dispatching local DRAG_STARTED to " + newWin);
-                }
-                return;
-            }
-        }
-
-        if (mDragInProgress && newWin.isPotentialDragTarget()) {
+        if (mDragInProgress && isValidDropTarget(newWin)) {
             DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
                     touchX, touchY, null, desc, null, null, false);
             try {
@@ -274,17 +281,33 @@
         }
     }
 
-    /* helper - construct and send a DRAG_STARTED event only if the window has not
+    private boolean isValidDropTarget(WindowState targetWin) {
+        if (targetWin == null) {
+            return false;
+        }
+        if (!targetWin.isPotentialDragTarget()) {
+            return false;
+        }
+        if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
+            // Drag is limited to the current window.
+            if (mLocalWin != targetWin.mClient.asBinder()) {
+                return false;
+            }
+        }
+
+        return mCrossProfileCopyAllowed ||
+                mSourceUserId == UserHandle.getUserId(targetWin.getOwningUid());
+    }
+
+    /* helper - send a ACTION_DRAG_STARTED event only if the window has not
      * previously been notified, i.e. it became visible after the drag operation
      * was begun.  This is a rare case.
      */
     void sendDragStartedIfNeededLw(WindowState newWin) {
         if (mDragInProgress) {
             // If we have sent the drag-started, we needn't do so again
-            for (WindowState ws : mNotifiedWindows) {
-                if (ws == newWin) {
-                    return;
-                }
+            if (isWindowNotified(newWin)) {
+                return;
             }
             if (DEBUG_DRAG) {
                 Slog.d(TAG_WM, "need to send DRAG_STARTED to new window " + newWin);
@@ -293,6 +316,15 @@
         }
     }
 
+    private boolean isWindowNotified(WindowState newWin) {
+        for (WindowState ws : mNotifiedWindows) {
+            if (ws == newWin) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private void broadcastDragEndedLw() {
         final int myPid = Process.myPid();
 
@@ -389,14 +421,13 @@
             if (DEBUG_DRAG) Slog.d(TAG_WM, "No touched win at x=" + x + " y=" + y);
             return;
         }
-        if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
-            final IBinder touchedBinder = touchedWin.mClient.asBinder();
-            if (touchedBinder != mLocalWin) {
-                // This drag is pinned only to the originating window, but the drag
-                // point is outside that window.  Pretend it's over empty space.
-                touchedWin = null;
-            }
+
+        if (!isWindowNotified(touchedWin)) {
+            // The drag point is over a window which was not notified about a drag start.
+            // Pretend it's over empty space.
+            touchedWin = null;
         }
+
         try {
             final int myPid = Process.myPid();
 
@@ -445,7 +476,7 @@
         mCurrentX = x;
         mCurrentY = y;
 
-        if (touchedWin == null) {
+        if (!isWindowNotified(touchedWin)) {
             // "drop" outside a valid window -- no recipient to apply a
             // timeout to, and we can send the drag-ended message immediately.
             mDragResult = false;
@@ -455,6 +486,9 @@
         if (DEBUG_DRAG) {
             Slog.d(TAG_WM, "sending DROP to " + touchedWin);
         }
+        if (mSourceUserId != UserHandle.getUserId(touchedWin.getOwningUid())){
+            mData.fixUris(mSourceUserId);
+        }
         final int myPid = Process.myPid();
         final IBinder token = touchedWin.mClient.asBinder();
         DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 0979cd3..e229c5e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -37,8 +37,8 @@
     static final boolean DEBUG = false;
     static final boolean DEBUG_ADD_REMOVE = false;
     static final boolean DEBUG_FOCUS = false;
-    static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
-    static final boolean DEBUG_ANIM = false;
+    static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || true;
+    static final boolean DEBUG_ANIM = true;
     static final boolean DEBUG_KEYGUARD = false;
     static final boolean DEBUG_LAYOUT = false;
     static final boolean DEBUG_LAYERS = false;
@@ -50,7 +50,7 @@
     static final boolean DEBUG_ORIENTATION = false;
     static final boolean DEBUG_APP_ORIENTATION = false;
     static final boolean DEBUG_CONFIGURATION = false;
-    static final boolean DEBUG_APP_TRANSITIONS = false;
+    static final boolean DEBUG_APP_TRANSITIONS = true;
     static final boolean DEBUG_STARTING_WINDOW = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d1ffaa0..d54e9e3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -769,7 +769,7 @@
                     mDragState.mUid,
                     dropTargetWin.getOwningPackage(),
                     mDragState.mFlags & DRAG_FLAGS_URI_PERMISSIONS,
-                    UserHandle.getUserId(mDragState.mUid),
+                    mDragState.mSourceUserId,
                     UserHandle.getUserId(dropTargetWin.getOwningUid()));
         }
 
@@ -1192,7 +1192,7 @@
                 break;
             }
         }
-        if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
                 "Based on layer: Adding window " + win + " at " + (i + 1) + " of "
                         + windows.size());
         windows.add(i + 1, win);
@@ -1224,7 +1224,7 @@
                 //apptoken note that the window could be a floating window
                 //that was created later or a window at the top of the list of
                 //windows associated with this token.
-                if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
                         "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of "
                                 + windows.size());
                 windows.add(newIdx + 1, win);
@@ -1262,7 +1262,7 @@
             }
         }
         i++;
-        if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
                 "Free window: Adding window " + win + " at " + i + " of " + windows.size());
         windows.add(i, win);
         mWindowsChanged = true;
@@ -1333,7 +1333,7 @@
     }
 
     private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
-        if (DEBUG_FOCUS_LIGHT) Slog.d(TAG_WM, "addWindowToListInOrderLocked: win=" + win +
+        if (DEBUG_FOCUS) Slog.d(TAG_WM, "addWindowToListInOrderLocked: win=" + win +
                 " Callers=" + Debug.getCallers(4));
         if (win.mAttachedWindow == null) {
             final WindowToken token = win.mToken;
@@ -4236,7 +4236,6 @@
 
             mOpeningApps.remove(wtoken);
             mClosingApps.remove(wtoken);
-            wtoken.mAppStopped = false;
             wtoken.waitingToShow = false;
             wtoken.hiddenRequested = !visible;
 
@@ -4246,6 +4245,8 @@
                 // if made visible again.
                 wtoken.appDied = false;
                 wtoken.removeAllWindows();
+            } else if (visible) {
+                wtoken.mAppStopped = false;
             }
 
             // If we are preparing an app transition, then delay changing
@@ -4863,6 +4864,7 @@
         }
     }
 
+    @Override
     public void getStackBounds(int stackId, Rect bounds) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2096ea0..5b9206d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2088,7 +2088,8 @@
         return mTmpRect;
     }
 
-    private int getStackId() {
+    @Override
+    public int getStackId() {
         final TaskStack stack = getStack();
         if (stack == null) {
             return INVALID_STACK_ID;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0201296..f8f8363 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1347,7 +1347,7 @@
             }
         } else {
             if (DEBUG_ANIM && isAnimating()) {
-                Slog.v(TAG, "prepareSurface: No changes in animation for " + this);
+                //Slog.v(TAG, "prepareSurface: No changes in animation for " + this);
             }
             displayed = true;
         }
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index b72cf4d..656c214 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -330,7 +330,7 @@
     jsize len = env->GetArrayLength(body);
     message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH);
     ScopedByteArrayRO bodyPtr(env, body);
-    std::memcpy(message.body, bodyPtr.get(), len);
+    std::memcpy(message.body, bodyPtr.get(), message.length);
 
     HdmiCecController* controller =
             reinterpret_cast<HdmiCecController*>(controllerPtr);
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e75775f..cdd5519 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -68,13 +68,14 @@
 static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
 static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;
 
-#define MAX_SATELLITE_COUNT 512
-#define MAX_GPS_SATELLITE_COUNT 512
+#define GPS_MAX_SATELLITE_COUNT 32
+#define GNSS_MAX_SATELLITE_COUNT 64
 
-#define PRN_SHIFT_WIDTH 3
+#define SVID_SHIFT_WIDTH 7
+#define CONSTELLATION_TYPE_SHIFT_WIDTH 3
 
 // temporary storage for GPS callbacks
-static GnssSvInfo sGnssSvList[MAX_SATELLITE_COUNT];
+static GnssSvInfo sGnssSvList[GNSS_MAX_SATELLITE_COUNT];
 static size_t sGnssSvListSize;
 static const char* sNmeaString;
 static int sNmeaStringLength;
@@ -113,56 +114,75 @@
 {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     size_t status_size = sv_status->size;
-    // Some drive doesn't set the size field correctly. Assume GpsSvStatus_v1 if
-    // it doesn't provide a valid size.
+    // Some drives doesn't set the size field correctly. Assume GpsSvStatus_v1
+    // if it doesn't provide a valid size.
     if (status_size == 0) {
-        status_size = sizeof(GpsSvStatus_v1);
+        ALOGW("Invalid size of GpsSvStatus found: %zd.", status_size);
     }
-    if (status_size == sizeof(GpsSvStatus)) {
-        sGnssSvListSize = sv_status->gnss_sv_list_size;
-        // Cramp the list size
-        if (sGnssSvListSize > MAX_SATELLITE_COUNT) {
-            sGnssSvListSize = MAX_SATELLITE_COUNT;
-        }
-        // Copy GNSS SV info into sGnssSvList, if any.
-        if (sGnssSvListSize > 0 && sv_status->gnss_sv_list) {
-            memcpy(sGnssSvList, sv_status->gnss_sv_list, sizeof(GnssSvInfo) * sGnssSvListSize);
-        }
-    } else if (status_size == sizeof(GpsSvStatus_v1)) {
-        sGnssSvListSize = sv_status->num_svs;
-        // Cramp the list size
-        if (sGnssSvListSize > MAX_GPS_SATELLITE_COUNT) {
-            sGnssSvListSize = MAX_GPS_SATELLITE_COUNT;
-        }
-        uint32_t ephemeris_mask = sv_status->ephemeris_mask;
-        uint32_t almanac_mask = sv_status->almanac_mask;
-        uint32_t used_in_fix_mask = sv_status->used_in_fix_mask;
-        for (size_t i = 0; i < sGnssSvListSize; i++) {
-            GnssSvInfo& info = sGnssSvList[i];
+    sGnssSvListSize = sv_status->num_svs;
+    // Clamp the list size. Legacy GpsSvStatus has only 32 elements in sv_list.
+    if (sGnssSvListSize > GPS_MAX_SATELLITE_COUNT) {
+        ALOGW("Too many satellites %zd. Clamps to %d.",
+              sGnssSvListSize,
+              GPS_MAX_SATELLITE_COUNT);
+        sGnssSvListSize = GPS_MAX_SATELLITE_COUNT;
+    }
+    uint32_t ephemeris_mask = sv_status->ephemeris_mask;
+    uint32_t almanac_mask = sv_status->almanac_mask;
+    uint32_t used_in_fix_mask = sv_status->used_in_fix_mask;
+    for (size_t i = 0; i < sGnssSvListSize; i++) {
+        GnssSvInfo& info = sGnssSvList[i];
+        info.svid = sv_status->sv_list[i].prn;
+        // TODO: implement the correct logic to derive the constellation type
+        // based on PRN ranges.
+        if (info.svid >=1 && info.svid <= 32) {
             info.constellation = GNSS_CONSTELLATION_GPS;
-            info.prn = sv_status->sv_list[i].prn;
-            info.snr = sv_status->sv_list[i].snr;
-            info.elevation = sv_status->sv_list[i].elevation;
-            info.azimuth = sv_status->sv_list[i].azimuth;
-            info.flags = GNSS_SV_FLAGS_NONE;
-            if (info.prn > 0 && info.prn <= 32) {
-              int32_t this_prn_mask = (1 << (info.prn - 1));
-              if ((ephemeris_mask & this_prn_mask) != 0) {
+        } else {
+            info.constellation = GNSS_CONSTELLATION_UNKNOWN;
+        }
+        info.snr = sv_status->sv_list[i].snr;
+        info.elevation = sv_status->sv_list[i].elevation;
+        info.azimuth = sv_status->sv_list[i].azimuth;
+        info.flags = GNSS_SV_FLAGS_NONE;
+        if (info.svid > 0 && info.svid <= 32) {
+            int32_t this_svid_mask = (1 << (info.svid - 1));
+            if ((ephemeris_mask & this_svid_mask) != 0) {
                 info.flags |= GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA;
-              }
-              if ((almanac_mask & this_prn_mask) != 0) {
+            }
+            if ((almanac_mask & this_svid_mask) != 0) {
                 info.flags |= GNSS_SV_FLAGS_HAS_ALMANAC_DATA;
-              }
-              if ((used_in_fix_mask & this_prn_mask) != 0) {
+            }
+            if ((used_in_fix_mask & this_svid_mask) != 0) {
                 info.flags |= GNSS_SV_FLAGS_USED_IN_FIX;
-              }
             }
         }
-    } else {
-        sGnssSvListSize = 0;
-        ALOGE("Invalid size of GpsSvStatus found: %zd.", status_size);
+    }
+    env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void gnss_sv_status_callback(GnssSvStatus* sv_status) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    size_t status_size = sv_status->size;
+    // Check the size, and reject the object that has invalid size.
+    if (status_size != sizeof(GnssSvStatus)) {
+        ALOGE("Invalid size of GnssSvStatus found: %zd.", status_size);
         return;
     }
+    sGnssSvListSize = sv_status->num_svs;
+    // Clamp the list size
+    if (sGnssSvListSize > GNSS_MAX_SATELLITE_COUNT) {
+        ALOGD("Too many satellites %zd. Clamps to %d.",
+              sGnssSvListSize,
+              GNSS_MAX_SATELLITE_COUNT);
+        sGnssSvListSize = GNSS_MAX_SATELLITE_COUNT;
+    }
+    // Copy GNSS SV info into sGnssSvList, if any.
+    if (sGnssSvListSize > 0) {
+        memcpy(sGnssSvList,
+               sv_status->gnss_sv_list,
+               sizeof(GnssSvInfo) * sGnssSvListSize);
+    }
     env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
@@ -228,6 +248,7 @@
     create_thread_callback,
     request_utc_time_callback,
     set_system_info_callback,
+    gnss_sv_status_callback,
 };
 
 static void xtra_download_request_callback()
@@ -677,31 +698,30 @@
 }
 
 static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
-        jintArray prnWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
-        jfloatArray azumArray, jintArray constellationTypeArray)
+        jintArray svidWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
+        jfloatArray azumArray)
 {
     // this should only be called from within a call to reportSvStatus
-    jint* prnWithFlags = env->GetIntArrayElements(prnWithFlagArray, 0);
+    jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
     jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
     jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
     jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
-    jint* constellationTypes = env->GetIntArrayElements(constellationTypeArray, 0);
 
     // GNSS SV info.
     for (size_t i = 0; i < sGnssSvListSize; ++i) {
         const GnssSvInfo& info = sGnssSvList[i];
-        constellationTypes[i] = info.constellation;
-        prnWithFlags[i] = (info.prn << PRN_SHIFT_WIDTH) | info.flags;
+        svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
+            (info.constellation << CONSTELLATION_TYPE_SHIFT_WIDTH) |
+            info.flags;
         snrs[i] = info.snr;
         elev[i] = info.elevation;
         azim[i] = info.azimuth;
     }
 
-    env->ReleaseIntArrayElements(prnWithFlagArray, prnWithFlags, 0);
+    env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
     env->ReleaseFloatArrayElements(snrArray, snrs, 0);
     env->ReleaseFloatArrayElements(elevArray, elev, 0);
     env->ReleaseFloatArrayElements(azumArray, azim, 0);
-    env->ReleaseIntArrayElements(constellationTypeArray, constellationTypes, 0);
     return (jint) sGnssSvListSize;
 }
 
@@ -968,370 +988,341 @@
     return JNI_FALSE;
 }
 
-static jobject translate_gps_clock(JNIEnv* env, void* data, size_t size) {
-    const char* doubleSignature = "(D)V";
-    const char* longSignature = "(J)V";
+template<class T>
+class JavaMethodHelper {
+  public:
+   // Helper function to call setter on a Java object.
+   static void callJavaMethod(
+           JNIEnv* env,
+           jclass clazz,
+           jobject object,
+           const char* method_name,
+           T value);
 
-    GpsClock* clock = reinterpret_cast<GpsClock*>(data);
+  private:
+    static const char *const signature_;
+};
 
-    jclass gpsClockClass = env->FindClass("android/location/GnssClock");
-    jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
+template<class T>
+void JavaMethodHelper<T>::callJavaMethod(
+        JNIEnv* env,
+        jclass clazz,
+        jobject object,
+        const char* method_name,
+        T value) {
+    jmethodID method = env->GetMethodID(clazz, method_name, signature_);
+    env->CallVoidMethod(object, method, value);
+}
 
-    jobject gpsClockObject = env->NewObject(gpsClockClass, gpsClockCtor);
+class JavaObject {
+  public:
+   JavaObject(JNIEnv* env, const char* class_name);
+   virtual ~JavaObject();
+
+   template<class T>
+   void callSetter(const char* method_name, T value);
+   template<class T>
+   void callSetter(const char* method_name, T* value, size_t size);
+   jobject get();
+
+  private:
+   JNIEnv* env_;
+   jclass clazz_;
+   jobject object_;
+};
+
+JavaObject::JavaObject(JNIEnv* env, const char* class_name) : env_(env) {
+    clazz_ = env_->FindClass(class_name);
+    jmethodID ctor = env->GetMethodID(clazz_, "<init>", "()V");
+    object_ = env_->NewObject(clazz_, ctor);
+}
+
+JavaObject::~JavaObject() {
+    env_->DeleteLocalRef(clazz_);
+}
+
+template<class T>
+void JavaObject::callSetter(const char* method_name, T value) {
+    JavaMethodHelper<T>::callJavaMethod(
+            env_, clazz_, object_, method_name, value);
+}
+
+template<>
+void JavaObject::callSetter(
+        const char* method_name, uint8_t* value, size_t size) {
+    jbyteArray array = env_->NewByteArray(size);
+    env_->SetByteArrayRegion(array, 0, size, (jbyte*) value);
+    jmethodID method = env_->GetMethodID(
+            clazz_,
+            method_name,
+            "([B)V");
+    env_->CallVoidMethod(object_, method, array);
+}
+
+jobject JavaObject::get() {
+    return object_;
+}
+
+// Define Java method signatures for all known types.
+
+template<>
+const char *const JavaMethodHelper<uint8_t>::signature_ = "(B)V";
+template<>
+const char *const JavaMethodHelper<int8_t>::signature_ = "(B)V";
+template<>
+const char *const JavaMethodHelper<int16_t>::signature_ = "(S)V";
+template<>
+const char *const JavaMethodHelper<uint16_t>::signature_ = "(S)V";
+template<>
+const char *const JavaMethodHelper<int>::signature_ = "(I)V";
+template<>
+const char *const JavaMethodHelper<int64_t>::signature_ = "(J)V";
+template<>
+const char *const JavaMethodHelper<float>::signature_ = "(F)V";
+template<>
+const char *const JavaMethodHelper<double>::signature_ = "(D)V";
+template<>
+const char *const JavaMethodHelper<bool>::signature_ = "(Z)V";
+
+#define SET(setter, value) object.callSetter("set" # setter, (value))
+#define SET_IF(flag, setter, value) \
+        if (flags & (flag)) object.callSetter("set" # setter, (value))
+
+static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
+    JavaObject object(env, "android/location/GnssClock");
     GpsClockFlags flags = clock->flags;
 
-    if (flags & GPS_CLOCK_HAS_LEAP_SECOND) {
-        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setLeapSecond", "(S)V");
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->leap_second);
-   }
+    SET_IF(GPS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
+    SET(Type, clock->type);
+    SET(TimeInNs, clock->time_ns);
+    SET_IF(GPS_CLOCK_HAS_TIME_UNCERTAINTY,
+           TimeUncertaintyInNs,
+           clock->time_uncertainty_ns);
+    SET_IF(GPS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
+    SET_IF(GPS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+    SET_IF(GPS_CLOCK_HAS_BIAS_UNCERTAINTY,
+           BiasUncertaintyInNs,
+           clock->bias_uncertainty_ns);
+    SET_IF(GPS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+    SET_IF(GPS_CLOCK_HAS_DRIFT_UNCERTAINTY,
+           DriftUncertaintyInNsPerSec,
+           clock->drift_uncertainty_nsps);
 
-   jmethodID typeSetterMethod = env->GetMethodID(gpsClockClass, "setType", "(B)V");
-   env->CallVoidMethod(gpsClockObject, typeSetterMethod, clock->type);
-
-    jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setTimeInNs", longSignature);
-    env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_ns);
-
-    if (flags & GPS_CLOCK_HAS_TIME_UNCERTAINTY) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsClockClass, "setTimeUncertaintyInNs", doubleSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_uncertainty_ns);
-    }
-
-    if (flags & GPS_CLOCK_HAS_FULL_BIAS) {
-        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setFullBiasInNs", longSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->full_bias_ns);
-    }
-
-    if (flags & GPS_CLOCK_HAS_BIAS) {
-        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setBiasInNs", doubleSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_ns);
-    }
-
-    if (flags & GPS_CLOCK_HAS_BIAS_UNCERTAINTY) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsClockClass, "setBiasUncertaintyInNs", doubleSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_uncertainty_ns);
-    }
-
-    if (flags & GPS_CLOCK_HAS_DRIFT) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsClockClass, "setDriftInNsPerSec", doubleSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_nsps);
-    }
-
-    if (flags & GPS_CLOCK_HAS_DRIFT_UNCERTAINTY) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsClockClass, "setDriftUncertaintyInNsPerSec", doubleSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
-    }
-
+    /*
     if (flags & GPS_CLOCK_TYPE_LOCAL_HW_TIME) {
-        if (size == sizeof(GpsClock)) {
+        if (size == sizeof(GnssClock)) {
             jmethodID setterMethod =
                     env->GetMethodID(gpsClockClass,
                                      "setTimeOfLastHwClockDiscontinuityInNs",
                                      longSignature);
             env->CallVoidMethod(gpsClockObject,
                                 setterMethod,
-                                clock->time_of_last_hw_clock_discontinuity_ns);
+                                reinterpret_cast<GnssClock*>(clock)->time_of_last_hw_clock_discontinuity_ns);
         }
     }
+    */
 
-    env->DeleteLocalRef(gpsClockClass);
-    return gpsClockObject;
+    return object.get();
 }
 
-static jobject translate_gps_measurement(JNIEnv* env, void* data, size_t size) {
-    const char* byteSignature = "(B)V";
-    const char* shortSignature = "(S)V";
-    const char* intSignature = "(I)V";
-    const char* longSignature = "(J)V";
-    const char* floatSignature = "(F)V";
-    const char* doubleSignature = "(D)V";
+static jobject translate_gnss_clock(JNIEnv* env, GnssClock* clock) {
+    JavaObject object(env, "android/location/GnssClock");
+    GpsClockFlags flags = clock->flags;
 
-    jclass gnssMeasurementClass = env->FindClass("android/location/GnssMeasurement");
-    jmethodID gnssMeasurementCtor = env->GetMethodID(gnssMeasurementClass, "<init>", "()V");
-    GpsMeasurement* measurement = reinterpret_cast<GpsMeasurement*>(data);
+    SET_IF(GPS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
+    SET(Type, clock->type);
+    SET(TimeInNs, clock->time_ns);
+    SET_IF(GPS_CLOCK_HAS_TIME_UNCERTAINTY,
+           TimeUncertaintyInNs,
+           clock->time_uncertainty_ns);
+    SET_IF(GPS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
+    SET_IF(GPS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+    SET_IF(GPS_CLOCK_HAS_BIAS_UNCERTAINTY,
+           BiasUncertaintyInNs,
+           clock->bias_uncertainty_ns);
+    SET_IF(GPS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+    SET_IF(GPS_CLOCK_HAS_DRIFT_UNCERTAINTY,
+           DriftUncertaintyInNsPerSec,
+           clock->drift_uncertainty_nsps);
 
-    jobject gnssMeasurementObject = env->NewObject(gnssMeasurementClass, gnssMeasurementCtor);
+    SET_IF(GPS_CLOCK_TYPE_LOCAL_HW_TIME,
+           TimeOfLastHwClockDiscontinuityInNs,
+           clock->time_of_last_hw_clock_discontinuity_ns);
+
+    return object.get();
+}
+
+static jobject translate_gps_measurement(JNIEnv* env,
+                                         GpsMeasurement* measurement) {
+    JavaObject object(env, "android/location/GnssMeasurement");
     GpsMeasurementFlags flags = measurement->flags;
 
-    jmethodID prnSetterMethod = env->GetMethodID(gnssMeasurementClass, "setPrn", byteSignature);
-    env->CallVoidMethod(gnssMeasurementObject, prnSetterMethod, measurement->prn);
+    SET(Svid, static_cast<int16_t>(measurement->prn));
+    SET(TimeOffsetInNs, measurement->time_offset_ns);
+    SET(State, measurement->state);
+    SET(ReceivedGpsTowInNs, measurement->received_gps_tow_ns);
+    SET(ReceivedGpsTowUncertaintyInNs,
+        measurement->received_gps_tow_uncertainty_ns);
+    SET(Cn0InDbHz, measurement->c_n0_dbhz);
+    SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
+    SET(PseudorangeRateUncertaintyInMetersPerSec,
+        measurement->pseudorange_rate_uncertainty_mps);
+    SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
+    SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
+    SET(AccumulatedDeltaRangeUncertaintyInMeters,
+        measurement->accumulated_delta_range_uncertainty_m);
+    SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE,
+           PseudorangeInMeters,
+           measurement->pseudorange_m);
+    SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
+           PseudorangeUncertaintyInMeters,
+           measurement->pseudorange_uncertainty_m);
+    SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE,
+           CodePhaseInChips,
+           measurement->code_phase_chips);
+    SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
+           CodePhaseUncertaintyInChips,
+           measurement->code_phase_uncertainty_chips);
+    SET_IF(GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
+           CarrierFrequencyInHz,
+           measurement->carrier_frequency_hz);
+    SET_IF(GPS_MEASUREMENT_HAS_CARRIER_CYCLES,
+           CarrierCycles,
+           measurement->carrier_cycles);
+    SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE,
+           CarrierPhase,
+           measurement->carrier_phase);
+    SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
+           CarrierPhaseUncertainty,
+           measurement->carrier_phase_uncertainty);
+    SET(LossOfLock, measurement->loss_of_lock);
+    SET_IF(GPS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
+    SET_IF(GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
+           TimeFromLastBitInMs,
+           measurement->time_from_last_bit_ms);
+    SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT,
+           DopplerShiftInHz,
+           measurement->doppler_shift_hz);
+    SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
+           DopplerShiftUncertaintyInHz,
+           measurement->doppler_shift_uncertainty_hz);
+    SET(MultipathIndicator, measurement->multipath_indicator);
+    SET_IF(GPS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
+    SET_IF(GPS_MEASUREMENT_HAS_ELEVATION,
+           ElevationInDeg,
+           measurement->elevation_deg);
+    SET_IF(GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
+           ElevationUncertaintyInDeg,
+           measurement->elevation_uncertainty_deg);
+    SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH,
+           AzimuthInDeg,
+           measurement->azimuth_deg);
+    SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
+           AzimuthUncertaintyInDeg,
+           measurement->azimuth_uncertainty_deg);
+    SET(UsedInFix,
+        (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
 
-    jmethodID timeOffsetSetterMethod =
-            env->GetMethodID(gnssMeasurementClass, "setTimeOffsetInNs", doubleSignature);
-    env->CallVoidMethod(
-            gnssMeasurementObject,
-            timeOffsetSetterMethod,
-            measurement->time_offset_ns);
-
-    jmethodID stateSetterMethod = env->GetMethodID(gnssMeasurementClass, "setState", shortSignature);
-    env->CallVoidMethod(gnssMeasurementObject, stateSetterMethod, measurement->state);
-
-    jmethodID receivedGpsTowSetterMethod =
-            env->GetMethodID(gnssMeasurementClass, "setReceivedGpsTowInNs", longSignature);
-    env->CallVoidMethod(
-            gnssMeasurementObject,
-            receivedGpsTowSetterMethod,
-            measurement->received_gps_tow_ns);
-
-    jmethodID receivedGpsTowUncertaintySetterMethod = env->GetMethodID(
-            gnssMeasurementClass,
-            "setReceivedGpsTowUncertaintyInNs",
-            longSignature);
-    env->CallVoidMethod(
-            gnssMeasurementObject,
-            receivedGpsTowUncertaintySetterMethod,
-            measurement->received_gps_tow_uncertainty_ns);
-
-    jmethodID cn0SetterMethod =
-            env->GetMethodID(gnssMeasurementClass, "setCn0InDbHz", doubleSignature);
-    env->CallVoidMethod(gnssMeasurementObject, cn0SetterMethod, measurement->c_n0_dbhz);
-
-    jmethodID pseudorangeRateSetterMethod = env->GetMethodID(
-            gnssMeasurementClass,
-            "setPseudorangeRateInMetersPerSec",
-            doubleSignature);
-    env->CallVoidMethod(
-            gnssMeasurementObject,
-            pseudorangeRateSetterMethod,
-            measurement->pseudorange_rate_mps);
-
-    jmethodID pseudorangeRateUncertaintySetterMethod = env->GetMethodID(
-            gnssMeasurementClass,
-            "setPseudorangeRateUncertaintyInMetersPerSec",
-            doubleSignature);
-    env->CallVoidMethod(
-            gnssMeasurementObject,
-            pseudorangeRateUncertaintySetterMethod,
-            measurement->pseudorange_rate_uncertainty_mps);
-
-    jmethodID accumulatedDeltaRangeStateSetterMethod =
-            env->GetMethodID(gnssMeasurementClass, "setAccumulatedDeltaRangeState", shortSignature);
-    env->CallVoidMethod(
-            gnssMeasurementObject,
-            accumulatedDeltaRangeStateSetterMethod,
-            measurement->accumulated_delta_range_state);
-
-    jmethodID accumulatedDeltaRangeSetterMethod = env->GetMethodID(
-            gnssMeasurementClass,
-            "setAccumulatedDeltaRangeInMeters",
-            doubleSignature);
-    env->CallVoidMethod(
-            gnssMeasurementObject,
-            accumulatedDeltaRangeSetterMethod,
-            measurement->accumulated_delta_range_m);
-
-    jmethodID accumulatedDeltaRangeUncertaintySetterMethod = env->GetMethodID(
-            gnssMeasurementClass,
-            "setAccumulatedDeltaRangeUncertaintyInMeters",
-            doubleSignature);
-    env->CallVoidMethod(
-            gnssMeasurementObject,
-            accumulatedDeltaRangeUncertaintySetterMethod,
-            measurement->accumulated_delta_range_uncertainty_m);
-
-    if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setPseudorangeInMeters", doubleSignature);
-        env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->pseudorange_m);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY) {
-        jmethodID setterMethod = env->GetMethodID(
-                gnssMeasurementClass,
-                "setPseudorangeUncertaintyInMeters",
-                doubleSignature);
-        env->CallVoidMethod(
-                gnssMeasurementObject,
-                setterMethod,
-                measurement->pseudorange_uncertainty_m);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setCodePhaseInChips", doubleSignature);
-        env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->code_phase_chips);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY) {
-        jmethodID setterMethod = env->GetMethodID(
-                gnssMeasurementClass,
-                "setCodePhaseUncertaintyInChips",
-                doubleSignature);
-        env->CallVoidMethod(
-                gnssMeasurementObject,
-                setterMethod,
-                measurement->code_phase_uncertainty_chips);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setCarrierFrequencyInHz", floatSignature);
-        env->CallVoidMethod(
-                gnssMeasurementObject,
-                setterMethod,
-                measurement->carrier_frequency_hz);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CARRIER_CYCLES) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setCarrierCycles", longSignature);
-        env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->carrier_cycles);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setCarrierPhase", doubleSignature);
-        env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->carrier_phase);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
-        jmethodID setterMethod = env->GetMethodID(
-                gnssMeasurementClass,
-                "setCarrierPhaseUncertainty",
-                doubleSignature);
-        env->CallVoidMethod(
-                gnssMeasurementObject,
-                setterMethod,
-                measurement->carrier_phase_uncertainty);
-    }
-
-    jmethodID lossOfLockSetterMethod =
-            env->GetMethodID(gnssMeasurementClass, "setLossOfLock", byteSignature);
-    env->CallVoidMethod(gnssMeasurementObject, lossOfLockSetterMethod, measurement->loss_of_lock);
-
-    if (flags & GPS_MEASUREMENT_HAS_BIT_NUMBER) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setBitNumber", intSignature);
-        env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->bit_number);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setTimeFromLastBitInMs", shortSignature);
-        env->CallVoidMethod(
-                gnssMeasurementObject,
-                setterMethod,
-                measurement->time_from_last_bit_ms);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setDopplerShiftInHz", doubleSignature);
-        env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->doppler_shift_hz);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY) {
-        jmethodID setterMethod = env->GetMethodID(
-                gnssMeasurementClass,
-                "setDopplerShiftUncertaintyInHz",
-                doubleSignature);
-        env->CallVoidMethod(
-                gnssMeasurementObject,
-                setterMethod,
-                measurement->doppler_shift_uncertainty_hz);
-    }
-
-    jmethodID multipathIndicatorSetterMethod =
-            env->GetMethodID(gnssMeasurementClass, "setMultipathIndicator", byteSignature);
-    env->CallVoidMethod(
-            gnssMeasurementObject,
-            multipathIndicatorSetterMethod,
-            measurement->multipath_indicator);
-
-    if (flags & GPS_MEASUREMENT_HAS_SNR) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setSnrInDb", doubleSignature);
-        env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->snr_db);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_ELEVATION) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setElevationInDeg", doubleSignature);
-        env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->elevation_deg);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setElevationUncertaintyInDeg", doubleSignature);
-        env->CallVoidMethod(
-                gnssMeasurementObject,
-                setterMethod,
-                measurement->elevation_uncertainty_deg);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_AZIMUTH) {
-        jmethodID setterMethod =
-                env->GetMethodID(gnssMeasurementClass, "setAzimuthInDeg", doubleSignature);
-        env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->azimuth_deg);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY) {
-        jmethodID setterMethod = env->GetMethodID(
-                gnssMeasurementClass,
-                "setAzimuthUncertaintyInDeg",
-                doubleSignature);
-        env->CallVoidMethod(
-                gnssMeasurementObject,
-                setterMethod,
-                measurement->azimuth_uncertainty_deg);
-    }
-
-    jmethodID usedInFixSetterMethod = env->GetMethodID(gnssMeasurementClass, "setUsedInFix", "(Z)V");
-    env->CallVoidMethod(
-            gnssMeasurementObject,
-            usedInFixSetterMethod,
-            (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
-
-    if (size == sizeof(GpsMeasurement)) {
-      jmethodID setterMethod =
-          env->GetMethodID(gnssMeasurementClass,
-                           "setPseudorangeRateCarrierInMetersPerSec",
-                           doubleSignature);
-      env->CallVoidMethod(
-          gnssMeasurementObject,
-          setterMethod,
-          measurement->pseudorange_rate_carrier_mps);
-
-      setterMethod =
-          env->GetMethodID(gnssMeasurementClass,
-                           "setPseudorangeRateCarrierUncertaintyInMetersPerSec",
-                           doubleSignature);
-      env->CallVoidMethod(
-          gnssMeasurementObject,
-          setterMethod,
-          measurement->pseudorange_rate_carrier_uncertainty_mps);
-    }
-
-    env->DeleteLocalRef(gnssMeasurementClass);
-    return gnssMeasurementObject;
+    return object.get();
 }
 
-/**
- * <T> can only be GpsData or GpsData_v1. Must rewrite this function if more
- * types are introduced in the future releases.
- */
-template<class T>
-static jobjectArray translate_gps_measurements(JNIEnv* env, void* data) {
-    T* gps_data = reinterpret_cast<T*>(data);
-    size_t measurementCount = gps_data->measurement_count;
-    if (measurementCount == 0) {
+static jobject translate_gnss_measurement(JNIEnv* env,
+                                          GnssMeasurement* measurement) {
+    JavaObject object(env, "android/location/GnssMeasurement");
+    GpsMeasurementFlags flags = measurement->flags;
+
+    SET(Svid, measurement->svid);
+    SET(TimeOffsetInNs, measurement->time_offset_ns);
+    SET(State, measurement->state);
+    SET(ReceivedGpsTowInNs, measurement->received_gps_tow_ns);
+    SET(ReceivedGpsTowUncertaintyInNs,
+        measurement->received_gps_tow_uncertainty_ns);
+    SET(Cn0InDbHz, measurement->c_n0_dbhz);
+    SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
+    SET(PseudorangeRateUncertaintyInMetersPerSec,
+        measurement->pseudorange_rate_uncertainty_mps);
+    SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
+    SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
+    SET(AccumulatedDeltaRangeUncertaintyInMeters,
+        measurement->accumulated_delta_range_uncertainty_m);
+    SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE,
+           PseudorangeInMeters,
+           measurement->pseudorange_m);
+    SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
+           PseudorangeUncertaintyInMeters,
+           measurement->pseudorange_uncertainty_m);
+    SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE,
+           CodePhaseInChips,
+           measurement->code_phase_chips);
+    SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
+           CodePhaseUncertaintyInChips,
+           measurement->code_phase_uncertainty_chips);
+    SET_IF(GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
+           CarrierFrequencyInHz,
+           measurement->carrier_frequency_hz);
+    SET_IF(GPS_MEASUREMENT_HAS_CARRIER_CYCLES,
+           CarrierCycles,
+           measurement->carrier_cycles);
+    SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE,
+           CarrierPhase,
+           measurement->carrier_phase);
+    SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
+           CarrierPhaseUncertainty,
+           measurement->carrier_phase_uncertainty);
+    SET(LossOfLock, measurement->loss_of_lock);
+    SET_IF(GPS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
+    SET_IF(GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
+           TimeFromLastBitInMs,
+           measurement->time_from_last_bit_ms);
+    SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT,
+           DopplerShiftInHz,
+           measurement->doppler_shift_hz);
+    SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
+           DopplerShiftUncertaintyInHz,
+           measurement->doppler_shift_uncertainty_hz);
+    SET(MultipathIndicator, measurement->multipath_indicator);
+    SET_IF(GPS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
+    SET_IF(GPS_MEASUREMENT_HAS_ELEVATION,
+           ElevationInDeg,
+           measurement->elevation_deg);
+    SET_IF(GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
+           ElevationUncertaintyInDeg,
+           measurement->elevation_uncertainty_deg);
+    SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH,
+           AzimuthInDeg,
+           measurement->azimuth_deg);
+    SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
+           AzimuthUncertaintyInDeg,
+           measurement->azimuth_uncertainty_deg);
+    SET(UsedInFix,
+        (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
+
+    SET(PseudorangeRateCarrierInMetersPerSec,
+        measurement->pseudorange_rate_carrier_mps);
+    SET(PseudorangeRateCarrierUncertaintyInMetersPerSec,
+        measurement->pseudorange_rate_carrier_uncertainty_mps);
+
+    return object.get();
+}
+
+static jobjectArray translate_gps_measurements(JNIEnv* env,
+                                               GpsMeasurement* measurements,
+                                               size_t count) {
+    if (count == 0) {
         return NULL;
     }
 
-    jclass gnssMeasurementClass = env->FindClass("android/location/GnssMeasurement");
+    jclass gnssMeasurementClass = env->FindClass(
+            "android/location/GnssMeasurement");
     jobjectArray gnssMeasurementArray = env->NewObjectArray(
-            measurementCount,
+            count,
             gnssMeasurementClass,
             NULL /* initialElement */);
 
-    for (uint16_t i = 0; i < measurementCount; ++i) {
+    for (uint16_t i = 0; i < count; ++i) {
         jobject gnssMeasurement = translate_gps_measurement(
             env,
-            &(gps_data->measurements[i]),
-            sizeof(gps_data->measurements[0]));
+            &measurements[i]);
         env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement);
         env->DeleteLocalRef(gnssMeasurement);
     }
@@ -1340,27 +1331,37 @@
     return gnssMeasurementArray;
 }
 
-static void measurement_callback(GpsData* data) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (data == NULL) {
-        ALOGE("Invalid data provided to gps_measurement_callback");
-        return;
-    }
-    if (data->size != sizeof(GpsData) && data->size != sizeof(GpsData_v1)) {
-        ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%zd", data->size);
-        return;
+static jobjectArray translate_gnss_measurements(JNIEnv* env,
+                                                GnssMeasurement* measurements,
+                                                size_t count) {
+    if (count == 0) {
+        return NULL;
     }
 
-    jobject gpsClock;
-    jobjectArray measurementArray;
-    if (data->size == sizeof(GpsData)) {
-        gpsClock = translate_gps_clock(env, &data->clock, sizeof(GpsClock));
-        measurementArray = translate_gps_measurements<GpsData>(env, data);
-    } else {
-        gpsClock = translate_gps_clock(env, &data->clock, sizeof(GpsClock_v1));
-        measurementArray = translate_gps_measurements<GpsData_v1>(env, data);
+    jclass gnssMeasurementClass = env->FindClass(
+            "android/location/GnssMeasurement");
+    jobjectArray gnssMeasurementArray = env->NewObjectArray(
+            count,
+            gnssMeasurementClass,
+            NULL /* initialElement */);
+
+    for (uint16_t i = 0; i < count; ++i) {
+        jobject gnssMeasurement = translate_gnss_measurement(
+            env,
+            &measurements[i]);
+        env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement);
+        env->DeleteLocalRef(gnssMeasurement);
     }
-    jclass gnssMeasurementsEventClass = env->FindClass("android/location/GnssMeasurementsEvent");
+
+    env->DeleteLocalRef(gnssMeasurementClass);
+    return gnssMeasurementArray;
+}
+
+static void set_measurement_data(JNIEnv *env,
+                                 jobject clock,
+                                 jobjectArray measurementArray) {
+    jclass gnssMeasurementsEventClass = env->FindClass(
+            "android/location/GnssMeasurementsEvent");
     jmethodID gnssMeasurementsEventCtor = env->GetMethodID(
         gnssMeasurementsEventClass,
         "<init>",
@@ -1369,21 +1370,68 @@
     jobject gnssMeasurementsEvent = env->NewObject(
         gnssMeasurementsEventClass,
         gnssMeasurementsEventCtor,
-        gpsClock,
+        clock,
         measurementArray);
-
-    env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gnssMeasurementsEvent);
+    env->CallVoidMethod(mCallbacksObj,
+                        method_reportMeasurementData,
+                        gnssMeasurementsEvent);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
-    env->DeleteLocalRef(gpsClock);
-    env->DeleteLocalRef(measurementArray);
     env->DeleteLocalRef(gnssMeasurementsEventClass);
     env->DeleteLocalRef(gnssMeasurementsEvent);
 }
 
+static void measurement_callback(GpsData* data) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (data == NULL) {
+        ALOGE("Invalid data provided to gps_measurement_callback");
+        return;
+    }
+    if (data->size != sizeof(GpsData)) {
+        ALOGE("Invalid GpsData size found in gps_measurement_callback, "
+              "size=%zd",
+              data->size);
+        return;
+    }
+
+    jobject clock;
+    jobjectArray measurementArray;
+    clock = translate_gps_clock(env, &data->clock);
+    measurementArray = translate_gps_measurements(
+            env, data->measurements, data->measurement_count);
+    set_measurement_data(env, clock, measurementArray);
+
+    env->DeleteLocalRef(clock);
+    env->DeleteLocalRef(measurementArray);
+}
+
+static void gnss_measurement_callback(GnssData* data) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (data == NULL) {
+        ALOGE("Invalid data provided to gps_measurement_callback");
+        return;
+    }
+    if (data->size != sizeof(GpsData)) {
+        ALOGE("Invalid GpsData size found in gps_measurement_callback, "
+              "size=%zd",
+              data->size);
+        return;
+    }
+
+    jobject clock;
+    jobjectArray measurementArray;
+    clock = translate_gnss_clock(env, &data->clock);
+    measurementArray = translate_gnss_measurements(
+            env, data->measurements, data->measurement_count);
+    set_measurement_data(env, clock, measurementArray);
+
+    env->DeleteLocalRef(clock);
+    env->DeleteLocalRef(measurementArray);
+}
+
 GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
     sizeof(GpsMeasurementCallbacks),
     measurement_callback,
+    gnss_measurement_callback,
 };
 
 static jboolean android_location_GnssLocationProvider_is_measurement_supported(
@@ -1431,69 +1479,86 @@
         ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
         return NULL;
     }
+    JavaObject object(env, "android/location/GnssNavigationMessage");
+    SET(Type, message->type);
+    SET(Svid, static_cast<int16_t>(message->prn));
+    SET(MessageId, message->message_id);
+    SET(SubmessageId, message->submessage_id);
+    object.callSetter("setData", data, dataLength);
+    return object.get();
+}
 
-    jclass navigationMessageClass = env->FindClass("android/location/GnssNavigationMessage");
-    jmethodID navigationMessageCtor = env->GetMethodID(navigationMessageClass, "<init>", "()V");
-    jobject navigationMessageObject = env->NewObject(navigationMessageClass, navigationMessageCtor);
+static jobject translate_gnss_navigation_message(
+        JNIEnv* env, GnssNavigationMessage* message) {
+    size_t dataLength = message->data_length;
+    uint8_t* data = message->data;
+    if (dataLength == 0 || data == NULL) {
+        ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
+        return NULL;
+    }
+    JavaObject object(env, "android/location/GnssNavigationMessage");
+    SET(Type, message->type);
+    SET(Svid, message->svid);
+    SET(MessageId, message->message_id);
+    SET(SubmessageId, message->submessage_id);
+    object.callSetter("setData", data, dataLength);
+    return object.get();
+}
 
-    jmethodID setTypeMethod = env->GetMethodID(navigationMessageClass, "setType", "(B)V");
-    env->CallVoidMethod(navigationMessageObject, setTypeMethod, message->type);
-
-    jmethodID setPrnMethod = env->GetMethodID(navigationMessageClass, "setPrn", "(B)V");
-    env->CallVoidMethod(navigationMessageObject, setPrnMethod, message->prn);
-
-    jmethodID setMessageIdMethod = env->GetMethodID(navigationMessageClass, "setMessageId", "(S)V");
-    env->CallVoidMethod(navigationMessageObject, setMessageIdMethod, message->message_id);
-
-    jmethodID setSubmessageIdMethod =
-            env->GetMethodID(navigationMessageClass, "setSubmessageId", "(S)V");
-    env->CallVoidMethod(navigationMessageObject, setSubmessageIdMethod, message->submessage_id);
-
-    jbyteArray dataArray = env->NewByteArray(dataLength);
-    env->SetByteArrayRegion(dataArray, 0, dataLength, (jbyte*) data);
-    jmethodID setDataMethod = env->GetMethodID(navigationMessageClass, "setData", "([B)V");
-    env->CallVoidMethod(navigationMessageObject, setDataMethod, dataArray);
-
-    env->DeleteLocalRef(navigationMessageClass);
-    env->DeleteLocalRef(dataArray);
-    return navigationMessageObject;
+static void set_navigation_message(jobject navigationMessage) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jclass navigationMessageEventClass =
+            env->FindClass("android/location/GnssNavigationMessageEvent");
+    jmethodID navigationMessageEventCtor = env->GetMethodID(
+            navigationMessageEventClass,
+            "<init>",
+            "(Landroid/location/GnssNavigationMessage;)V");
+    jobject navigationMessageEvent = env->NewObject(
+            navigationMessageEventClass,
+            navigationMessageEventCtor,
+            navigationMessage);
+    env->CallVoidMethod(mCallbacksObj,
+                        method_reportNavigationMessages,
+                        navigationMessageEvent);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    env->DeleteLocalRef(navigationMessageEventClass);
+    env->DeleteLocalRef(navigationMessageEvent);
 }
 
 static void navigation_message_callback(GpsNavigationMessage* message) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
     if (message == NULL) {
         ALOGE("Invalid Navigation Message provided to callback");
         return;
     }
-
-    if (message->size == sizeof(GpsNavigationMessage)) {
-        jobject navigationMessage = translate_gps_navigation_message(env, message);
-
-        jclass navigationMessageEventClass =
-                env->FindClass("android/location/GnssNavigationMessageEvent");
-        jmethodID navigationMessageEventCtor = env->GetMethodID(
-                navigationMessageEventClass,
-                "<init>",
-                "(Landroid/location/GnssNavigationMessage;)V");
-        jobject navigationMessageEvent = env->NewObject(
-                navigationMessageEventClass,
-                navigationMessageEventCtor,
-                navigationMessage);
-
-        env->CallVoidMethod(mCallbacksObj, method_reportNavigationMessages, navigationMessageEvent);
-        checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
-        env->DeleteLocalRef(navigationMessage);
-        env->DeleteLocalRef(navigationMessageEventClass);
-        env->DeleteLocalRef(navigationMessageEvent);
-    } else {
+    if (message->size != sizeof(GpsNavigationMessage)) {
         ALOGE("Invalid GpsNavigationMessage size found: %zd", message->size);
+        return;
     }
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jobject navigationMessage = translate_gps_navigation_message(env, message);
+    set_navigation_message(navigationMessage);
+    env->DeleteLocalRef(navigationMessage);
+}
+
+static void gnss_navigation_message_callback(GnssNavigationMessage* message) {
+    if (message == NULL) {
+        ALOGE("Invalid Navigation Message provided to callback");
+        return;
+    }
+    if (message->size != sizeof(GnssNavigationMessage)) {
+        ALOGE("Invalid GnssNavigationMessage size found: %zd", message->size);
+        return;
+    }
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jobject navigationMessage = translate_gnss_navigation_message(env, message);
+    set_navigation_message(navigationMessage);
+    env->DeleteLocalRef(navigationMessage);
 }
 
 GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
     sizeof(GpsNavigationMessageCallbacks),
     navigation_message_callback,
+    gnss_navigation_message_callback,
 };
 
 static jboolean android_location_GnssLocationProvider_is_navigation_message_supported(
@@ -1567,7 +1632,7 @@
             "(I)V",
             (void*)android_location_GnssLocationProvider_delete_aiding_data},
     {"native_read_sv_status",
-            "([I[F[F[F[I)I",
+            "([I[F[F[F)I",
             (void*)android_location_GnssLocationProvider_read_sv_status},
     {"native_read_nmea", "([BI)I", (void*)android_location_GnssLocationProvider_read_nmea},
     {"native_inject_time", "(JJI)V", (void*)android_location_GnssLocationProvider_inject_time},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f0fc0b3..916b66d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3524,11 +3524,14 @@
 
     @Override
     public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) {
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
-            // This API can only be called by an active device admin,
-            // so try to retrieve it to check that the caller is one.
-            getActiveAdminForCallerLocked(
-                    null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+            if (!isCallerWithSystemUid()) {
+                // This API can only be called by an active device admin,
+                // so try to retrieve it to check that the caller is one.
+                getActiveAdminForCallerLocked(
+                        null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+            }
 
             DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
 
@@ -8038,7 +8041,8 @@
 
     boolean isPackageInstalledForUser(String packageName, int userHandle) {
         try {
-            PackageInfo pi = mIPackageManager.getPackageInfo(packageName, 0, userHandle);
+            PackageInfo pi = mInjector.getIPackageManager().getPackageInfo(packageName, 0,
+                    userHandle);
             return (pi != null) && (pi.applicationInfo.flags != 0);
         } catch (RemoteException re) {
             throw new RuntimeException("Package manager has died", re);
@@ -8533,26 +8537,32 @@
             mPackagesToRemove.add(packageUserPair);
         }
 
-        final List<ComponentName> activeAdminsList = getActiveAdmins(userId);
-        if (activeAdminsList == null || activeAdminsList.size() == 0) {
-            startUninstallIntent(packageName, userId);
-            return;
-        }
+        // All active admins on the user.
+        final List<ComponentName> allActiveAdmins = getActiveAdmins(userId);
 
-        for (ComponentName activeAdmin : activeAdminsList) {
-            if (packageName.equals(activeAdmin.getPackageName())) {
-                removeActiveAdmin(activeAdmin, userId);
+        // Active admins in the target package.
+        final List<ComponentName> packageActiveAdmins = new ArrayList<>();
+        if (allActiveAdmins != null) {
+            for (ComponentName activeAdmin : allActiveAdmins) {
+                if (packageName.equals(activeAdmin.getPackageName())) {
+                    packageActiveAdmins.add(activeAdmin);
+                    removeActiveAdmin(activeAdmin, userId);
+                }
             }
         }
-        mHandler.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                for (ComponentName activeAdmin : activeAdminsList) {
-                    removeAdminArtifacts(activeAdmin, userId);
+        if (packageActiveAdmins.size() == 0) {
+            startUninstallIntent(packageName, userId);
+        } else {
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    for (ComponentName activeAdmin : packageActiveAdmins) {
+                        removeAdminArtifacts(activeAdmin, userId);
+                    }
+                    startUninstallIntent(packageName, userId);
                 }
-                startUninstallIntent(packageName, userId);
-            }
-        }, DEVICE_ADMIN_DEACTIVATE_TIMEOUT); // Start uninstall after timeout anyway.
+            }, DEVICE_ADMIN_DEACTIVATE_TIMEOUT); // Start uninstall after timeout anyway.
+        }
     }
 
     private void removePackageIfRequired(final String packageName, final int userId) {
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 2329b42..ceabfce 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -27,7 +27,6 @@
 import android.content.IntentFilter;
 import android.net.DhcpResults;
 import android.net.BaseDhcpStateMachine;
-import android.net.DhcpStateMachine;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.NetworkUtils;
@@ -103,12 +102,35 @@
     // t=0, t=2, t=6, t=14, t=30, allowing for 10% jitter.
     private static final int DHCP_TIMEOUT_MS    =  36 * SECONDS;
 
+    private static final int PUBLIC_BASE = Protocol.BASE_DHCP;
+
+    /* Commands from controller to start/stop DHCP */
+    public static final int CMD_START_DHCP                  = PUBLIC_BASE + 1;
+    public static final int CMD_STOP_DHCP                   = PUBLIC_BASE + 2;
+    public static final int CMD_RENEW_DHCP                  = PUBLIC_BASE + 3;
+
+    /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+    public static final int CMD_PRE_DHCP_ACTION             = PUBLIC_BASE + 4;
+    /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+     * success/failure */
+    public static final int CMD_POST_DHCP_ACTION            = PUBLIC_BASE + 5;
+    /* Notification from DHCP state machine before quitting */
+    public static final int CMD_ON_QUIT                     = PUBLIC_BASE + 6;
+
+    /* Command from controller to indicate DHCP discovery/renewal can continue
+     * after pre DHCP action is complete */
+    public static final int CMD_PRE_DHCP_ACTION_COMPLETE    = PUBLIC_BASE + 7;
+
+    /* Message.arg1 arguments to CMD_POST_DHCP notification */
+    public static final int DHCP_SUCCESS = 1;
+    public static final int DHCP_FAILURE = 2;
+
     // Messages.
-    private static final int BASE                 = Protocol.BASE_DHCP + 100;
-    private static final int CMD_KICK             = BASE + 1;
-    private static final int CMD_RECEIVED_PACKET  = BASE + 2;
-    private static final int CMD_TIMEOUT          = BASE + 3;
-    private static final int CMD_ONESHOT_TIMEOUT  = BASE + 4;
+    private static final int PRIVATE_BASE         = Protocol.BASE_DHCP + 100;
+    private static final int CMD_KICK             = PRIVATE_BASE + 1;
+    private static final int CMD_RECEIVED_PACKET  = PRIVATE_BASE + 2;
+    private static final int CMD_TIMEOUT          = PRIVATE_BASE + 3;
+    private static final int CMD_ONESHOT_TIMEOUT  = PRIVATE_BASE + 4;
 
     // DHCP parameters that we request.
     private static final byte[] REQUESTED_PARAMS = new byte[] {
@@ -211,7 +233,7 @@
         // Used to time out PacketRetransmittingStates.
         mTimeoutAlarm = makeWakeupMessage("TIMEOUT", CMD_TIMEOUT);
         // Used to schedule DHCP renews.
-        mRenewAlarm = makeWakeupMessage("RENEW", DhcpStateMachine.CMD_RENEW_DHCP);
+        mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP);
         // Used to tell the caller when its request (CMD_START_DHCP or CMD_RENEW_DHCP) timed out.
         // TODO: when the legacy DHCP client is gone, make the client fully asynchronous and
         // remove this.
@@ -400,13 +422,12 @@
     }
 
     private void notifySuccess() {
-        mController.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION,
-                DhcpStateMachine.DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
+        mController.sendMessage(
+                CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
     }
 
     private void notifyFailure() {
-        mController.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION,
-                DhcpStateMachine.DHCP_FAILURE, 0, null);
+        mController.sendMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0, null);
     }
 
     private void clearDhcpState() {
@@ -428,7 +449,7 @@
 
     protected void onQuitting() {
         Log.d(TAG, "onQuitting");
-        mController.sendMessage(DhcpStateMachine.CMD_ON_QUIT);
+        mController.sendMessage(CMD_ON_QUIT);
     }
 
     private void maybeLog(String msg) {
@@ -442,17 +463,17 @@
 
         private String messageName(int what) {
             switch (what) {
-                case DhcpStateMachine.CMD_START_DHCP:
+                case CMD_START_DHCP:
                     return "CMD_START_DHCP";
-                case DhcpStateMachine.CMD_STOP_DHCP:
+                case CMD_STOP_DHCP:
                     return "CMD_STOP_DHCP";
-                case DhcpStateMachine.CMD_RENEW_DHCP:
+                case CMD_RENEW_DHCP:
                     return "CMD_RENEW_DHCP";
-                case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+                case CMD_PRE_DHCP_ACTION:
                     return "CMD_PRE_DHCP_ACTION";
-                case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
+                case CMD_PRE_DHCP_ACTION_COMPLETE:
                     return "CMD_PRE_DHCP_ACTION_COMPLETE";
-                case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+                case CMD_POST_DHCP_ACTION:
                     return "CMD_POST_DHCP_ACTION";
                 case CMD_KICK:
                     return "CMD_KICK";
@@ -495,14 +516,14 @@
         @Override
         public void enter() {
             super.enter();
-            mController.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION);
+            mController.sendMessage(CMD_PRE_DHCP_ACTION);
         }
 
         @Override
         public boolean processMessage(Message message) {
             super.processMessage(message);
             switch (message.what) {
-                case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
+                case CMD_PRE_DHCP_ACTION_COMPLETE:
                     transitionTo(mOtherState);
                     return HANDLED;
                 default:
@@ -532,7 +553,7 @@
         public boolean processMessage(Message message) {
             super.processMessage(message);
             switch (message.what) {
-                case DhcpStateMachine.CMD_START_DHCP:
+                case CMD_START_DHCP:
                     scheduleOneshotTimeout();
                     if (mRegisteredForPreDhcpNotification) {
                         transitionTo(mWaitBeforeStartState);
@@ -588,7 +609,7 @@
         public boolean processMessage(Message message) {
             super.processMessage(message);
             switch (message.what) {
-                case DhcpStateMachine.CMD_STOP_DHCP:
+                case CMD_STOP_DHCP:
                     transitionTo(mStoppedState);
                     return HANDLED;
                 case CMD_ONESHOT_TIMEOUT:
@@ -810,7 +831,7 @@
         public boolean processMessage(Message message) {
             super.processMessage(message);
             switch (message.what) {
-                case DhcpStateMachine.CMD_RENEW_DHCP:
+                case CMD_RENEW_DHCP:
                     if (mRegisteredForPreDhcpNotification) {
                         transitionTo(mWaitBeforeRenewalState);
                     } else {
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 4fe97c1..a388a26 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -258,12 +258,12 @@
                 return "EVENT_PRE_DHCP_ACTION_COMPLETE";
             case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
                 return "EVENT_NETLINK_LINKPROPERTIES_CHANGED";
-            case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
-                return "DhcpStateMachine.CMD_PRE_DHCP_ACTION";
-            case DhcpStateMachine.CMD_POST_DHCP_ACTION:
-                return "DhcpStateMachine.CMD_POST_DHCP_ACTION";
-            case DhcpStateMachine.CMD_ON_QUIT:
-                return "DhcpStateMachine.CMD_ON_QUIT";
+            case DhcpClient.CMD_PRE_DHCP_ACTION:
+                return "DhcpClient.CMD_PRE_DHCP_ACTION";
+            case DhcpClient.CMD_POST_DHCP_ACTION:
+                return "DhcpClient.CMD_POST_DHCP_ACTION";
+            case DhcpClient.CMD_ON_QUIT:
+                return "DhcpClient.CMD_ON_QUIT";
         }
         return "UNKNOWN:" + Integer.toString(what);
     }
@@ -541,7 +541,7 @@
                     setLinkProperties(assembleLinkProperties());
                     break;
 
-                case DhcpStateMachine.CMD_ON_QUIT:
+                case DhcpClient.CMD_ON_QUIT:
                     // Everything is already stopped.
                     Log.e(mTag, "Unexpected CMD_ON_QUIT (already stopped).");
                     break;
@@ -565,7 +565,7 @@
         @Override
         public boolean processMessage(Message msg) {
             switch (msg.what) {
-                case DhcpStateMachine.CMD_ON_QUIT:
+                case DhcpClient.CMD_ON_QUIT:
                     mDhcpStateMachine = null;
                     transitionTo(mStoppedState);
                     break;
@@ -617,7 +617,7 @@
                 // Start DHCPv4.
                 makeDhcpStateMachine();
                 mDhcpStateMachine.registerForPreDhcpNotification();
-                mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
+                mDhcpStateMachine.sendMessage(DhcpClient.CMD_START_DHCP);
             }
         }
 
@@ -627,7 +627,7 @@
             mIpReachabilityMonitor = null;
 
             if (mDhcpStateMachine != null) {
-                mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
+                mDhcpStateMachine.sendMessage(DhcpClient.CMD_STOP_DHCP);
                 mDhcpStateMachine.doQuit();
             }
 
@@ -660,8 +660,7 @@
                     // calls completedPreDhcpAction() after provisioning with
                     // a static IP configuration.
                     if (mDhcpStateMachine != null) {
-                        mDhcpStateMachine.sendMessage(
-                                DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+                        mDhcpStateMachine.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
                     }
                     break;
 
@@ -678,12 +677,12 @@
                     break;
                 }
 
-                case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+                case DhcpClient.CMD_PRE_DHCP_ACTION:
                     if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); }
                     mCallback.onPreDhcpAction();
                     break;
 
-                case DhcpStateMachine.CMD_POST_DHCP_ACTION: {
+                case DhcpClient.CMD_POST_DHCP_ACTION: {
                     // Note that onPostDhcpAction() is likely to be
                     // asynchronous, and thus there is no guarantee that we
                     // will be able to observe any of its effects here.
@@ -692,10 +691,10 @@
 
                     final DhcpResults dhcpResults = (DhcpResults) msg.obj;
                     switch (msg.arg1) {
-                        case DhcpStateMachine.DHCP_SUCCESS:
+                        case DhcpClient.DHCP_SUCCESS:
                             handleIPv4Success(dhcpResults);
                             break;
-                        case DhcpStateMachine.DHCP_FAILURE:
+                        case DhcpClient.DHCP_FAILURE:
                             handleIPv4Failure();
                             break;
                         default:
@@ -704,7 +703,7 @@
                     break;
                 }
 
-                case DhcpStateMachine.CMD_ON_QUIT:
+                case DhcpClient.CMD_ON_QUIT:
                     // DHCPv4 quit early for some reason.
                     Log.e(mTag, "Unexpected CMD_ON_QUIT.");
                     mDhcpStateMachine = null;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 64f60d93..467ecd7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -22,9 +22,12 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.net.wifi.WifiInfo;
 import android.os.Build.VERSION_CODES;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Process;
 import android.os.UserHandle;
@@ -995,6 +998,7 @@
     public void testApplicationRestrictionsManagingApp() throws Exception {
         setAsProfileOwner(admin1);
 
+        final String nonExistAppRestrictionsManagerPackage = "com.google.app.restrictions.manager2";
         final String appRestrictionsManagerPackage = "com.google.app.restrictions.manager";
         final int appRestrictionsManagerAppId = 20987;
         final int appRestrictionsManagerUid = UserHandle.getUid(
@@ -1004,6 +1008,14 @@
                 eq(DpmMockContext.CALLER_USER_HANDLE));
         mContext.binder.callingUid = appRestrictionsManagerUid;
 
+        final PackageInfo pi = new PackageInfo();
+        pi.applicationInfo = new ApplicationInfo();
+        pi.applicationInfo.flags = ApplicationInfo.FLAG_HAS_CODE;
+        doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
+                eq(appRestrictionsManagerPackage),
+                anyInt(),
+                eq(DpmMockContext.CALLER_USER_HANDLE));
+
         // appRestrictionsManager package shouldn't be able to manage restrictions as the PO hasn't
         // delegated that permission yet.
         assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
@@ -1028,6 +1040,16 @@
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
         assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
 
+        // Check the API does not allow setting a non-existent package
+        try {
+            dpm.setApplicationRestrictionsManagingPackage(admin1,
+                    nonExistAppRestrictionsManagerPackage);
+            fail("Non-existent app set as app restriction manager.");
+        } catch (IllegalArgumentException expected) {
+            MoreAsserts.assertContainsRegex(
+                    "is not installed on the current user", expected.getMessage());
+        }
+
         // Let appRestrictionsManagerPackage manage app restrictions
         dpm.setApplicationRestrictionsManagingPackage(admin1, appRestrictionsManagerPackage);
         assertEquals(appRestrictionsManagerPackage,
diff --git a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
index 23a69d1..69259d0 100644
--- a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
@@ -17,6 +17,7 @@
 package com.android.ims.internal;
 
 import com.android.ims.ImsReasonInfo;
+
 /**
  * A listener type for receiving notifications about the changes to
  * the IMS connection(registration).
@@ -26,15 +27,36 @@
 interface IImsRegistrationListener {
     /**
      * Notifies the application when the device is connected to the IMS network.
+     *
+     * @deprecated see {@link registrationConnectedWithRadioTech}
      */
     void registrationConnected();
 
     /**
      * Notifies the application when the device is trying to connect the IMS network.
+     *
+     * @deprecated see {@link registrationProgressingWithRadioTech}
      */
     void registrationProgressing();
 
     /**
+     * Notifies the application when the device is connected to the IMS network.
+     *
+     * @param imsRadioTech the radio access technology. Valid values are {@code
+     * RIL_RADIO_TECHNOLOGY_*} defined in {@link ServiceState}.
+     */
+    void registrationConnectedWithRadioTech(int imsRadioTech);
+
+    /**
+     * Notifies the application when the device is trying to connect the IMS network.
+     *
+     * @param imsRadioTech the radio access technology. Valid values are {@code
+     * RIL_RADIO_TECHNOLOGY_*} defined in {@link ServiceState}.
+     */
+    void registrationProgressingWithRadioTech(int imsRadioTech);
+
+
+    /**
      * Notifies the application when the device is disconnected from the IMS network.
      */
     void registrationDisconnected(in ImsReasonInfo imsReasonInfo);
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 4d9ba6c..18a1943 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1883,8 +1883,6 @@
                     //printf("Comment of %s: %s\n", String8(e).string(),
                     //        String8(cmt).string());
                     syms->appendComment(String8(e), String16(cmt), srcPos);
-                } else {
-                    //printf("No comment for %s\n", String8(e).string());
                 }
                 syms->makeSymbolPublic(String8(e), srcPos);
             } else if (strcmp16(block.getElementName(&len), uses_permission16.string()) == 0) {
@@ -2535,10 +2533,6 @@
             fprintf(fp,
                     "%s/** %s\n",
                     getIndentSpace(indent), cmt.string());
-        } else if (sym.isPublic && !includePrivate) {
-            sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
-                assets->getPackage().string(), className.string(),
-                String8(sym.name).string());
         }
         String16 typeComment(sym.typeComment);
         if (typeComment.size() > 0) {
@@ -2581,10 +2575,6 @@
                      "%s */\n",
                     getIndentSpace(indent), cmt.string(),
                     getIndentSpace(indent));
-        } else if (sym.isPublic && !includePrivate) {
-            sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
-                assets->getPackage().string(), className.string(),
-                String8(sym.name).string());
         }
         ann.printAnnotations(fp, getIndentSpace(indent));
         fprintf(fp, "%spublic static final String %s=\"%s\";\n",
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index c7b24bc..b6588b6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -288,8 +288,10 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean nAddFontWeightStyle(long nativeFamily, final String path,
+    /*package*/ static boolean nAddFontWeightStyle(long nativeFamily,
+            final String path, final int index, final List<FontListParser.Axis> axes,
             final int weight, final boolean isItalic) {
+        // 'index' and 'axes' are not supported by java.awt.Font
         final FontFamily_Delegate delegate = getDelegate(nativeFamily);
         if (delegate != null) {
             if (sFontLocation == null) {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index d45ba03..4921073 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -44,6 +44,7 @@
 import com.android.internal.util.Protocol;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 
@@ -1319,13 +1320,15 @@
      * @return the list of access points found in the most recent scan. An app must hold
      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
-     * in order to get valid results.
+     * in order to get valid results.  If there is a remote exception (e.g., either a communication
+     * problem with the system service or an exception within the framework) an empty list will be
+     * returned.
      */
     public List<ScanResult> getScanResults() {
         try {
             return mService.getScanResults(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            return null;
+            return new ArrayList<ScanResult>();
         }
     }
 
diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
index 5c18bd7..9e6ed4e 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
@@ -36,7 +36,7 @@
  */
 public class WifiNanEventListener {
     private static final String TAG = "WifiNanEventListener";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
     /**
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index cb82268..667c4b1 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -38,7 +38,7 @@
  */
 public class WifiNanManager {
     private static final String TAG = "WifiNanManager";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
     private IBinder mBinder;
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index d0a9410..bc1787f 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -27,7 +27,7 @@
  */
 public class WifiNanSession {
     private static final String TAG = "WifiNanSession";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
     /**
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
index 0925087..b9af7def 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
@@ -43,7 +43,7 @@
  */
 public class WifiNanSessionListener {
     private static final String TAG = "WifiNanSessionListener";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
     /**