Merge "TIF: Refactor TvInputInfo"
diff --git a/Android.mk b/Android.mk
index c947b0e..5983b30 100644
--- a/Android.mk
+++ b/Android.mk
@@ -331,10 +331,10 @@
 	location/java/android/location/IFusedProvider.aidl \
 	location/java/android/location/IGeocodeProvider.aidl \
 	location/java/android/location/IGeofenceProvider.aidl \
+	location/java/android/location/IGnssStatusListener.aidl \
+	location/java/android/location/IGnssStatusProvider.aidl \
 	location/java/android/location/IGpsMeasurementsListener.aidl \
 	location/java/android/location/IGpsNavigationMessageListener.aidl \
-	location/java/android/location/IGpsStatusListener.aidl \
-	location/java/android/location/IGpsStatusProvider.aidl \
 	location/java/android/location/ILocationListener.aidl \
 	location/java/android/location/ILocationManager.aidl \
 	location/java/android/location/IFusedGeofenceHardware.aidl \
diff --git a/api/current.txt b/api/current.txt
index 50f8b21..aa503af 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -506,6 +506,8 @@
     field public static final int encryptionAware = 16844038; // 0x1010506
     field public static final int end = 16843996; // 0x10104dc
     field public static final int endColor = 16843166; // 0x101019e
+    field public static final int endX = 16844051; // 0x1010513
+    field public static final int endY = 16844052; // 0x1010514
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
     field public static final int entries = 16842930; // 0x10100b2
@@ -881,6 +883,7 @@
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
     field public static final int numericShortcut = 16843236; // 0x10101e4
+    field public static final int offset = 16844053; // 0x1010515
     field public static final int onClick = 16843375; // 0x101026f
     field public static final int oneshot = 16843159; // 0x1010197
     field public static final int opacity = 16843550; // 0x101031e
@@ -1128,6 +1131,8 @@
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
+    field public static final int startX = 16844049; // 0x1010511
+    field public static final int startY = 16844050; // 0x1010512
     field public static final deprecated int startYear = 16843132; // 0x101017c
     field public static final int stateListAnimator = 16843848; // 0x1010448
     field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -6511,8 +6516,9 @@
     field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
     field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
     field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
-    field public static final int TAG_DEVICE_LOCKED = 210007; // 0x33457
-    field public static final int TAG_DEVICE_UNLOCK_ATTEMPT = 210006; // 0x33456
+    field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+    field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+    field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
     field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
     field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
   }
@@ -9949,7 +9955,7 @@
     method public final long skip(long) throws java.io.IOException;
   }
 
-  public class ColorStateList implements android.os.Parcelable {
+  public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
     ctor public ColorStateList(int[][], int[]);
     method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -9958,13 +9964,18 @@
     method public int getColorForState(int[], int);
     method public int getDefaultColor();
     method public boolean isOpaque();
-    method public boolean isStateful();
     method public static android.content.res.ColorStateList valueOf(int);
     method public android.content.res.ColorStateList withAlpha(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
   }
 
+  public abstract class ComplexColor {
+    ctor public ComplexColor();
+    method public abstract int getDefaultColor();
+    method public boolean isStateful();
+  }
+
   public final class Configuration implements java.lang.Comparable android.os.Parcelable {
     ctor public Configuration();
     ctor public Configuration(android.content.res.Configuration);
@@ -10068,6 +10079,11 @@
     field public int uiMode;
   }
 
+  public class GradientColor extends android.content.res.ComplexColor {
+    method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public int getDefaultColor();
+  }
+
   public class ObbInfo implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -10127,6 +10143,7 @@
     method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
+    method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
     method public final android.content.res.Resources.Theme newTheme();
     method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
     method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10162,6 +10179,7 @@
     method public int getChangingConfigurations();
     method public int getColor(int, int);
     method public android.content.res.ColorStateList getColorStateList(int);
+    method public android.content.res.ComplexColor getComplexColor(int);
     method public float getDimension(int, float);
     method public int getDimensionPixelOffset(int, int);
     method public int getDimensionPixelSize(int, int);
@@ -13419,6 +13437,21 @@
     field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
   }
 
+  public class SensorAdditionalInfo {
+    field public static final int TYPE_FRAME_BEGIN = 0; // 0x0
+    field public static final int TYPE_FRAME_END = 1; // 0x1
+    field public static final int TYPE_INTERNAL_TEMPERATURE = 65537; // 0x10001
+    field public static final int TYPE_SAMPLING = 65540; // 0x10004
+    field public static final int TYPE_SENSOR_PLACEMENT = 65539; // 0x10003
+    field public static final int TYPE_UNTRACKED_DELAY = 65536; // 0x10000
+    field public static final int TYPE_VEC3_CALIBRATION = 65538; // 0x10002
+    field public final float[] floatValues;
+    field public final int[] intValues;
+    field public final android.hardware.Sensor sensor;
+    field public final int serial;
+    field public final int type;
+  }
+
   public class SensorEvent {
     field public int accuracy;
     field public android.hardware.Sensor sensor;
@@ -13426,6 +13459,14 @@
     field public final float[] values;
   }
 
+  public abstract class SensorEventCallback implements android.hardware.SensorEventListener2 {
+    ctor public SensorEventCallback();
+    method public void onAccuracyChanged(android.hardware.Sensor, int);
+    method public void onFlushCompleted(android.hardware.Sensor);
+    method public void onSensorAdditionalInfo(android.hardware.SensorAdditionalInfo);
+    method public void onSensorChanged(android.hardware.SensorEvent);
+  }
+
   public abstract interface SensorEventListener {
     method public abstract void onAccuracyChanged(android.hardware.Sensor, int);
     method public abstract void onSensorChanged(android.hardware.SensorEvent);
@@ -19036,6 +19077,288 @@
     method public static boolean isPresent();
   }
 
+  public abstract interface GnssNmeaListener {
+    method public abstract void onNmeaReceived(long, java.lang.String);
+  }
+
+  public final class GnssStatus {
+    method public float getAzimuth(int);
+    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 boolean hasAlmanac(int);
+    method public boolean hasEphemeris(int);
+    method public boolean usedInFix(int);
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+  }
+
+  public abstract class GnssStatusCallback {
+    ctor public GnssStatusCallback();
+    method public void onFirstFix(int);
+    method public void onSatelliteStatusChanged(android.location.GnssStatus);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  public final class GpsClock implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getBiasInNs();
+    method public double getBiasUncertaintyInNs();
+    method public double getDriftInNsPerSec();
+    method public double getDriftUncertaintyInNsPerSec();
+    method public long getFullBiasInNs();
+    method public short getLeapSecond();
+    method public long getTimeInNs();
+    method public long getTimeOfLastHwClockDiscontinuityInNs();
+    method public double getTimeUncertaintyInNs();
+    method public byte getType();
+    method public boolean hasBiasInNs();
+    method public boolean hasBiasUncertaintyInNs();
+    method public boolean hasDriftInNsPerSec();
+    method public boolean hasDriftUncertaintyInNsPerSec();
+    method public boolean hasFullBiasInNs();
+    method public boolean hasLeapSecond();
+    method public boolean hasTimeUncertaintyInNs();
+    method public void reset();
+    method public void resetBiasInNs();
+    method public void resetBiasUncertaintyInNs();
+    method public void resetDriftInNsPerSec();
+    method public void resetDriftUncertaintyInNsPerSec();
+    method public void resetFullBiasInNs();
+    method public void resetLeapSecond();
+    method public void resetTimeUncertaintyInNs();
+    method public void set(android.location.GpsClock);
+    method public void setBiasInNs(double);
+    method public void setBiasUncertaintyInNs(double);
+    method public void setDriftInNsPerSec(double);
+    method public void setDriftUncertaintyInNsPerSec(double);
+    method public void setFullBiasInNs(long);
+    method public void setLeapSecond(short);
+    method public void setTimeInNs(long);
+    method public void setTimeOfLastHwClockDiscontinuityInNs(long);
+    method public void setTimeUncertaintyInNs(double);
+    method public void setType(byte);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
+    field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
+    field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
+    field public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
+  }
+
+  public static abstract class GpsClock.GpsClockType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurement implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getAccumulatedDeltaRangeInMeters();
+    method public short getAccumulatedDeltaRangeState();
+    method public double getAccumulatedDeltaRangeUncertaintyInMeters();
+    method public double getAzimuthInDeg();
+    method public double getAzimuthUncertaintyInDeg();
+    method public int getBitNumber();
+    method public long getCarrierCycles();
+    method public float getCarrierFrequencyInHz();
+    method public double getCarrierPhase();
+    method public double getCarrierPhaseUncertainty();
+    method public double getCn0InDbHz();
+    method public double getCodePhaseInChips();
+    method public double getCodePhaseUncertaintyInChips();
+    method public double getDopplerShiftInHz();
+    method public double getDopplerShiftUncertaintyInHz();
+    method public double getElevationInDeg();
+    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();
+    method public double getPseudorangeRateInMetersPerSec();
+    method public double getPseudorangeRateUncertaintyInMetersPerSec();
+    method public double getPseudorangeUncertaintyInMeters();
+    method public long getReceivedGpsTowInNs();
+    method public long getReceivedGpsTowUncertaintyInNs();
+    method public double getSnrInDb();
+    method public short getState();
+    method public short getTimeFromLastBitInMs();
+    method public double getTimeOffsetInNs();
+    method public boolean hasAzimuthInDeg();
+    method public boolean hasAzimuthUncertaintyInDeg();
+    method public boolean hasBitNumber();
+    method public boolean hasCarrierCycles();
+    method public boolean hasCarrierFrequencyInHz();
+    method public boolean hasCarrierPhase();
+    method public boolean hasCarrierPhaseUncertainty();
+    method public boolean hasCodePhaseInChips();
+    method public boolean hasCodePhaseUncertaintyInChips();
+    method public boolean hasDopplerShiftInHz();
+    method public boolean hasDopplerShiftUncertaintyInHz();
+    method public boolean hasElevationInDeg();
+    method public boolean hasElevationUncertaintyInDeg();
+    method public boolean hasPseudorangeInMeters();
+    method public boolean hasPseudorangeUncertaintyInMeters();
+    method public boolean hasSnrInDb();
+    method public boolean hasTimeFromLastBitInMs();
+    method public boolean isPseudorangeRateCorrected();
+    method public boolean isUsedInFix();
+    method public void reset();
+    method public void resetAzimuthInDeg();
+    method public void resetAzimuthUncertaintyInDeg();
+    method public void resetBitNumber();
+    method public void resetCarrierCycles();
+    method public void resetCarrierFrequencyInHz();
+    method public void resetCarrierPhase();
+    method public void resetCarrierPhaseUncertainty();
+    method public void resetCodePhaseInChips();
+    method public void resetCodePhaseUncertaintyInChips();
+    method public void resetDopplerShiftInHz();
+    method public void resetDopplerShiftUncertaintyInHz();
+    method public void resetElevationInDeg();
+    method public void resetElevationUncertaintyInDeg();
+    method public void resetPseudorangeInMeters();
+    method public void resetPseudorangeUncertaintyInMeters();
+    method public void resetSnrInDb();
+    method public void resetTimeFromLastBitInMs();
+    method public void set(android.location.GpsMeasurement);
+    method public void setAccumulatedDeltaRangeInMeters(double);
+    method public void setAccumulatedDeltaRangeState(short);
+    method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
+    method public void setAzimuthInDeg(double);
+    method public void setAzimuthUncertaintyInDeg(double);
+    method public void setBitNumber(int);
+    method public void setCarrierCycles(long);
+    method public void setCarrierFrequencyInHz(float);
+    method public void setCarrierPhase(double);
+    method public void setCarrierPhaseUncertainty(double);
+    method public void setCn0InDbHz(double);
+    method public void setCodePhaseInChips(double);
+    method public void setCodePhaseUncertaintyInChips(double);
+    method public void setDopplerShiftInHz(double);
+    method public void setDopplerShiftUncertaintyInHz(double);
+    method public void setElevationInDeg(double);
+    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);
+    method public void setPseudorangeRateInMetersPerSec(double);
+    method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
+    method public void setPseudorangeUncertaintyInMeters(double);
+    method public void setReceivedGpsTowInNs(long);
+    method public void setReceivedGpsTowUncertaintyInNs(long);
+    method public void setSnrInDb(double);
+    method public void setState(short);
+    method public void setTimeFromLastBitInMs(short);
+    method public void setTimeOffsetInNs(double);
+    method public void setUsedInFix(boolean);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final short ADR_STATE_RESET = 2; // 0x2
+    field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
+    field public static final short ADR_STATE_VALID = 1; // 0x1
+    field public static final android.os.Parcelable.Creator<android.location.GpsMeasurement> CREATOR;
+    field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
+    field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
+    field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
+    field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+    field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final short STATE_BIT_SYNC = 2; // 0x2
+    field public static final short STATE_CODE_LOCK = 1; // 0x1
+    field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
+    field public static final short STATE_TOW_DECODED = 8; // 0x8
+    field public static final short STATE_UNKNOWN = 0; // 0x0
+  }
+
+  public static abstract class GpsMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class GpsMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurementsEvent implements android.os.Parcelable {
+    ctor public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
+    method public int describeContents();
+    method public android.location.GpsClock getClock();
+    method public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
+    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public static abstract class GpsMeasurementsEvent.Callback {
+    ctor public GpsMeasurementsEvent.Callback();
+    method public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+    method public void onStatusChanged(int);
+  }
+
+  public static abstract class GpsMeasurementsEvent.GpsMeasurementsStatus implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessage implements android.os.Parcelable {
+    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 byte getType();
+    method public void reset();
+    method public void set(android.location.GpsNavigationMessage);
+    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 setType(byte);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+    field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
+    field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
+    field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
+    field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
+    field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
+    field public static final short STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final short STATUS_UNKNOWN = 0; // 0x0
+  }
+
+  public static abstract class GpsNavigationMessage.GpsNavigationMessageType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessageEvent implements android.os.Parcelable {
+    ctor public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
+    method public int describeContents();
+    method public android.location.GpsNavigationMessage getNavigationMessage();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
+    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public static abstract class GpsNavigationMessageEvent.Callback {
+    ctor public GpsNavigationMessageEvent.Callback();
+    method public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+    method public void onStatusChanged(int);
+  }
+
+  public static abstract class GpsNavigationMessageEvent.GpsNavigationMessageStatus implements java.lang.annotation.Annotation {
+  }
+
   public final class GpsSatellite {
     method public float getAzimuth();
     method public float getElevation();
@@ -19120,8 +19443,10 @@
   }
 
   public class LocationManager {
-    method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
-    method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public deprecated boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener, android.os.Handler);
     method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
     method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
     method public void clearTestProviderEnabled(java.lang.String);
@@ -19129,14 +19454,21 @@
     method public void clearTestProviderStatus(java.lang.String);
     method public java.util.List<java.lang.String> getAllProviders();
     method public java.lang.String getBestProvider(android.location.Criteria, boolean);
-    method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+    method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
     method public android.location.Location getLastKnownLocation(java.lang.String);
     method public android.location.LocationProvider getProvider(java.lang.String);
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isProviderEnabled(java.lang.String);
-    method public void removeGpsStatusListener(android.location.GpsStatus.Listener);
-    method public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback, android.os.Handler);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback, android.os.Handler);
+    method public deprecated void removeGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public void removeNmeaListener(android.location.GnssNmeaListener);
     method public void removeProximityAlert(android.app.PendingIntent);
     method public void removeTestProvider(java.lang.String);
     method public void removeUpdates(android.location.LocationListener);
@@ -19154,6 +19486,9 @@
     method public void setTestProviderEnabled(java.lang.String, boolean);
     method public void setTestProviderLocation(java.lang.String, android.location.Location);
     method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
+    method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
+    method public void unregisterGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public void unregisterGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
     field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
     field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -19585,8 +19920,11 @@
 
   public class AudioRecordConfiguration implements android.os.Parcelable {
     method public int describeContents();
-    method public int getAudioSessionId();
+    method public android.media.AudioDeviceInfo getAudioDevice();
+    method public int getClientAudioSessionId();
     method public int getClientAudioSource();
+    method public android.media.AudioFormat getClientFormat();
+    method public android.media.AudioFormat getFormat();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
   }
@@ -19760,6 +20098,16 @@
     ctor public DeniedByServerException(java.lang.String);
   }
 
+  public abstract class DrmInitData {
+    ctor public DrmInitData();
+    method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+  }
+
+  public static final class DrmInitData.SchemeInitData {
+    field public final byte[] data;
+    field public final java.lang.String mimeType;
+  }
+
   public class ExifInterface {
     ctor public ExifInterface(java.lang.String) throws java.io.IOException;
     method public double getAltitude(double);
@@ -20450,6 +20798,7 @@
     ctor public MediaExtractor();
     method public boolean advance();
     method public long getCachedDuration();
+    method public android.media.DrmInitData getDrmInitData();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -22812,6 +23161,7 @@
     field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
     field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
     field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+    field public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 38337; // 0x95c1
     field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
     field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
     field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
@@ -22849,6 +23199,7 @@
     method public android.mtp.MtpObjectInfo getObjectInfo(int);
     method public long getParent(int);
     method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
+    method public long getPartialObject64(int, long, long, byte[]) throws java.io.IOException;
     method public long getStorageId(int);
     method public int[] getStorageIds();
     method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -22857,7 +23208,7 @@
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
     method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
-    method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
+    method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
 
@@ -22888,23 +23239,31 @@
     method public final int getAssociationDesc();
     method public final int getAssociationType();
     method public final int getCompressedSize();
+    method public final long getCompressedSizeLong();
     method public final long getDateCreated();
     method public final long getDateModified();
     method public final int getFormat();
     method public final int getImagePixDepth();
+    method public final long getImagePixDepthLong();
     method public final int getImagePixHeight();
+    method public final long getImagePixHeightLong();
     method public final int getImagePixWidth();
+    method public final long getImagePixWidthLong();
     method public final java.lang.String getKeywords();
     method public final java.lang.String getName();
     method public final int getObjectHandle();
     method public final int getParent();
     method public final int getProtectionStatus();
     method public final int getSequenceNumber();
+    method public final long getSequenceNumberLong();
     method public final int getStorageId();
     method public final int getThumbCompressedSize();
+    method public final long getThumbCompressedSizeLong();
     method public final int getThumbFormat();
     method public final int getThumbPixHeight();
+    method public final long getThumbPixHeightLong();
     method public final int getThumbPixWidth();
+    method public final long getThumbPixWidthLong();
   }
 
   public static class MtpObjectInfo.Builder {
@@ -22913,24 +23272,24 @@
     method public android.mtp.MtpObjectInfo build();
     method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
     method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
-    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
     method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
     method public android.mtp.MtpObjectInfo.Builder setFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(long);
     method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
-    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
+    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(long);
     method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(long);
   }
 
   public final class MtpStorageInfo {
@@ -28874,6 +29233,8 @@
     field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
     field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
     field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+    field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
+    field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
   }
 
   public abstract class Vibrator {
@@ -31225,7 +31586,9 @@
     method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
     method public static java.lang.String getTreeDocumentId(android.net.Uri);
     method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+    method public static boolean isTreeUri(android.net.Uri);
     method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri);
+    method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
     field public static final java.lang.String EXTRA_ERROR = "error";
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -31251,6 +31614,7 @@
     field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80
     field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
     field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
+    field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800
     field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
@@ -31298,6 +31662,7 @@
     method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
     method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+    method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public final void revokeDocumentPermission(java.lang.String);
     method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -35427,14 +35792,14 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
   }
 
-  public class CallScreeningService.CallResponse {
+  public static class CallScreeningService.CallResponse {
     method public boolean getDisallowCall();
     method public boolean getRejectCall();
     method public boolean getSkipCallLog();
     method public boolean getSkipNotification();
   }
 
-  public class CallScreeningService.CallResponse.Builder {
+  public static class CallScreeningService.CallResponse.Builder {
     ctor public CallScreeningService.CallResponse.Builder();
     method public android.telecom.CallScreeningService.CallResponse build();
     method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
@@ -36821,7 +37186,7 @@
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
     method public T getActivity();
@@ -36829,14 +37194,14 @@
     method public void setActivityIntent(android.content.Intent);
   }
 
-  public abstract class ActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public ActivityTestCase();
     method protected android.app.Activity getActivity();
     method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
     method protected void setActivity(android.app.Activity);
   }
 
-  public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
     ctor public ActivityUnitTestCase(java.lang.Class<T>);
     method public T getActivity();
     method public int getFinishedActivityRequest();
@@ -36849,7 +37214,7 @@
     method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
   }
 
-  public class AndroidTestCase extends junit.framework.TestCase {
+  public deprecated class AndroidTestCase extends junit.framework.TestCase {
     ctor public AndroidTestCase();
     method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
     method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
@@ -36861,7 +37226,7 @@
     field protected android.content.Context mContext;
   }
 
-  public class AndroidTestRunner extends junit.runner.BaseTestRunner {
+  public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
     ctor public AndroidTestRunner();
     method public void addTestListener(junit.framework.TestListener);
     method public void clearTestListeners();
@@ -36882,7 +37247,7 @@
     method public void testStarted(java.lang.String);
   }
 
-  public abstract class ApplicationTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
     ctor public ApplicationTestCase(java.lang.Class<T>);
     method protected final void createApplication();
     method public T getApplication();
@@ -36900,10 +37265,10 @@
     ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
   }
 
-  public abstract class FlakyTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
   }
 
-  public class InstrumentationTestCase extends junit.framework.TestCase {
+  public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
     ctor public InstrumentationTestCase();
     method public android.app.Instrumentation getInstrumentation();
     method public deprecated void injectInsrumentation(android.app.Instrumentation);
@@ -36916,7 +37281,7 @@
     method public void sendRepeatedKeys(int...);
   }
 
-  public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+  public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
     ctor public InstrumentationTestRunner();
     method public junit.framework.TestSuite getAllTests();
     method protected android.test.AndroidTestRunner getAndroidTestRunner();
@@ -36935,14 +37300,14 @@
     field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
   }
 
-  public class InstrumentationTestSuite extends junit.framework.TestSuite {
+  public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
     ctor public InstrumentationTestSuite(android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
     method public void addTestSuite(java.lang.Class);
   }
 
-  public class IsolatedContext extends android.content.ContextWrapper {
+  public deprecated class IsolatedContext extends android.content.ContextWrapper {
     ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
     method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
   }
@@ -36952,7 +37317,7 @@
     method public T getLoaderResultSynchronously(android.content.Loader<T>);
   }
 
-  public final class MoreAsserts {
+  public final deprecated class MoreAsserts {
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
     method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
@@ -36991,7 +37356,7 @@
     method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
   }
 
-  public abstract interface PerformanceTestCase {
+  public abstract deprecated interface PerformanceTestCase {
     method public abstract boolean isPerformanceOnly();
     method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
   }
@@ -37020,7 +37385,7 @@
     method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public class RenamingDelegatingContext extends android.content.ContextWrapper {
+  public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
     ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
     method public java.lang.String getDatabasePrefix();
@@ -37029,7 +37394,7 @@
     method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract class ServiceTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
     ctor public ServiceTestCase(java.lang.Class<T>);
     method protected android.os.IBinder bindService(android.content.Intent);
     method public android.app.Application getApplication();
@@ -37042,23 +37407,23 @@
     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+  public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
     ctor public SyncBaseInstrumentation();
     method protected void cancelSyncsandDisableAutoSync();
     method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
   }
 
-  public abstract interface TestSuiteProvider {
+  public abstract deprecated interface TestSuiteProvider {
     method public abstract junit.framework.TestSuite getTestSuite();
   }
 
-  public class TouchUtils {
+  public deprecated class TouchUtils {
     ctor public TouchUtils();
     method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
     method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
@@ -37093,10 +37458,10 @@
     method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
   }
 
-  public abstract class UiThreadTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
   }
 
-  public class ViewAsserts {
+  public deprecated class ViewAsserts {
     method public static void assertBaselineAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View, int);
@@ -37121,11 +37486,11 @@
 
 package android.test.mock {
 
-  public class MockApplication extends android.app.Application {
+  public deprecated class MockApplication extends android.app.Application {
     ctor public MockApplication();
   }
 
-  public class MockContentProvider extends android.content.ContentProvider {
+  public deprecated class MockContentProvider extends android.content.ContentProvider {
     ctor protected MockContentProvider();
     ctor public MockContentProvider(android.content.Context);
     ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
@@ -37137,13 +37502,13 @@
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
   }
 
-  public class MockContentResolver extends android.content.ContentResolver {
+  public deprecated class MockContentResolver extends android.content.ContentResolver {
     ctor public MockContentResolver();
     ctor public MockContentResolver(android.content.Context);
     method public void addProvider(java.lang.String, android.content.ContentProvider);
   }
 
-  public class MockContext extends android.content.Context {
+  public deprecated class MockContext extends android.content.Context {
     ctor public MockContext();
     method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
     method public int checkCallingOrSelfPermission(java.lang.String);
@@ -37243,7 +37608,7 @@
     method public void unregisterReceiver(android.content.BroadcastReceiver);
   }
 
-  public class MockCursor implements android.database.Cursor {
+  public deprecated class MockCursor implements android.database.Cursor {
     ctor public MockCursor();
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -37288,13 +37653,13 @@
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
-  public class MockDialogInterface implements android.content.DialogInterface {
+  public deprecated class MockDialogInterface implements android.content.DialogInterface {
     ctor public MockDialogInterface();
     method public void cancel();
     method public void dismiss();
   }
 
-  public class MockPackageManager extends android.content.pm.PackageManager {
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
     ctor public MockPackageManager();
     method public void addPackageToPreferred(java.lang.String);
     method public boolean addPermission(android.content.pm.PermissionInfo);
@@ -37381,7 +37746,7 @@
     method public void verifyPendingInstall(int, int);
   }
 
-  public class MockResources extends android.content.res.Resources {
+  public deprecated class MockResources extends android.content.res.Resources {
     ctor public MockResources();
   }
 
@@ -37422,19 +37787,19 @@
 
 package android.test.suitebuilder.annotation {
 
-  public abstract class LargeTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class MediumTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class SmallTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Smoke implements java.lang.annotation.Annotation {
+  public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Suppress implements java.lang.annotation.Annotation {
+  public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
   }
 
 }
diff --git a/api/removed.txt b/api/removed.txt
index 6b7961e..2c6729d 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -201,7 +201,7 @@
 
 package android.test.mock {
 
-  public class MockPackageManager extends android.content.pm.PackageManager {
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
     method public deprecated java.lang.String getDefaultBrowserPackageName(int);
     method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index b876ca9..95c19d7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -601,6 +601,8 @@
     field public static final int encryptionAware = 16844038; // 0x1010506
     field public static final int end = 16843996; // 0x10104dc
     field public static final int endColor = 16843166; // 0x101019e
+    field public static final int endX = 16844051; // 0x1010513
+    field public static final int endY = 16844052; // 0x1010514
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
     field public static final int entries = 16842930; // 0x10100b2
@@ -976,6 +978,7 @@
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
     field public static final int numericShortcut = 16843236; // 0x10101e4
+    field public static final int offset = 16844053; // 0x1010515
     field public static final int onClick = 16843375; // 0x101026f
     field public static final int oneshot = 16843159; // 0x1010197
     field public static final int opacity = 16843550; // 0x101031e
@@ -1227,6 +1230,8 @@
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
+    field public static final int startX = 16844049; // 0x1010511
+    field public static final int startY = 16844050; // 0x1010512
     field public static final deprecated int startYear = 16843132; // 0x101017c
     field public static final int stateListAnimator = 16843848; // 0x1010448
     field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -6769,8 +6774,9 @@
     field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
     field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
     field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
-    field public static final int TAG_DEVICE_LOCKED = 210007; // 0x33457
-    field public static final int TAG_DEVICE_UNLOCK_ATTEMPT = 210006; // 0x33456
+    field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+    field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+    field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
     field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
     field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
   }
@@ -10349,7 +10355,7 @@
     method public final long skip(long) throws java.io.IOException;
   }
 
-  public class ColorStateList implements android.os.Parcelable {
+  public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
     ctor public ColorStateList(int[][], int[]);
     method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -10358,13 +10364,18 @@
     method public int getColorForState(int[], int);
     method public int getDefaultColor();
     method public boolean isOpaque();
-    method public boolean isStateful();
     method public static android.content.res.ColorStateList valueOf(int);
     method public android.content.res.ColorStateList withAlpha(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
   }
 
+  public abstract class ComplexColor {
+    ctor public ComplexColor();
+    method public abstract int getDefaultColor();
+    method public boolean isStateful();
+  }
+
   public final class Configuration implements java.lang.Comparable android.os.Parcelable {
     ctor public Configuration();
     ctor public Configuration(android.content.res.Configuration);
@@ -10468,6 +10479,11 @@
     field public int uiMode;
   }
 
+  public class GradientColor extends android.content.res.ComplexColor {
+    method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public int getDefaultColor();
+  }
+
   public class ObbInfo implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -10527,6 +10543,7 @@
     method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
+    method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
     method public final android.content.res.Resources.Theme newTheme();
     method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
     method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10562,6 +10579,7 @@
     method public int getChangingConfigurations();
     method public int getColor(int, int);
     method public android.content.res.ColorStateList getColorStateList(int);
+    method public android.content.res.ComplexColor getComplexColor(int);
     method public float getDimension(int, float);
     method public int getDimensionPixelOffset(int, int);
     method public int getDimensionPixelSize(int, int);
@@ -13824,6 +13842,21 @@
     field public static final int TYPE_WRIST_TILT_GESTURE = 26; // 0x1a
   }
 
+  public class SensorAdditionalInfo {
+    field public static final int TYPE_FRAME_BEGIN = 0; // 0x0
+    field public static final int TYPE_FRAME_END = 1; // 0x1
+    field public static final int TYPE_INTERNAL_TEMPERATURE = 65537; // 0x10001
+    field public static final int TYPE_SAMPLING = 65540; // 0x10004
+    field public static final int TYPE_SENSOR_PLACEMENT = 65539; // 0x10003
+    field public static final int TYPE_UNTRACKED_DELAY = 65536; // 0x10000
+    field public static final int TYPE_VEC3_CALIBRATION = 65538; // 0x10002
+    field public final float[] floatValues;
+    field public final int[] intValues;
+    field public final android.hardware.Sensor sensor;
+    field public final int serial;
+    field public final int type;
+  }
+
   public class SensorEvent {
     field public int accuracy;
     field public android.hardware.Sensor sensor;
@@ -13831,6 +13864,14 @@
     field public final float[] values;
   }
 
+  public abstract class SensorEventCallback implements android.hardware.SensorEventListener2 {
+    ctor public SensorEventCallback();
+    method public void onAccuracyChanged(android.hardware.Sensor, int);
+    method public void onFlushCompleted(android.hardware.Sensor);
+    method public void onSensorAdditionalInfo(android.hardware.SensorAdditionalInfo);
+    method public void onSensorChanged(android.hardware.SensorEvent);
+  }
+
   public abstract interface SensorEventListener {
     method public abstract void onAccuracyChanged(android.hardware.Sensor, int);
     method public abstract void onSensorChanged(android.hardware.SensorEvent);
@@ -20072,7 +20113,38 @@
     method public static boolean isPresent();
   }
 
-  public class GpsClock implements android.os.Parcelable {
+  public abstract interface GnssNmeaListener {
+    method public abstract void onNmeaReceived(long, java.lang.String);
+  }
+
+  public final class GnssStatus {
+    method public float getAzimuth(int);
+    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 boolean hasAlmanac(int);
+    method public boolean hasEphemeris(int);
+    method public boolean usedInFix(int);
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+  }
+
+  public abstract class GnssStatusCallback {
+    ctor public GnssStatusCallback();
+    method public void onFirstFix(int);
+    method public void onSatelliteStatusChanged(android.location.GnssStatus);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  public final class GpsClock implements android.os.Parcelable {
     method public int describeContents();
     method public double getBiasInNs();
     method public double getBiasUncertaintyInNs();
@@ -20081,6 +20153,7 @@
     method public long getFullBiasInNs();
     method public short getLeapSecond();
     method public long getTimeInNs();
+    method public long getTimeOfLastHwClockDiscontinuityInNs();
     method public double getTimeUncertaintyInNs();
     method public byte getType();
     method public boolean hasBiasInNs();
@@ -20106,16 +20179,20 @@
     method public void setFullBiasInNs(long);
     method public void setLeapSecond(short);
     method public void setTimeInNs(long);
+    method public void setTimeOfLastHwClockDiscontinuityInNs(long);
     method public void setTimeUncertaintyInNs(double);
     method public void setType(byte);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
+    field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
+    field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
     field public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
-    field public static final byte TYPE_GPS_TIME = 2; // 0x2
-    field public static final byte TYPE_LOCAL_HW_TIME = 1; // 0x1
-    field public static final byte TYPE_UNKNOWN = 0; // 0x0
   }
 
-  public class GpsMeasurement implements android.os.Parcelable {
+  public static abstract class GpsClock.GpsClockType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurement implements android.os.Parcelable {
     method public int describeContents();
     method public double getAccumulatedDeltaRangeInMeters();
     method public short getAccumulatedDeltaRangeState();
@@ -20138,6 +20215,8 @@
     method public byte getMultipathIndicator();
     method public byte getPrn();
     method public double getPseudorangeInMeters();
+    method public double getPseudorangeRateCarrierInMetersPerSec();
+    method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
     method public double getPseudorangeRateInMetersPerSec();
     method public double getPseudorangeRateUncertaintyInMetersPerSec();
     method public double getPseudorangeUncertaintyInMeters();
@@ -20206,6 +20285,8 @@
     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);
     method public void setPseudorangeRateInMetersPerSec(double);
     method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
     method public void setPseudorangeUncertaintyInMeters(double);
@@ -20236,7 +20317,13 @@
     field public static final short STATE_UNKNOWN = 0; // 0x0
   }
 
-  public class GpsMeasurementsEvent implements android.os.Parcelable {
+  public static abstract class GpsMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class GpsMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurementsEvent implements android.os.Parcelable {
     ctor public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
     method public int describeContents();
     method public android.location.GpsClock getClock();
@@ -20248,12 +20335,16 @@
     field public static final int STATUS_READY = 1; // 0x1
   }
 
-  public static abstract interface GpsMeasurementsEvent.Listener {
-    method public abstract void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
-    method public abstract void onStatusChanged(int);
+  public static abstract class GpsMeasurementsEvent.Callback {
+    ctor public GpsMeasurementsEvent.Callback();
+    method public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+    method public void onStatusChanged(int);
   }
 
-  public class GpsNavigationMessage implements android.os.Parcelable {
+  public static abstract class GpsMeasurementsEvent.GpsMeasurementsStatus implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessage implements android.os.Parcelable {
     method public int describeContents();
     method public byte[] getData();
     method public short getMessageId();
@@ -20271,30 +20362,37 @@
     method public void setType(byte);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+    field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
+    field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
+    field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
+    field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
+    field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
     field public static final short STATUS_PARITY_PASSED = 1; // 0x1
     field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
     field public static final short STATUS_UNKNOWN = 0; // 0x0
-    field public static final byte TYPE_CNAV2 = 4; // 0x4
-    field public static final byte TYPE_L1CA = 1; // 0x1
-    field public static final byte TYPE_L2CNAV = 2; // 0x2
-    field public static final byte TYPE_L5CNAV = 3; // 0x3
-    field public static final byte TYPE_UNKNOWN = 0; // 0x0
   }
 
-  public class GpsNavigationMessageEvent implements android.os.Parcelable {
+  public static abstract class GpsNavigationMessage.GpsNavigationMessageType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessageEvent implements android.os.Parcelable {
     ctor public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
     method public int describeContents();
     method public android.location.GpsNavigationMessage getNavigationMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
-    field public static int STATUS_GPS_LOCATION_DISABLED;
-    field public static int STATUS_NOT_SUPPORTED;
-    field public static int STATUS_READY;
+    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field public static final int STATUS_READY = 1; // 0x1
   }
 
-  public static abstract interface GpsNavigationMessageEvent.Listener {
-    method public abstract void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
-    method public abstract void onStatusChanged(int);
+  public static abstract class GpsNavigationMessageEvent.Callback {
+    ctor public GpsNavigationMessageEvent.Callback();
+    method public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+    method public void onStatusChanged(int);
+  }
+
+  public static abstract class GpsNavigationMessageEvent.GpsNavigationMessageStatus implements java.lang.annotation.Annotation {
   }
 
   public final class GpsSatellite {
@@ -20401,10 +20499,10 @@
   }
 
   public class LocationManager {
-    method public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
-    method public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
-    method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
-    method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public deprecated boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener, android.os.Handler);
     method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
     method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
     method public void clearTestProviderEnabled(java.lang.String);
@@ -20412,16 +20510,21 @@
     method public void clearTestProviderStatus(java.lang.String);
     method public java.util.List<java.lang.String> getAllProviders();
     method public java.lang.String getBestProvider(android.location.Criteria, boolean);
-    method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+    method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
     method public android.location.Location getLastKnownLocation(java.lang.String);
     method public android.location.LocationProvider getProvider(java.lang.String);
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isProviderEnabled(java.lang.String);
-    method public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
-    method public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
-    method public void removeGpsStatusListener(android.location.GpsStatus.Listener);
-    method public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback, android.os.Handler);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback, android.os.Handler);
+    method public deprecated void removeGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public void removeNmeaListener(android.location.GnssNmeaListener);
     method public void removeProximityAlert(android.app.PendingIntent);
     method public void removeTestProvider(java.lang.String);
     method public void removeUpdates(android.location.LocationListener);
@@ -20441,6 +20544,9 @@
     method public void setTestProviderEnabled(java.lang.String, boolean);
     method public void setTestProviderLocation(java.lang.String, android.location.Location);
     method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
+    method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
+    method public void unregisterGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public void unregisterGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
     field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
     field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -20938,8 +21044,11 @@
 
   public class AudioRecordConfiguration implements android.os.Parcelable {
     method public int describeContents();
-    method public int getAudioSessionId();
+    method public android.media.AudioDeviceInfo getAudioDevice();
+    method public int getClientAudioSessionId();
     method public int getClientAudioSource();
+    method public android.media.AudioFormat getClientFormat();
+    method public android.media.AudioFormat getFormat();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
   }
@@ -21113,6 +21222,16 @@
     ctor public DeniedByServerException(java.lang.String);
   }
 
+  public abstract class DrmInitData {
+    ctor public DrmInitData();
+    method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+  }
+
+  public static final class DrmInitData.SchemeInitData {
+    field public final byte[] data;
+    field public final java.lang.String mimeType;
+  }
+
   public class ExifInterface {
     ctor public ExifInterface(java.lang.String) throws java.io.IOException;
     method public double getAltitude(double);
@@ -21803,6 +21922,7 @@
     ctor public MediaExtractor();
     method public boolean advance();
     method public long getCachedDuration();
+    method public android.media.DrmInitData getDrmInitData();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -23185,12 +23305,15 @@
   public class AudioMixingRule {
     field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
     field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1
+    field public static final int RULE_MATCH_UID = 4; // 0x4
   }
 
   public static class AudioMixingRule.Builder {
     ctor public AudioMixingRule.Builder();
+    method public android.media.audiopolicy.AudioMixingRule.Builder addMixRule(int, java.lang.Object) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule.Builder addRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule build();
+    method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, java.lang.Object) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule.Builder excludeRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
   }
 
@@ -23696,6 +23819,38 @@
 
 }
 
+package android.media.soundtrigger {
+
+  public final class SoundTriggerDetector {
+    method public boolean startRecognition();
+    method public boolean stopRecognition();
+  }
+
+  public abstract class SoundTriggerDetector.Callback {
+    ctor public SoundTriggerDetector.Callback();
+    method public abstract void onAvailabilityChanged(int);
+    method public abstract void onDetected();
+    method public abstract void onError();
+    method public abstract void onRecognitionPaused();
+    method public abstract void onRecognitionResumed();
+  }
+
+  public final class SoundTriggerManager {
+    method public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, android.media.soundtrigger.SoundTriggerDetector.Callback, android.os.Handler);
+    method public void deleteModel(java.util.UUID);
+    method public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
+    method public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
+  }
+
+  public static class SoundTriggerManager.Model {
+    method public static android.media.soundtrigger.SoundTriggerManager.Model create(java.util.UUID, java.util.UUID, byte[]);
+    method public byte[] getModelData();
+    method public java.util.UUID getModelUuid();
+    method public java.util.UUID getVendorUuid();
+  }
+
+}
+
 package android.media.tv {
 
   public final class TvContentRating {
@@ -24425,6 +24580,7 @@
     field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
     field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
     field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+    field public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 38337; // 0x95c1
     field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
     field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
     field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
@@ -24462,6 +24618,7 @@
     method public android.mtp.MtpObjectInfo getObjectInfo(int);
     method public long getParent(int);
     method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
+    method public long getPartialObject64(int, long, long, byte[]) throws java.io.IOException;
     method public long getStorageId(int);
     method public int[] getStorageIds();
     method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -24470,7 +24627,7 @@
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
     method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
-    method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
+    method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
 
@@ -24501,23 +24658,31 @@
     method public final int getAssociationDesc();
     method public final int getAssociationType();
     method public final int getCompressedSize();
+    method public final long getCompressedSizeLong();
     method public final long getDateCreated();
     method public final long getDateModified();
     method public final int getFormat();
     method public final int getImagePixDepth();
+    method public final long getImagePixDepthLong();
     method public final int getImagePixHeight();
+    method public final long getImagePixHeightLong();
     method public final int getImagePixWidth();
+    method public final long getImagePixWidthLong();
     method public final java.lang.String getKeywords();
     method public final java.lang.String getName();
     method public final int getObjectHandle();
     method public final int getParent();
     method public final int getProtectionStatus();
     method public final int getSequenceNumber();
+    method public final long getSequenceNumberLong();
     method public final int getStorageId();
     method public final int getThumbCompressedSize();
+    method public final long getThumbCompressedSizeLong();
     method public final int getThumbFormat();
     method public final int getThumbPixHeight();
+    method public final long getThumbPixHeightLong();
     method public final int getThumbPixWidth();
+    method public final long getThumbPixWidthLong();
   }
 
   public static class MtpObjectInfo.Builder {
@@ -24526,24 +24691,24 @@
     method public android.mtp.MtpObjectInfo build();
     method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
     method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
-    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
     method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
     method public android.mtp.MtpObjectInfo.Builder setFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(long);
     method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
-    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
+    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(long);
     method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(long);
   }
 
   public final class MtpStorageInfo {
@@ -30969,6 +31134,8 @@
     field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
     field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
     field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+    field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
+    field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
   }
 
   public abstract class Vibrator {
@@ -33350,7 +33517,9 @@
     method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
     method public static java.lang.String getTreeDocumentId(android.net.Uri);
     method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+    method public static boolean isTreeUri(android.net.Uri);
     method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri);
+    method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
     field public static final java.lang.String EXTRA_ERROR = "error";
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -33376,6 +33545,7 @@
     field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80
     field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
     field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
+    field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800
     field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
@@ -33423,6 +33593,7 @@
     method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
     method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+    method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public final void revokeDocumentPermission(java.lang.String);
     method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -37735,14 +37906,14 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
   }
 
-  public class CallScreeningService.CallResponse {
+  public static class CallScreeningService.CallResponse {
     method public boolean getDisallowCall();
     method public boolean getRejectCall();
     method public boolean getSkipCallLog();
     method public boolean getSkipNotification();
   }
 
-  public class CallScreeningService.CallResponse.Builder {
+  public static class CallScreeningService.CallResponse.Builder {
     ctor public CallScreeningService.CallResponse.Builder();
     method public android.telecom.CallScreeningService.CallResponse build();
     method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
@@ -39275,7 +39446,7 @@
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
     method public T getActivity();
@@ -39283,14 +39454,14 @@
     method public void setActivityIntent(android.content.Intent);
   }
 
-  public abstract class ActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public ActivityTestCase();
     method protected android.app.Activity getActivity();
     method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
     method protected void setActivity(android.app.Activity);
   }
 
-  public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
     ctor public ActivityUnitTestCase(java.lang.Class<T>);
     method public T getActivity();
     method public int getFinishedActivityRequest();
@@ -39303,7 +39474,7 @@
     method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
   }
 
-  public class AndroidTestCase extends junit.framework.TestCase {
+  public deprecated class AndroidTestCase extends junit.framework.TestCase {
     ctor public AndroidTestCase();
     method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
     method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
@@ -39315,7 +39486,7 @@
     field protected android.content.Context mContext;
   }
 
-  public class AndroidTestRunner extends junit.runner.BaseTestRunner {
+  public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
     ctor public AndroidTestRunner();
     method public void addTestListener(junit.framework.TestListener);
     method public void clearTestListeners();
@@ -39336,7 +39507,7 @@
     method public void testStarted(java.lang.String);
   }
 
-  public abstract class ApplicationTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
     ctor public ApplicationTestCase(java.lang.Class<T>);
     method protected final void createApplication();
     method public T getApplication();
@@ -39354,10 +39525,10 @@
     ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
   }
 
-  public abstract class FlakyTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
   }
 
-  public class InstrumentationTestCase extends junit.framework.TestCase {
+  public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
     ctor public InstrumentationTestCase();
     method public android.app.Instrumentation getInstrumentation();
     method public deprecated void injectInsrumentation(android.app.Instrumentation);
@@ -39370,7 +39541,7 @@
     method public void sendRepeatedKeys(int...);
   }
 
-  public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+  public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
     ctor public InstrumentationTestRunner();
     method public junit.framework.TestSuite getAllTests();
     method protected android.test.AndroidTestRunner getAndroidTestRunner();
@@ -39389,14 +39560,14 @@
     field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
   }
 
-  public class InstrumentationTestSuite extends junit.framework.TestSuite {
+  public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
     ctor public InstrumentationTestSuite(android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
     method public void addTestSuite(java.lang.Class);
   }
 
-  public class IsolatedContext extends android.content.ContextWrapper {
+  public deprecated class IsolatedContext extends android.content.ContextWrapper {
     ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
     method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
   }
@@ -39406,7 +39577,7 @@
     method public T getLoaderResultSynchronously(android.content.Loader<T>);
   }
 
-  public final class MoreAsserts {
+  public final deprecated class MoreAsserts {
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
     method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
@@ -39445,7 +39616,7 @@
     method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
   }
 
-  public abstract interface PerformanceTestCase {
+  public abstract deprecated interface PerformanceTestCase {
     method public abstract boolean isPerformanceOnly();
     method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
   }
@@ -39474,7 +39645,7 @@
     method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public class RenamingDelegatingContext extends android.content.ContextWrapper {
+  public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
     ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
     method public java.lang.String getDatabasePrefix();
@@ -39483,7 +39654,7 @@
     method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract class ServiceTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
     ctor public ServiceTestCase(java.lang.Class<T>);
     method protected android.os.IBinder bindService(android.content.Intent);
     method public android.app.Application getApplication();
@@ -39496,23 +39667,23 @@
     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+  public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
     ctor public SyncBaseInstrumentation();
     method protected void cancelSyncsandDisableAutoSync();
     method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
   }
 
-  public abstract interface TestSuiteProvider {
+  public abstract deprecated interface TestSuiteProvider {
     method public abstract junit.framework.TestSuite getTestSuite();
   }
 
-  public class TouchUtils {
+  public deprecated class TouchUtils {
     ctor public TouchUtils();
     method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
     method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
@@ -39547,10 +39718,10 @@
     method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
   }
 
-  public abstract class UiThreadTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
   }
 
-  public class ViewAsserts {
+  public deprecated class ViewAsserts {
     method public static void assertBaselineAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View, int);
@@ -39575,11 +39746,11 @@
 
 package android.test.mock {
 
-  public class MockApplication extends android.app.Application {
+  public deprecated class MockApplication extends android.app.Application {
     ctor public MockApplication();
   }
 
-  public class MockContentProvider extends android.content.ContentProvider {
+  public deprecated class MockContentProvider extends android.content.ContentProvider {
     ctor protected MockContentProvider();
     ctor public MockContentProvider(android.content.Context);
     ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
@@ -39591,13 +39762,13 @@
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
   }
 
-  public class MockContentResolver extends android.content.ContentResolver {
+  public deprecated class MockContentResolver extends android.content.ContentResolver {
     ctor public MockContentResolver();
     ctor public MockContentResolver(android.content.Context);
     method public void addProvider(java.lang.String, android.content.ContentProvider);
   }
 
-  public class MockContext extends android.content.Context {
+  public deprecated class MockContext extends android.content.Context {
     ctor public MockContext();
     method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
     method public int checkCallingOrSelfPermission(java.lang.String);
@@ -39701,7 +39872,7 @@
     method public void unregisterReceiver(android.content.BroadcastReceiver);
   }
 
-  public class MockCursor implements android.database.Cursor {
+  public deprecated class MockCursor implements android.database.Cursor {
     ctor public MockCursor();
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -39746,13 +39917,13 @@
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
-  public class MockDialogInterface implements android.content.DialogInterface {
+  public deprecated class MockDialogInterface implements android.content.DialogInterface {
     ctor public MockDialogInterface();
     method public void cancel();
     method public void dismiss();
   }
 
-  public class MockPackageManager extends android.content.pm.PackageManager {
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
     ctor public MockPackageManager();
     method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public void addPackageToPreferred(java.lang.String);
@@ -39846,7 +40017,7 @@
     method public void verifyPendingInstall(int, int);
   }
 
-  public class MockResources extends android.content.res.Resources {
+  public deprecated class MockResources extends android.content.res.Resources {
     ctor public MockResources();
   }
 
@@ -39887,19 +40058,19 @@
 
 package android.test.suitebuilder.annotation {
 
-  public abstract class LargeTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class MediumTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class SmallTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Smoke implements java.lang.annotation.Annotation {
+  public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Suppress implements java.lang.annotation.Annotation {
+  public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
   }
 
 }
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 90a5dc7..27de913 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -192,7 +192,7 @@
 
 package android.test.mock {
 
-  public class MockPackageManager extends android.content.pm.PackageManager {
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
     method public deprecated java.lang.String getDefaultBrowserPackageName(int);
     method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 57332a2..081c471 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -506,6 +506,8 @@
     field public static final int encryptionAware = 16844038; // 0x1010506
     field public static final int end = 16843996; // 0x10104dc
     field public static final int endColor = 16843166; // 0x101019e
+    field public static final int endX = 16844051; // 0x1010513
+    field public static final int endY = 16844052; // 0x1010514
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
     field public static final int entries = 16842930; // 0x10100b2
@@ -881,6 +883,7 @@
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
     field public static final int numericShortcut = 16843236; // 0x10101e4
+    field public static final int offset = 16844053; // 0x1010515
     field public static final int onClick = 16843375; // 0x101026f
     field public static final int oneshot = 16843159; // 0x1010197
     field public static final int opacity = 16843550; // 0x101031e
@@ -1128,6 +1131,8 @@
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
+    field public static final int startX = 16844049; // 0x1010511
+    field public static final int startY = 16844050; // 0x1010512
     field public static final deprecated int startYear = 16843132; // 0x101017c
     field public static final int stateListAnimator = 16843848; // 0x1010448
     field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -6513,8 +6518,9 @@
     field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
     field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
     field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
-    field public static final int TAG_DEVICE_LOCKED = 210007; // 0x33457
-    field public static final int TAG_DEVICE_UNLOCK_ATTEMPT = 210006; // 0x33456
+    field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+    field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+    field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
     field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
     field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
   }
@@ -9957,7 +9963,7 @@
     method public final long skip(long) throws java.io.IOException;
   }
 
-  public class ColorStateList implements android.os.Parcelable {
+  public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
     ctor public ColorStateList(int[][], int[]);
     method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -9966,13 +9972,18 @@
     method public int getColorForState(int[], int);
     method public int getDefaultColor();
     method public boolean isOpaque();
-    method public boolean isStateful();
     method public static android.content.res.ColorStateList valueOf(int);
     method public android.content.res.ColorStateList withAlpha(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
   }
 
+  public abstract class ComplexColor {
+    ctor public ComplexColor();
+    method public abstract int getDefaultColor();
+    method public boolean isStateful();
+  }
+
   public final class Configuration implements java.lang.Comparable android.os.Parcelable {
     ctor public Configuration();
     ctor public Configuration(android.content.res.Configuration);
@@ -10076,6 +10087,11 @@
     field public int uiMode;
   }
 
+  public class GradientColor extends android.content.res.ComplexColor {
+    method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public int getDefaultColor();
+  }
+
   public class ObbInfo implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -10135,6 +10151,7 @@
     method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
+    method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
     method public final android.content.res.Resources.Theme newTheme();
     method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
     method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10170,6 +10187,7 @@
     method public int getChangingConfigurations();
     method public int getColor(int, int);
     method public android.content.res.ColorStateList getColorStateList(int);
+    method public android.content.res.ComplexColor getComplexColor(int);
     method public float getDimension(int, float);
     method public int getDimensionPixelOffset(int, int);
     method public int getDimensionPixelSize(int, int);
@@ -13427,6 +13445,21 @@
     field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
   }
 
+  public class SensorAdditionalInfo {
+    field public static final int TYPE_FRAME_BEGIN = 0; // 0x0
+    field public static final int TYPE_FRAME_END = 1; // 0x1
+    field public static final int TYPE_INTERNAL_TEMPERATURE = 65537; // 0x10001
+    field public static final int TYPE_SAMPLING = 65540; // 0x10004
+    field public static final int TYPE_SENSOR_PLACEMENT = 65539; // 0x10003
+    field public static final int TYPE_UNTRACKED_DELAY = 65536; // 0x10000
+    field public static final int TYPE_VEC3_CALIBRATION = 65538; // 0x10002
+    field public final float[] floatValues;
+    field public final int[] intValues;
+    field public final android.hardware.Sensor sensor;
+    field public final int serial;
+    field public final int type;
+  }
+
   public class SensorEvent {
     field public int accuracy;
     field public android.hardware.Sensor sensor;
@@ -13434,6 +13467,14 @@
     field public final float[] values;
   }
 
+  public abstract class SensorEventCallback implements android.hardware.SensorEventListener2 {
+    ctor public SensorEventCallback();
+    method public void onAccuracyChanged(android.hardware.Sensor, int);
+    method public void onFlushCompleted(android.hardware.Sensor);
+    method public void onSensorAdditionalInfo(android.hardware.SensorAdditionalInfo);
+    method public void onSensorChanged(android.hardware.SensorEvent);
+  }
+
   public abstract interface SensorEventListener {
     method public abstract void onAccuracyChanged(android.hardware.Sensor, int);
     method public abstract void onSensorChanged(android.hardware.SensorEvent);
@@ -19044,6 +19085,288 @@
     method public static boolean isPresent();
   }
 
+  public abstract interface GnssNmeaListener {
+    method public abstract void onNmeaReceived(long, java.lang.String);
+  }
+
+  public final class GnssStatus {
+    method public float getAzimuth(int);
+    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 boolean hasAlmanac(int);
+    method public boolean hasEphemeris(int);
+    method public boolean usedInFix(int);
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+  }
+
+  public abstract class GnssStatusCallback {
+    ctor public GnssStatusCallback();
+    method public void onFirstFix(int);
+    method public void onSatelliteStatusChanged(android.location.GnssStatus);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  public final class GpsClock implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getBiasInNs();
+    method public double getBiasUncertaintyInNs();
+    method public double getDriftInNsPerSec();
+    method public double getDriftUncertaintyInNsPerSec();
+    method public long getFullBiasInNs();
+    method public short getLeapSecond();
+    method public long getTimeInNs();
+    method public long getTimeOfLastHwClockDiscontinuityInNs();
+    method public double getTimeUncertaintyInNs();
+    method public byte getType();
+    method public boolean hasBiasInNs();
+    method public boolean hasBiasUncertaintyInNs();
+    method public boolean hasDriftInNsPerSec();
+    method public boolean hasDriftUncertaintyInNsPerSec();
+    method public boolean hasFullBiasInNs();
+    method public boolean hasLeapSecond();
+    method public boolean hasTimeUncertaintyInNs();
+    method public void reset();
+    method public void resetBiasInNs();
+    method public void resetBiasUncertaintyInNs();
+    method public void resetDriftInNsPerSec();
+    method public void resetDriftUncertaintyInNsPerSec();
+    method public void resetFullBiasInNs();
+    method public void resetLeapSecond();
+    method public void resetTimeUncertaintyInNs();
+    method public void set(android.location.GpsClock);
+    method public void setBiasInNs(double);
+    method public void setBiasUncertaintyInNs(double);
+    method public void setDriftInNsPerSec(double);
+    method public void setDriftUncertaintyInNsPerSec(double);
+    method public void setFullBiasInNs(long);
+    method public void setLeapSecond(short);
+    method public void setTimeInNs(long);
+    method public void setTimeOfLastHwClockDiscontinuityInNs(long);
+    method public void setTimeUncertaintyInNs(double);
+    method public void setType(byte);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
+    field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
+    field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
+    field public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
+  }
+
+  public static abstract class GpsClock.GpsClockType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurement implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getAccumulatedDeltaRangeInMeters();
+    method public short getAccumulatedDeltaRangeState();
+    method public double getAccumulatedDeltaRangeUncertaintyInMeters();
+    method public double getAzimuthInDeg();
+    method public double getAzimuthUncertaintyInDeg();
+    method public int getBitNumber();
+    method public long getCarrierCycles();
+    method public float getCarrierFrequencyInHz();
+    method public double getCarrierPhase();
+    method public double getCarrierPhaseUncertainty();
+    method public double getCn0InDbHz();
+    method public double getCodePhaseInChips();
+    method public double getCodePhaseUncertaintyInChips();
+    method public double getDopplerShiftInHz();
+    method public double getDopplerShiftUncertaintyInHz();
+    method public double getElevationInDeg();
+    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();
+    method public double getPseudorangeRateInMetersPerSec();
+    method public double getPseudorangeRateUncertaintyInMetersPerSec();
+    method public double getPseudorangeUncertaintyInMeters();
+    method public long getReceivedGpsTowInNs();
+    method public long getReceivedGpsTowUncertaintyInNs();
+    method public double getSnrInDb();
+    method public short getState();
+    method public short getTimeFromLastBitInMs();
+    method public double getTimeOffsetInNs();
+    method public boolean hasAzimuthInDeg();
+    method public boolean hasAzimuthUncertaintyInDeg();
+    method public boolean hasBitNumber();
+    method public boolean hasCarrierCycles();
+    method public boolean hasCarrierFrequencyInHz();
+    method public boolean hasCarrierPhase();
+    method public boolean hasCarrierPhaseUncertainty();
+    method public boolean hasCodePhaseInChips();
+    method public boolean hasCodePhaseUncertaintyInChips();
+    method public boolean hasDopplerShiftInHz();
+    method public boolean hasDopplerShiftUncertaintyInHz();
+    method public boolean hasElevationInDeg();
+    method public boolean hasElevationUncertaintyInDeg();
+    method public boolean hasPseudorangeInMeters();
+    method public boolean hasPseudorangeUncertaintyInMeters();
+    method public boolean hasSnrInDb();
+    method public boolean hasTimeFromLastBitInMs();
+    method public boolean isPseudorangeRateCorrected();
+    method public boolean isUsedInFix();
+    method public void reset();
+    method public void resetAzimuthInDeg();
+    method public void resetAzimuthUncertaintyInDeg();
+    method public void resetBitNumber();
+    method public void resetCarrierCycles();
+    method public void resetCarrierFrequencyInHz();
+    method public void resetCarrierPhase();
+    method public void resetCarrierPhaseUncertainty();
+    method public void resetCodePhaseInChips();
+    method public void resetCodePhaseUncertaintyInChips();
+    method public void resetDopplerShiftInHz();
+    method public void resetDopplerShiftUncertaintyInHz();
+    method public void resetElevationInDeg();
+    method public void resetElevationUncertaintyInDeg();
+    method public void resetPseudorangeInMeters();
+    method public void resetPseudorangeUncertaintyInMeters();
+    method public void resetSnrInDb();
+    method public void resetTimeFromLastBitInMs();
+    method public void set(android.location.GpsMeasurement);
+    method public void setAccumulatedDeltaRangeInMeters(double);
+    method public void setAccumulatedDeltaRangeState(short);
+    method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
+    method public void setAzimuthInDeg(double);
+    method public void setAzimuthUncertaintyInDeg(double);
+    method public void setBitNumber(int);
+    method public void setCarrierCycles(long);
+    method public void setCarrierFrequencyInHz(float);
+    method public void setCarrierPhase(double);
+    method public void setCarrierPhaseUncertainty(double);
+    method public void setCn0InDbHz(double);
+    method public void setCodePhaseInChips(double);
+    method public void setCodePhaseUncertaintyInChips(double);
+    method public void setDopplerShiftInHz(double);
+    method public void setDopplerShiftUncertaintyInHz(double);
+    method public void setElevationInDeg(double);
+    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);
+    method public void setPseudorangeRateInMetersPerSec(double);
+    method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
+    method public void setPseudorangeUncertaintyInMeters(double);
+    method public void setReceivedGpsTowInNs(long);
+    method public void setReceivedGpsTowUncertaintyInNs(long);
+    method public void setSnrInDb(double);
+    method public void setState(short);
+    method public void setTimeFromLastBitInMs(short);
+    method public void setTimeOffsetInNs(double);
+    method public void setUsedInFix(boolean);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final short ADR_STATE_RESET = 2; // 0x2
+    field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
+    field public static final short ADR_STATE_VALID = 1; // 0x1
+    field public static final android.os.Parcelable.Creator<android.location.GpsMeasurement> CREATOR;
+    field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
+    field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
+    field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
+    field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+    field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final short STATE_BIT_SYNC = 2; // 0x2
+    field public static final short STATE_CODE_LOCK = 1; // 0x1
+    field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
+    field public static final short STATE_TOW_DECODED = 8; // 0x8
+    field public static final short STATE_UNKNOWN = 0; // 0x0
+  }
+
+  public static abstract class GpsMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class GpsMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurementsEvent implements android.os.Parcelable {
+    ctor public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
+    method public int describeContents();
+    method public android.location.GpsClock getClock();
+    method public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
+    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public static abstract class GpsMeasurementsEvent.Callback {
+    ctor public GpsMeasurementsEvent.Callback();
+    method public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+    method public void onStatusChanged(int);
+  }
+
+  public static abstract class GpsMeasurementsEvent.GpsMeasurementsStatus implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessage implements android.os.Parcelable {
+    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 byte getType();
+    method public void reset();
+    method public void set(android.location.GpsNavigationMessage);
+    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 setType(byte);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+    field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
+    field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
+    field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
+    field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
+    field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
+    field public static final short STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final short STATUS_UNKNOWN = 0; // 0x0
+  }
+
+  public static abstract class GpsNavigationMessage.GpsNavigationMessageType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessageEvent implements android.os.Parcelable {
+    ctor public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
+    method public int describeContents();
+    method public android.location.GpsNavigationMessage getNavigationMessage();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
+    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public static abstract class GpsNavigationMessageEvent.Callback {
+    ctor public GpsNavigationMessageEvent.Callback();
+    method public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+    method public void onStatusChanged(int);
+  }
+
+  public static abstract class GpsNavigationMessageEvent.GpsNavigationMessageStatus implements java.lang.annotation.Annotation {
+  }
+
   public final class GpsSatellite {
     method public float getAzimuth();
     method public float getElevation();
@@ -19128,8 +19451,10 @@
   }
 
   public class LocationManager {
-    method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
-    method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public deprecated boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener, android.os.Handler);
     method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
     method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
     method public void clearTestProviderEnabled(java.lang.String);
@@ -19137,14 +19462,22 @@
     method public void clearTestProviderStatus(java.lang.String);
     method public java.util.List<java.lang.String> getAllProviders();
     method public java.lang.String getBestProvider(android.location.Criteria, boolean);
-    method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+    method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+    method public int getGpsYearOfHardware();
     method public android.location.Location getLastKnownLocation(java.lang.String);
     method public android.location.LocationProvider getProvider(java.lang.String);
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isProviderEnabled(java.lang.String);
-    method public void removeGpsStatusListener(android.location.GpsStatus.Listener);
-    method public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback, android.os.Handler);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback, android.os.Handler);
+    method public deprecated void removeGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public void removeNmeaListener(android.location.GnssNmeaListener);
     method public void removeProximityAlert(android.app.PendingIntent);
     method public void removeTestProvider(java.lang.String);
     method public void removeUpdates(android.location.LocationListener);
@@ -19162,6 +19495,9 @@
     method public void setTestProviderEnabled(java.lang.String, boolean);
     method public void setTestProviderLocation(java.lang.String, android.location.Location);
     method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
+    method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
+    method public void unregisterGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public void unregisterGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
     field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
     field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -19593,8 +19929,11 @@
 
   public class AudioRecordConfiguration implements android.os.Parcelable {
     method public int describeContents();
-    method public int getAudioSessionId();
+    method public android.media.AudioDeviceInfo getAudioDevice();
+    method public int getClientAudioSessionId();
     method public int getClientAudioSource();
+    method public android.media.AudioFormat getClientFormat();
+    method public android.media.AudioFormat getFormat();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
   }
@@ -19768,6 +20107,16 @@
     ctor public DeniedByServerException(java.lang.String);
   }
 
+  public abstract class DrmInitData {
+    ctor public DrmInitData();
+    method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+  }
+
+  public static final class DrmInitData.SchemeInitData {
+    field public final byte[] data;
+    field public final java.lang.String mimeType;
+  }
+
   public class ExifInterface {
     ctor public ExifInterface(java.lang.String) throws java.io.IOException;
     method public double getAltitude(double);
@@ -20458,6 +20807,7 @@
     ctor public MediaExtractor();
     method public boolean advance();
     method public long getCachedDuration();
+    method public android.media.DrmInitData getDrmInitData();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -22820,6 +23170,7 @@
     field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
     field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
     field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+    field public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 38337; // 0x95c1
     field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
     field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
     field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
@@ -22857,6 +23208,7 @@
     method public android.mtp.MtpObjectInfo getObjectInfo(int);
     method public long getParent(int);
     method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
+    method public long getPartialObject64(int, long, long, byte[]) throws java.io.IOException;
     method public long getStorageId(int);
     method public int[] getStorageIds();
     method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -22865,7 +23217,7 @@
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
     method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
-    method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
+    method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
 
@@ -22896,23 +23248,31 @@
     method public final int getAssociationDesc();
     method public final int getAssociationType();
     method public final int getCompressedSize();
+    method public final long getCompressedSizeLong();
     method public final long getDateCreated();
     method public final long getDateModified();
     method public final int getFormat();
     method public final int getImagePixDepth();
+    method public final long getImagePixDepthLong();
     method public final int getImagePixHeight();
+    method public final long getImagePixHeightLong();
     method public final int getImagePixWidth();
+    method public final long getImagePixWidthLong();
     method public final java.lang.String getKeywords();
     method public final java.lang.String getName();
     method public final int getObjectHandle();
     method public final int getParent();
     method public final int getProtectionStatus();
     method public final int getSequenceNumber();
+    method public final long getSequenceNumberLong();
     method public final int getStorageId();
     method public final int getThumbCompressedSize();
+    method public final long getThumbCompressedSizeLong();
     method public final int getThumbFormat();
     method public final int getThumbPixHeight();
+    method public final long getThumbPixHeightLong();
     method public final int getThumbPixWidth();
+    method public final long getThumbPixWidthLong();
   }
 
   public static class MtpObjectInfo.Builder {
@@ -22921,24 +23281,24 @@
     method public android.mtp.MtpObjectInfo build();
     method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
     method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
-    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
     method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
     method public android.mtp.MtpObjectInfo.Builder setFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(long);
     method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
-    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
+    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(long);
     method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(long);
   }
 
   public final class MtpStorageInfo {
@@ -28883,6 +29243,8 @@
     field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
     field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
     field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+    field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
+    field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
   }
 
   public abstract class Vibrator {
@@ -31237,7 +31599,9 @@
     method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
     method public static java.lang.String getTreeDocumentId(android.net.Uri);
     method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+    method public static boolean isTreeUri(android.net.Uri);
     method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri);
+    method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
     field public static final java.lang.String EXTRA_ERROR = "error";
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -31263,6 +31627,7 @@
     field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80
     field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
     field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
+    field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800
     field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
@@ -31310,6 +31675,7 @@
     method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
     method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+    method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public final void revokeDocumentPermission(java.lang.String);
     method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -35441,14 +35807,14 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
   }
 
-  public class CallScreeningService.CallResponse {
+  public static class CallScreeningService.CallResponse {
     method public boolean getDisallowCall();
     method public boolean getRejectCall();
     method public boolean getSkipCallLog();
     method public boolean getSkipNotification();
   }
 
-  public class CallScreeningService.CallResponse.Builder {
+  public static class CallScreeningService.CallResponse.Builder {
     ctor public CallScreeningService.CallResponse.Builder();
     method public android.telecom.CallScreeningService.CallResponse build();
     method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
@@ -36835,7 +37201,7 @@
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
     method public T getActivity();
@@ -36843,14 +37209,14 @@
     method public void setActivityIntent(android.content.Intent);
   }
 
-  public abstract class ActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public ActivityTestCase();
     method protected android.app.Activity getActivity();
     method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
     method protected void setActivity(android.app.Activity);
   }
 
-  public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
     ctor public ActivityUnitTestCase(java.lang.Class<T>);
     method public T getActivity();
     method public int getFinishedActivityRequest();
@@ -36863,7 +37229,7 @@
     method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
   }
 
-  public class AndroidTestCase extends junit.framework.TestCase {
+  public deprecated class AndroidTestCase extends junit.framework.TestCase {
     ctor public AndroidTestCase();
     method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
     method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
@@ -36875,7 +37241,7 @@
     field protected android.content.Context mContext;
   }
 
-  public class AndroidTestRunner extends junit.runner.BaseTestRunner {
+  public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
     ctor public AndroidTestRunner();
     method public void addTestListener(junit.framework.TestListener);
     method public void clearTestListeners();
@@ -36896,7 +37262,7 @@
     method public void testStarted(java.lang.String);
   }
 
-  public abstract class ApplicationTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
     ctor public ApplicationTestCase(java.lang.Class<T>);
     method protected final void createApplication();
     method public T getApplication();
@@ -36914,10 +37280,10 @@
     ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
   }
 
-  public abstract class FlakyTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
   }
 
-  public class InstrumentationTestCase extends junit.framework.TestCase {
+  public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
     ctor public InstrumentationTestCase();
     method public android.app.Instrumentation getInstrumentation();
     method public deprecated void injectInsrumentation(android.app.Instrumentation);
@@ -36930,7 +37296,7 @@
     method public void sendRepeatedKeys(int...);
   }
 
-  public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+  public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
     ctor public InstrumentationTestRunner();
     method public junit.framework.TestSuite getAllTests();
     method protected android.test.AndroidTestRunner getAndroidTestRunner();
@@ -36949,14 +37315,14 @@
     field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
   }
 
-  public class InstrumentationTestSuite extends junit.framework.TestSuite {
+  public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
     ctor public InstrumentationTestSuite(android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
     method public void addTestSuite(java.lang.Class);
   }
 
-  public class IsolatedContext extends android.content.ContextWrapper {
+  public deprecated class IsolatedContext extends android.content.ContextWrapper {
     ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
     method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
   }
@@ -36966,7 +37332,7 @@
     method public T getLoaderResultSynchronously(android.content.Loader<T>);
   }
 
-  public final class MoreAsserts {
+  public final deprecated class MoreAsserts {
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
     method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
@@ -37005,7 +37371,7 @@
     method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
   }
 
-  public abstract interface PerformanceTestCase {
+  public abstract deprecated interface PerformanceTestCase {
     method public abstract boolean isPerformanceOnly();
     method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
   }
@@ -37034,7 +37400,7 @@
     method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public class RenamingDelegatingContext extends android.content.ContextWrapper {
+  public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
     ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
     method public java.lang.String getDatabasePrefix();
@@ -37043,7 +37409,7 @@
     method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract class ServiceTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
     ctor public ServiceTestCase(java.lang.Class<T>);
     method protected android.os.IBinder bindService(android.content.Intent);
     method public android.app.Application getApplication();
@@ -37056,23 +37422,23 @@
     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+  public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
     ctor public SyncBaseInstrumentation();
     method protected void cancelSyncsandDisableAutoSync();
     method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
   }
 
-  public abstract interface TestSuiteProvider {
+  public abstract deprecated interface TestSuiteProvider {
     method public abstract junit.framework.TestSuite getTestSuite();
   }
 
-  public class TouchUtils {
+  public deprecated class TouchUtils {
     ctor public TouchUtils();
     method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
     method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
@@ -37107,10 +37473,10 @@
     method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
   }
 
-  public abstract class UiThreadTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
   }
 
-  public class ViewAsserts {
+  public deprecated class ViewAsserts {
     method public static void assertBaselineAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View, int);
@@ -37135,11 +37501,11 @@
 
 package android.test.mock {
 
-  public class MockApplication extends android.app.Application {
+  public deprecated class MockApplication extends android.app.Application {
     ctor public MockApplication();
   }
 
-  public class MockContentProvider extends android.content.ContentProvider {
+  public deprecated class MockContentProvider extends android.content.ContentProvider {
     ctor protected MockContentProvider();
     ctor public MockContentProvider(android.content.Context);
     ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
@@ -37151,13 +37517,13 @@
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
   }
 
-  public class MockContentResolver extends android.content.ContentResolver {
+  public deprecated class MockContentResolver extends android.content.ContentResolver {
     ctor public MockContentResolver();
     ctor public MockContentResolver(android.content.Context);
     method public void addProvider(java.lang.String, android.content.ContentProvider);
   }
 
-  public class MockContext extends android.content.Context {
+  public deprecated class MockContext extends android.content.Context {
     ctor public MockContext();
     method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
     method public int checkCallingOrSelfPermission(java.lang.String);
@@ -37258,7 +37624,7 @@
     method public void unregisterReceiver(android.content.BroadcastReceiver);
   }
 
-  public class MockCursor implements android.database.Cursor {
+  public deprecated class MockCursor implements android.database.Cursor {
     ctor public MockCursor();
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -37303,13 +37669,13 @@
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
-  public class MockDialogInterface implements android.content.DialogInterface {
+  public deprecated class MockDialogInterface implements android.content.DialogInterface {
     ctor public MockDialogInterface();
     method public void cancel();
     method public void dismiss();
   }
 
-  public class MockPackageManager extends android.content.pm.PackageManager {
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
     ctor public MockPackageManager();
     method public void addPackageToPreferred(java.lang.String);
     method public boolean addPermission(android.content.pm.PermissionInfo);
@@ -37397,7 +37763,7 @@
     method public void verifyPendingInstall(int, int);
   }
 
-  public class MockResources extends android.content.res.Resources {
+  public deprecated class MockResources extends android.content.res.Resources {
     ctor public MockResources();
   }
 
@@ -37438,19 +37804,19 @@
 
 package android.test.suitebuilder.annotation {
 
-  public abstract class LargeTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class MediumTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class SmallTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Smoke implements java.lang.annotation.Annotation {
+  public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Suppress implements java.lang.annotation.Annotation {
+  public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
   }
 
 }
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 6b7961e..2c6729d 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -201,7 +201,7 @@
 
 package android.test.mock {
 
-  public class MockPackageManager extends android.content.pm.PackageManager {
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
     method public deprecated java.lang.String getDefaultBrowserPackageName(int);
     method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
   }
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 72e8c3b..d45bc5d 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -47,7 +47,6 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -79,7 +78,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashSet;
 import java.util.List;
 
 public class Am extends BaseCommand {
@@ -159,6 +157,7 @@
                 "       am stack start <DISPLAY_ID> <INTENT>\n" +
                 "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
                 "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+                "       am stack resize-animated <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
                 "       am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]\n" +
                 "       am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" +
                 "       am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
@@ -1688,6 +1687,9 @@
             case "resize":
                 runStackResize();
                 break;
+            case "resize-animated":
+                runStackResizeAnimated();
+                break;
             case "resize-docked-stack":
                 runStackResizeDocked();
                 break;
@@ -1756,7 +1758,18 @@
             System.err.println("Error: invalid input bounds");
             return;
         }
-        resizeStack(stackId, bounds, 0);
+        resizeStack(stackId, bounds, 0, false);
+    }
+
+    private void runStackResizeAnimated() throws Exception {
+        String stackIdStr = nextArgRequired();
+        int stackId = Integer.valueOf(stackIdStr);
+        final Rect bounds = getBounds();
+        if (bounds == null) {
+            System.err.println("Error: invalid input bounds");
+            return;
+        }
+        resizeStack(stackId, bounds, 0, true);
     }
 
     private void runStackResizeDocked() throws Exception {
@@ -1773,14 +1786,15 @@
         }
     }
 
-    private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception {
+    private void resizeStack(int stackId, Rect bounds, int delayMs, boolean animate)
+            throws Exception {
         if (bounds == null) {
             showError("Error: invalid input bounds");
             return;
         }
 
         try {
-            mAm.resizeStack(stackId, bounds, false);
+            mAm.resizeStack(stackId, bounds, false, false, animate);
             Thread.sleep(delayMs);
         } catch (RemoteException e) {
             showError("Error: resizing stack " + e);
@@ -1894,7 +1908,7 @@
             maxChange = Math.min(stepSize, currentPoint - minPoint);
             currentPoint -= maxChange;
             setBoundsSide(bounds, side, currentPoint);
-            resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+            resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
         }
 
         System.out.println("Growing docked stack side=" + side);
@@ -1902,7 +1916,7 @@
             maxChange = Math.min(stepSize, maxPoint - currentPoint);
             currentPoint += maxChange;
             setBoundsSide(bounds, side, currentPoint);
-            resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+            resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
         }
 
         System.out.println("Back to Original size side=" + side);
@@ -1910,7 +1924,7 @@
             maxChange = Math.min(stepSize, currentPoint - startPoint);
             currentPoint -= maxChange;
             setBoundsSide(bounds, side, currentPoint);
-            resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+            resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
         }
     }
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 420bf31..90feab4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -564,8 +564,7 @@
          * there isn't a display gap.
          */
         public static boolean preserveWindowOnTaskMove(int stackId) {
-            return stackId == FULLSCREEN_WORKSPACE_STACK_ID
-                    || stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID;
+            return stackId == FULLSCREEN_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
         }
 
         /**
@@ -616,6 +615,14 @@
         public static boolean keepVisibleDeadAppWindowOnScreen(int stackId) {
             return stackId != PINNED_STACK_ID;
         }
+
+        /**
+         * Returns true if the backdrop on the client side should match the frame of the window.
+         * Returns false, if the backdrop should be fullscreen.
+         */
+        public static boolean useWindowFrameForBackdrop(int stackId) {
+            return stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == PINNED_STACK_ID;
+        }
     }
 
     /**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 42ff8e8..cd5797e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -816,7 +816,9 @@
                 r = Rect.CREATOR.createFromParcel(data);
             }
             final boolean allowResizeInDockedMode = data.readInt() == 1;
-            resizeStack(stackId, r, allowResizeInDockedMode);
+            final boolean preserveWindows = data.readInt() == 1;
+            final boolean animate = data.readInt() == 1;
+            resizeStack(stackId, r, allowResizeInDockedMode, preserveWindows, animate);
             reply.writeNoException();
             return true;
         }
@@ -3815,9 +3817,8 @@
         return res;
     }
     @Override
-    public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode)
-            throws RemoteException
-    {
+    public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode,
+            boolean preserveWindows, boolean animate) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3829,6 +3830,8 @@
             data.writeInt(0);
         }
         data.writeInt(allowResizeInDockedMode ? 1 : 0);
+        data.writeInt(preserveWindows ? 1 : 0);
+        data.writeInt(animate ? 1 : 0);
         mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 22de2ff..5b3ffe0 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -146,8 +146,8 @@
     public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) throws RemoteException;
     public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
-    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode)
-            throws RemoteException;
+    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
+            boolean preserveWindows, boolean animate) throws RemoteException;
 
     /**
      * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index fef2a0e..e4e97a1 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -30,6 +30,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
 import android.net.ProxyInfo;
 import android.net.Uri;
@@ -2973,6 +2974,34 @@
     }
 
     /**
+     * Should be called when keyguard has been dismissed.
+     * @hide
+     */
+    public void reportKeyguardDismissed() {
+        if (mService != null) {
+            try {
+                mService.reportKeyguardDismissed();
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
+     * Should be called when keyguard view has been shown to the user.
+     * @hide
+     */
+    public void reportKeyguardSecured() {
+        if (mService != null) {
+            try {
+                mService.reportKeyguardSecured();
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
      * @hide
      * Sets the given package as the device owner.
      * Same as {@link #setDeviceOwner(ComponentName, String)} but without setting a device owner name.
@@ -5318,6 +5347,22 @@
     }
 
     /**
+     * Called by the system to obtain a {@link DevicePolicyManager} whose calls act on the parent
+     * profile.
+     *
+     * @hide
+     */
+    public DevicePolicyManager getParentProfileInstance(UserInfo uInfo) {
+        mContext.checkSelfPermission(
+                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        if (!uInfo.isManagedProfile()) {
+            throw new SecurityException("The user " + uInfo.id
+                    + " does not have a parent profile.");
+        }
+        return new DevicePolicyManager(mContext, true);
+    }
+
+    /**
      * Called by a profile owner of a managed profile to set the color used for customization.
      * This color is used as background color of the confirm credentials screen for that user.
      * The default color is {@link android.graphics.Color#GRAY}.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 20d4a29..6333013 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -116,6 +116,9 @@
     void reportFailedPasswordAttempt(int userHandle);
     void reportSuccessfulPasswordAttempt(int userHandle);
 
+    void reportKeyguardDismissed();
+    void reportKeyguardSecured();
+
     boolean setDeviceOwner(in ComponentName who, String ownerName, int userId);
     ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
     String getDeviceOwnerName();
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index e8373a1..1a9bf4e 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -52,10 +52,12 @@
  * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be
  * {@link NetworkStats.Bucket#ROAMING_ALL}.
  * <p />
- * <b>NOTE:</b> Accessing stats for apps other than the calling app requires the permission
- * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and
- * will not be granted to third-party apps. However, declaring the permission implies intention to
- * use the API and the user of the device can grant permission through the Settings application.
+ * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the
+ * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS},
+ * which is a system-level permission and will not be granted to third-party apps. However,
+ * declaring the permission implies intention to use the API and the user of the device can grant
+ * permission through the Settings application.
+ * <p />
  * Profile owner apps are automatically granted permission to query data on the profile they manage
  * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier-
  * privileged apps likewise get access to usage data for all users on the device.
diff --git a/core/java/android/auditing/SecurityLog.java b/core/java/android/auditing/SecurityLog.java
index 87dc1d8..8d8d2f5 100644
--- a/core/java/android/auditing/SecurityLog.java
+++ b/core/java/android/auditing/SecurityLog.java
@@ -34,7 +34,8 @@
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({TAG_ADB_SHELL_INTERACTIVE, TAG_ADB_SHELL_CMD, TAG_SYNC_RECV_FILE, TAG_SYNC_SEND_FILE,
-        TAG_APP_PROCESS_START, TAG_DEVICE_UNLOCK_ATTEMPT, TAG_DEVICE_LOCKED})
+        TAG_APP_PROCESS_START, TAG_KEYGUARD_DISMISSED, TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
+        TAG_KEYGUARD_SECURED})
     public @interface SECURITY_LOG_TAG {}
 
     /**
@@ -68,21 +69,24 @@
      * seinfo tag (String), SHA-256 hash of the APK in hexadecimal (String)
      */
     public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
-
     /**
-     * Indicate that there has been an attempt to unlock the device. The log entry contains the
-     * following information about the attempt in order, accessible via
-     * {@link SecurityEvent#getData()}}: unlock result (integer, 1 for successful unlock, 0 for
-     * unsuccessful), unlock method (String)
+     * Indicate that keyguard is being dismissed.
+     * There is no extra payload in the log event.
      */
-    public static final int TAG_DEVICE_UNLOCK_ATTEMPT =
-            SecurityLogTags.SECURITY_DEVICE_UNLOCK_ATTEMPT;
-
+    public static final int TAG_KEYGUARD_DISMISSED =
+            SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
+    /**
+     * Indicate that there has been an authentication attempt to dismiss the keyguard. The log entry
+     * contains the attempt result (integer, 1 for successful, 0 for unsuccessful), accessible via
+     * {@link SecurityEvent#getData()}}
+     */
+    public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT =
+            SecurityLogTags.SECURITY_KEYGUARD_DISMISS_AUTH_ATTEMPT;
     /**
      * Indicate that the device has been locked, either by user or by timeout.
+     * There is no extra payload in the log event.
      */
-    public static final int TAG_DEVICE_LOCKED = SecurityLogTags.SECURITY_DEVICE_LOCKED;
-
+    public static final int TAG_KEYGUARD_SECURED = SecurityLogTags.SECURITY_KEYGUARD_SECURED;
 
     /**
      * Returns if device logging is enabled. Log producers should only write new logs if this is
@@ -128,7 +132,9 @@
          * Returns the tag of this log entry, which specifies entry's semantics.
          * Could be one of {@link SecurityLog#TAG_SYNC_RECV_FILE},
          * {@link SecurityLog#TAG_SYNC_SEND_FILE}, {@link SecurityLog#TAG_ADB_SHELL_CMD},
-         * {@link SecurityLog#TAG_ADB_SHELL_INTERACTIVE}, {@link SecurityLog#TAG_APP_PROCESS_START}.
+         * {@link SecurityLog#TAG_ADB_SHELL_INTERACTIVE}, {@link SecurityLog#TAG_APP_PROCESS_START},
+         * {@link SecurityLog#TAG_KEYGUARD_DISMISSED}, {@link SecurityLog#TAG_KEYGUARD_SECURED},
+         * {@link SecurityLog#TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT}.
          */
         public @SECURITY_LOG_TAG int getTag() {
             return mEvent.getTag();
diff --git a/core/java/android/auditing/SecurityLogTags.logtags b/core/java/android/auditing/SecurityLogTags.logtags
index 455acff..cf85894 100644
--- a/core/java/android/auditing/SecurityLogTags.logtags
+++ b/core/java/android/auditing/SecurityLogTags.logtags
@@ -3,9 +3,10 @@
 option java_package android.auditing
 
 210001 security_adb_shell_interactive
-210002 security_adb_shell_command        (command|3)
-210003 security_adb_sync_recv            (path|3)
-210004 security_adb_sync_send            (path|3)
-210005 security_app_process_start        (process|3),(start_time|2|3),(uid|1),(pid|1),(seinfo|3),(sha256|3)
-210006 security_device_unlock_attempt    (success|1),(method|3)
-210007 security_device_locked
\ No newline at end of file
+210002 security_adb_shell_command               (command|3)
+210003 security_adb_sync_recv                   (path|3)
+210004 security_adb_sync_send                   (path|3)
+210005 security_app_process_start               (process|3),(start_time|2|3),(uid|1),(pid|1),(seinfo|3),(sha256|3)
+210006 security_keyguard_dismissed
+210007 security_keyguard_dismiss_auth_attempt   (success|1)
+210008 security_keyguard_secured
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 158a284..49b8363 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1575,6 +1575,14 @@
             = "android.intent.extra.UNINSTALL_ALL_USERS";
 
     /**
+     * Specified when the uninstall confirmation dialog is not required to be shown.
+     * Use with {@link #ACTION_UNINSTALL_PACKAGE}
+     * @hide
+     */
+    public static final String EXTRA_SKIP_UNINSTALL_CONFIRMATION =
+            "android.intent.extra.SKIP_UNINSTALL_CONFIRMATION";
+
+    /**
      * A string associated with a {@link #ACTION_UPGRADE_SETUP} activity
      * describing the last run version of the platform that was setup.
      * @hide
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 1d16516..7f9e176 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -30,8 +30,7 @@
  * when they are committed to storage.  Objects that are returned from the
  * various <code>get</code> methods must be treated as immutable by the application.
  *
- * <p><em>Note: currently this class does not support use across multiple
- * processes.  This will be added later.</em>
+ * <p><em>Note: This class does not support use across multiple processes.</em>
  *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index dedf07f5..91a8e0a 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -156,6 +156,35 @@
     public String targetActivity;
 
     /**
+     * Activity can not be resized and always occupies the fullscreen area with all windows fully
+     * visible.
+     * @hide
+     */
+    public static final int RESIZE_MODE_UNRESIZEABLE = 0;
+    /**
+     * Activity can not be resized and always occupies the fullscreen area with all windows cropped
+     * to either the task or stack bounds.
+     * @hide
+     */
+    public static final int RESIZE_MODE_CROP_WINDOWS = 1;
+    /**
+     * Activity is resizeable.
+     * @hide
+     */
+    public static final int RESIZE_MODE_RESIZEABLE = 2;
+    /**
+     * Activity is resizeable and supported picture-in-picture mode.
+     * @hide
+     */
+    public static final int RESIZE_MODE_RESIZEABLE_AND_PIPABLE = 3;
+    /**
+     * Value indicating if the resizing mode the activity supports.
+     * See {@link android.R.attr#resizeableActivity}.
+     * @hide
+     */
+    public int resizeMode;
+
+    /**
      * Bit in {@link #flags} indicating whether this activity is able to
      * run in multiple processes.  If
      * true, the system may instantiate it in the some process as the
@@ -283,20 +312,6 @@
     public static final int FLAG_ENABLE_VR_MODE = 0x8000;
 
     /**
-     * Bit in {@link #flags} indicating if the activity is resizeable to any dimension.
-     * See {@link android.R.attr#resizeableActivity}.
-     * @hide
-     */
-    public static final int FLAG_RESIZEABLE = 0x10000;
-
-    /**
-     * Bit in {@link #flags} indicating if the activity is supports picture-in-picture form of
-     * multi-window mode. See {@link android.R.attr#supportsPictureInPicture}.
-     * @hide
-     */
-    public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x20000;
-
-    /**
      * Bit in {@link #flags} indicating if the activity is always focusable regardless of if it is
      * in a task/stack whose activities are normally not focusable.
      * See android.R.attr#alwaysFocusable.
@@ -746,6 +761,7 @@
         maxRecents = orig.maxRecents;
         lockTaskLaunchMode = orig.lockTaskLaunchMode;
         layout = orig.layout;
+        resizeMode = orig.resizeMode;
     }
 
     /**
@@ -768,6 +784,22 @@
         }
     }
 
+    /** @hide */
+    public static final String resizeModeToString(int mode) {
+        switch (mode) {
+            case RESIZE_MODE_UNRESIZEABLE:
+                return "RESIZE_MODE_UNRESIZEABLE";
+            case RESIZE_MODE_CROP_WINDOWS:
+                return "RESIZE_MODE_CROP_WINDOWS";
+            case RESIZE_MODE_RESIZEABLE:
+                return "RESIZE_MODE_RESIZEABLE";
+            case RESIZE_MODE_RESIZEABLE_AND_PIPABLE:
+                return "RESIZE_MODE_RESIZEABLE_AND_PIPABLE";
+            default:
+                return "unknown=" + mode;
+        }
+    }
+
     public void dump(Printer pw, String prefix) {
         dump(pw, prefix, DUMP_FLAG_ALL);
     }
@@ -806,6 +838,7 @@
                     + layout.widthFraction + ", " + layout.height + "|"
                     + layout.heightFraction + ", " + layout.gravity);
         }
+        pw.println(prefix + "resizeMode=" + resizeModeToString(resizeMode));
         super.dumpBack(pw, prefix, flags);
     }
 
@@ -847,6 +880,7 @@
         } else {
             dest.writeInt(0);
         }
+        dest.writeInt(resizeMode);
     }
 
     public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -879,6 +913,7 @@
         if (source.readInt() == 1) {
             layout = new Layout(source);
         }
+        resizeMode = source.readInt();
     }
 
     public static final class Layout {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index a6fec9f..9319c2e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -16,15 +16,12 @@
 
 package android.content.pm;
 
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
-import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import android.app.ActivityManager;
 import android.content.ComponentName;
@@ -55,15 +52,6 @@
 import android.util.jar.StrictJarFile;
 import android.view.Gravity;
 
-import com.android.internal.R;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.XmlUtils;
-
-import libcore.io.IoUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -87,6 +75,25 @@
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.zip.ZipEntry;
 
+import libcore.io.IoUtils;
+
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
 /**
  * Parser for package files (APKs) on disk. This supports apps packaged either
  * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple
@@ -3219,24 +3226,29 @@
                 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
             }
 
-            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
-                    owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) {
-                a.info.flags |= ActivityInfo.FLAG_RESIZEABLE;
+            a.info.screenOrientation = sa.getInt(
+                    R.styleable.AndroidManifestActivity_screenOrientation,
+                    SCREEN_ORIENTATION_UNSPECIFIED);
 
-                if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
-                        false)) {
-                    a.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+            a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+            if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, true)) {
+                    if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
+                            false)) {
+                        a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+                    } else {
+                        a.info.resizeMode = RESIZE_MODE_RESIZEABLE;
+                    }
                 }
+            } else if (a.info.screenOrientation == SCREEN_ORIENTATION_UNSPECIFIED
+                    && (a.info.flags & FLAG_IMMERSIVE) == 0) {
+                a.info.resizeMode = RESIZE_MODE_CROP_WINDOWS;
             }
 
             if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
-                a.info.flags |= ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+                a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
             }
 
-            a.info.screenOrientation = sa.getInt(
-                    R.styleable.AndroidManifestActivity_screenOrientation,
-                    ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
-
             a.info.lockTaskLaunchMode =
                     sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
 
@@ -3478,6 +3490,7 @@
         info.parentActivityName = target.info.parentActivityName;
         info.maxRecents = target.info.maxRecents;
         info.layout = target.info.layout;
+        info.resizeMode = target.info.resizeMode;
 
         Activity a = new Activity(mParseActivityAliasArgs, info);
         if (outError[0] != null) {
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 19921b5..9e1b312 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -69,7 +69,7 @@
  * href="{@docRoot}guide/topics/resources/color-list-resource.html">Color State
  * List Resource</a>.</p>
  */
-public class ColorStateList implements Parcelable {
+public class ColorStateList extends ComplexColor implements Parcelable {
     private static final String TAG = "ColorStateList";
 
     private static final int DEFAULT_COLOR = Color.RED;
@@ -209,7 +209,7 @@
      * @return A new color state list for the current tag.
      */
     @NonNull
-    private static ColorStateList createFromXmlInner(@NonNull Resources r,
+    static ColorStateList createFromXmlInner(@NonNull Resources r,
             @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         final String name = parser.getName();
@@ -340,6 +340,7 @@
      * @return whether a theme can be applied to this color state list
      * @hide only for resource preloading
      */
+    @Override
     public boolean canApplyTheme() {
         return mThemeAttrs != null;
     }
@@ -419,6 +420,7 @@
      *         attributes
      * @hide only for resource preloading
      */
+    @Override
     public ColorStateList obtainForTheme(Theme t) {
         if (t == null || !canApplyTheme()) {
             return this;
@@ -460,6 +462,7 @@
      *         otherwise.
      * @see #getColorForState(int[], int)
      */
+    @Override
     public boolean isStateful() {
         return mStateSpecs.length > 1;
     }
@@ -602,14 +605,14 @@
      * @return a factory that can create new instances of this ColorStateList
      * @hide only for resource preloading
      */
-    public ConstantState<ColorStateList> getConstantState() {
+    public ConstantState<ComplexColor> getConstantState() {
         if (mFactory == null) {
             mFactory = new ColorStateListFactory(this);
         }
         return mFactory;
     }
 
-    private static class ColorStateListFactory extends ConstantState<ColorStateList> {
+    private static class ColorStateListFactory extends ConstantState<ComplexColor> {
         private final ColorStateList mSrc;
 
         public ColorStateListFactory(ColorStateList src) {
@@ -628,7 +631,7 @@
 
         @Override
         public ColorStateList newInstance(Resources res, Theme theme) {
-            return mSrc.obtainForTheme(theme);
+            return (ColorStateList) mSrc.obtainForTheme(theme);
         }
     }
 
diff --git a/core/java/android/content/res/ComplexColor.java b/core/java/android/content/res/ComplexColor.java
new file mode 100644
index 0000000..d96ec62
--- /dev/null
+++ b/core/java/android/content/res/ComplexColor.java
@@ -0,0 +1,55 @@
+/*
+ * 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 android.content.res;
+
+import android.annotation.ColorInt;
+import android.content.res.Resources.Theme;
+import android.graphics.Color;
+
+/**
+ * Defines an abstract class for the complex color information, like
+ * {@link android.content.res.ColorStateList} or {@link android.content.res.GradientColor}
+ */
+public abstract class ComplexColor {
+    /**
+     * @return {@code true}  if this ComplexColor changes color based on state, {@code false}
+     * otherwise.
+     */
+    public boolean isStateful() { return false; }
+
+    /**
+     * @return the default color.
+     */
+    @ColorInt
+    public abstract int getDefaultColor();
+
+    /**
+     * @hide only for resource preloading
+     *
+     */
+    public abstract ConstantState<ComplexColor> getConstantState();
+
+    /**
+     * @hide only for resource preloading
+     */
+    public abstract boolean canApplyTheme();
+
+    /**
+     * @hide only for resource preloading
+     */
+    public abstract ComplexColor obtainForTheme(Theme t);
+}
diff --git a/core/java/android/content/res/GradientColor.java b/core/java/android/content/res/GradientColor.java
new file mode 100644
index 0000000..98ef2ea
--- /dev/null
+++ b/core/java/android/content/res/GradientColor.java
@@ -0,0 +1,523 @@
+/*
+ * 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 android.content.res;
+
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources.Theme;
+
+import com.android.internal.R;
+import com.android.internal.util.GrowingArrayUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.graphics.LinearGradient;
+import android.graphics.RadialGradient;
+import android.graphics.Shader;
+import android.graphics.SweepGradient;
+import android.graphics.drawable.GradientDrawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import java.io.IOException;
+
+
+public class GradientColor extends ComplexColor {
+    private static final String TAG = "GradientColor";
+
+    private static final boolean DBG_GRADIENT = false;
+
+    /** Lazily-created factory for this GradientColor. */
+    private GradientColorFactory mFactory;
+
+    private int mChangingConfigurations;
+    private int mDefaultColor;
+
+    // After parsing all the attributes from XML, this shader is the ultimate result containing
+    // all the XML information.
+    private Shader mShader = null;
+
+    // Below are the attributes at the root element <gradient>
+    private int mGradientType = GradientDrawable.LINEAR_GRADIENT;
+
+    private float mCenterX = 0f;
+    private float mCenterY = 0f;
+
+    private float mStartX = 0f;
+    private float mStartY = 0f;
+    private float mEndX = 0f;
+    private float mEndY = 0f;
+
+    private int mStartColor = 0;
+    private int mCenterColor = 0;
+    private int mEndColor = 0;
+    private boolean mHasCenterColor = false;
+
+    private float mGradientRadius = 0f;
+
+    // Below are the attributes for the <item> element.
+    private int[] mItemColors;
+    private float[] mItemOffsets;
+
+    // Theme attributes for the root and item elements.
+    private int[] mThemeAttrs;
+    private int[][] mItemsThemeAttrs;
+
+    private GradientColor() {
+    }
+
+    private GradientColor(GradientColor copy) {
+        if (copy != null) {
+            mChangingConfigurations = copy.mChangingConfigurations;
+            mDefaultColor = copy.mDefaultColor;
+            mShader = copy.mShader;
+            mGradientType = copy.mGradientType;
+            mCenterX = copy.mCenterX;
+            mCenterY = copy.mCenterY;
+            mStartX = copy.mStartX;
+            mStartY = copy.mStartY;
+            mEndX = copy.mEndX;
+            mEndY = copy.mEndY;
+            mStartColor = copy.mStartColor;
+            mCenterColor = copy.mCenterColor;
+            mEndColor = copy.mEndColor;
+            mHasCenterColor = copy.mHasCenterColor;
+            mGradientRadius = copy.mGradientRadius;
+
+            if (copy.mItemColors != null) {
+                mItemColors = copy.mItemColors.clone();
+            }
+            if (copy.mItemOffsets != null) {
+                mItemOffsets = copy.mItemOffsets.clone();
+            }
+
+            if (copy.mThemeAttrs != null) {
+                mThemeAttrs = copy.mThemeAttrs.clone();
+            }
+            if (copy.mItemsThemeAttrs != null) {
+                mItemsThemeAttrs = copy.mItemsThemeAttrs.clone();
+            }
+        }
+    }
+
+    /**
+     * Update the root level's attributes, either for inflate or applyTheme.
+     */
+    private void updateRootElementState(TypedArray a) {
+        // Extract the theme attributes, if any.
+        mThemeAttrs = a.extractThemeAttrs();
+
+        mStartX = a.getFloat(
+                R.styleable.GradientColor_startX, mStartX);
+        mStartY = a.getFloat(
+                R.styleable.GradientColor_startY, mStartY);
+        mEndX = a.getFloat(
+                R.styleable.GradientColor_endX, mEndX);
+        mEndY = a.getFloat(
+                R.styleable.GradientColor_endY, mEndY);
+
+        mCenterX = a.getFloat(
+                R.styleable.GradientColor_centerX, mCenterX);
+        mCenterY = a.getFloat(
+                R.styleable.GradientColor_centerY, mCenterY);
+
+        mGradientType = a.getInt(
+                R.styleable.GradientColor_type, mGradientType);
+
+        mStartColor = a.getColor(
+                R.styleable.GradientColor_startColor, mStartColor);
+        mHasCenterColor |= a.hasValue(
+                R.styleable.GradientColor_centerColor);
+        mCenterColor = a.getColor(
+                R.styleable.GradientColor_centerColor, mCenterColor);
+        mEndColor = a.getColor(
+                R.styleable.GradientColor_endColor, mEndColor);
+
+        if (DBG_GRADIENT) {
+            Log.v(TAG, "hasCenterColor is " + mHasCenterColor);
+            if (mHasCenterColor) {
+                Log.v(TAG, "centerColor:" + mCenterColor);
+            }
+            Log.v(TAG, "startColor: " + mStartColor);
+            Log.v(TAG, "endColor: " + mEndColor);
+        }
+
+        mGradientRadius = a.getFloat(R.styleable.GradientColor_gradientRadius,
+                mGradientRadius);
+    }
+
+    /**
+     * Check if the XML content is valid.
+     *
+     * @throws XmlPullParserException if errors were found.
+     */
+    private void validateXmlContent() throws XmlPullParserException {
+        if (mGradientRadius <= 0
+                && mGradientType == GradientDrawable.RADIAL_GRADIENT) {
+            throw new XmlPullParserException(
+                    "<gradient> tag requires 'gradientRadius' "
+                            + "attribute with radial type");
+        }
+    }
+
+    /**
+     * The shader information will be applied to the native VectorDrawable's path.
+     * @hide
+     */
+    public Shader getShader() {
+        return mShader;
+    }
+
+    /**
+     * A public method to create GradientColor from a XML resource.
+     */
+    public static GradientColor createFromXml(Resources r, XmlResourceParser parser, Theme theme)
+            throws XmlPullParserException, IOException {
+        final AttributeSet attrs = Xml.asAttributeSet(parser);
+
+        int type;
+        while ((type = parser.next()) != XmlPullParser.START_TAG
+                && type != XmlPullParser.END_DOCUMENT) {
+            // Seek parser to start tag.
+        }
+
+        if (type != XmlPullParser.START_TAG) {
+            throw new XmlPullParserException("No start tag found");
+        }
+
+        return createFromXmlInner(r, parser, attrs, theme);
+    }
+
+    /**
+     * Create from inside an XML document. Called on a parser positioned at a
+     * tag in an XML document, tries to create a GradientColor from that tag.
+     *
+     * @return A new GradientColor for the current tag.
+     * @throws XmlPullParserException if the current tag is not &lt;gradient>
+     */
+    @NonNull
+    static GradientColor createFromXmlInner(@NonNull Resources r,
+            @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final String name = parser.getName();
+        if (!name.equals("gradient")) {
+            throw new XmlPullParserException(
+                    parser.getPositionDescription() + ": invalid gradient color tag " + name);
+        }
+
+        final GradientColor gradientColor = new GradientColor();
+        gradientColor.inflate(r, parser, attrs, theme);
+        return gradientColor;
+    }
+
+    /**
+     * Fill in this object based on the contents of an XML "gradient" element.
+     */
+    private void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final TypedArray a = Resources.obtainAttributes(r, theme, attrs, R.styleable.GradientColor);
+        updateRootElementState(a);
+        mChangingConfigurations |= a.getChangingConfigurations();
+        a.recycle();
+
+        // Check correctness and throw exception if errors found.
+        validateXmlContent();
+
+        inflateChildElements(r, parser, attrs, theme);
+
+        onColorsChange();
+    }
+
+    /**
+     * Inflates child elements "item"s for each color stop.
+     *
+     * Note that at root level, we need to save ThemeAttrs for theme applied later.
+     * Here similarly, at each child item, we need to save the theme's attributes, and apply theme
+     * later as applyItemsAttrsTheme().
+     */
+    private void inflateChildElements(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @NonNull Theme theme)
+            throws XmlPullParserException, IOException {
+        final int innerDepth = parser.getDepth() + 1;
+        int type;
+        int depth;
+
+        // Pre-allocate the array with some size, for better performance.
+        float[] offsetList = new float[20];
+        int[] colorList = new int[offsetList.length];
+        int[][] themeAttrsList = new int[offsetList.length][];
+
+        int listSize = 0;
+        boolean hasUnresolvedAttrs = false;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth
+                || type != XmlPullParser.END_TAG)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            if (depth > innerDepth || !parser.getName().equals("item")) {
+                continue;
+            }
+
+            final TypedArray a = Resources.obtainAttributes(r, theme, attrs,
+                    R.styleable.GradientColorItem);
+            boolean hasColor = a.hasValue(R.styleable.GradientColorItem_color);
+            boolean hasOffset = a.hasValue(R.styleable.GradientColorItem_offset);
+            if (!hasColor || !hasOffset) {
+                throw new XmlPullParserException(
+                        parser.getPositionDescription()
+                                + ": <item> tag requires a 'color' attribute and a 'offset' "
+                                + "attribute!");
+            }
+
+            final int[] themeAttrs = a.extractThemeAttrs();
+            int color = a.getColor(R.styleable.GradientColorItem_color, 0);
+            float offset = a.getFloat(R.styleable.GradientColorItem_offset, 0);
+
+            if (DBG_GRADIENT) {
+                Log.v(TAG, "new item color " + color + " " + Integer.toHexString(color));
+                Log.v(TAG, "offset" + offset);
+            }
+            mChangingConfigurations |= a.getChangingConfigurations();
+            a.recycle();
+
+            if (themeAttrs != null) {
+                hasUnresolvedAttrs = true;
+            }
+
+            colorList = GrowingArrayUtils.append(colorList, listSize, color);
+            offsetList = GrowingArrayUtils.append(offsetList, listSize, offset);
+            themeAttrsList = GrowingArrayUtils.append(themeAttrsList, listSize, themeAttrs);
+            listSize++;
+        }
+        if (listSize > 0) {
+            if (hasUnresolvedAttrs) {
+                mItemsThemeAttrs = new int[listSize][];
+                System.arraycopy(themeAttrsList, 0, mItemsThemeAttrs, 0, listSize);
+            } else {
+                mItemsThemeAttrs = null;
+            }
+
+            mItemColors = new int[listSize];
+            mItemOffsets = new float[listSize];
+            System.arraycopy(colorList, 0, mItemColors, 0, listSize);
+            System.arraycopy(offsetList, 0, mItemOffsets, 0, listSize);
+        }
+    }
+
+    /**
+     * Apply theme to all the items.
+     */
+    private void applyItemsAttrsTheme(Theme t) {
+        if (mItemsThemeAttrs == null) {
+            return;
+        }
+
+        boolean hasUnresolvedAttrs = false;
+
+        final int[][] themeAttrsList = mItemsThemeAttrs;
+        final int N = themeAttrsList.length;
+        for (int i = 0; i < N; i++) {
+            if (themeAttrsList[i] != null) {
+                final TypedArray a = t.resolveAttributes(themeAttrsList[i],
+                        R.styleable.GradientColorItem);
+
+                // Extract the theme attributes, if any, before attempting to
+                // read from the typed array. This prevents a crash if we have
+                // unresolved attrs.
+                themeAttrsList[i] = a.extractThemeAttrs(themeAttrsList[i]);
+                if (themeAttrsList[i] != null) {
+                    hasUnresolvedAttrs = true;
+                }
+
+                mItemColors[i] = a.getColor(R.styleable.GradientColorItem_color, mItemColors[i]);
+                mItemOffsets[i] = a.getFloat(R.styleable.GradientColorItem_offset, mItemOffsets[i]);
+                if (DBG_GRADIENT) {
+                    Log.v(TAG, "applyItemsAttrsTheme Colors[i] " + i + " " +
+                            Integer.toHexString(mItemColors[i]));
+                    Log.v(TAG, "Offsets[i] " + i + " " + mItemOffsets[i]);
+                }
+
+                // Account for any configuration changes.
+                mChangingConfigurations |= a.getChangingConfigurations();
+
+                a.recycle();
+            }
+        }
+
+        if (!hasUnresolvedAttrs) {
+            mItemsThemeAttrs = null;
+        }
+    }
+
+    private void onColorsChange() {
+        int[] tempColors = null;
+        float[] tempOffsets = null;
+
+        if (mItemColors != null) {
+            int length = mItemColors.length;
+            tempColors = new int[length];
+            tempOffsets = new float[length];
+
+            for (int i = 0; i < length; i++) {
+                tempColors[i] = mItemColors[i];
+                tempOffsets[i] = mItemOffsets[i];
+            }
+        } else {
+            if (mHasCenterColor) {
+                tempColors = new int[3];
+                tempColors[0] = mStartColor;
+                tempColors[1] = mCenterColor;
+                tempColors[2] = mEndColor;
+
+                tempOffsets = new float[3];
+                tempOffsets[0] = 0.0f;
+                // Since 0.5f is default value, try to take the one that isn't 0.5f
+                tempOffsets[1] = 0.5f;
+                tempOffsets[2] = 1f;
+            } else {
+                tempColors = new int[2];
+                tempColors[0] = mStartColor;
+                tempColors[1] = mEndColor;
+            }
+        }
+        if (tempColors.length < 2) {
+            Log.w(TAG, "<gradient> tag requires 2 color values specified!" + tempColors.length
+                    + " " + tempColors);
+        }
+
+        if (mGradientType == GradientDrawable.LINEAR_GRADIENT) {
+            mShader = new LinearGradient(mStartX, mStartY, mEndX, mEndY, tempColors, tempOffsets,
+                    Shader.TileMode.CLAMP);
+        } else {
+            if (mGradientType == GradientDrawable.RADIAL_GRADIENT) {
+                mShader = new RadialGradient(mCenterX, mCenterY, mGradientRadius, tempColors,
+                        tempOffsets, Shader.TileMode.CLAMP);
+            } else {
+                mShader = new SweepGradient(mCenterX, mCenterY, tempColors, tempOffsets);
+            }
+        }
+        mDefaultColor = tempColors[0];
+    }
+
+    /**
+     * For Gradient color, the default color is not very useful, since the gradient will override
+     * the color information anyway.
+     */
+    @Override
+    @ColorInt
+    public int getDefaultColor() {
+        return mDefaultColor;
+    }
+
+    /**
+     * Similar to ColorStateList, setup constant state and its factory.
+     * @hide only for resource preloading
+     */
+    @Override
+    public ConstantState<ComplexColor> getConstantState() {
+        if (mFactory == null) {
+            mFactory = new GradientColorFactory(this);
+        }
+        return mFactory;
+    }
+
+    private static class GradientColorFactory extends ConstantState<ComplexColor> {
+        private final GradientColor mSrc;
+
+        public GradientColorFactory(GradientColor src) {
+            mSrc = src;
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mSrc.mChangingConfigurations;
+        }
+
+        @Override
+        public GradientColor newInstance() {
+            return mSrc;
+        }
+
+        @Override
+        public GradientColor newInstance(Resources res, Theme theme) {
+            return mSrc.obtainForTheme(theme);
+        }
+    }
+
+    /**
+     * Returns an appropriately themed gradient color.
+     *
+     * @param t the theme to apply
+     * @return a copy of the gradient color the theme applied, or the
+     * gradient itself if there were no unresolved theme
+     * attributes
+     * @hide only for resource preloading
+     */
+    @Override
+    public GradientColor obtainForTheme(Theme t) {
+        if (t == null || !canApplyTheme()) {
+            return this;
+        }
+
+        final GradientColor clone = new GradientColor(this);
+        clone.applyTheme(t);
+        return clone;
+    }
+
+    private void applyTheme(Theme t) {
+        if (mThemeAttrs != null) {
+            applyRootAttrsTheme(t);
+        }
+        if (mItemsThemeAttrs != null) {
+            applyItemsAttrsTheme(t);
+        }
+        onColorsChange();
+    }
+
+    private void applyRootAttrsTheme(Theme t) {
+        final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.GradientColor);
+        // mThemeAttrs will be set to null if if there are no theme attributes in the
+        // typed array.
+        mThemeAttrs = a.extractThemeAttrs(mThemeAttrs);
+        // merging the attributes update inside the updateRootElementState().
+        updateRootElementState(a);
+
+        // Account for any configuration changes.
+        mChangingConfigurations |= a.getChangingConfigurations();
+        a.recycle();
+    }
+
+
+    /**
+     * Returns whether a theme can be applied to this gradient color, which
+     * usually indicates that the gradient color has unresolved theme
+     * attributes.
+     *
+     * @return whether a theme can be applied to this gradient color.
+     * @hide only for resource preloading
+     */
+    @Override
+    public boolean canApplyTheme() {
+        return mThemeAttrs != null || mItemsThemeAttrs != null;
+    }
+
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index e404429..4967d05 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -56,6 +56,7 @@
 import android.util.Pools.SynchronizedPool;
 import android.util.Slog;
 import android.util.TypedValue;
+import android.util.Xml;
 import android.view.ViewDebug;
 import android.view.ViewHierarchyEncoder;
 
@@ -115,8 +116,8 @@
     private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
     private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
             = new LongSparseArray<>();
-    private static final LongSparseArray<android.content.res.ConstantState<ColorStateList>>
-            sPreloadedColorStateLists = new LongSparseArray<>();
+    private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
+            sPreloadedComplexColors = new LongSparseArray<>();
 
     // Pool of TypedArrays targeted to this Resources object.
     final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
@@ -133,7 +134,7 @@
     private final Configuration mTmpConfig = new Configuration();
     private final DrawableCache mDrawableCache = new DrawableCache(this);
     private final DrawableCache mColorDrawableCache = new DrawableCache(this);
-    private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache =
+    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
             new ConfigurationBoundResourceCache<>(this);
     private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
             new ConfigurationBoundResourceCache<>(this);
@@ -1987,7 +1988,7 @@
 
             mDrawableCache.onConfigurationChange(configChanges);
             mColorDrawableCache.onConfigurationChange(configChanges);
-            mColorStateListCache.onConfigurationChange(configChanges);
+            mComplexColorCache.onConfigurationChange(configChanges);
             mAnimatorCache.onConfigurationChange(configChanges);
             mStateListAnimatorCache.onConfigurationChange(configChanges);
 
@@ -2613,6 +2614,82 @@
         return dr;
     }
 
+    /**
+     * Given the value and id, we can get the XML filename as in value.data, based on that, we
+     * first try to load CSL from the cache. If not found, try to get from the constant state.
+     * Last, parse the XML and generate the CSL.
+     */
+    private ComplexColor loadComplexColorFromName(Theme theme, TypedValue value, int id) {
+        final long key = (((long) value.assetCookie) << 32) | value.data;
+        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
+        ComplexColor complexColor = cache.getInstance(key, theme);
+        if (complexColor != null) {
+            return complexColor;
+        }
+
+        final android.content.res.ConstantState<ComplexColor> factory =
+                sPreloadedComplexColors.get(key);
+
+        if (factory != null) {
+            complexColor = factory.newInstance(this, theme);
+        }
+        if (complexColor == null) {
+            complexColor = loadComplexColorForCookie(value, id, theme);
+        }
+
+        if (complexColor != null) {
+            if (mPreloading) {
+                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+                        "color")) {
+                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
+                }
+            } else {
+                cache.put(key, theme, complexColor.getConstantState());
+            }
+        }
+        return complexColor;
+    }
+
+    @Nullable
+    public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, Theme theme) {
+        if (TRACE_FOR_PRELOAD) {
+            // Log only framework resources
+            if ((id >>> 24) == 0x1) {
+                final String name = getResourceName(id);
+                if (name != null) android.util.Log.d("loadComplexColor", name);
+            }
+        }
+
+        final long key = (((long) value.assetCookie) << 32) | value.data;
+
+        // Handle inline color definitions.
+        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+            return getColorStateListFromInt(value, key);
+        }
+
+        final String file = value.string.toString();
+
+        ComplexColor complexColor;
+        if (file.endsWith(".xml")) {
+            try {
+                complexColor = loadComplexColorFromName(theme, value, id);
+            } catch (Exception e) {
+                final NotFoundException rnf = new NotFoundException(
+                        "File " + file + " from complex color resource ID #0x"
+                                + Integer.toHexString(id));
+                rnf.initCause(e);
+                throw rnf;
+            }
+        } else {
+            throw new NotFoundException(
+                    "File " + file + " from drawable resource ID #0x"
+                            + Integer.toHexString(id) + ": .xml extension required");
+        }
+
+        return complexColor;
+    }
+
     @Nullable
     ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
             throws NotFoundException {
@@ -2626,63 +2703,57 @@
 
         final long key = (((long) value.assetCookie) << 32) | value.data;
 
-        ColorStateList csl;
-
         // Handle inline color definitions.
         if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
                 && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-            final android.content.res.ConstantState<ColorStateList> factory =
-                    sPreloadedColorStateLists.get(key);
-            if (factory != null) {
-                return factory.newInstance();
-            }
-
-            csl = ColorStateList.valueOf(value.data);
-
-            if (mPreloading) {
-                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
-                        "color")) {
-                    sPreloadedColorStateLists.put(key, csl.getConstantState());
-                }
-            }
-
-            return csl;
+            return getColorStateListFromInt(value, key);
         }
 
-        final ConfigurationBoundResourceCache<ColorStateList> cache = mColorStateListCache;
-        csl = cache.getInstance(key, theme);
-        if (csl != null) {
-            return csl;
+        ComplexColor complexColor = loadComplexColorFromName(theme, value, id);
+        if (complexColor != null && complexColor instanceof ColorStateList) {
+            return (ColorStateList) complexColor;
         }
 
-        final android.content.res.ConstantState<ColorStateList> factory =
-                sPreloadedColorStateLists.get(key);
+        throw new NotFoundException(
+                "Can't find ColorStateList from drawable resource ID #0x"
+                        + Integer.toHexString(id));
+    }
+
+    @NonNull
+    private ColorStateList getColorStateListFromInt(@NonNull  TypedValue value, long key) {
+        ColorStateList csl;
+        final android.content.res.ConstantState<ComplexColor> factory =
+                sPreloadedComplexColors.get(key);
         if (factory != null) {
-            csl = factory.newInstance(this, theme);
+            return (ColorStateList) factory.newInstance();
         }
 
-        if (csl == null) {
-            csl = loadColorStateListForCookie(value, id, theme);
-        }
+        csl = ColorStateList.valueOf(value.data);
 
-        if (csl != null) {
-            if (mPreloading) {
-                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
-                        "color")) {
-                    sPreloadedColorStateLists.put(key, csl.getConstantState());
-                }
-            } else {
-                cache.put(key, theme, csl.getConstantState());
+        if (mPreloading) {
+            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+                    "color")) {
+                sPreloadedComplexColors.put(key, csl.getConstantState());
             }
         }
 
         return csl;
     }
 
-    private ColorStateList loadColorStateListForCookie(TypedValue value, int id, Theme theme) {
+    /**
+     * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
+     * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
+     *
+     * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
+     * and selector tag.
+     *
+     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
+     */
+    @Nullable
+    private ComplexColor loadComplexColorForCookie(TypedValue value, int id, Theme theme) {
         if (value.string == null) {
             throw new UnsupportedOperationException(
-                    "Can't convert to color state list: type=0x" + value.type);
+                    "Can't convert to ComplexColor: type=0x" + value.type);
         }
 
         final String file = value.string.toString();
@@ -2692,29 +2763,45 @@
             if ((id >>> 24) == 0x1) {
                 final String name = getResourceName(id);
                 if (name != null) {
-                    Log.d(TAG, "Loading framework color state list #" + Integer.toHexString(id)
+                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
                             + ": " + name + " at " + file);
                 }
             }
         }
 
         if (DEBUG_LOAD) {
-            Log.v(TAG, "Loading color state list for cookie " + value.assetCookie + ": " + file);
+            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
         }
 
-        final ColorStateList csl;
+        ComplexColor complexColor = null;
 
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
         if (file.endsWith(".xml")) {
             try {
-                final XmlResourceParser rp = loadXmlResourceParser(
-                        file, id, value.assetCookie, "colorstatelist");
-                csl = ColorStateList.createFromXml(this, rp, theme);
-                rp.close();
+                final XmlResourceParser parser = loadXmlResourceParser(
+                        file, id, value.assetCookie, "ComplexColor");
+
+                final AttributeSet attrs = Xml.asAttributeSet(parser);
+                int type;
+                while ((type = parser.next()) != XmlPullParser.START_TAG
+                        && type != XmlPullParser.END_DOCUMENT) {
+                    // Seek parser to start tag.
+                }
+                if (type != XmlPullParser.START_TAG) {
+                    throw new XmlPullParserException("No start tag found");
+                }
+
+                final String name = parser.getName();
+                if (name.equals("gradient")) {
+                    complexColor = GradientColor.createFromXmlInner(this, parser, attrs, theme);
+                } else if (name.equals("selector")) {
+                    complexColor = ColorStateList.createFromXmlInner(this, parser, attrs, theme);
+                }
+                parser.close();
             } catch (Exception e) {
                 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
                 final NotFoundException rnf = new NotFoundException(
-                        "File " + file + " from color state list resource ID #0x"
+                        "File " + file + " from ComplexColor resource ID #0x"
                                 + Integer.toHexString(id));
                 rnf.initCause(e);
                 throw rnf;
@@ -2727,7 +2814,7 @@
         }
         Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
 
-        return csl;
+        return complexColor;
     }
 
     /**
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index cc65e1e..6067577 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -454,6 +454,39 @@
     }
 
     /**
+     * Retrieve the ComplexColor for the attribute at <var>index</var>.
+     * The value may be either a {@link android.content.res.ColorStateList} which can wrap a simple
+     * color value or a {@link android.content.res.GradientColor}
+     * <p>
+     * This method will return {@code null} if the attribute is not defined or
+     * is not an integer color, color state list or GradientColor.
+     *
+     * @param index Index of attribute to retrieve.
+     *
+     * @return ComplexColor for the attribute, or {@code null} if not defined.
+     * @throws RuntimeException if the attribute if the TypedArray has already
+     *         been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not an integer color, color state list or GradientColor.
+     */
+    @Nullable
+    public ComplexColor getComplexColor(@StyleableRes int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
+        final TypedValue value = mValue;
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+            if (value.type == TypedValue.TYPE_ATTRIBUTE) {
+                throw new UnsupportedOperationException(
+                        "Failed to resolve attribute at index " + index + ": " + value);
+            }
+            return mResources.loadComplexColor(value, value.resourceId, mTheme);
+        }
+        return null;
+    }
+
+    /**
      * Retrieve the ColorStateList for the attribute at <var>index</var>.
      * The value may be either a single solid color or a reference to
      * a color or complex {@link android.content.res.ColorStateList}
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
new file mode 100644
index 0000000..8e5b8a3
--- /dev/null
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -0,0 +1,142 @@
+/*
+ * 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 android.hardware;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class represents a {@link android.hardware.Sensor Sensor} additional information frame,
+ * which is reported through listener callback {@link
+ * android.hardware.SensorEventCallback#onSensorAdditionalInfo onSensorAdditionalInfo}.
+ *
+ * @see SensorManager
+ * @see SensorEventListener3
+ * @see Sensor
+ *
+ */
+
+public class SensorAdditionalInfo {
+
+    /**
+     * The sensor that generated this event. See
+     * {@link android.hardware.SensorManager SensorManager} for details.
+     */
+    public final Sensor sensor;
+
+    /**
+     * Type of this additional info frame.
+     */
+    public final int type;
+
+    /**
+     * Sequence number of frame for a certain type.
+     */
+    public final int serial;
+
+    /**
+     * Additional info payload data represented in float values. Depending on the type of
+     * information, this may be null.
+     */
+    public final float[] floatValues;
+
+    /**
+     * Additional info payload data represented in int values. Depending on the type of information,
+     * this may be null.
+     */
+    public final int[] intValues;
+
+    /**
+     * Typical values of additional infomation type. The set of values is subject to extension in
+     * newer versions and vendors have the freedom of define their own custom values.
+     *
+     * @hide
+     */
+    @IntDef({TYPE_FRAME_BEGIN, TYPE_FRAME_END, TYPE_UNTRACKED_DELAY, TYPE_INTERNAL_TEMPERATURE,
+             TYPE_VEC3_CALIBRATION, TYPE_SENSOR_PLACEMENT, TYPE_SAMPLING})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AdditionalInfoType {}
+
+    /**
+     * Mark the beginning of a set of additional info frames.
+     */
+    public static final int TYPE_FRAME_BEGIN = 0;
+
+    /**
+     * Mark the end of a set of additional info frames.
+     */
+    public static final int TYPE_FRAME_END = 1;
+
+    /**
+     * Untracked delay. Delays that are introduced by data processing, such as filtering, which is
+     * not taken into account by sensor timestamps.
+     *
+     * Payload:
+     *     floatValues[0]: delay estimation in seconds
+     *     floatValues[1]: delay estimation standard deviation
+     */
+    public static final int TYPE_UNTRACKED_DELAY = 0x10000;
+
+    /**
+     * Internal temperature. Sensor hardware device internal temperature.
+     *
+     * Payload:
+     *     floatValues[0]: internal temperature in Celsius.
+     */
+    public static final int TYPE_INTERNAL_TEMPERATURE = 0x10001;
+
+    /**
+     * Vector calibration parameter. Calibration applied to a sensor with 3 elements vector output,
+     * such as accelerometer, gyro, etc.
+     *
+     * Payload:
+     *     floatValues[0..11]: First 3 rows of a homogenous matrix in row major order that captures
+     *     any linear transformation, including rotation, scaling, shear, shift.
+     */
+    public static final int TYPE_VEC3_CALIBRATION = 0x10002;
+
+    /**
+     * Sensor placement. Describes location and installation angle of the sensor device.
+     *
+     * Payload:
+     *     floatValues[0..11]: First 3 rows of homogeneous matrix in row major order that describes
+     *     the location and orientation of the sensor. Origin of reference will be the mobile device
+     *     geometric sensor. Reference frame is defined as the same as Android sensor frame.
+     */
+    public static final int TYPE_SENSOR_PLACEMENT = 0x10003;
+
+    /**
+     * Sampling parameter. Describes the raw sample period and estimated jitter of sample time in
+     * terms of standard deviation.
+     *
+     * Payload:
+     *     floatValues[0]: raw sample period in seconds.
+     *     floatValues[1]: standard deviation of sampling period.
+     */
+    public static final int TYPE_SAMPLING = 0x10004;
+
+    SensorAdditionalInfo(
+            Sensor aSensor, int aType, int aSerial, int [] aIntValues, float [] aFloatValues) {
+        sensor = aSensor;
+        type = aType;
+        serial = aSerial;
+        intValues = aIntValues;
+        floatValues = aFloatValues;
+    }
+}
diff --git a/core/java/android/hardware/SensorEventCallback.java b/core/java/android/hardware/SensorEventCallback.java
new file mode 100644
index 0000000..bac212a
--- /dev/null
+++ b/core/java/android/hardware/SensorEventCallback.java
@@ -0,0 +1,55 @@
+/*
+ * 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 android.hardware;
+
+/**
+ * Used for receiving sensor additional information frames.
+ */
+public abstract class SensorEventCallback implements SensorEventListener2 {
+
+    /**
+     * Called when sensor values have changed.
+     *
+     * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
+     */
+    @Override
+    public void onSensorChanged(SensorEvent event) {}
+
+    /**
+     * Called when the accuracy of the registered sensor has changed.
+     *
+     * @see android.hardware.SensorEventListener#onAccuracyChanged(Sensor, int)
+     */
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+
+    /**
+     * Called after flush() is completed.
+     *
+     * @see android.hardware.SensorEventListener2#onFlushCompleted(Sensor)
+     */
+    @Override
+    public void onFlushCompleted(Sensor sensor) {}
+
+    /**
+     * Called when a sensor additional information frame is available.
+     *
+     * @param info A {@link android.hardware.SensorAdditionalInfo SensorAdditionalInfo} frame
+     * reported from sensor hardware.
+     */
+    public void onSensorAdditionalInfo(SensorAdditionalInfo info) {}
+}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index e91195c..c4afbfb 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -490,7 +490,7 @@
      */
     private static abstract class BaseEventQueue {
         private static native long nativeInitBaseEventQueue(long nativeManager,
-                WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch,
+                WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,
                 String packageName, int mode, String opPackageName);
         private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
                 int maxBatchReportLatencyUs);
@@ -504,7 +504,6 @@
         private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
         protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
         private final CloseGuard mCloseGuard = CloseGuard.get();
-        private final float[] mScratch = new float[16];
         protected final SystemSensorManager mManager;
 
         protected static final int OPERATING_MODE_NORMAL = 0;
@@ -513,7 +512,7 @@
         BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {
             if (packageName == null) packageName = "";
             nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
-                    new WeakReference<>(this), looper.getQueue(), mScratch,
+                    new WeakReference<>(this), looper.getQueue(),
                     packageName, mode, manager.mContext.getOpPackageName());
             mCloseGuard.open("dispose");
             mManager = manager;
@@ -625,6 +624,11 @@
                 long timestamp);
         protected abstract void dispatchFlushCompleteEvent(int handle);
 
+        protected void dispatchAdditionalInfoEvent(
+                int handle, int type, int serial, float[] floatValues, int[] intValues) {
+            // default implementation is do nothing
+        }
+
         protected abstract void addSensorEvent(Sensor sensor);
         protected abstract void removeSensorEvent(Sensor sensor);
     }
@@ -691,7 +695,9 @@
             mListener.onSensorChanged(t);
         }
 
+        // Called from native code.
         @SuppressWarnings("unused")
+        @Override
         protected void dispatchFlushCompleteEvent(int handle) {
             if (mListener instanceof SensorEventListener2) {
                 final Sensor sensor = mManager.mHandleToSensor.get(handle);
@@ -703,6 +709,23 @@
             }
             return;
         }
+
+        // Called from native code.
+        @SuppressWarnings("unused")
+        @Override
+        protected void dispatchAdditionalInfoEvent(
+                int handle, int type, int serial, float[] floatValues, int[] intValues) {
+            if (mListener instanceof SensorEventCallback) {
+                final Sensor sensor = mManager.mHandleToSensor.get(handle);
+                if (sensor == null) {
+                    // sensor disconnected
+                    return;
+                }
+                SensorAdditionalInfo info =
+                        new SensorAdditionalInfo(sensor, type, serial, intValues, floatValues);
+                ((SensorEventCallback)mListener).onSensorAdditionalInfo(info);
+            }
+        }
     }
 
     static final class TriggerEventQueue extends BaseEventQueue {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 92c721b..25b38c0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1189,7 +1189,7 @@
             return TYPE_NONE;
         }
 
-        // Do this only for SUPL, until GpsLocationProvider is fixed. http://b/25876485 .
+        // Do this only for SUPL, until GnssLocationProvider is fixed. http://b/25876485 .
         if (!netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
             // NOTE: if this causes app breakage, we should not just comment out this early return;
             // instead, we should make this early return conditional on the requesting app's target
@@ -3170,7 +3170,7 @@
 
     // Checks whether the calling app can use the legacy routing API (startUsingNetworkFeature,
     // stopUsingNetworkFeature, requestRouteToHost), and if not throw UnsupportedOperationException.
-    // TODO: convert the existing system users (Tethering, GpsLocationProvider) to the new APIs and
+    // TODO: convert the existing system users (Tethering, GnssLocationProvider) to the new APIs and
     // remove these exemptions. Note that this check is not secure, and apps can still access these
     // functions by accessing ConnectivityService directly. However, it should be clear that doing
     // so is unsupported and may break in the future. http://b/22728205
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index eca2c3b..1552a3c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -150,6 +150,12 @@
     public static final int AUDIOSERVER_UID = 1041;
 
     /**
+     * Defines the UID/GID for the cameraserver process
+     * @hide
+     */
+    public static final int CAMERASERVER_UID = 1046;
+
+    /**
      * Defines the start of a range of UIDs (and GIDs), going from this
      * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
      * to applications.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index fe834a1..6321122 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -21,6 +21,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.UserIdInt;
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.admin.DevicePolicyManager;
@@ -621,6 +622,20 @@
     /** @hide */
     public static final int PIN_VERIFICATION_SUCCESS = -1;
 
+    /**
+     * Error result indicating that this user is not allowed to add other users on this device.
+     * This is a result code returned from the activity created by the intent
+     * {@link #createUserCreationIntent(String, String, String, PersistableBundle)}.
+     */
+    public static final int USER_CREATION_FAILED_NOT_PERMITTED = Activity.RESULT_FIRST_USER;
+
+    /**
+     * Error result indicating that no more users can be created on this device.
+     * This is a result code returned from the activity created by the intent
+     * {@link #createUserCreationIntent(String, String, String, PersistableBundle)}.
+     */
+    public static final int USER_CREATION_FAILED_NO_MORE_USERS = Activity.RESULT_FIRST_USER + 1;
+
     /** @hide */
     public static UserManager get(Context context) {
         return (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -1194,7 +1209,10 @@
      * If this device does not support multiple users, null is returned.
      * <p/>
      * The intent should be launched using startActivityForResult and the return result will
-     * indicate if the user consented to adding a new user and if the operation succeeded.
+     * indicate if the user consented to adding a new user and if the operation succeeded. Any
+     * errors in creating the user will be returned in the result code. If the user cancels the
+     * request, the return result will be {@link Activity#RESULT_CANCELED}. On success, the
+     * result code will be {@link Activity#RESULT_OK}.
      * <p/>
      * The new user is created but not initialized. After switching into the user for the first
      * time, the preferred user name and account information are used by the setup process for that
@@ -1211,6 +1229,8 @@
      *                       Handler)}.
      * @return An Intent that can be launched from an Activity or null if creating users is not
      *         supported on this device.
+     * @see #USER_CREATION_FAILED_NOT_PERMITTED
+     * @see #USER_CREATION_FAILED_NO_MORE_USERS
      */
     public static Intent createUserCreationIntent(@Nullable String userName,
             @Nullable String accountName,
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index cdd88f6..032d83d 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -234,6 +234,9 @@
          * @see #FLAG_DIR_PREFERS_LAST_MODIFIED
          * @see #FLAG_VIRTUAL_DOCUMENT
          * @see #FLAG_ARCHIVE
+         * @see #FLAG_SUPPORTS_COPY
+         * @see #FLAG_SUPPORTS_MOVE
+         * @see #FLAG_SUPPORTS_REMOVE
          */
         public static final String COLUMN_FLAGS = "flags";
 
@@ -371,6 +374,15 @@
         public static final int FLAG_ARCHIVE = 1 << 10;
 
         /**
+         * Flag indicating that a document can be removed from a parent.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsContract#removeDocument(ContentProviderClient, Uri, Uri)
+         * @see DocumentsProvider#removeDocument(String, String)
+         */
+        public static final int FLAG_SUPPORTS_REMOVE = 1 << 11;
+
+        /**
          * Flag indicating that document titles should be hidden when viewing
          * this directory in a larger format grid. For example, a directory
          * containing only images may want the image thumbnails to speak for
@@ -612,6 +624,8 @@
     public static final String METHOD_MOVE_DOCUMENT = "android:moveDocument";
     /** {@hide} */
     public static final String METHOD_IS_CHILD_DOCUMENT = "android:isChildDocument";
+    /** {@hide} */
+    public static final String METHOD_REMOVE_DOCUMENT = "android:removeDocument";
 
     /** {@hide} */
     public static final String EXTRA_PARENT_URI = "parentUri";
@@ -835,7 +849,12 @@
         return uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme());
     }
 
-    /** {@hide} */
+    /**
+     * Test if the given URI represents a {@link Document} tree.
+     *
+     * @see #buildTreeDocumentUri(String, String)
+     * @see #getTreeDocumentId(Uri, String)
+     */
     public static boolean isTreeUri(Uri uri) {
         final List<String> paths = uri.getPathSegments();
         return (paths.size() >= 2 && PATH_TREE.equals(paths.get(0)));
@@ -1204,6 +1223,41 @@
     }
 
     /**
+     * Removes the given document from a parent directory.
+     *
+     * <p>In contrast to {@link #deleteDocument} it requires specifying the parent.
+     * This method is especially useful if the document can be in multiple parents.
+     *
+     * @param documentUri document with {@link Document#FLAG_SUPPORTS_REMOVE}
+     * @param parentDocumentUri parent document of the document to remove.
+     * @return true if the document was removed successfully.
+     */
+    public static boolean removeDocument(ContentResolver resolver, Uri documentUri,
+            Uri parentDocumentUri) {
+        final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+                documentUri.getAuthority());
+        try {
+            removeDocument(client, documentUri, parentDocumentUri);
+            return true;
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to remove document", e);
+            return false;
+        } finally {
+            ContentProviderClient.releaseQuietly(client);
+        }
+    }
+
+    /** {@hide} */
+    public static void removeDocument(ContentProviderClient client, Uri documentUri,
+            Uri parentDocumentUri) throws RemoteException {
+        final Bundle in = new Bundle();
+        in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+        in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, parentDocumentUri);
+
+        client.call(METHOD_REMOVE_DOCUMENT, null, in);
+    }
+
+    /**
      * Open the given image for thumbnail purposes, using any embedded EXIF
      * thumbnail if available, and providing orientation hints from the parent
      * image.
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index bae928d..7a82cd1e 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -21,6 +21,7 @@
 import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT;
 import static android.provider.DocumentsContract.METHOD_IS_CHILD_DOCUMENT;
 import static android.provider.DocumentsContract.METHOD_MOVE_DOCUMENT;
+import static android.provider.DocumentsContract.METHOD_REMOVE_DOCUMENT;
 import static android.provider.DocumentsContract.METHOD_RENAME_DOCUMENT;
 import static android.provider.DocumentsContract.buildDocumentUri;
 import static android.provider.DocumentsContract.buildDocumentUriMaybeUsingTree;
@@ -300,6 +301,25 @@
             throws FileNotFoundException {
         throw new UnsupportedOperationException("Move not supported");
     }
+
+    /**
+     * Removes the requested document or a document tree.
+     *
+     * <p>In contrast to {@link #deleteDocument} it requires specifying the parent.
+     * This method is especially useful if the document can be in multiple parents.
+     *
+     * <p>It's the responsibility of the provider to revoke grants if the document is
+     * removed from the last parent, and effectively the document is deleted.
+     *
+     * @param documentId the document to remove.
+     * @param parentDocumentId the parent of the document to move.
+     */
+    @SuppressWarnings("unused")
+    public boolean removeDocument(String documentId, String parentDocumentId)
+            throws FileNotFoundException {
+        throw new UnsupportedOperationException("Remove not supported");
+    }
+
     /**
      * Return all roots currently provided. To display to users, you must define
      * at least one root. You should avoid making network requests to keep this
@@ -822,6 +842,17 @@
             // Original document no longer exists, clean up any grants.
             revokeDocumentPermission(documentId);
 
+        } else if (METHOD_REMOVE_DOCUMENT.equals(method)) {
+            final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI);
+            final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri);
+
+            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            removeDocument(documentId, parentSourceId);
+
+            // It's responsibility of the provider to revoke any grants, as the document may be
+            // still attached to another parents.
+
         } else {
             throw new UnsupportedOperationException("Method not supported " + method);
         }
diff --git a/core/java/android/test/AndroidTestCase.java b/core/java/android/test/AndroidTestCase.java
index 2ecbfae..1e6bd9c 100644
--- a/core/java/android/test/AndroidTestCase.java
+++ b/core/java/android/test/AndroidTestCase.java
@@ -29,7 +29,13 @@
 
 /**
  * Extend this if you need to access Resources or other things that depend on Activity Context.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class AndroidTestCase extends TestCase {
 
     protected Context mContext;
diff --git a/core/java/android/test/FlakyTest.java b/core/java/android/test/FlakyTest.java
index 919767f..4e5c4e3 100644
--- a/core/java/android/test/FlakyTest.java
+++ b/core/java/android/test/FlakyTest.java
@@ -26,7 +26,13 @@
  * test methods. When the annotation is present, the test method is re-executed if
  * the test fails. The total number of executions is specified by the tolerance and
  * defaults to 1.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/FlakyTest.html">
+ * FlakyTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Target(ElementType.METHOD)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface FlakyTest {
diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java
index ca427ea..6b79314 100644
--- a/core/java/android/test/InstrumentationTestCase.java
+++ b/core/java/android/test/InstrumentationTestCase.java
@@ -32,7 +32,13 @@
 
 /**
  * A test case that has access to {@link Instrumentation}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class InstrumentationTestCase extends TestCase {
 
     private Instrumentation mInstrumentation;
@@ -40,7 +46,7 @@
     /**
      * Injects instrumentation into this test case. This method is
      * called by the test runner during test setup.
-     * 
+     *
      * @param instrumentation the instrumentation to use with this instance
      */
     public void injectInstrumentation(Instrumentation instrumentation) {
diff --git a/core/java/android/test/InstrumentationTestSuite.java b/core/java/android/test/InstrumentationTestSuite.java
index 7a78ffb..a53fa26 100644
--- a/core/java/android/test/InstrumentationTestSuite.java
+++ b/core/java/android/test/InstrumentationTestSuite.java
@@ -25,7 +25,13 @@
 /**
  * A {@link junit.framework.TestSuite} that injects {@link android.app.Instrumentation} into
  * {@link InstrumentationTestCase} before running them.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class InstrumentationTestSuite extends TestSuite {
 
     private final Instrumentation mInstrumentation;
diff --git a/core/java/android/test/PerformanceTestCase.java b/core/java/android/test/PerformanceTestCase.java
index 679ad40..65bd4a4 100644
--- a/core/java/android/test/PerformanceTestCase.java
+++ b/core/java/android/test/PerformanceTestCase.java
@@ -18,10 +18,11 @@
 
 /**
  * More complex interface performance for test cases.
- * 
+ *
  * If you want your test to be used as a performance test, you must
  * implement this interface.
  */
+@Deprecated
 public interface PerformanceTestCase
 {
     /**
@@ -37,27 +38,27 @@
     }
 
     /**
-     * Set up to begin performance tests.  The 'intermediates' is a
+     * Set up to begin performance tests. The 'intermediates' is a
      * communication channel to send back intermediate performance numbers --
      * if you use it, you will probably want to ensure your test is only
      * executed once by returning 1.  Otherwise, return 0 to allow the test
      * harness to decide the number of iterations.
-     * 
+     *
      * <p>If you return a non-zero iteration count, you should call
      * {@link Intermediates#startTiming intermediates.startTiming} and
      * {@link Intermediates#finishTiming intermediates.endTiming} to report the
      * duration of the test whose performance should actually be measured.
-     * 
+     *
      * @param intermediates Callback for sending intermediate results.
-     * 
+     *
      * @return int Maximum number of iterations to run, or 0 to let the caller
-     *         decide.
+     * decide.
      */
     int startPerformance(Intermediates intermediates);
-    
+
     /**
      * This method is used to determine what modes this test case can run in.
-     * 
+     *
      * @return true if this test case can only be run in performance mode.
      */
     boolean isPerformanceOnly();
diff --git a/core/java/android/test/UiThreadTest.java b/core/java/android/test/UiThreadTest.java
index cd92231..cd06ab8 100644
--- a/core/java/android/test/UiThreadTest.java
+++ b/core/java/android/test/UiThreadTest.java
@@ -26,7 +26,13 @@
  * When the annotation is present, the test method is executed on the application's
  * main thread (or UI thread.) Note that instrumentation methods may not be used
  * when this annotation is present.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/annotation/UiThreadTest.html">
+ * UiThreadTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Target(ElementType.METHOD)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface UiThreadTest {
diff --git a/core/java/android/test/suitebuilder/annotation/LargeTest.java b/core/java/android/test/suitebuilder/annotation/LargeTest.java
index a6269e7..dc77ee6 100644
--- a/core/java/android/test/suitebuilder/annotation/LargeTest.java
+++ b/core/java/android/test/suitebuilder/annotation/LargeTest.java
@@ -23,7 +23,13 @@
 
 /**
  * Marks a test that should run as part of the large tests.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/LargeTest.html">
+ * LargeTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD, ElementType.TYPE})
 public @interface LargeTest {
diff --git a/core/java/android/test/suitebuilder/annotation/MediumTest.java b/core/java/android/test/suitebuilder/annotation/MediumTest.java
index 8afeb91..b941da0 100644
--- a/core/java/android/test/suitebuilder/annotation/MediumTest.java
+++ b/core/java/android/test/suitebuilder/annotation/MediumTest.java
@@ -24,7 +24,12 @@
 /**
  * Marks a test that should run as part of the medium tests.
  *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/MediumTest.html">
+ * MediumTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD, ElementType.TYPE})
 public @interface MediumTest {
diff --git a/core/java/android/test/suitebuilder/annotation/SmallTest.java b/core/java/android/test/suitebuilder/annotation/SmallTest.java
index ad530e2..d3c74f0 100644
--- a/core/java/android/test/suitebuilder/annotation/SmallTest.java
+++ b/core/java/android/test/suitebuilder/annotation/SmallTest.java
@@ -23,7 +23,13 @@
 
 /**
  * Marks a test that should run as part of the small tests.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/SmallTest.html">
+ * SmallTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD, ElementType.TYPE})
 public @interface SmallTest {
diff --git a/core/java/android/test/suitebuilder/annotation/Smoke.java b/core/java/android/test/suitebuilder/annotation/Smoke.java
index 237e033..aac2937 100644
--- a/core/java/android/test/suitebuilder/annotation/Smoke.java
+++ b/core/java/android/test/suitebuilder/annotation/Smoke.java
@@ -27,7 +27,11 @@
  * will run all tests with this annotation.
  *
  * @see android.test.suitebuilder.SmokeTestSuiteBuilder
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD, ElementType.TYPE})
 public @interface Smoke {
diff --git a/core/java/android/test/suitebuilder/annotation/Suppress.java b/core/java/android/test/suitebuilder/annotation/Suppress.java
index f16c8fa..629a3cf 100644
--- a/core/java/android/test/suitebuilder/annotation/Suppress.java
+++ b/core/java/android/test/suitebuilder/annotation/Suppress.java
@@ -26,7 +26,12 @@
  * suite. If the annotation appears on the class then no tests in that class will be included. If
  * the annotation appears only on a test method then only that method will be excluded.
  *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/Suppress.html">
+ * Suppress</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD, ElementType.TYPE})
 public @interface Suppress {
diff --git a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
index 53d7793..03da9bc 100644
--- a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
+++ b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
@@ -64,6 +64,10 @@
 
         String message = checkUserCreationRequirements();
 
+        if (message == null) {
+            finish();
+            return;
+        }
         final AlertController.AlertParams ap = mAlertParams;
         ap.mMessage = message;
         ap.mPositiveButtonText = getString(android.R.string.ok);
@@ -104,11 +108,11 @@
         mCanProceed = true;
         final String appName = appInfo.loadLabel(getPackageManager()).toString();
         if (cantCreateUser) {
-            message = getString(R.string.user_creation_cannot_add, appName);
-            mCanProceed = false;
+            setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED);
+            return null;
         } else if (cantCreateAnyMoreUsers) {
-            message = getString(R.string.user_creation_cannot_add_any_more, appName);
-            mCanProceed = false;
+            setResult(UserManager.USER_CREATION_FAILED_NO_MORE_USERS);
+            return null;
         } else if (accountExists) {
             message = getString(R.string.user_creation_account_exists, appName, mAccountName);
         } else {
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index b951f50e..d3bae16 100644
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -133,7 +133,7 @@
         notificationId = -1;
     }
 
-    // Respond to NI Handler under GpsLocationProvider, 1 = accept, 2 = deny
+    // Respond to NI Handler under GnssLocationProvider, 1 = accept, 2 = deny
     private void sendUserResponse(int response) {
         if (DEBUG) Log.d(TAG, "sendUserResponse, response: " + response);
         LocationManager locationManager = (LocationManager)
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index aa38de7..ec148c55 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1231,7 +1231,9 @@
                 }
 
                 // Filter out any activities that the launched uid does not
-                // have permission for.  We don't do this when we have an explicit
+                // have permission for.
+                // Also filter out those that are suspended because they couldn't
+                // be started. We don't do this when we have an explicit
                 // list of resolved activities, because that only happens when
                 // we are being subclassed, so we can safely launch whatever
                 // they gave us.
@@ -1242,7 +1244,9 @@
                         int granted = ActivityManager.checkComponentPermission(
                                 ai.permission, mLaunchedFromUid,
                                 ai.applicationInfo.uid, ai.exported);
-                        if (granted != PackageManager.PERMISSION_GRANTED) {
+                        boolean suspended = (ai.applicationInfo.flags
+                                & ApplicationInfo.FLAG_SUSPENDED) != 0;
+                        if (granted != PackageManager.PERMISSION_GRANTED || suspended) {
                             // Access not allowed!
                             if (mOrigResolveList == currentResolveList) {
                                 mOrigResolveList = new ArrayList<>(mOrigResolveList);
diff --git a/core/java/com/android/internal/util/GrowingArrayUtils.java b/core/java/com/android/internal/util/GrowingArrayUtils.java
index b4d2d730..968d920 100644
--- a/core/java/com/android/internal/util/GrowingArrayUtils.java
+++ b/core/java/com/android/internal/util/GrowingArrayUtils.java
@@ -97,6 +97,21 @@
     }
 
     /**
+     * Primitive float version of {@link #append(Object[], int, Object)}.
+     */
+    public static float[] append(float[] array, int currentSize, float element) {
+        assert currentSize <= array.length;
+
+        if (currentSize + 1 > array.length) {
+            float[] newArray = ArrayUtils.newUnpaddedFloatArray(growSize(currentSize));
+            System.arraycopy(array, 0, newArray, 0, currentSize);
+            array = newArray;
+        }
+        array[currentSize] = element;
+        return array;
+    }
+
+    /**
      * Inserts an element into the array at the specified index, growing the array if there is no
      * more room.
      *
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 3a00469..976ef4b 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -1264,7 +1264,7 @@
         }
 
         private void maybeComputeTransitionDurationScale() {
-            if (mMainPanelSize == null || mOverflowPanel == null) {
+            if (mMainPanelSize != null && mOverflowPanelSize != null) {
                 int w = mMainPanelSize.getWidth() - mOverflowPanelSize.getWidth();
                 int h = mOverflowPanelSize.getHeight() - mMainPanelSize.getHeight();
                 mTransitionDurationScale = (int) (Math.sqrt(w * w + h * h) /
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 4e4552d..b07e36a 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -39,4 +39,5 @@
     void registerStrongAuthTracker(in IStrongAuthTracker tracker);
     void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
     void requireStrongAuth(int strongAuthReason, int userId);
+    void systemReady();
 }
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 53d4c6a..563ec8b 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -90,6 +90,18 @@
             strokeLineJoin);
 }
 
+static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
+    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+    SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
+    path->setFillGradient(fillShader);
+}
+
+static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
+    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+    SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
+    path->setStrokeGradient(strokeShader);
+}
+
 static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
         jbyteArray outProperties, jint length) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
@@ -331,6 +343,8 @@
         {"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
         {"nCreateFullPath", "!(J)J", (void*)createFullPath},
         {"nUpdateFullPathProperties", "!(JFIFIFFFFFII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
+        {"nUpdateFullPathFillGradient", "!(JJ)V", (void*)updateFullPathFillGradient},
+        {"nUpdateFullPathStrokeGradient", "!(JJ)V", (void*)updateFullPathStrokeGradient},
         {"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
         {"nGetGroupProperties", "(J[FI)Z", (void*)getGroupProperties},
 
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 414eba7..806fcc3 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -534,7 +534,7 @@
     if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
         // Default path: hal version is don't care, do normal camera connect.
         camera = Camera::connect(cameraId, clientName,
-                Camera::USE_CALLING_UID);
+                Camera::USE_CALLING_UID, Camera::USE_CALLING_PID);
     } else {
         jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
                 Camera::USE_CALLING_UID, camera);
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index a582492..4842e1b 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -40,6 +40,7 @@
     jclass clazz;
     jmethodID dispatchSensorEvent;
     jmethodID dispatchFlushCompleteEvent;
+    jmethodID dispatchAdditionalInfoEvent;
 } gBaseEventQueueClassInfo;
 
 namespace android {
@@ -266,21 +267,25 @@
     sp<SensorEventQueue> mSensorQueue;
     sp<MessageQueue> mMessageQueue;
     jobject mReceiverWeakGlobal;
-    jfloatArray mScratch;
+    jfloatArray mFloatScratch;
+    jintArray   mIntScratch;
 public:
     Receiver(const sp<SensorEventQueue>& sensorQueue,
             const sp<MessageQueue>& messageQueue,
-            jobject receiverWeak, jfloatArray scratch) {
+            jobject receiverWeak) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
         mSensorQueue = sensorQueue;
         mMessageQueue = messageQueue;
         mReceiverWeakGlobal = env->NewGlobalRef(receiverWeak);
-        mScratch = (jfloatArray)env->NewGlobalRef(scratch);
+
+        mIntScratch = (jintArray) env->NewGlobalRef(env->NewIntArray(16));
+        mFloatScratch = (jfloatArray) env->NewGlobalRef(env->NewFloatArray(16));
     }
     ~Receiver() {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
         env->DeleteGlobalRef(mReceiverWeakGlobal);
-        env->DeleteGlobalRef(mScratch);
+        env->DeleteGlobalRef(mFloatScratch);
+        env->DeleteGlobalRef(mIntScratch);
     }
     sp<SensorEventQueue> getSensorEventQueue() const {
         return mSensorQueue;
@@ -309,14 +314,19 @@
                 if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
                     // step-counter returns a uint64, but the java API only deals with floats
                     float value = float(buffer[i].u64.step_counter);
-                    env->SetFloatArrayRegion(mScratch, 0, 1, &value);
+                    env->SetFloatArrayRegion(mFloatScratch, 0, 1, &value);
                 } else if (buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {
                     float value[2];
                     value[0] = buffer[i].dynamic_sensor_meta.connected ? 1.f: 0.f;
                     value[1] = float(buffer[i].dynamic_sensor_meta.handle);
-                    env->SetFloatArrayRegion(mScratch, 0, 2, value);
+                    env->SetFloatArrayRegion(mFloatScratch, 0, 2, value);
+                } else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
+                    env->SetIntArrayRegion(mIntScratch, 0, 14,
+                                           buffer[i].additional_info.data_int32);
+                    env->SetFloatArrayRegion(mFloatScratch, 0, 14,
+                                             buffer[i].additional_info.data_float);
                 } else {
-                    env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
+                    env->SetFloatArrayRegion(mFloatScratch, 0, 16, buffer[i].data);
                 }
 
                 if (buffer[i].type == SENSOR_TYPE_META_DATA) {
@@ -327,7 +337,21 @@
                                             gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
                                             buffer[i].meta_data.sensor);
                     }
-                } else {
+                } else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
+                    // This is a flush complete sensor event. Call dispatchAdditionalInfoEvent
+                    // method.
+                    if (receiverObj.get()) {
+                        int type = buffer[i].additional_info.type;
+                        int serial = buffer[i].additional_info.serial;
+                        env->CallVoidMethod(receiverObj.get(),
+                                            gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent,
+                                            buffer[i].sensor,
+                                            type, serial,
+                                            mFloatScratch,
+                                            mIntScratch,
+                                            buffer[i].timestamp);
+                    }
+                }else {
                     int8_t status;
                     switch (buffer[i].type) {
                     case SENSOR_TYPE_ORIENTATION:
@@ -349,7 +373,7 @@
                         env->CallVoidMethod(receiverObj.get(),
                                             gBaseEventQueueClassInfo.dispatchSensorEvent,
                                             buffer[i].sensor,
-                                            mScratch,
+                                            mFloatScratch,
                                             status,
                                             buffer[i].timestamp);
                     }
@@ -370,7 +394,7 @@
 };
 
 static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,
-        jobject eventQWeak, jobject msgQ, jfloatArray scratch, jstring packageName, jint mode) {
+        jobject eventQWeak, jobject msgQ, jstring packageName, jint mode) {
     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
     ScopedUtfChars packageUtf(env, packageName);
     String8 clientName(packageUtf.c_str());
@@ -382,7 +406,7 @@
         return 0;
     }
 
-    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak, scratch);
+    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak);
     receiver->incStrong((void*)nativeInitSensorEventQueue);
     return jlong(receiver.get());
 }
@@ -446,7 +470,7 @@
 
 static const JNINativeMethod gBaseEventQueueMethods[] = {
     {"nativeInitBaseEventQueue",
-             "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;ILjava/lang/String;)J",
+             "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;Ljava/lang/String;ILjava/lang/String;)J",
              (void*)nativeInitSensorEventQueue },
 
     {"nativeEnableSensor",
@@ -491,5 +515,8 @@
     gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,
             gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");
 
+    gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent = GetMethodIDOrDie(env,
+            gBaseEventQueueClassInfo.clazz, "dispatchAdditionalInfoEvent", "(III[F[I)V");
+
     return 0;
 }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 041e693..4194aa4 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -608,7 +608,7 @@
     jlong capabilities = 0;
 
     // Grant CAP_WAKE_ALARM to the Bluetooth process.
-    if (uid == AID_BLUETOOTH) {
+    if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
       capabilities |= (1LL << CAP_WAKE_ALARM);
     }
 
diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml
index aaa2dbc..46a2b2a 100644
--- a/core/res/res/layout/app_error_dialog.xml
+++ b/core/res/res/layout/app_error_dialog.xml
@@ -26,7 +26,7 @@
 >
 
 
-    <TextView
+    <Button
             android:id="@+id/aerr_restart"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -34,7 +34,7 @@
             style="@style/aerr_list_item"
     />
 
-    <TextView
+    <Button
             android:id="@+id/aerr_reset"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -42,7 +42,7 @@
             style="@style/aerr_list_item"
     />
 
-    <TextView
+    <Button
             android:id="@+id/aerr_report"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -50,7 +50,7 @@
             style="@style/aerr_list_item"
     />
 
-    <TextView
+    <Button
             android:id="@+id/aerr_close"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -58,7 +58,7 @@
             style="@style/aerr_list_item"
     />
 
-    <TextView
+    <Button
             android:id="@+id/aerr_mute"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 713038b..1f7206e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3727,7 +3727,7 @@
         <!-- Controls how the image should be resized or moved to match the size
              of this ImageView.  See {@link android.widget.ImageView.ScaleType} -->
         <attr name="scaleType">
-            <!-- Scale using the image matrix when drawing. See  
+            <!-- Scale using the image matrix when drawing. See
                  {@link android.widget.ImageView#setImageMatrix(Matrix)}. -->
             <enum name="matrix" value="0" />
             <!-- Scale the image using {@link android.graphics.Matrix.ScaleToFit#FILL}. -->
@@ -3740,7 +3740,7 @@
             <enum name="fitEnd" value="4" />
             <!-- Center the image in the view, but perform no scaling. -->
             <enum name="center" value="5" />
-            <!-- Scale the image uniformly (maintain the image's aspect ratio) so both dimensions 
+            <!-- Scale the image uniformly (maintain the image's aspect ratio) so both dimensions
                  (width and height) of the image will be equal to or larger than the corresponding
                  dimension of the view (minus padding). The image is then centered in the view. -->
             <enum name="centerCrop" value="6" />
@@ -8135,4 +8135,52 @@
         <attr name="entries" />
         <attr name="entryValues" />
     </declare-styleable>
+
+    <!-- Used to describe the gradient for fill or stroke in a path of VectorDrawable. -->
+    <declare-styleable name="GradientColor">
+        <!-- Start color of the gradient. -->
+        <attr name="startColor" />
+        <!-- Optional center color. -->
+        <attr name="centerColor" />
+        <!-- End color of the gradient. -->
+        <attr name="endColor" />
+        <!-- Type of gradient. The default type is linear. -->
+        <attr name="type" />
+
+        <!-- Only applied to RadialGradient-->
+        <!-- Radius of the gradient, used only with radial gradient. -->
+        <attr name="gradientRadius" />
+
+        <!-- Only applied to SweepGradient / RadialGradient-->
+        <!-- X coordinate of the center of the gradient within the path. -->
+        <attr name="centerX" />
+        <!-- Y coordinate of the center of the gradient within the path. -->
+        <attr name="centerY" />
+
+        <!-- LinearGradient specific -->
+        <!-- X coordinate of the start point origin of the gradient.
+             Defined in same coordinates as the path itself -->
+        <attr name="startX" format="float" />
+        <!-- Y coordinate of the start point of the gradient within the shape.
+             Defined in same coordinates as the path itself -->
+        <attr name="startY" format="float" />
+        <!-- X coordinate of the end point origin of the gradient.
+             Defined in same coordinates as the path itself -->
+        <attr name="endX" format="float" />
+        <!-- Y coordinate of the end point of the gradient within the shape.
+             Defined in same coordinates as the path itself -->
+        <attr name="endY" format="float" />
+
+    </declare-styleable>
+
+    <!-- Describes an item of a GradientColor. Minimally need 2 items to define the gradient
+         Colors defined in <item> override the simple color attributes such as
+         "startColor / centerColor / endColor" are ignored -->
+    <declare-styleable name="GradientColorItem">
+        <!-- The offset (or ratio) of this current color item inside the gradient.
+             The value is only meaningful when it is between 0 and 1. -->
+        <attr name="offset" format="float" />
+        <!-- The current color for the offset inside the gradient. -->
+        <attr name="color" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 57132ea..a2ad09b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2691,6 +2691,11 @@
     <public type="attr" name="canPerformGestures" />
     <public type="attr" name="externalService" />
     <public type="attr" name="supportsLocalInteraction" />
+    <public type="attr" name="startX" />
+    <public type="attr" name="startY" />
+    <public type="attr" name="endX" />
+    <public type="attr" name="endY" />
+    <public type="attr" name="offset" />
 
     <public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
     <public type="style" name="Widget.Material.SeekBar.Discrete" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a276854..b2eab4c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -559,6 +559,9 @@
     <!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen -->
     <string name="notification_hidden_text">Contents hidden</string>
 
+    <!-- Text shown in place of notification contents when the notification is hidden by policy on a secure lockscreen -->
+    <string name="notification_hidden_by_policy_text">Contents hidden by policy</string>
+
     <!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
     <string name="safeMode">Safe mode</string>
 
@@ -4149,14 +4152,10 @@
     <string name="importance_from_topic">You set the importance of these notifications.</string>
     <string name="importance_from_person">This is important because of the people involved.</string>
 
-    <!-- Message to user that app trying to create user is not allowed to due to restrictions. [CHAR LIMIT=none] -->
-    <string name="user_creation_cannot_add"><b><xliff:g id="app" example="Gmail">%1$s</xliff:g></b> is trying to add a new user, but is currently prohibited.</string>
-    <!-- Message to user that app trying to create user is not allowed to due to user limit being reached. [CHAR LIMIT=none] -->
-    <string name="user_creation_cannot_add_any_more"><b><xliff:g id="app" example="Gmail">%1$s</xliff:g></b> is trying to add a new user, but the user limit has been reached.</string>
     <!-- Message to user that app trying to create user for an account that already exists. [CHAR LIMIT=none] -->
-    <string name="user_creation_account_exists"><b><xliff:g id="app" example="Gmail">%1$s</xliff:g></b> is trying to add a new user, but the account <b><xliff:g id="account" example="foobar">%2$s</xliff:g></b> already exists on this device. Proceed anyway?</string>
+    <string name="user_creation_account_exists">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar@gmail.com">%2$s</xliff:g> ?</string>
     <!-- Message to user that app is trying to create user for a specified account. [CHAR LIMIT=none] -->
-    <string name="user_creation_adding"><b><xliff:g id="app" example="Gmail">%1$s</xliff:g></b> is trying to add a new user for the account <b><xliff:g id="account" example="foobar">%2$s</xliff:g></b>. Proceed?</string>
+    <string name="user_creation_adding">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar">%2$s</xliff:g> (a User with this account already exists) ?</string>
 
     <!-- Locale picker strings -->
 
@@ -4190,4 +4189,12 @@
     <string name="new_sms_notification_title">You have new messages</string>
     <!-- Notification content shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
     <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">Device encrypted</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">Some functions might not be available</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">Touch to continue</string>
+
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index b660277..f0960c7 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1398,7 +1398,7 @@
     </style>
 
     <!-- @hide -->
-    <style name="aerr_list_item" parent="Widget.Material.Light.TextView">
+    <style name="aerr_list_item" parent="Widget.Material.Light.Button.Borderless">
         <item name="minHeight">?attr/listPreferredItemHeightSmall</item>
         <item name="textAppearance">?attr/textAppearanceListItemSmall</item>
         <item name="textColor">?attr/textColorAlertDialogListItem</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 81705b4..aa44d7c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -937,8 +937,6 @@
   <java-symbol type="string" name="time_picker_increment_minute_button" />
   <java-symbol type="string" name="time_picker_increment_set_pm_button" />
   <java-symbol type="string" name="upload_file" />
-  <java-symbol type="string" name="user_creation_cannot_add" />
-  <java-symbol type="string" name="user_creation_cannot_add_any_more" />
   <java-symbol type="string" name="user_creation_account_exists" />
   <java-symbol type="string" name="user_creation_adding" />
   <java-symbol type="string" name="user_switched" />
@@ -2401,6 +2399,7 @@
 
   <java-symbol type="string" name="notification_children_count_bracketed" />
   <java-symbol type="string" name="notification_hidden_text" />
+  <java-symbol type="string" name="notification_hidden_by_policy_text" />
   <java-symbol type="id" name="app_name_text" />
   <java-symbol type="id" name="number_of_children" />
   <java-symbol type="id" name="header_sub_text" />
@@ -2505,4 +2504,10 @@
   <java-symbol type="string" name="new_sms_notification_content" />
 
   <java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
+
+  <!-- Encryption notification while accounts are locked by credential encryption -->
+  <java-symbol type="string" name="user_encrypted_title" />
+  <java-symbol type="string" name="user_encrypted_message" />
+  <java-symbol type="string" name="user_encrypted_detail" />
+
 </resources>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 999d47b..d412d7c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -4,9 +4,9 @@
      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.
@@ -136,6 +136,12 @@
     <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
     <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
 
+    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
+    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
+    <assign-permission name="android.permission.WAKE_LOCK" uid="cameraserver" />
+    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
+    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />
+
     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
 
     <!-- This is a list of all the libraries available for application
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index adb282f..94983b3 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -117,7 +117,10 @@
         }
     }
 
-    /* package */ long getNativeInstance() {
+    /**
+     * @hide
+     */
+    public long getNativeInstance() {
         return native_instance;
     }
 
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 6526021..1fc1b83 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -17,6 +17,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.ColorStateList;
+import android.content.res.ComplexColor;
+import android.content.res.GradientColor;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
@@ -27,6 +29,7 @@
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.Shader;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -121,9 +124,9 @@
  * <dd>Defines path data using exactly same format as "d" attribute
  * in the SVG's path data. This is defined in the viewport space.</dd>
  * <dt><code>android:fillColor</code></dt>
- * <dd>Specifies the color used to fill the path. May be a color or (SDK 24+ only) a color state
- * list. If this property is animated, any value set by the animation will override the original
- * value. No path fill is drawn if this property is not specified.</dd>
+ * <dd>Specifies the color used to fill the path. May be a color, also may be a color state list or
+ * a gradient color for SDK 24+. If this property is animated, any value set by the animation will
+ * override the original value. No path fill is drawn if this property is not specified.</dd>
  * <dt><code>android:strokeColor</code></dt>
  * <dd>Specifies the color used to draw the path outline. May be a color or (SDK 24+ only) a color
  * state list. If this property is animated, any value set by the animation will override the
@@ -1276,8 +1279,9 @@
         /////////////////////////////////////////////////////
         // Variables below need to be copied (deep copy if applicable) for mutation.
         private int[] mThemeAttrs;
-        ColorStateList mStrokeColors = null;
-        ColorStateList mFillColors = null;
+
+        ComplexColor mStrokeColors = null;
+        ComplexColor mFillColors = null;
         private long mNativePtr = 0;
 
         public VFullPath() {
@@ -1297,23 +1301,25 @@
         public boolean onStateChange(int[] stateSet) {
             boolean changed = false;
 
-            if (mStrokeColors != null) {
+            if (mStrokeColors != null && mStrokeColors instanceof ColorStateList) {
                 final int oldStrokeColor = getStrokeColor();
-                final int newStrokeColor = mStrokeColors.getColorForState(stateSet, oldStrokeColor);
+                final int newStrokeColor =
+                        ((ColorStateList) mStrokeColors).getColorForState(stateSet, oldStrokeColor);
                 changed |= oldStrokeColor != newStrokeColor;
                 if (oldStrokeColor != newStrokeColor) {
                     nSetStrokeColor(mNativePtr, newStrokeColor);
                 }
             }
 
-            if (mFillColors != null) {
+            if (mFillColors != null && mFillColors instanceof ColorStateList) {
                 final int oldFillColor = getFillColor();
-                final int newFillColor = mFillColors.getColorForState(stateSet, oldFillColor);
+                final int newFillColor = ((ColorStateList) mFillColors).getColorForState(stateSet, oldFillColor);
                 changed |= oldFillColor != newFillColor;
                 if (oldFillColor != newFillColor) {
                     nSetFillColor(mNativePtr, newFillColor);
                 }
             }
+
             return changed;
         }
 
@@ -1372,7 +1378,8 @@
             int strokeLineCap =  properties.getInt(STROKE_LINE_CAP_INDEX * 4);
             int strokeLineJoin = properties.getInt(STROKE_LINE_JOIN_INDEX * 4);
             float strokeMiterLimit = properties.getFloat(STROKE_MITER_LIMIT_INDEX * 4);
-
+            Shader fillGradient = null;
+            Shader strokeGradient = null;
             // Account for any configuration changes.
             mChangingConfigurations |= a.getChangingConfigurations();
 
@@ -1391,23 +1398,43 @@
                 nSetPathString(mNativePtr, pathString, pathString.length());
             }
 
-            final ColorStateList fillColors = a.getColorStateList(
+            final ComplexColor fillColors = a.getComplexColor(
                     R.styleable.VectorDrawablePath_fillColor);
             if (fillColors != null) {
-                // If the color state list isn't stateful, discard the state
-                // list and keep the default (e.g. the only) color.
-                mFillColors = fillColors.isStateful() ? fillColors : null;
+                // If the colors is a gradient color, or the color state list is stateful, keep the
+                // colors information. Otherwise, discard the colors and keep the default color.
+                if (fillColors instanceof  GradientColor) {
+                    mFillColors = fillColors;
+                    fillGradient = ((GradientColor) fillColors).getShader();
+                } else if (fillColors.isStateful()) {
+                    mFillColors = fillColors;
+                } else {
+                    mFillColors = null;
+                }
                 fillColor = fillColors.getDefaultColor();
             }
 
-            final ColorStateList strokeColors = a.getColorStateList(
+            final ComplexColor strokeColors = a.getComplexColor(
                     R.styleable.VectorDrawablePath_strokeColor);
             if (strokeColors != null) {
-                // If the color state list isn't stateful, discard the state
-                // list and keep the default (e.g. the only) color.
-                mStrokeColors = strokeColors.isStateful() ? strokeColors : null;
+                // If the colors is a gradient color, or the color state list is stateful, keep the
+                // colors information. Otherwise, discard the colors and keep the default color.
+                if (strokeColors instanceof GradientColor) {
+                    mStrokeColors = strokeColors;
+                    strokeGradient = ((GradientColor) strokeColors).getShader();
+                } else if (strokeColors.isStateful()) {
+                    mStrokeColors = strokeColors;
+                } else {
+                    mStrokeColors = null;
+                }
                 strokeColor = strokeColors.getDefaultColor();
             }
+            // Update the gradient info, even if the gradiet is null.
+            nUpdateFullPathFillGradient(mNativePtr,
+                    fillGradient != null ? fillGradient.getNativeInstance() : 0);
+            nUpdateFullPathStrokeGradient(mNativePtr,
+                    strokeGradient != null ? strokeGradient.getNativeInstance() : 0);
+
             fillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, fillAlpha);
 
             strokeLineCap = a.getInt(
@@ -1434,18 +1461,44 @@
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null;
+            if (mThemeAttrs != null) {
+                return true;
+            }
+            boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
+            boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+            if (fillCanApplyTheme || strokeCanApplyTheme) {
+                return true;
+            }
+            return false;
+
         }
 
         @Override
         public void applyTheme(Theme t) {
-            if (mThemeAttrs == null) {
-                return;
+            if (mThemeAttrs != null) {
+                final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
+                updateStateFromTypedArray(a);
+                a.recycle();
             }
 
-            final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
-            updateStateFromTypedArray(a);
-            a.recycle();
+            boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
+            boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+            if (fillCanApplyTheme) {
+                mFillColors = mFillColors.obtainForTheme(t);
+                nUpdateFullPathFillGradient(mNativePtr,
+                        ((GradientColor)mFillColors).getShader().getNativeInstance());
+            }
+
+            if (strokeCanApplyTheme) {
+                mStrokeColors = mStrokeColors.obtainForTheme(t);
+                nUpdateFullPathStrokeGradient(mNativePtr,
+                        ((GradientColor)mStrokeColors).getShader().getNativeInstance());
+            }
+        }
+
+        private boolean canGradientApplyTheme(ComplexColor complexColor) {
+            return complexColor != null && complexColor.canApplyTheme()
+                    && complexColor instanceof GradientColor;
         }
 
         /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@@ -1560,6 +1613,8 @@
             int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
             float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
             int strokeLineJoin);
+    private static native void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr);
+    private static native void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr);
 
     private static native long nCreateClipPath();
     private static native long nCreateClipPath(long clipPathPtr);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 1d31c9e..4d4acb9 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -18,6 +18,7 @@
 
 #include "PathParser.h"
 #include "SkImageInfo.h"
+#include "SkShader.h"
 #include <utils/Log.h>
 #include "utils/Macros.h"
 #include "utils/VectorDrawableUtils.h"
@@ -49,7 +50,7 @@
 
     float minScale = fmin(scaleX, scaleY);
     float strokeScale = minScale * matrixScale;
-    drawPath(outCanvas, renderPath, strokeScale);
+    drawPath(outCanvas, renderPath, strokeScale, pathMatrix);
 }
 
 void Path::setPathData(const Data& data) {
@@ -148,6 +149,9 @@
     mStrokeMiterLimit = path.mStrokeMiterLimit;
     mStrokeLineCap = path.mStrokeLineCap;
     mStrokeLineJoin = path.mStrokeLineJoin;
+
+    SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient);
+    SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient);
 }
 
 const SkPath& FullPath::getUpdatedPath() {
@@ -186,22 +190,44 @@
     return SkColorSetA(color, alphaBytes * alpha);
 }
 
-void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale){
-    // Draw path's fill, if fill color isn't transparent.
-    if (mFillColor != SK_ColorTRANSPARENT) {
-        mPaint.setStyle(SkPaint::Style::kFill_Style);
-        mPaint.setAntiAlias(true);
+void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale,
+                        const SkMatrix& matrix){
+    // Draw path's fill, if fill color or gradient is valid
+    bool needsFill = false;
+    if (mFillGradient != nullptr) {
+        mPaint.setColor(applyAlpha(SK_ColorBLACK, mFillAlpha));
+        SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix);
+        mPaint.setShader(newShader);
+        needsFill = true;
+    } else if (mFillColor != SK_ColorTRANSPARENT) {
         mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
         outCanvas->drawPath(renderPath, mPaint);
+        needsFill = true;
     }
-    // Draw path's stroke, if stroke color isn't transparent
-    if (mStrokeColor != SK_ColorTRANSPARENT) {
+
+    if (needsFill) {
+        mPaint.setStyle(SkPaint::Style::kFill_Style);
+        mPaint.setAntiAlias(true);
+        outCanvas->drawPath(renderPath, mPaint);
+    }
+
+    // Draw path's stroke, if stroke color or gradient is valid
+    bool needsStroke = false;
+    if (mStrokeGradient != nullptr) {
+        mPaint.setColor(applyAlpha(SK_ColorBLACK, mStrokeAlpha));
+        SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix);
+        mPaint.setShader(newShader);
+        needsStroke = true;
+    } else if (mStrokeColor != SK_ColorTRANSPARENT) {
+        mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
+        needsStroke = true;
+    }
+    if (needsStroke) {
         mPaint.setStyle(SkPaint::Style::kStroke_Style);
         mPaint.setAntiAlias(true);
         mPaint.setStrokeJoin(mStrokeLineJoin);
         mPaint.setStrokeCap(mStrokeLineCap);
         mPaint.setStrokeMiter(mStrokeMiterLimit);
-        mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
         mPaint.setStrokeWidth(mStrokeWidth * strokeScale);
         outCanvas->drawPath(renderPath, mPaint);
     }
@@ -288,7 +314,7 @@
 }
 
 void ClipPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
-        float strokeScale){
+        float strokeScale, const SkMatrix& matrix){
     outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
 }
 
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 5ae5f6a..09bdce5 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -26,6 +26,7 @@
 #include <SkPath.h>
 #include <SkPathMeasure.h>
 #include <SkRect.h>
+#include <SkShader.h>
 
 #include <cutils/compiler.h>
 #include <stddef.h>
@@ -95,7 +96,7 @@
 protected:
     virtual const SkPath& getUpdatedPath();
     virtual void drawPath(SkCanvas *outCanvas, const SkPath& renderPath,
-            float strokeScale) = 0;
+            float strokeScale, const SkMatrix& matrix) = 0;
     Data mData;
     SkPath mSkPath;
     bool mSkPathDirty = true;
@@ -108,6 +109,11 @@
     FullPath() : Path() {}
     FullPath(const Data& nodes) : Path(nodes) {}
 
+    ~FullPath() {
+        SkSafeUnref(mFillGradient);
+        SkSafeUnref(mStrokeGradient);
+    }
+
     void updateProperties(float strokeWidth, SkColor strokeColor,
             float strokeAlpha, SkColor fillColor, float fillAlpha,
             float trimPathStart, float trimPathEnd, float trimPathOffset,
@@ -162,10 +168,18 @@
     }
     bool getProperties(int8_t* outProperties, int length);
 
+    void setFillGradient(SkShader* fillGradient) {
+        SkRefCnt_SafeAssign(mFillGradient, fillGradient);
+    };
+    void setStrokeGradient(SkShader* strokeGradient) {
+        SkRefCnt_SafeAssign(mStrokeGradient, strokeGradient);
+    };
+
+
 protected:
     const SkPath& getUpdatedPath() override;
     void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
-            float strokeScale) override;
+            float strokeScale, const SkMatrix& matrix) override;
 
 private:
     // Applies trimming to the specified path.
@@ -174,6 +188,8 @@
     SkColor mStrokeColor = SK_ColorTRANSPARENT;
     float mStrokeAlpha = 1;
     SkColor mFillColor = SK_ColorTRANSPARENT;
+    SkShader* mStrokeGradient = nullptr;
+    SkShader* mFillGradient = nullptr;
     float mFillAlpha = 1;
     float mTrimPathStart = 0;
     float mTrimPathEnd = 1;
@@ -195,7 +211,7 @@
 
 protected:
     void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
-            float strokeScale) override;
+            float strokeScale, const SkMatrix& matrix) override;
 };
 
 class ANDROID_API Group: public Node {
diff --git a/location/java/android/location/GnssNmeaListener.java b/location/java/android/location/GnssNmeaListener.java
new file mode 100644
index 0000000..6c9b08a
--- /dev/null
+++ b/location/java/android/location/GnssNmeaListener.java
@@ -0,0 +1,30 @@
+/*
+ * 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 android.location;
+
+/**
+* Used for receiving NMEA sentences from the GNSS.
+* NMEA 0183 is a standard for communicating with marine electronic devices
+* and is a common method for receiving data from a GNSS, typically over a serial port.
+* See <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA 0183</a> for more details.
+* You can implement this interface and call {@link LocationManager#addNmeaListener}
+* to receive NMEA data from the GNSS engine.
+*/
+public interface GnssNmeaListener {
+    /** Called when an NMEA message is received. */
+    void onNmeaReceived(long timestamp, String nmea);
+}
\ No newline at end of file
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
new file mode 100644
index 0000000..77e8a5b
--- /dev/null
+++ b/location/java/android/location/GnssStatus.java
@@ -0,0 +1,140 @@
+/*
+ * 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 android.location;
+
+/**
+ * This class represents the current state of the GNSS engine.
+ * This class is used in conjunction with the {@link GnssStatusCallback}.
+ */
+public final class GnssStatus {
+    /** Unknown constellation type. */
+    public static final int CONSTELLATION_UNKNOWN = 0;
+    /** Constellation type constant for GPS. */
+    public static final int CONSTELLATION_GPS = 1;
+    /** Constellation type constant for SBAS. */
+    public static final int CONSTELLATION_SBAS = 2;
+    /** Constellation type constant for Glonass. */
+    public static final int CONSTELLATION_GLONASS = 3;
+    /** Constellation type constant for QZSS. */
+    public static final int CONSTELLATION_QZSS = 4;
+    /** Constellation type constant for Beidou. */
+    public static final int CONSTELLATION_BEIDOU = 5;
+    /** Constellation type constant for Galileo. */
+    public static final int CONSTELLATION_GALILEO = 6;
+
+    // these must match the definitions in gps.h
+    /** @hide */
+    public static final int GNSS_SV_FLAGS_NONE = 0;
+    /** @hide */
+    public static final int GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA = (1 << 0);
+    /** @hide */
+    public static final int GNSS_SV_FLAGS_HAS_ALMANAC_DATA = (1 << 1);
+    /** @hide */
+    public static final int GNSS_SV_FLAGS_USED_IN_FIX = (1 << 2);
+
+    /** @hide */
+    public static final int PRN_SHIFT_WIDTH = 3;
+
+    /* These package private values are modified by the LocationManager class */
+    /* package */ int[] mPrnWithFlags;
+    /* 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) {
+        mSvCount = svCount;
+        mPrnWithFlags = prnWithFlags;
+        mSnrs = snrs;
+        mElevations = elevations;
+        mAzimuths = azimuths;
+        mConstellationTypes = constellationTypes;
+    }
+
+    /**
+     * Gets the total number of satellites in satellite list.
+     */
+    public int getNumSatellites() {
+        return mSvCount;
+    }
+
+    /**
+     * Retrieves the constellation type of the satellite at the specified position.
+     * @param satIndex the index of the satellite in the list.
+     */
+    public int getConstellationType(int satIndex) {
+        return mConstellationTypes[satIndex];
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Retrieves the signal-noise ration of the satellite at the specified position.
+     * @param satIndex the index of the satellite in the list.
+     */
+    public float getSnr(int satIndex) {
+        return mSnrs[satIndex];
+    }
+
+    /**
+     * Retrieves the elevation of the satellite at the specified position.
+     * @param satIndex the index of the satellite in the list.
+     */
+    public float getElevation(int satIndex) {
+        return 0f;
+    }
+
+    /**
+     * Retrieves the azimuth the satellite at the specified position.
+     * @param satIndex the index of the satellite in the list.
+     */
+    public float getAzimuth(int satIndex) {
+        return mAzimuths[satIndex];
+    }
+
+    /**
+     * Detects whether the satellite at the specified position has ephemeris data.
+     * @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;
+    }
+
+    /**
+     * Detects whether the satellite at the specified position has almanac data.
+     * @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;
+    }
+
+    /**
+     * Detects whether the satellite at the specified position is used in fix.
+     * @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;
+    }
+}
diff --git a/location/java/android/location/GnssStatusCallback.java b/location/java/android/location/GnssStatusCallback.java
new file mode 100644
index 0000000..b86171b
--- /dev/null
+++ b/location/java/android/location/GnssStatusCallback.java
@@ -0,0 +1,44 @@
+/*
+ * 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 android.location;
+
+/**
+ * Used for receiving notifications when GNSS events happen.
+ */
+public abstract class GnssStatusCallback {
+    /**
+     * Called when GNSS system has started.
+     */
+    public void onStarted() {}
+
+    /**
+     * Called when GNSS system has stopped.
+     */
+    public void onStopped() {}
+
+    /**
+     * Called when the GNSS system has received its first fix since starting.
+     * @param ttff the time from start to first fix.
+     */
+    public void onFirstFix(int ttff) {}
+
+    /**
+     * Called periodically to report GNSS satellite status.
+     * @param status the current status of all satellites.
+     */
+    public void onSatelliteStatusChanged(GnssStatus status) {}
+}
\ No newline at end of file
diff --git a/location/java/android/location/GpsClock.java b/location/java/android/location/GpsClock.java
index 4135a1c..719e56f 100644
--- a/location/java/android/location/GpsClock.java
+++ b/location/java/android/location/GpsClock.java
@@ -16,36 +16,41 @@
 
 package android.location;
 
-import android.annotation.SystemApi;
+import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A class containing a GPS clock timestamp.
  * It represents a measurement of the GPS receiver's clock.
- *
- * @hide
  */
-@SystemApi
-public class GpsClock implements Parcelable {
+public final class GpsClock implements Parcelable {
 
     // The following enumerations must be in sync with the values declared in gps.h
 
+    /** The type of the GPS Clock. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({CLOCK_TYPE_UNKNOWN, CLOCK_TYPE_LOCAL_HW_TIME, CLOCK_TYPE_GPS_TIME})
+    public @interface GpsClockType {}
+
     /**
      * The type of the time stored is not available or it is unknown.
      */
-    public static final byte TYPE_UNKNOWN = 0;
+    public static final byte CLOCK_TYPE_UNKNOWN = 0;
 
     /**
      * The source of the time value reported by this class is the 'Local Hardware Clock'.
      */
-    public static final byte TYPE_LOCAL_HW_TIME = 1;
+    public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1;
 
     /**
      * The source of the time value reported by this class is the 'GPS time' derived from
      * satellites (epoch = Jan 6, 1980).
      */
-    public static final byte TYPE_GPS_TIME = 2;
+    public static final byte CLOCK_TYPE_GPS_TIME = 2;
 
     private static final short HAS_NO_FLAGS = 0;
     private static final short HAS_LEAP_SECOND = (1<<0);
@@ -68,6 +73,7 @@
     private double mBiasUncertaintyInNs;
     private double mDriftInNsPerSec;
     private double mDriftUncertaintyInNsPerSec;
+    private long mTimeOfLastHwClockDiscontinuityInNs;
 
     GpsClock() {
         initialize();
@@ -87,6 +93,7 @@
         mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
         mDriftInNsPerSec = clock.mDriftInNsPerSec;
         mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
+        mTimeOfLastHwClockDiscontinuityInNs = clock.mTimeOfLastHwClockDiscontinuityInNs;
     }
 
     /**
@@ -99,6 +106,7 @@
     /**
      * Gets the type of time reported by {@link #getTimeInNs()}.
      */
+    @GpsClockType
     public byte getType() {
         return mType;
     }
@@ -106,7 +114,7 @@
     /**
      * Sets the type of time reported.
      */
-    public void setType(byte value) {
+    public void setType(@GpsClockType byte value) {
         mType = value;
     }
 
@@ -116,11 +124,11 @@
      */
     private String getTypeString() {
         switch (mType) {
-            case TYPE_UNKNOWN:
+            case CLOCK_TYPE_UNKNOWN:
                 return "Unknown";
-            case TYPE_GPS_TIME:
+            case CLOCK_TYPE_GPS_TIME:
                 return "GpsTime";
-            case TYPE_LOCAL_HW_TIME:
+            case CLOCK_TYPE_LOCAL_HW_TIME:
                 return "LocalHwClock";
             default:
                 return "<Invalid:" + mType + ">";
@@ -163,8 +171,8 @@
 
     /**
      * Gets the GPS receiver internal clock value in nanoseconds.
-     * This can be either the 'local hardware clock' value ({@link #TYPE_LOCAL_HW_TIME}), or the
-     * current GPS time derived inside GPS receiver ({@link #TYPE_GPS_TIME}).
+     * This can be either the 'local hardware clock' value ({@link #CLOCK_TYPE_LOCAL_HW_TIME}), or the
+     * current GPS time derived inside GPS receiver ({@link #CLOCK_TYPE_GPS_TIME}).
      * {@link #getType()} defines the time reported.
      *
      * For 'local hardware clock' this value is expected to be monotonically increasing during the
@@ -223,7 +231,7 @@
     }
 
     /**
-     * Returns true if {@link @getFullBiasInNs()} is available, false otherwise.
+     * Returns true if {@link #getFullBiasInNs()} is available, false otherwise.
      */
     public boolean hasFullBiasInNs() {
         return isFlagSet(HAS_FULL_BIAS);
@@ -233,7 +241,7 @@
      * Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and
      * the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
      *
-     * This value is available if {@link #TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved
+     * This value is available if {@link #CLOCK_TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved
      * the clock for GPS time.
      * {@link #getBiasUncertaintyInNs()} should be used for quality check.
      *
@@ -387,6 +395,20 @@
     }
 
     /**
+     * Gets time of last hardware clock discontinuity.
+     */
+    public long getTimeOfLastHwClockDiscontinuityInNs() {
+        return mTimeOfLastHwClockDiscontinuityInNs;
+    }
+
+    /**
+     * Sets time of last hardware clock discontinuity.
+     */
+    public void setTimeOfLastHwClockDiscontinuityInNs(long timeOfLastHwClockDiscontinuityInNs) {
+        mTimeOfLastHwClockDiscontinuityInNs = timeOfLastHwClockDiscontinuityInNs;
+    }
+
+    /**
      * Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
      */
     public void resetDriftUncertaintyInNsPerSec() {
@@ -409,6 +431,7 @@
             gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
             gpsClock.mDriftInNsPerSec = parcel.readDouble();
             gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
+            gpsClock.mTimeOfLastHwClockDiscontinuityInNs = parcel.readLong();
 
             return gpsClock;
         }
@@ -430,6 +453,7 @@
         parcel.writeDouble(mBiasUncertaintyInNs);
         parcel.writeDouble(mDriftInNsPerSec);
         parcel.writeDouble(mDriftUncertaintyInNsPerSec);
+        parcel.writeLong(mTimeOfLastHwClockDiscontinuityInNs);
     }
 
     @Override
@@ -473,13 +497,17 @@
                 "DriftUncertaintyInNsPerSec",
                 hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
 
+        builder.append(String.format(format, "TimeOfLastHwClockDiscontinuityInNs",
+                getType() == CLOCK_TYPE_LOCAL_HW_TIME
+                        ? mTimeOfLastHwClockDiscontinuityInNs : null));
+
         return builder.toString();
     }
 
     private void initialize() {
         mFlags = HAS_NO_FLAGS;
         resetLeapSecond();
-        setType(TYPE_UNKNOWN);
+        setType(CLOCK_TYPE_UNKNOWN);
         setTimeInNs(Long.MIN_VALUE);
         resetTimeUncertaintyInNs();
         resetFullBiasInNs();
@@ -487,6 +515,7 @@
         resetBiasUncertaintyInNs();
         resetDriftInNsPerSec();
         resetDriftUncertaintyInNsPerSec();
+        setTimeOfLastHwClockDiscontinuityInNs(Long.MIN_VALUE);
     }
 
     private void setFlag(short flag) {
diff --git a/location/java/android/location/GpsMeasurement.java b/location/java/android/location/GpsMeasurement.java
index f13a440..366ad61 100644
--- a/location/java/android/location/GpsMeasurement.java
+++ b/location/java/android/location/GpsMeasurement.java
@@ -16,17 +16,17 @@
 
 package android.location;
 
-import android.annotation.SystemApi;
+import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A class representing a GPS satellite measurement, containing raw and computed information.
- *
- * @hide
  */
-@SystemApi
-public class GpsMeasurement implements Parcelable {
+public final class GpsMeasurement implements Parcelable {
     private int mFlags;
     private byte mPrn;
     private double mTimeOffsetInNs;
@@ -59,6 +59,8 @@
     private double mAzimuthInDeg;
     private double mAzimuthUncertaintyInDeg;
     private boolean mUsedInFix;
+    private double mPseudorangeRateCarrierInMetersPerSec;
+    private double mPseudorangeRateCarrierUncertaintyInMetersPerSec;
 
     // The following enumerations must be in sync with the values declared in gps.h
 
@@ -83,6 +85,11 @@
     private static final int HAS_USED_IN_FIX = (1<<17);
     private static final int GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18);
 
+    /** The status of 'loss of lock'. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({LOSS_OF_LOCK_UNKNOWN, LOSS_OF_LOCK_OK, LOSS_OF_LOCK_CYCLE_SLIP})
+    public @interface LossOfLockStatus {}
+
     /**
      * The indicator is not available or it is unknown.
      */
@@ -98,6 +105,12 @@
      */
     public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2;
 
+    /** The status of multipath. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({MULTIPATH_INDICATOR_UNKNOWN, MULTIPATH_INDICATOR_DETECTED,
+        MULTIPATH_INDICATOR_NOT_USED})
+    public @interface MultipathIndicator {}
+
     /**
      * The indicator is not available or it is unknown.
      */
@@ -218,6 +231,10 @@
         mAzimuthInDeg = measurement.mAzimuthInDeg;
         mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg;
         mUsedInFix = measurement.mUsedInFix;
+        mPseudorangeRateCarrierInMetersPerSec =
+                measurement.mPseudorangeRateCarrierInMetersPerSec;
+        mPseudorangeRateCarrierUncertaintyInMetersPerSec =
+                measurement.mPseudorangeRateCarrierUncertaintyInMetersPerSec;
     }
 
     /**
@@ -776,6 +793,7 @@
     /**
      * Gets a value indicating the 'loss of lock' state of the event.
      */
+    @LossOfLockStatus
     public byte getLossOfLock() {
         return mLossOfLock;
     }
@@ -783,7 +801,7 @@
     /**
      * Sets the 'loss of lock' status.
      */
-    public void setLossOfLock(byte value) {
+    public void setLossOfLock(@LossOfLockStatus byte value) {
         mLossOfLock = value;
     }
 
@@ -941,6 +959,7 @@
     /**
      * Gets a value indicating the 'multipath' state of the event.
      */
+    @MultipathIndicator
     public byte getMultipathIndicator() {
         return mMultipathIndicator;
     }
@@ -948,7 +967,7 @@
     /**
      * Sets the 'multi-path' indicator.
      */
-    public void setMultipathIndicator(byte value) {
+    public void setMultipathIndicator(@MultipathIndicator byte value) {
         mMultipathIndicator = value;
     }
 
@@ -1157,6 +1176,34 @@
         mUsedInFix = value;
     }
 
+    /**
+     * Gets pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
+     */
+    public double getPseudorangeRateCarrierInMetersPerSec() {
+        return mPseudorangeRateCarrierInMetersPerSec;
+    }
+
+    /**
+     * Sets pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
+     */
+    public void setPseudorangeRateCarrierInMetersPerSec(double value) {
+        mPseudorangeRateCarrierInMetersPerSec = value;
+    }
+
+    /**
+     * Gets 1-Sigma uncertainty of the pseudorange rate carrier.
+     */
+    public double getPseudorangeRateCarrierUncertaintyInMetersPerSec() {
+        return mPseudorangeRateCarrierUncertaintyInMetersPerSec;
+    }
+
+    /**
+     * Sets 1-Sigma uncertainty of the pseudorange rate carrier.
+     */
+    public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double value) {
+        mPseudorangeRateCarrierUncertaintyInMetersPerSec = value;
+    }
+
     public static final Creator<GpsMeasurement> CREATOR = new Creator<GpsMeasurement>() {
         @Override
         public GpsMeasurement createFromParcel(Parcel parcel) {
@@ -1194,6 +1241,8 @@
             gpsMeasurement.mAzimuthInDeg = parcel.readDouble();
             gpsMeasurement.mAzimuthUncertaintyInDeg = parcel.readDouble();
             gpsMeasurement.mUsedInFix = parcel.readInt() != 0;
+            gpsMeasurement.mPseudorangeRateCarrierInMetersPerSec = parcel.readDouble();
+            gpsMeasurement.mPseudorangeRateCarrierUncertaintyInMetersPerSec = parcel.readDouble();
 
             return gpsMeasurement;
         }
@@ -1237,6 +1286,8 @@
         parcel.writeDouble(mAzimuthInDeg);
         parcel.writeDouble(mAzimuthUncertaintyInDeg);
         parcel.writeInt(mUsedInFix ? 1 : 0);
+        parcel.writeDouble(mPseudorangeRateCarrierInMetersPerSec);
+        parcel.writeDouble(mPseudorangeRateCarrierUncertaintyInMetersPerSec);
     }
 
     @Override
@@ -1361,6 +1412,11 @@
 
         builder.append(String.format(format, "UsedInFix", mUsedInFix));
 
+        builder.append(String.format(format, "PseudorangeRateCarrierInMetersPerSec",
+                    mPseudorangeRateCarrierInMetersPerSec));
+        builder.append(String.format(format, "PseudorangeRateCarrierUncertaintyInMetersPerSec",
+                    mPseudorangeRateCarrierUncertaintyInMetersPerSec));
+
         return builder.toString();
     }
 
@@ -1397,6 +1453,8 @@
         resetAzimuthInDeg();
         resetAzimuthUncertaintyInDeg();
         setUsedInFix(false);
+        setPseudorangeRateCarrierInMetersPerSec(Double.MIN_VALUE);
+        setPseudorangeRateCarrierUncertaintyInMetersPerSec(Double.MIN_VALUE);
     }
 
     private void setFlag(int flag) {
diff --git a/location/java/android/location/GpsMeasurementListenerTransport.java b/location/java/android/location/GpsMeasurementCallbackTransport.java
similarity index 68%
rename from location/java/android/location/GpsMeasurementListenerTransport.java
rename to location/java/android/location/GpsMeasurementCallbackTransport.java
index 610da96..02d9026 100644
--- a/location/java/android/location/GpsMeasurementListenerTransport.java
+++ b/location/java/android/location/GpsMeasurementCallbackTransport.java
@@ -20,17 +20,17 @@
 import android.os.RemoteException;
 
 /**
- * A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener}.
+ * A handler class to manage transport callbacks for {@link GpsMeasurementsEvent.Callback}.
  *
  * @hide
  */
-class GpsMeasurementListenerTransport
-        extends LocalListenerHelper<GpsMeasurementsEvent.Listener> {
+class GpsMeasurementCallbackTransport
+        extends LocalListenerHelper<GpsMeasurementsEvent.Callback> {
     private final ILocationManager mLocationManager;
 
     private final IGpsMeasurementsListener mListenerTransport = new ListenerTransport();
 
-    public GpsMeasurementListenerTransport(Context context, ILocationManager locationManager) {
+    public GpsMeasurementCallbackTransport(Context context, ILocationManager locationManager) {
         super(context, "GpsMeasurementListenerTransport");
         mLocationManager = locationManager;
     }
@@ -50,11 +50,11 @@
     private class ListenerTransport extends IGpsMeasurementsListener.Stub {
         @Override
         public void onGpsMeasurementsReceived(final GpsMeasurementsEvent event) {
-            ListenerOperation<GpsMeasurementsEvent.Listener> operation =
-                    new ListenerOperation<GpsMeasurementsEvent.Listener>() {
+            ListenerOperation<GpsMeasurementsEvent.Callback> operation =
+                    new ListenerOperation<GpsMeasurementsEvent.Callback>() {
                 @Override
-                public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException {
-                    listener.onGpsMeasurementsReceived(event);
+                public void execute(GpsMeasurementsEvent.Callback callback) throws RemoteException {
+                    callback.onGpsMeasurementsReceived(event);
                 }
             };
             foreach(operation);
@@ -62,11 +62,11 @@
 
         @Override
         public void onStatusChanged(final int status) {
-            ListenerOperation<GpsMeasurementsEvent.Listener> operation =
-                    new ListenerOperation<GpsMeasurementsEvent.Listener>() {
+            ListenerOperation<GpsMeasurementsEvent.Callback> operation =
+                    new ListenerOperation<GpsMeasurementsEvent.Callback>() {
                 @Override
-                public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException {
-                    listener.onStatusChanged(status);
+                public void execute(GpsMeasurementsEvent.Callback callback) throws RemoteException {
+                    callback.onStatusChanged(status);
                 }
             };
             foreach(operation);
diff --git a/location/java/android/location/GpsMeasurementsEvent.java b/location/java/android/location/GpsMeasurementsEvent.java
index 1366873..ef9edeb 100644
--- a/location/java/android/location/GpsMeasurementsEvent.java
+++ b/location/java/android/location/GpsMeasurementsEvent.java
@@ -16,11 +16,13 @@
 
 package android.location;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.security.InvalidParameterException;
 import java.util.Arrays;
 import java.util.Collection;
@@ -28,12 +30,13 @@
 
 /**
  * A class implementing a container for data associated with a measurement event.
- * Events are delivered to registered instances of {@link Listener}.
- *
- * @hide
+ * Events are delivered to registered instances of {@link Callback}.
  */
-@SystemApi
-public class GpsMeasurementsEvent implements Parcelable {
+public final class GpsMeasurementsEvent implements Parcelable {
+    /** The status of GPS measurements event. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+    public @interface GpsMeasurementsStatus {}
 
     /**
      * The system does not support tracking of GPS Measurements. This status will not change in the
@@ -58,22 +61,20 @@
     /**
      * Used for receiving GPS satellite measurements from the GPS engine.
      * Each measurement contains raw and computed data identifying a satellite.
-     * You can implement this interface and call {@link LocationManager#addGpsMeasurementListener}.
-     *
-     * @hide
+     * You can implement this interface and call
+     * {@link LocationManager#registerGpsMeasurementCallback}.
      */
-    @SystemApi
-    public interface Listener {
+    public static abstract class Callback {
 
         /**
          * Returns the latest collected GPS Measurements.
          */
-        void onGpsMeasurementsReceived(GpsMeasurementsEvent eventArgs);
+        public void onGpsMeasurementsReceived(GpsMeasurementsEvent eventArgs) {}
 
         /**
          * Returns the latest status of the GPS Measurements sub-system.
          */
-        void onStatusChanged(int status);
+        public void onStatusChanged(@GpsMeasurementsStatus int status) {}
     }
 
     public GpsMeasurementsEvent(GpsClock clock, GpsMeasurement[] measurements) {
diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
index 5c3c710..d799572 100644
--- a/location/java/android/location/GpsNavigationMessage.java
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -16,49 +16,54 @@
 
 package android.location;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.security.InvalidParameterException;
 
 /**
  * A class containing a GPS satellite Navigation Message.
- *
- * @hide
  */
-@SystemApi
-public class GpsNavigationMessage implements Parcelable {
+public final class GpsNavigationMessage implements Parcelable {
 
     private static final byte[] EMPTY_ARRAY = new byte[0];
 
+    /** The type of the GPS Clock. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({MESSAGE_TYPE_UNKNOWN, MESSAGE_TYPE_L1CA, MESSAGE_TYPE_L2CNAV, MESSAGE_TYPE_L5CNAV,
+            MESSAGE_TYPE_CNAV2})
+    public @interface GpsNavigationMessageType {}
+
     // The following enumerations must be in sync with the values declared in gps.h
 
     /**
      * The type of the navigation message is not available or unknown.
      */
-    public static final byte TYPE_UNKNOWN = 0;
+    public static final byte MESSAGE_TYPE_UNKNOWN = 0;
 
     /**
      * The Navigation Message is of type L1 C/A.
      */
-    public static final byte TYPE_L1CA = 1;
+    public static final byte MESSAGE_TYPE_L1CA = 1;
 
     /**
      * The Navigation Message is of type L1-CNAV.
      */
-    public static final byte TYPE_L2CNAV = 2;
+    public static final byte MESSAGE_TYPE_L2CNAV = 2;
 
     /**
      * The Navigation Message is of type L5-CNAV.
      */
-    public static final byte TYPE_L5CNAV = 3;
+    public static final byte MESSAGE_TYPE_L5CNAV = 3;
 
     /**
      * The Navigation Message is of type CNAV-2.
      */
-    public static final byte TYPE_CNAV2 = 4;
+    public static final byte MESSAGE_TYPE_CNAV2 = 4;
 
     /**
      * The Navigation Message Status is 'unknown'.
@@ -111,6 +116,7 @@
     /**
      * Gets the type of the navigation message contained in the object.
      */
+    @GpsNavigationMessageType
     public byte getType() {
         return mType;
     }
@@ -118,7 +124,7 @@
     /**
      * Sets the type of the navigation message.
      */
-    public void setType(byte value) {
+    public void setType(@GpsNavigationMessageType byte value) {
         mType = value;
     }
 
@@ -128,15 +134,15 @@
      */
     private String getTypeString() {
         switch (mType) {
-            case TYPE_UNKNOWN:
+            case MESSAGE_TYPE_UNKNOWN:
                 return "Unknown";
-            case TYPE_L1CA:
+            case MESSAGE_TYPE_L1CA:
                 return "L1 C/A";
-            case TYPE_L2CNAV:
+            case MESSAGE_TYPE_L2CNAV:
                 return "L2-CNAV";
-            case TYPE_L5CNAV:
+            case MESSAGE_TYPE_L5CNAV:
                 return "L5-CNAV";
-            case TYPE_CNAV2:
+            case MESSAGE_TYPE_CNAV2:
                 return "CNAV-2";
             default:
                 return "<Invalid:" + mType + ">";
@@ -314,7 +320,7 @@
     }
 
     private void initialize() {
-        mType = TYPE_UNKNOWN;
+        mType = MESSAGE_TYPE_UNKNOWN;
         mPrn = 0;
         mMessageId = -1;
         mSubmessageId = -1;
diff --git a/location/java/android/location/GpsNavigationMessageListenerTransport.java b/location/java/android/location/GpsNavigationMessageCallbackTransport.java
similarity index 73%
rename from location/java/android/location/GpsNavigationMessageListenerTransport.java
rename to location/java/android/location/GpsNavigationMessageCallbackTransport.java
index f6ba407..155d96d 100644
--- a/location/java/android/location/GpsNavigationMessageListenerTransport.java
+++ b/location/java/android/location/GpsNavigationMessageCallbackTransport.java
@@ -20,20 +20,20 @@
 import android.os.RemoteException;
 
 /**
- * A handler class to manage transport listeners for {@link GpsNavigationMessageEvent.Listener}.
+ * A handler class to manage transport callback for {@link GpsNavigationMessageEvent.Callback}.
  *
  * @hide
  */
-class GpsNavigationMessageListenerTransport
-        extends LocalListenerHelper<GpsNavigationMessageEvent.Listener> {
+class GpsNavigationMessageCallbackTransport
+        extends LocalListenerHelper<GpsNavigationMessageEvent.Callback> {
     private final ILocationManager mLocationManager;
 
     private final IGpsNavigationMessageListener mListenerTransport = new ListenerTransport();
 
-    public GpsNavigationMessageListenerTransport(
+    public GpsNavigationMessageCallbackTransport(
             Context context,
             ILocationManager locationManager) {
-        super(context, "GpsNavigationMessageListenerTransport");
+        super(context, "GpsNavigationMessageCallbackTransport");
         mLocationManager = locationManager;
     }
 
@@ -52,12 +52,12 @@
     private class ListenerTransport extends IGpsNavigationMessageListener.Stub {
         @Override
         public void onGpsNavigationMessageReceived(final GpsNavigationMessageEvent event) {
-            ListenerOperation<GpsNavigationMessageEvent.Listener> operation =
-                    new ListenerOperation<GpsNavigationMessageEvent.Listener>() {
+            ListenerOperation<GpsNavigationMessageEvent.Callback> operation =
+                    new ListenerOperation<GpsNavigationMessageEvent.Callback>() {
                 @Override
-                public void execute(GpsNavigationMessageEvent.Listener listener)
+                public void execute(GpsNavigationMessageEvent.Callback callback)
                         throws RemoteException {
-                    listener.onGpsNavigationMessageReceived(event);
+                    callback.onGpsNavigationMessageReceived(event);
                 }
             };
             foreach(operation);
@@ -65,12 +65,12 @@
 
         @Override
         public void onStatusChanged(final int status) {
-            ListenerOperation<GpsNavigationMessageEvent.Listener> operation =
-                    new ListenerOperation<GpsNavigationMessageEvent.Listener>() {
+            ListenerOperation<GpsNavigationMessageEvent.Callback> operation =
+                    new ListenerOperation<GpsNavigationMessageEvent.Callback>() {
                 @Override
-                public void execute(GpsNavigationMessageEvent.Listener listener)
+                public void execute(GpsNavigationMessageEvent.Callback callback)
                         throws RemoteException {
-                    listener.onStatusChanged(status);
+                    callback.onStatusChanged(status);
                 }
             };
             foreach(operation);
diff --git a/location/java/android/location/GpsNavigationMessageEvent.java b/location/java/android/location/GpsNavigationMessageEvent.java
index bd6921c..b16a485 100644
--- a/location/java/android/location/GpsNavigationMessageEvent.java
+++ b/location/java/android/location/GpsNavigationMessageEvent.java
@@ -16,60 +16,60 @@
 
 package android.location;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.security.InvalidParameterException;
 
 /**
  * A class implementing a container for data associated with a navigation message event.
- * Events are delivered to registered instances of {@link Listener}.
- *
- * @hide
+ * Events are delivered to registered instances of {@link Callback}.
  */
-@SystemApi
-public class GpsNavigationMessageEvent implements Parcelable {
+public final class GpsNavigationMessageEvent implements Parcelable {
+    /** The status of GPS measurements event. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+    public @interface GpsNavigationMessageStatus {}
 
     /**
      * The system does not support tracking of GPS Navigation Messages. This status will not change
      * in the future.
      */
-    public static int STATUS_NOT_SUPPORTED = 0;
+    public static final int STATUS_NOT_SUPPORTED = 0;
 
     /**
      * GPS Navigation Messages are successfully being tracked, it will receive updates once they are
      * available.
      */
-    public static int STATUS_READY = 1;
+    public static final int STATUS_READY = 1;
 
     /**
      * GPS provider or Location is disabled, updated will not be received until they are enabled.
      */
-    public static int STATUS_GPS_LOCATION_DISABLED = 2;
+    public static final int STATUS_GPS_LOCATION_DISABLED = 2;
 
     private final GpsNavigationMessage mNavigationMessage;
 
     /**
      * Used for receiving GPS satellite Navigation Messages from the GPS engine.
      * You can implement this interface and call
-     * {@link LocationManager#addGpsNavigationMessageListener}.
-     *
-     * @hide
+     * {@link LocationManager#registerGpsNavigationMessageCallback}.
      */
-    @SystemApi
-    public interface Listener {
+    public static abstract class Callback {
 
         /**
          * Returns the latest collected GPS Navigation Message.
          */
-        void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event);
+        public void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event) {}
 
         /**
          * Returns the latest status of the GPS Navigation Messages sub-system.
          */
-        void onStatusChanged(int status);
+        public void onStatusChanged(@GpsNavigationMessageStatus int status) {}
     }
 
     public GpsNavigationMessageEvent(GpsNavigationMessage message) {
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 323f326..8d2f781 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -34,17 +34,15 @@
     private final SparseArray<GpsSatellite> mSatellites = new SparseArray<>();
 
     private final class SatelliteIterator implements Iterator<GpsSatellite> {
-
-        private final SparseArray<GpsSatellite> mSatellites;
         private final int mSatellitesCount;
 
         private int mIndex = 0;
 
-        SatelliteIterator(SparseArray<GpsSatellite> satellites) {
-            mSatellites = satellites;
-            mSatellitesCount = satellites.size();
+        SatelliteIterator() {
+            mSatellitesCount = mSatellites.size();
         }
 
+        @Override
         public boolean hasNext() {
             for (; mIndex < mSatellitesCount; ++mIndex) {
                 GpsSatellite satellite = mSatellites.valueAt(mIndex);
@@ -55,6 +53,7 @@
             return false;
         }
 
+        @Override
         public GpsSatellite next() {
             while (mIndex < mSatellitesCount) {
                 GpsSatellite satellite = mSatellites.valueAt(mIndex);
@@ -66,14 +65,16 @@
             throw new NoSuchElementException();
         }
 
+        @Override
         public void remove() {
             throw new UnsupportedOperationException();
         }
     }
 
     private Iterable<GpsSatellite> mSatelliteList = new Iterable<GpsSatellite>() {
+        @Override
         public Iterator<GpsSatellite> iterator() {
-            return new SatelliteIterator(mSatellites);
+            return new SatelliteIterator();
         }
     };
 
@@ -137,18 +138,15 @@
     // For API-compat a public ctor() is not available
     GpsStatus() {}
 
-    /**
-     * Used internally within {@link LocationManager} to copy GPS status
-     * data from the Location Manager Service to its cached GpsStatus instance.
-     * Is synchronized to ensure that GPS status updates are atomic.
-     */
-    synchronized void setStatus(int svCount, int[] prns, float[] snrs,
-            float[] elevations, float[] azimuths, int ephemerisMask,
-            int almanacMask, int usedInFixMask) {
+    private void setStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations,
+            float[] azimuths, int[] constellationTypes) { 
         clearSatellites();
         for (int i = 0; i < svCount; i++) {
-            int prn = prns[i];
-            int prnShift = (1 << (prn - 1));
+            // Skip all non-GPS satellites.
+            if (constellationTypes[i] != GnssStatus.CONSTELLATION_GPS) {
+                continue;
+            }
+            int prn = prnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH;
             if (prn > 0 && prn <= NUM_SATELLITES) {
                 GpsSatellite satellite = mSatellites.get(prn);
                 if (satellite == null) {
@@ -160,53 +158,26 @@
                 satellite.mSnr = snrs[i];
                 satellite.mElevation = elevations[i];
                 satellite.mAzimuth = azimuths[i];
-                satellite.mHasEphemeris = ((ephemerisMask & prnShift) != 0);
-                satellite.mHasAlmanac = ((almanacMask & prnShift) != 0);
-                satellite.mUsedInFix = ((usedInFixMask & prnShift) != 0);
+                satellite.mHasEphemeris =
+                        (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+                satellite.mHasAlmanac =
+                        (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+                satellite.mUsedInFix =
+                        (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
             }
         }
     }
 
     /**
-     * Used by {@link LocationManager#getGpsStatus} to copy LocationManager's
-     * cached GpsStatus instance to the client's copy.
+     * Copies GPS satellites information from GnssStatus object.
      * Since this method is only used within {@link LocationManager#getGpsStatus},
      * it does not need to be synchronized.
+     * @hide
      */
-    void setStatus(GpsStatus status) {
-        mTimeToFirstFix = status.getTimeToFirstFix();
-        clearSatellites();
-
-        SparseArray<GpsSatellite> otherSatellites = status.mSatellites;
-        int otherSatellitesCount = otherSatellites.size();
-        int satelliteIndex = 0;
-        // merge both sparse arrays, note that we have already invalidated the elements in the
-        // receiver array
-        for (int i = 0; i < otherSatellitesCount; ++i) {
-            GpsSatellite otherSatellite = otherSatellites.valueAt(i);
-            int otherSatellitePrn = otherSatellite.getPrn();
-
-            int satellitesCount = mSatellites.size();
-            while (satelliteIndex < satellitesCount
-                    && mSatellites.valueAt(satelliteIndex).getPrn() < otherSatellitePrn) {
-                ++satelliteIndex;
-            }
-
-            if (satelliteIndex < mSatellites.size()) {
-                GpsSatellite satellite = mSatellites.valueAt(satelliteIndex);
-                if (satellite.getPrn() == otherSatellitePrn) {
-                    satellite.setStatus(otherSatellite);
-                } else {
-                    satellite = new GpsSatellite(otherSatellitePrn);
-                    satellite.setStatus(otherSatellite);
-                    mSatellites.put(otherSatellitePrn, satellite);
-                }
-            } else {
-                GpsSatellite satellite = new GpsSatellite(otherSatellitePrn);
-                satellite.setStatus(otherSatellite);
-                mSatellites.append(otherSatellitePrn, satellite);
-            }
-        }
+    void setStatus(GnssStatus status, int timeToFirstFix) {
+        mTimeToFirstFix = timeToFirstFix;
+        setStatus(status.mSvCount, status.mPrnWithFlags, status.mSnrs, status.mElevations,
+                status.mAzimuths, status.mConstellationTypes);
     }
 
     void setTimeToFirstFix(int ttff) {
diff --git a/location/java/android/location/IGpsStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
similarity index 73%
rename from location/java/android/location/IGpsStatusListener.aidl
rename to location/java/android/location/IGnssStatusListener.aidl
index 62b1c6b..d1c6a85 100644
--- a/location/java/android/location/IGpsStatusListener.aidl
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -21,13 +21,12 @@
 /**
  * {@hide}
  */
-oneway interface IGpsStatusListener
+oneway interface IGnssStatusListener
 {
-    void onGpsStarted();
-    void onGpsStopped();
+    void onGnssStarted();
+    void onGnssStopped();
     void onFirstFix(int ttff);
-    void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs, 
-            in float[] elevations, in float[] azimuths, 
-            int ephemerisMask, int almanacMask, int usedInFixMask);
+    void onSvStatusChanged(int svCount, in int[] prnWithFlags, in float[] snrs,
+            in float[] elevations, in float[] azimuths, in int[] constellationTypes);
     void onNmeaReceived(long timestamp, String nmea);
 }
diff --git a/location/java/android/location/IGpsStatusProvider.aidl b/location/java/android/location/IGnssStatusProvider.aidl
similarity index 70%
rename from location/java/android/location/IGpsStatusProvider.aidl
rename to location/java/android/location/IGnssStatusProvider.aidl
index cf277c8..006b5d3 100644
--- a/location/java/android/location/IGpsStatusProvider.aidl
+++ b/location/java/android/location/IGnssStatusProvider.aidl
@@ -16,14 +16,14 @@
 
 package android.location;
 
-import android.location.IGpsStatusListener;
+import android.location.IGnssStatusListener;
 
 /**
- * An interface for location providers that provide GPS status information.
+ * An interface for location providers that provide GNSS status information.
  *
  * {@hide}
  */
-interface IGpsStatusProvider {
-    void addGpsStatusListener(IGpsStatusListener listener);
-    void removeGpsStatusListener(IGpsStatusListener listener);
+interface IGnssStatusProvider {
+    void registerGnssStatusCallback(IGnssStatusListener callback);
+    void unregisterGnssStatusCallback(IGnssStatusListener callback);
 }
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index f3d755c..49d841f 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -21,9 +21,9 @@
 import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.Geofence;
+import android.location.IGnssStatusListener;
 import android.location.IGpsMeasurementsListener;
 import android.location.IGpsNavigationMessageListener;
-import android.location.IGpsStatusListener;
 import android.location.ILocationListener;
 import android.location.Location;
 import android.location.LocationRequest;
@@ -48,8 +48,8 @@
 
     Location getLastLocation(in LocationRequest request, String packageName);
 
-    boolean addGpsStatusListener(IGpsStatusListener listener, String packageName);
-    void removeGpsStatusListener(IGpsStatusListener listener);
+    boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName);
+    void unregisterGnssStatusCallback(IGnssStatusListener callback);
 
     boolean geocoderIsPresent();
     String getFromLocation(double latitude, double longitude, int maxResults,
@@ -69,6 +69,8 @@
             in String packageName);
     void removeGpsNavigationMessageListener(in IGpsNavigationMessageListener listener);
 
+    int getGpsYearOfHardware();
+
     // --- deprecated ---
     List<String> getAllProviders();
     List<String> getProviders(in Criteria criteria, boolean enabledOnly);
diff --git a/location/java/android/location/LocalListenerHelper.java b/location/java/android/location/LocalListenerHelper.java
index 458c451..d7d2c513 100644
--- a/location/java/android/location/LocalListenerHelper.java
+++ b/location/java/android/location/LocalListenerHelper.java
@@ -20,12 +20,14 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * A base handler class to manage transport and local listeners.
@@ -33,7 +35,7 @@
  * @hide
  */
 abstract class LocalListenerHelper<TListener> {
-    private final HashSet<TListener> mListeners = new HashSet<>();
+    private final HashMap<TListener, Handler> mListeners = new HashMap<>();
 
     private final String mTag;
     private final Context mContext;
@@ -44,7 +46,7 @@
         mTag = name;
     }
 
-    public boolean add(@NonNull TListener listener) {
+    public boolean add(@NonNull TListener listener, Handler handler) {
         Preconditions.checkNotNull(listener);
         synchronized (mListeners) {
             // we need to register with the service first, because we need to find out if the
@@ -62,17 +64,19 @@
                     return false;
                 }
             }
-            if (mListeners.contains(listener)) {
+            if (mListeners.containsKey(listener)) {
                 return true;
             }
-            return mListeners.add(listener);
+            mListeners.put(listener, handler);
+            return true;
         }
     }
 
     public void remove(@NonNull TListener listener) {
         Preconditions.checkNotNull(listener);
         synchronized (mListeners) {
-            boolean removed = mListeners.remove(listener);
+            boolean removed = mListeners.containsKey(listener);
+            mListeners.remove(listener);
             boolean isLastRemoved = removed && mListeners.isEmpty();
             if (isLastRemoved) {
                 try {
@@ -95,17 +99,30 @@
         return mContext;
     }
 
-    protected void foreach(ListenerOperation<TListener> operation) {
-        Collection<TListener> listeners;
-        synchronized (mListeners) {
-            listeners = new ArrayList<>(mListeners);
+    private void executeOperation(ListenerOperation<TListener> operation, TListener listener) {
+        try {
+            operation.execute(listener);
+        } catch (RemoteException e) {
+            Log.e(mTag, "Error in monitored listener.", e);
+            // don't return, give a fair chance to all listeners to receive the event
         }
-        for (TListener listener : listeners) {
-            try {
-                operation.execute(listener);
-            } catch (RemoteException e) {
-                Log.e(mTag, "Error in monitored listener.", e);
-                // don't return, give a fair chance to all listeners to receive the event
+    }
+
+    protected void foreach(final ListenerOperation<TListener> operation) {
+        Collection<Map.Entry<TListener, Handler>> listeners;
+        synchronized (mListeners) {
+            listeners = new ArrayList<>(mListeners.entrySet());
+        }
+        for (final Map.Entry<TListener, Handler> listener : listeners) {
+            if (listener.getValue() == null) {
+                executeOperation(operation, listener.getKey());
+            } else {
+                listener.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        executeOperation(operation, listener.getKey());
+                    }
+                });
             }
         }
     }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 2c19324..5447bb1 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -20,6 +20,7 @@
 
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -63,13 +64,18 @@
 
     private final Context mContext;
     private final ILocationManager mService;
-    private final GpsMeasurementListenerTransport mGpsMeasurementListenerTransport;
-    private final GpsNavigationMessageListenerTransport mGpsNavigationMessageListenerTransport;
-    private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
-            new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
-    private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
-            new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>();
-    private final GpsStatus mGpsStatus = new GpsStatus();
+    private final GpsMeasurementCallbackTransport mGpsMeasurementCallbackTransport;
+    private final GpsNavigationMessageCallbackTransport mGpsNavigationMessageCallbackTransport;
+    private final HashMap<GpsStatus.Listener, GnssStatusListenerTransport> mGpsStatusListeners =
+            new HashMap<>();
+    private final HashMap<GpsStatus.NmeaListener, GnssStatusListenerTransport> mGpsNmeaListeners =
+            new HashMap<>();
+    private final HashMap<GnssStatusCallback, GnssStatusListenerTransport> mGnssStatusListeners =
+            new HashMap<>();
+    private final HashMap<GnssNmeaListener, GnssStatusListenerTransport> mGnssNmeaListeners =
+            new HashMap<>();
+    private GnssStatus mGnssStatus;
+    private int mTimeToFirstFix;
 
     /**
      * Name of the network location provider.
@@ -315,9 +321,9 @@
     public LocationManager(Context context, ILocationManager service) {
         mService = service;
         mContext = context;
-        mGpsMeasurementListenerTransport = new GpsMeasurementListenerTransport(mContext, mService);
-        mGpsNavigationMessageListenerTransport =
-                new GpsNavigationMessageListenerTransport(mContext, mService);
+        mGpsMeasurementCallbackTransport = new GpsMeasurementCallbackTransport(mContext, mService);
+        mGpsNavigationMessageCallbackTransport =
+                new GpsNavigationMessageCallbackTransport(mContext, mService);
     }
 
     private LocationProvider createProvider(String name, ProviderProperties properties) {
@@ -1389,11 +1395,51 @@
 
     // --- GPS-specific support ---
 
-    // This class is used to send GPS status events to the client's main thread.
-    private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
+    // This class is used to send Gnss status events to the client's specific thread.
+    private class GnssStatusListenerTransport extends IGnssStatusListener.Stub {
 
-        private final GpsStatus.Listener mListener;
-        private final GpsStatus.NmeaListener mNmeaListener;
+        private final GpsStatus.Listener mGpsListener;
+        private final GpsStatus.NmeaListener mGpsNmeaListener;
+        private final GnssStatusCallback mGnssCallback;
+        private final GnssNmeaListener mGnssNmeaListener;
+
+        private class GnssHandler extends Handler {
+            public GnssHandler(Handler handler) {
+                super(handler != null ? handler.getLooper() : Looper.myLooper());
+            }
+
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case NMEA_RECEIVED:
+                        synchronized (mNmeaBuffer) {
+                            int length = mNmeaBuffer.size();
+                            for (int i = 0; i < length; i++) {
+                                Nmea nmea = mNmeaBuffer.get(i);
+                                mGnssNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
+                            }
+                            mNmeaBuffer.clear();
+                        }
+                        break;
+                    case GpsStatus.GPS_EVENT_STARTED:
+                        mGnssCallback.onStarted();
+                        break;
+                    case GpsStatus.GPS_EVENT_STOPPED:
+                        mGnssCallback.onStopped();
+                        break;
+                    case GpsStatus.GPS_EVENT_FIRST_FIX:
+                        mGnssCallback.onFirstFix(mTimeToFirstFix);
+                        break;
+                    case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
+                        mGnssCallback.onSatelliteStatusChanged(mGnssStatus);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        private final Handler mGnssHandler;
 
         // This must not equal any of the GpsStatus event IDs
         private static final int NMEA_RECEIVED = 1000;
@@ -1407,97 +1453,141 @@
                 mNmea = nmea;
             }
         }
-        private ArrayList<Nmea> mNmeaBuffer;
+        private final ArrayList<Nmea> mNmeaBuffer;
 
-        GpsStatusListenerTransport(GpsStatus.Listener listener) {
-            mListener = listener;
-            mNmeaListener = null;
+        GnssStatusListenerTransport(GpsStatus.Listener listener) {
+            this(listener, null);
         }
 
-        GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
-            mNmeaListener = listener;
-            mListener = null;
+        GnssStatusListenerTransport(GpsStatus.Listener listener, Handler handler) {
+            mGpsListener = listener;
+            mGnssHandler = new GnssHandler(handler);
+            mGpsNmeaListener = null;
+            mNmeaBuffer = null;
+            mGnssCallback = new GnssStatusCallback() {
+                @Override
+                public void onStarted() {
+                    mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STARTED);
+                }
+
+                @Override
+                public void onStopped() {
+                    mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STOPPED);
+                }
+
+                @Override
+                public void onFirstFix(int ttff) {
+                    mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_FIRST_FIX);
+                }
+
+                @Override
+                public void onSatelliteStatusChanged(GnssStatus status) {
+                    mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
+                }
+            };
+            mGnssNmeaListener = null;
+        }
+
+        GnssStatusListenerTransport(GpsStatus.NmeaListener listener) {
+            this(listener, null);
+        }
+
+        GnssStatusListenerTransport(GpsStatus.NmeaListener listener, Handler handler) {
+            mGpsListener = null;
+            mGnssHandler = new GnssHandler(handler);
+            mGpsNmeaListener = listener;
+            mNmeaBuffer = new ArrayList<Nmea>();
+            mGnssCallback = null;
+            mGnssNmeaListener = new GnssNmeaListener() {
+                @Override
+                public void onNmeaReceived(long timestamp, String nmea) {
+                    mGpsNmeaListener.onNmeaReceived(timestamp, nmea);
+                }
+            };
+        }
+
+        GnssStatusListenerTransport(GnssStatusCallback callback) {
+            this(callback, null);
+        }
+
+        GnssStatusListenerTransport(GnssStatusCallback callback, Handler handler) {
+            mGnssCallback = callback;
+            mGnssHandler = new GnssHandler(handler);
+            mGnssNmeaListener = null;
+            mNmeaBuffer = null;
+            mGpsListener = null;
+            mGpsNmeaListener = null;
+        }
+
+        GnssStatusListenerTransport(GnssNmeaListener listener) {
+            this(listener, null);
+        }
+
+        GnssStatusListenerTransport(GnssNmeaListener listener, Handler handler) {
+            mGnssCallback = null;
+            mGnssHandler = new GnssHandler(handler);
+            mGnssNmeaListener = listener;
+            mGpsListener = null;
+            mGpsNmeaListener = null;
             mNmeaBuffer = new ArrayList<Nmea>();
         }
 
         @Override
-        public void onGpsStarted() {
-            if (mListener != null) {
+        public void onGnssStarted() {
+            if (mGpsListener != null) {
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_STARTED;
-                mGpsHandler.sendMessage(msg);
+                mGnssHandler.sendMessage(msg);
             }
         }
 
         @Override
-        public void onGpsStopped() {
-            if (mListener != null) {
+        public void onGnssStopped() {
+            if (mGpsListener != null) {
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_STOPPED;
-                mGpsHandler.sendMessage(msg);
+                mGnssHandler.sendMessage(msg);
             }
         }
 
         @Override
         public void onFirstFix(int ttff) {
-            if (mListener != null) {
-                mGpsStatus.setTimeToFirstFix(ttff);
+            if (mGpsListener != null) {
+                mTimeToFirstFix = ttff;
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
-                mGpsHandler.sendMessage(msg);
+                mGnssHandler.sendMessage(msg);
             }
         }
 
         @Override
-        public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
-                float[] elevations, float[] azimuths, int ephemerisMask,
-                int almanacMask, int usedInFixMask) {
-            if (mListener != null) {
-                mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
-                        ephemerisMask, almanacMask, usedInFixMask);
+        public void onSvStatusChanged(int svCount, int[] prnWithFlags,
+                float[] snrs, float[] elevations, float[] azimuths, int[] constellationTypes) {
+            if (mGnssCallback != null) {
+                mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths,
+                        constellationTypes);
 
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
                 // remove any SV status messages already in the queue
-                mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
-                mGpsHandler.sendMessage(msg);
+                mGnssHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
+                mGnssHandler.sendMessage(msg);
             }
         }
 
         @Override
         public void onNmeaReceived(long timestamp, String nmea) {
-            if (mNmeaListener != null) {
+            if (mGnssNmeaListener != null) {
                 synchronized (mNmeaBuffer) {
                     mNmeaBuffer.add(new Nmea(timestamp, nmea));
                 }
                 Message msg = Message.obtain();
                 msg.what = NMEA_RECEIVED;
                 // remove any NMEA_RECEIVED messages already in the queue
-                mGpsHandler.removeMessages(NMEA_RECEIVED);
-                mGpsHandler.sendMessage(msg);
+                mGnssHandler.removeMessages(NMEA_RECEIVED);
+                mGnssHandler.sendMessage(msg);
             }
         }
-
-        private final Handler mGpsHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                if (msg.what == NMEA_RECEIVED) {
-                    synchronized (mNmeaBuffer) {
-                        int length = mNmeaBuffer.size();
-                        for (int i = 0; i < length; i++) {
-                            Nmea nmea = mNmeaBuffer.get(i);
-                            mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
-                        }
-                        mNmeaBuffer.clear();
-                    }
-                } else {
-                    // synchronize on mGpsStatus to ensure the data is copied atomically.
-                    synchronized(mGpsStatus) {
-                        mListener.onGpsStatusChanged(msg.what);
-                    }
-                }
-            }
-        };
     }
 
     /**
@@ -1508,7 +1598,9 @@
      * @return true if the listener was successfully added
      *
      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     * @deprecated use {@link #registerGnssStatusCallback(GnssStatusCallback)} instead.
      */
+    @Deprecated
     @RequiresPermission(ACCESS_FINE_LOCATION)
     public boolean addGpsStatusListener(GpsStatus.Listener listener) {
         boolean result;
@@ -1518,8 +1610,8 @@
             return true;
         }
         try {
-            GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
-            result = mService.addGpsStatusListener(transport, mContext.getPackageName());
+            GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener);
+            result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
             if (result) {
                 mGpsStatusListeners.put(listener, transport);
             }
@@ -1536,17 +1628,81 @@
      *
      * @param listener GPS status listener object to remove
      */
+    @Deprecated
     public void removeGpsStatusListener(GpsStatus.Listener listener) {
         try {
-            GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
+            GnssStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
             if (transport != null) {
-                mService.removeGpsStatusListener(transport);
+                mService.unregisterGnssStatusCallback(transport);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
         }
     }
 
+
+    /**
+     * Registers a GNSS status listener.
+     *
+     * @param callback GNSS status listener object to register
+     *
+     * @return true if the listener was successfully added
+     *
+     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     */
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGnssStatusCallback(GnssStatusCallback callback) {
+        return registerGnssStatusCallback(callback, null);
+    }
+
+    /**
+     * Registers a GNSS status listener.
+     *
+     * @param callback GNSS status listener object to register
+     * @param handler the handler that the callback runs on.
+     *
+     * @return true if the listener was successfully added
+     *
+     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     */
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGnssStatusCallback(GnssStatusCallback callback, Handler handler) {
+        boolean result;
+        if (mGnssStatusListeners.get(callback) != null) {
+            // listener is already registered
+            return true;
+        }
+        try {
+            GnssStatusListenerTransport transport =
+                    new GnssStatusListenerTransport(callback, handler);
+            result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
+            if (result) {
+                mGnssStatusListeners.put(callback, transport);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in registerGnssStatusCallback: ", e);
+            result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * Removes a GNSS status listener.
+     *
+     * @param callback GNSS status listener object to remove
+     */
+    public void unregisterGnssStatusCallback(GnssStatusCallback callback) {
+        try {
+            GnssStatusListenerTransport transport = mGnssStatusListeners.remove(callback);
+            if (transport != null) {
+                mService.unregisterGnssStatusCallback(transport);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in unregisterGnssStatusCallback: ", e);
+        }
+    }
+
     /**
      * Adds an NMEA listener.
      *
@@ -1555,20 +1711,22 @@
      * @return true if the listener was successfully added
      *
      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     * @deprecated use {@link #addNmeaListener(GnssNmeaListener)} instead.
      */
+    @Deprecated
     @RequiresPermission(ACCESS_FINE_LOCATION)
     public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
         boolean result;
 
-        if (mNmeaListeners.get(listener) != null) {
+        if (mGpsNmeaListeners.get(listener) != null) {
             // listener is already registered
             return true;
         }
         try {
-            GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
-            result = mService.addGpsStatusListener(transport, mContext.getPackageName());
+            GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener);
+            result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
             if (result) {
-                mNmeaListeners.put(listener, transport);
+                mGpsNmeaListeners.put(listener, transport);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
@@ -1583,11 +1741,12 @@
      *
      * @param listener a {@link GpsStatus.NmeaListener} object to remove
      */
+    @Deprecated
     public void removeNmeaListener(GpsStatus.NmeaListener listener) {
         try {
-            GpsStatusListenerTransport transport = mNmeaListeners.remove(listener);
+            GnssStatusListenerTransport transport = mGpsNmeaListeners.remove(listener);
             if (transport != null) {
-                mService.removeGpsStatusListener(transport);
+                mService.unregisterGnssStatusCallback(transport);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
@@ -1595,54 +1754,133 @@
     }
 
     /**
-     * Adds a GPS Measurement listener.
+     * Adds an NMEA listener.
      *
-     * @param listener a {@link GpsMeasurementsEvent.Listener} object to register.
-     * @return {@code true} if the listener was added successfully, {@code false} otherwise.
+     * @param listener a {@link GnssNmeaListener} object to register
      *
-     * @hide
+     * @return true if the listener was successfully added
+     *
+     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
      */
-    @SystemApi
-    public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
-        return mGpsMeasurementListenerTransport.add(listener);
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean addNmeaListener(GnssNmeaListener listener) {
+        return addNmeaListener(listener, null);
     }
 
     /**
-     * Removes a GPS Measurement listener.
+     * Adds an NMEA listener.
      *
-     * @param listener a {@link GpsMeasurementsEvent.Listener} object to remove.
+     * @param listener a {@link GnssNmeaListener} object to register
+     * @param handler the handler that the listener runs on.
      *
-     * @hide
+     * @return true if the listener was successfully added
+     *
+     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
      */
-    @SystemApi
-    public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
-        mGpsMeasurementListenerTransport.remove(listener);
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean addNmeaListener(GnssNmeaListener listener, Handler handler) {
+        boolean result;
+
+        if (mGpsNmeaListeners.get(listener) != null) {
+            // listener is already registered
+            return true;
+        }
+        try {
+            GnssStatusListenerTransport transport =
+                    new GnssStatusListenerTransport(listener, handler);
+            result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
+            if (result) {
+                mGnssNmeaListeners.put(listener, transport);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in registerGnssStatusCallback: ", e);
+            result = false;
+        }
+
+        return result;
     }
 
     /**
-     * Adds a GPS Navigation Message listener.
+     * Removes an NMEA listener.
      *
-     * @param listener a {@link GpsNavigationMessageEvent.Listener} object to register.
-     * @return {@code true} if the listener was added successfully, {@code false} otherwise.
-     *
-     * @hide
+     * @param listener a {@link GnssNmeaListener} object to remove
      */
-    @SystemApi
-    public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
-        return mGpsNavigationMessageListenerTransport.add(listener);
+    public void removeNmeaListener(GnssNmeaListener listener) {
+        try {
+            GnssStatusListenerTransport transport = mGnssNmeaListeners.remove(listener);
+            if (transport != null) {
+                mService.unregisterGnssStatusCallback(transport);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in unregisterGnssStatusCallback: ", e);
+        }
     }
 
     /**
-     * Removes a GPS Navigation Message listener.
+     * Registers a GPS Measurement callback.
      *
-     * @param listener a {@link GpsNavigationMessageEvent.Listener} object to remove.
-     *
-     * @hide
+     * @param callback a {@link GpsMeasurementsEvent.Callback} object to register.
+     * @return {@code true} if the callback was added successfully, {@code false} otherwise.
      */
-    @SystemApi
-    public void removeGpsNavigationMessageListener(
-            GpsNavigationMessageEvent.Listener listener) {
-        mGpsNavigationMessageListenerTransport.remove(listener);
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGpsMeasurementCallback(GpsMeasurementsEvent.Callback callback) {
+        return registerGpsMeasurementCallback(callback, null);
+    }
+
+    /**
+     * Registers a GPS Measurement callback.
+     *
+     * @param callback a {@link GpsMeasurementsEvent.Callback} object to register.
+     * @param handler the handler that the callback runs on.
+     * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+     */
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGpsMeasurementCallback(GpsMeasurementsEvent.Callback callback,
+            Handler handler) {
+        return mGpsMeasurementCallbackTransport.add(callback, handler);
+    }
+
+    /**
+     * Unregisters a GPS Measurement callback.
+     *
+     * @param callback a {@link GpsMeasurementsEvent.Callback} object to remove.
+     */
+    public void unregisterGpsMeasurementCallback(GpsMeasurementsEvent.Callback callback) {
+        mGpsMeasurementCallbackTransport.remove(callback);
+    }
+
+    /**
+     * Registers a GPS Navigation Message callback.
+     *
+     * @param callback a {@link GpsNavigationMessageEvent.Callback} object to register.
+     * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+     */
+    public boolean registerGpsNavigationMessageCallback(
+            GpsNavigationMessageEvent.Callback callback) {
+        return registerGpsNavigationMessageCallback(callback, null);
+    }
+
+    /**
+     * Registers a GPS Navigation Message callback.
+     *
+     * @param callback a {@link GpsNavigationMessageEvent.Callback} object to register.
+     * @param handler the handler that the callback runs on.
+     * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+     */
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGpsNavigationMessageCallback(
+            GpsNavigationMessageEvent.Callback callback, Handler handler) {
+        return mGpsNavigationMessageCallbackTransport.add(callback, handler);
+    }
+
+    /**
+     * Unregisters a GPS Navigation Message callback.
+     *
+     * @param callback a {@link GpsNavigationMessageEvent.Callback} object to remove.
+     */
+    public void unregisterGpsNavigationMessageCallback(
+            GpsNavigationMessageEvent.Callback callback) {
+        mGpsNavigationMessageCallbackTransport.remove(callback);
     }
 
      /**
@@ -1656,15 +1894,36 @@
      * @param status object containing GPS status details, or null.
      * @return status object containing updated GPS status.
      */
+    @Deprecated
+    @RequiresPermission(ACCESS_FINE_LOCATION)
     public GpsStatus getGpsStatus(GpsStatus status) {
         if (status == null) {
             status = new GpsStatus();
         }
-        status.setStatus(mGpsStatus);
+        // When mGnssStatus is null, that means that this method is called outside
+        // onGpsStatusChanged().  Return an empty status  to maintain backwards compatibility.
+        if (mGnssStatus != null) {
+            status.setStatus(mGnssStatus, mTimeToFirstFix);
+        }
         return status;
     }
 
     /**
+     * Returns the system information of the GPS hardware.
+     * May return 0 if GPS hardware is earlier than 2016.
+     * @hide
+     */
+    @TestApi
+    public int getGpsYearOfHardware() {
+        try {
+            return mService.getGpsYearOfHardware();
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in getGpsSystemInfo: ", e);
+            return 0;
+        }
+    }
+
+    /**
      * Sends additional commands to a location provider.
      * Can be used to support provider specific extensions to the Location Manager API
      *
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 260f380..93e86af 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -62,7 +62,7 @@
     public static final String NI_INTENT_KEY_TIMEOUT = "timeout";
     public static final String NI_INTENT_KEY_DEFAULT_RESPONSE = "default_resp";
 
-    // the extra command to send NI response to GpsLocationProvider
+    // the extra command to send NI response to GnssLocationProvider
     public static final String NI_RESPONSE_EXTRA_CMD = "send_ni_response";
 
     // the extra command parameter names in the Bundle
diff --git a/media/java/android/media/AudioRecordConfiguration.java b/media/java/android/media/AudioRecordConfiguration.java
index c7d219d..69df88f 100644
--- a/media/java/android/media/AudioRecordConfiguration.java
+++ b/media/java/android/media/AudioRecordConfiguration.java
@@ -23,7 +23,7 @@
 
 /**
  * The AudioRecordConfiguration class collects the information describing an audio recording
- * session. This information is returned through the 
+ * session. This information is returned through the
  * {@link AudioManager#getActiveRecordConfigurations()} method.
  *
  */
@@ -33,12 +33,32 @@
 
     private final int mClientSource;
 
+    private final AudioFormat mDeviceFormat;
+    private final AudioFormat mClientFormat;
+
+    private final AudioDeviceInfo mRecDevice;
+
     /**
      * @hide
      */
     public AudioRecordConfiguration(int session, int source) {
         mSessionId = session;
         mClientSource = source;
+        mDeviceFormat = new AudioFormat.Builder().build();
+        mClientFormat = new AudioFormat.Builder().build();
+        mRecDevice = null;
+    }
+
+    /**
+     * @hide
+     */
+    public AudioRecordConfiguration(int session, int source, AudioFormat devFormat,
+            AudioFormat clientFormat, AudioDeviceInfo device) {
+        mSessionId = session;
+        mClientSource = source;
+        mDeviceFormat = devFormat;
+        mClientFormat = clientFormat;
+        mRecDevice = device;
     }
 
     /**
@@ -57,7 +77,28 @@
      * Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}.
      * @return the session number.
      */
-    public int getAudioSessionId() { return mSessionId; }
+    public int getClientAudioSessionId() { return mSessionId; }
+
+    /**
+     * Returns the audio format at which audio is recorded on this Android device.
+     * Note that it may differ from the client application recording format
+     * (see {@link #getClientFormat()}).
+     * @return the device recording format
+     */
+    public AudioFormat getFormat() { return mDeviceFormat; }
+
+    /**
+     * Returns the audio format at which the client application is recording audio.
+     * Note that it may differ from the actual recording format (see {@link #getFormat()}).
+     * @return the recording format
+     */
+    public AudioFormat getClientFormat() { return mClientFormat; }
+
+    /**
+     * Returns the audio input device used for this recording.
+     * @return the audio recording device
+     */
+    public AudioDeviceInfo getAudioDevice() { return mRecDevice; }
 
     public static final Parcelable.Creator<AudioRecordConfiguration> CREATOR
             = new Parcelable.Creator<AudioRecordConfiguration>() {
@@ -93,6 +134,9 @@
     private AudioRecordConfiguration(Parcel in) {
         mSessionId = in.readInt();
         mClientSource = in.readInt();
+        mDeviceFormat = new AudioFormat.Builder().build();
+        mClientFormat = new AudioFormat.Builder().build();
+        mRecDevice = null;
     }
 
     @Override
diff --git a/media/java/android/media/DrmInitData.java b/media/java/android/media/DrmInitData.java
new file mode 100644
index 0000000..06fe6ff
--- /dev/null
+++ b/media/java/android/media/DrmInitData.java
@@ -0,0 +1,83 @@
+/*
+ * 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 android.media;
+
+import android.media.MediaDrm;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Encapsulates initialization data required by a {@link MediaDrm} instance.
+ */
+public abstract class DrmInitData {
+
+    /**
+     * Retrieves initialization data for a given DRM scheme, specified by its UUID.
+     *
+     * @param schemeUuid The DRM scheme's UUID.
+     * @return The initialization data for the scheme, or null if the scheme is not supported.
+     */
+    public abstract SchemeInitData get(UUID schemeUuid);
+
+    /**
+     * Scheme initialization data.
+     */
+    public static final class SchemeInitData {
+
+        /**
+         * The mimeType of {@link #data}.
+         */
+        public final String mimeType;
+        /**
+         * The initialization data.
+         */
+        public final byte[] data;
+
+        /**
+         * @param mimeType The mimeType of the initialization data.
+         * @param data The initialization data.
+         *
+         * @hide
+         */
+        public SchemeInitData(String mimeType, byte[] data) {
+            this.mimeType = mimeType;
+            this.data = data;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof SchemeInitData)) {
+                return false;
+            }
+            if (obj == this) {
+                return true;
+            }
+
+            SchemeInitData other = (SchemeInitData) obj;
+            return mimeType.equals(other.mimeType) && Arrays.equals(data, other.data);
+        }
+
+        @Override
+        public int hashCode() {
+            return mimeType.hashCode() + 31 * Arrays.hashCode(data);
+        }
+
+    }
+
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 0bf995f..b339925 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -34,7 +34,9 @@
 import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -226,6 +228,46 @@
     public native final int getTrackCount();
 
     /**
+     * Extract DRM initialization data if it exists
+     *
+     * @return DRM initialization data in the content, or {@code null}
+     * if no recognizable DRM format is found;
+     * @see DrmInitData
+     */
+    public DrmInitData getDrmInitData() {
+        Map<String, Object> formatMap = getFileFormatNative();
+        if (formatMap == null) {
+            return null;
+        }
+        if (formatMap.containsKey("pssh")) {
+            Map<UUID, byte[]> psshMap = getPsshInfo();
+            final Map<UUID, DrmInitData.SchemeInitData> initDataMap =
+                new HashMap<UUID, DrmInitData.SchemeInitData>();
+            for (Map.Entry<UUID, byte[]> e: psshMap.entrySet()) {
+                UUID uuid = e.getKey();
+                byte[] data = e.getValue();
+                initDataMap.put(uuid, new DrmInitData.SchemeInitData("cenc", data));
+            }
+            return new DrmInitData() {
+                public SchemeInitData get(UUID schemeUuid) {
+                    return initDataMap.get(schemeUuid);
+                }
+            };
+        } else if (formatMap.containsKey("crypto-key")) {
+            ByteBuffer buf = (ByteBuffer) formatMap.get("crypto-key");
+            buf.rewind();
+            final byte[] data = new byte[buf.remaining()];
+            buf.get(data);
+            return new DrmInitData() {
+                public SchemeInitData get(UUID schemeUuid) {
+                    return new DrmInitData.SchemeInitData("webm", data);
+                }
+            };
+        }
+        return null;
+    }
+
+    /**
      * Get the PSSH info if present.
      * @return a map of uuid-to-bytes, with the uuid specifying
      * the crypto scheme, and the bytes being the data specific to that scheme.
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 02b03d2..b9fcba2 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemApi;
 import android.media.AudioAttributes;
 import android.os.Parcel;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -48,14 +49,27 @@
 
     /**
      * A rule requiring the usage information of the {@link AudioAttributes} to match.
+     * This mixing rule can be added with {@link Builder#addRule(AudioAttributes, int)} or
+     * {@link Builder#addMixRule(int, Object)} where the Object parameter is an instance of
+     * {@link AudioAttributes}.
      */
     @SystemApi
     public static final int RULE_MATCH_ATTRIBUTE_USAGE = 0x1;
     /**
      * A rule requiring the capture preset information of the {@link AudioAttributes} to match.
+     * This mixing rule can be added with {@link Builder#addRule(AudioAttributes, int)} or
+     * {@link Builder#addMixRule(int, Object)} where the Object parameter is an instance of
+     * {@link AudioAttributes}.
      */
     @SystemApi
     public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 0x1 << 1;
+    /**
+     * A rule requiring the UID of the audio stream to match that specified.
+     * This mixing rule can be added with {@link Builder#addMixRule(int, Object)} where the Object
+     * parameter is an instance of {@link java.lang.Integer}.
+     */
+    @SystemApi
+    public static final int RULE_MATCH_UID = 0x1 << 2;
 
     private final static int RULE_EXCLUSION_MASK = 0x8000;
     /**
@@ -70,29 +84,53 @@
      */
     public static final int RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET =
             RULE_EXCLUSION_MASK | RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET;
+    /**
+     * @hide
+     * A rule requiring the UID information to differ.
+     */
+    public static final int RULE_EXCLUDE_UID =
+            RULE_EXCLUSION_MASK | RULE_MATCH_UID;
 
     static final class AttributeMatchCriterion {
-        AudioAttributes mAttr;
-        int mRule;
+        final AudioAttributes mAttr;
+        final Integer mIntProp;
+        final int mRule;
 
         /** input parameters must be valid */
         AttributeMatchCriterion(AudioAttributes attributes, int rule) {
             mAttr = attributes;
+            mIntProp = null;
+            mRule = rule;
+        }
+        /** input parameters must be valid */
+        AttributeMatchCriterion(Integer intProp, int rule) {
+            mAttr = null;
+            mIntProp = intProp;
             mRule = rule;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(mAttr, mRule);
+            return Objects.hash(mAttr, mIntProp, mRule);
         }
 
         void writeToParcel(Parcel dest) {
             dest.writeInt(mRule);
-            if ((mRule == RULE_MATCH_ATTRIBUTE_USAGE) || (mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
+            final int match_rule = mRule & ~RULE_EXCLUSION_MASK;
+            switch (match_rule) {
+            case RULE_MATCH_ATTRIBUTE_USAGE:
                 dest.writeInt(mAttr.getUsage());
-            } else {
-                // capture preset rule
+                break;
+            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
                 dest.writeInt(mAttr.getCapturePreset());
+                break;
+            case RULE_MATCH_UID:
+                dest.writeInt(mIntProp.intValue());
+                break;
+            default:
+                Log.e("AttributeMatchCriterion", "Unknown match rule" + match_rule
+                        + " when writing to Parcel");
+                dest.writeInt(-1);
             }
         }
     }
@@ -111,18 +149,31 @@
         switch(rule) {
             case RULE_MATCH_ATTRIBUTE_USAGE:
             case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+            case RULE_MATCH_UID:
                 return true;
             default:
                 return false;
         }
     }
 
-    private static boolean isValidIntRule(int rule) {
+    private static boolean isValidAttributesSystemApiRule(int rule) {
+        switch(rule) {
+            case RULE_MATCH_ATTRIBUTE_USAGE:
+            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private static boolean isValidRule(int rule) {
         switch(rule) {
             case RULE_MATCH_ATTRIBUTE_USAGE:
             case RULE_EXCLUDE_ATTRIBUTE_USAGE:
             case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
             case RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET:
+            case RULE_MATCH_UID:
+            case RULE_EXCLUDE_UID:
                 return true;
             default:
                 return false;
@@ -130,8 +181,24 @@
     }
 
     private static boolean isPlayerRule(int rule) {
-        return ((rule == RULE_MATCH_ATTRIBUTE_USAGE)
-                || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE));
+        final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+        switch (match_rule) {
+        case RULE_MATCH_ATTRIBUTE_USAGE:
+        case RULE_MATCH_UID:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    private static boolean isAudioAttributeRule(int match_rule) {
+        switch(match_rule) {
+            case RULE_MATCH_ATTRIBUTE_USAGE:
+            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+                return true;
+            default:
+                return false;
+        }
     }
 
     /**
@@ -158,14 +225,15 @@
          *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}.
          * @return the same Builder instance.
          * @throws IllegalArgumentException
+         * @see {@link #excludeRule(AudioAttributes, int)}
          */
         @SystemApi
         public Builder addRule(AudioAttributes attrToMatch, int rule)
                 throws IllegalArgumentException {
-            if (!isValidSystemApiRule(rule)) {
+            if (!isValidAttributesSystemApiRule(rule)) {
                 throw new IllegalArgumentException("Illegal rule value " + rule);
             }
-            return addRuleInt(attrToMatch, rule);
+            return checkAddRuleObjInternal(rule, attrToMatch);
         }
 
         /**
@@ -186,33 +254,82 @@
          *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}.
          * @return the same Builder instance.
          * @throws IllegalArgumentException
+         * @see {@link #addRule(AudioAttributes, int)}
          */
         @SystemApi
         public Builder excludeRule(AudioAttributes attrToMatch, int rule)
                 throws IllegalArgumentException {
+            if (!isValidAttributesSystemApiRule(rule)) {
+                throw new IllegalArgumentException("Illegal rule value " + rule);
+            }
+            return checkAddRuleObjInternal(rule | RULE_EXCLUSION_MASK, attrToMatch);
+        }
+
+        /**
+         * Add a rule for the selection of which streams are mixed together.
+         * The rule defines what the matching will be made on. It also determines the type of the
+         * property to match against.
+         * @param rule one of {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
+         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
+         *     {@link AudioMixingRule#RULE_MATCH_UID}.
+         * @param property see the definition of each rule for the type to use (either an
+         *     {@link AudioAttributes} or an {@link java.lang.Integer}).
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         * @see {@link #excludeMixRule(int, Object)}
+         */
+        @SystemApi
+        public Builder addMixRule(int rule, Object property) throws IllegalArgumentException {
             if (!isValidSystemApiRule(rule)) {
                 throw new IllegalArgumentException("Illegal rule value " + rule);
             }
-            return addRuleInt(attrToMatch, rule | RULE_EXCLUSION_MASK);
+            return checkAddRuleObjInternal(rule, property);
+        }
+
+        /**
+         * Add a rule by exclusion for the selection of which streams are mixed together.
+         * <br>For instance the following code
+         * <br><pre>
+         * AudioAttributes mediaAttr = new AudioAttributes.Builder()
+         *         .setUsage(AudioAttributes.USAGE_MEDIA)
+         *         .build();
+         * AudioMixingRule noMediaRule = new AudioMixingRule.Builder()
+         *         .addMixRule(AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE, mediaAttr)
+         *         .excludeMixRule(AudioMixingRule.RULE_MATCH_UID, new Integer(uidToExclude)
+         *         .build();
+         * </pre>
+         * <br>will create a rule which maps to usage USAGE_MEDIA, but excludes any stream
+         * coming from the specified UID.
+         * @param rule one of {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
+         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
+         *     {@link AudioMixingRule#RULE_MATCH_UID}.
+         * @param property see the definition of each rule for the type to use (either an
+         *     {@link AudioAttributes} or an {@link java.lang.Integer}).
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         */
+        @SystemApi
+        public Builder excludeMixRule(int rule, Object property) throws IllegalArgumentException {
+            if (!isValidSystemApiRule(rule)) {
+                throw new IllegalArgumentException("Illegal rule value " + rule);
+            }
+            return checkAddRuleObjInternal(rule | RULE_EXCLUSION_MASK, property);
         }
 
         /**
          * Add or exclude a rule for the selection of which streams are mixed together.
-         * @param attrToMatch a non-null AudioAttributes instance for which a contradictory
-         *     rule hasn't been set yet.
-         * @param rule one of {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_USAGE},
-         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
-         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
-         *     {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET}.
+         * Does error checking on the parameters.
+         * @param rule
+         * @param property
          * @return the same Builder instance.
          * @throws IllegalArgumentException
          */
-        Builder addRuleInt(AudioAttributes attrToMatch, int rule)
+        private Builder checkAddRuleObjInternal(int rule, Object property)
                 throws IllegalArgumentException {
-            if (attrToMatch == null) {
-                throw new IllegalArgumentException("Illegal null AudioAttributes argument");
+            if (property == null) {
+                throw new IllegalArgumentException("Illegal null Object argument");
             }
-            if (!isValidIntRule(rule)) {
+            if (!isValidRule(rule)) {
                 throw new IllegalArgumentException("Illegal rule value " + rule);
             } else {
                 // as rules are added to the Builder, we verify they are consistent with the type
@@ -229,36 +346,87 @@
                     throw new IllegalArgumentException("Incompatible rule for mix");
                 }
             }
+            final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+            if (isAudioAttributeRule(match_rule)) {
+                if (!(property instanceof AudioAttributes)) {
+                    throw new IllegalArgumentException("Invalid AudioAttributes argument");
+                }
+                return addRuleInternal((AudioAttributes) property, null, rule);
+            } else {
+                // implies integer match rule
+                if (!(property instanceof Integer)) {
+                    throw new IllegalArgumentException("Invalid Integer argument");
+                }
+                return addRuleInternal(null, (Integer) property, rule);
+            }
+        }
+
+        /**
+         * Add or exclude a rule on AudioAttributes or integer property for the selection of which
+         * streams are mixed together.
+         * No rule-to-parameter type check, all done in {@link #checkAddRuleObjInternal(int, Object)}.
+         * Exceptions are thrown only when incompatible rules are added.
+         * @param attrToMatch a non-null AudioAttributes instance for which a contradictory
+         *     rule hasn't been set yet, null if not used.
+         * @param intProp an integer property to match or exclude, null if not used.
+         * @param rule one of {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_USAGE},
+         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
+         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
+         *     {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET},
+         *     {@link AudioMixingRule#RULE_MATCH_UID}, {@link AudioMixingRule#RULE_EXCLUDE_UID}.
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         */
+        private Builder addRuleInternal(AudioAttributes attrToMatch, Integer intProp, int rule)
+                throws IllegalArgumentException {
             synchronized (mCriteria) {
                 Iterator<AttributeMatchCriterion> crIterator = mCriteria.iterator();
+                final int match_rule = rule & ~RULE_EXCLUSION_MASK;
                 while (crIterator.hasNext()) {
                     final AttributeMatchCriterion criterion = crIterator.next();
-                    if ((rule == RULE_MATCH_ATTRIBUTE_USAGE)
-                            || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
-                        // "usage"-based rule
-                        if (criterion.mAttr.getUsage() == attrToMatch.getUsage()) {
-                            if (criterion.mRule == rule) {
-                                // rule already exists, we're done
-                                return this;
-                            } else {
-                                // criterion already exists with a another rule, it is incompatible
-                                throw new IllegalArgumentException("Contradictory rule exists for "
-                                        + attrToMatch);
+                    switch (match_rule) {
+                        case RULE_MATCH_ATTRIBUTE_USAGE:
+                            // "usage"-based rule
+                            if (criterion.mAttr.getUsage() == attrToMatch.getUsage()) {
+                                if (criterion.mRule == rule) {
+                                    // rule already exists, we're done
+                                    return this;
+                                } else {
+                                    // criterion already exists with a another rule,
+                                    // it is incompatible
+                                    throw new IllegalArgumentException("Contradictory rule exists"
+                                            + " for " + attrToMatch);
+                                }
                             }
-                        }
-                    } else if ((rule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
-                            || (rule == RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET)) {
-                        // "capture preset"-base rule
-                        if (criterion.mAttr.getCapturePreset() == attrToMatch.getCapturePreset()) {
-                            if (criterion.mRule == rule) {
-                             // rule already exists, we're done
-                                return this;
-                            } else {
-                                // criterion already exists with a another rule, it is incompatible
-                                throw new IllegalArgumentException("Contradictory rule exists for "
-                                        + attrToMatch);
+                            break;
+                        case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+                            // "capture preset"-base rule
+                            if (criterion.mAttr.getCapturePreset() == attrToMatch.getCapturePreset()) {
+                                if (criterion.mRule == rule) {
+                                    // rule already exists, we're done
+                                    return this;
+                                } else {
+                                    // criterion already exists with a another rule,
+                                    // it is incompatible
+                                    throw new IllegalArgumentException("Contradictory rule exists"
+                                            + " for " + attrToMatch);
+                                }
                             }
-                        }
+                            break;
+                        case RULE_MATCH_UID:
+                            // "usage"-based rule
+                            if (criterion.mIntProp.intValue() == intProp.intValue()) {
+                                if (criterion.mRule == rule) {
+                                    // rule already exists, we're done
+                                    return this;
+                                } else {
+                                    // criterion already exists with a another rule,
+                                    // it is incompatible
+                                    throw new IllegalArgumentException("Contradictory rule exists"
+                                            + " for UID " + intProp);
+                                }
+                            }
+                            break;
                     }
                 }
                 // rule didn't exist, add it
@@ -268,22 +436,30 @@
         }
 
         Builder addRuleFromParcel(Parcel in) throws IllegalArgumentException {
-            int rule = in.readInt();
-            AudioAttributes attr;
-            if ((rule == RULE_MATCH_ATTRIBUTE_USAGE) || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
-                int usage = in.readInt();
-                attr = new AudioAttributes.Builder()
-                        .setUsage(usage).build();
-            } else if ((rule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
-                    || (rule == RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET)) {
-                int preset = in.readInt();
-                attr = new AudioAttributes.Builder()
-                        .setInternalCapturePreset(preset).build();
-            } else {
-                in.readInt(); // assume there was in int value to read as for now they come in pair
-                throw new IllegalArgumentException("Illegal rule value " + rule + " in parcel");
+            final int rule = in.readInt();
+            final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+            AudioAttributes attr = null;
+            Integer intProp = null;
+            switch (match_rule) {
+                case RULE_MATCH_ATTRIBUTE_USAGE:
+                    int usage = in.readInt();
+                    attr = new AudioAttributes.Builder()
+                            .setUsage(usage).build();
+                    break;
+                case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+                    int preset = in.readInt();
+                    attr = new AudioAttributes.Builder()
+                            .setInternalCapturePreset(preset).build();
+                    break;
+                case RULE_MATCH_UID:
+                    intProp = new Integer(in.readInt());
+                    break;
+                default:
+                    // assume there was in int value to read as for now they come in pair
+                    in.readInt();
+                    throw new IllegalArgumentException("Illegal rule value " + rule + " in parcel");
             }
-            return addRuleInt(attr, rule);
+            return addRuleInternal(attr, intProp, rule);
         }
 
         /**
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 252f5f4..5ad6126 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -169,6 +169,14 @@
                         textDump += "  match capture preset ";
                         textDump += criterion.mAttr.getCapturePreset();
                         break;
+                    case AudioMixingRule.RULE_MATCH_UID:
+                        textDump += "  match UID ";
+                        textDump += criterion.mIntProp.toString();
+                        break;
+                    case AudioMixingRule.RULE_EXCLUDE_UID:
+                        textDump += "  exclude UID ";
+                        textDump += criterion.mIntProp.toString();
+                        break;
                     default:
                         textDump += "invalid rule!";
                 }
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index ebba343..707db06 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -40,6 +40,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class SoundTriggerDetector {
     private static final boolean DBG = false;
     private static final String TAG = "SoundTriggerDetector";
@@ -132,6 +133,9 @@
         return true;
     }
 
+    /**
+     * @hide
+     */
     public void dump(String prefix, PrintWriter pw) {
         synchronized (mLock) {
             // TODO: Dump useful debug information.
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index 4ae8e72..4fd3310 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -37,8 +37,8 @@
  * OEMs to write apps that can manage non-voice based sound trigger models.
  *
  * @hide
- * TODO: Mark this as a SystemApi and get approval.
  */
+@SystemApi
 public final class SoundTriggerManager {
     private static final boolean DBG = false;
     private static final String TAG = "SoundTriggerManager";
diff --git a/media/java/android/mtp/MtpConstants.java b/media/java/android/mtp/MtpConstants.java
index ef2cf2b..0dcc718 100644
--- a/media/java/android/mtp/MtpConstants.java
+++ b/media/java/android/mtp/MtpConstants.java
@@ -690,4 +690,6 @@
     public static final int OPERATION_SET_OBJECT_REFERENCES = 0x9811;
     /** Operation code for Skip */
     public static final int OPERATION_SKIP = 0x9820;
+    /** Operation code for GetPartialObject64 */
+    public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 0x95C1;
 }
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 4379a99..0e7013c 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -153,10 +153,11 @@
      *
      * @param objectHandle handle of the object to read
      * @param objectSize the size of the object (this should match
-     *      {@link MtpObjectInfo#getCompressedSize}
+     *      {@link MtpObjectInfo#getCompressedSize})
      * @return the object's data, or null if reading fails
      */
     public byte[] getObject(int objectHandle, int objectSize) {
+        Preconditions.checkArgumentNonnegative(objectSize, "objectSize should not be negative");
         return native_get_object(objectHandle, objectSize);
     }
 
@@ -179,6 +180,27 @@
     }
 
     /**
+     * Obtains object bytes in the specified range and writes it to an array.
+     * This call may block for an arbitrary amount of time depending on the size
+     * of the data and speed of the devices.
+     *
+     * This is a vender-extended operation supported by Android that enables us to pass
+     * unsigned 64-bit offset. Check if the MTP device supports the operation by using
+     * {@link MtpDeviceInfo#getOperationsSupported()}.
+     *
+     * @param objectHandle handle of the object to read
+     * @param offset Start index of reading range. It must be a non-negative value.
+     * @param size Size of reading range. It must be a non-negative value at most 0xffffffff.
+     * @param buffer Array to write data.
+     * @return Size of bytes that are actually read.
+     * @see MtpConstants#OPERATION_GET_PARTIAL_OBJECT_64
+     */
+    public long getPartialObject64(int objectHandle, long offset, long size, byte[] buffer)
+            throws IOException {
+        return native_get_partial_object_64(objectHandle, offset, size, buffer);
+    }
+
+    /**
      * Returns the thumbnail data for an object as a byte array.
      * The size and format of the thumbnail data can be determined via
      * {@link MtpObjectInfo#getThumbCompressedSize} and
@@ -284,7 +306,7 @@
      * @param descriptor file descriptor to read the data from.
      * @return true if the file transfer succeeds
      */
-    public boolean sendObject(int objectHandle, int size, ParcelFileDescriptor descriptor) {
+    public boolean sendObject(int objectHandle, long size, ParcelFileDescriptor descriptor) {
         return native_send_object(objectHandle, size, descriptor.getFd());
     }
 
@@ -343,16 +365,18 @@
     private native MtpStorageInfo native_get_storage_info(int storageId);
     private native int[] native_get_object_handles(int storageId, int format, int objectHandle);
     private native MtpObjectInfo native_get_object_info(int objectHandle);
-    private native byte[] native_get_object(int objectHandle, int objectSize);
+    private native byte[] native_get_object(int objectHandle, long objectSize);
     private native long native_get_partial_object(
             int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
+    private native int native_get_partial_object_64(
+            int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
     private native byte[] native_get_thumbnail(int objectHandle);
     private native boolean native_delete_object(int objectHandle);
-    private native long native_get_parent(int objectHandle);
-    private native long native_get_storage_id(int objectHandle);
+    private native int native_get_parent(int objectHandle);
+    private native int native_get_storage_id(int objectHandle);
     private native boolean native_import_file(int objectHandle, String destPath);
     private native boolean native_import_file(int objectHandle, int fd);
-    private native boolean native_send_object(int objectHandle, int size, int fd);
+    private native boolean native_send_object(int objectHandle, long size, int fd);
     private native MtpObjectInfo native_send_object_info(MtpObjectInfo info);
     private native int native_submit_event_request();
     private native MtpEvent native_reap_event_request(int handle);
diff --git a/media/java/android/mtp/MtpObjectInfo.java b/media/java/android/mtp/MtpObjectInfo.java
index 64aa997..02092b1 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -16,6 +16,8 @@
 
 package android.mtp;
 
+import com.android.internal.util.Preconditions;
+
 /**
  * This class encapsulates information about an object on an MTP device.
  * This corresponds to the ObjectInfo Dataset described in
@@ -96,10 +98,20 @@
      * @return the object size
      */
     public final int getCompressedSize() {
+        Preconditions.checkState(mCompressedSize >= 0);
         return mCompressedSize;
     }
 
     /**
+     * Returns the size of the MTP object
+     *
+     * @return the object size
+     */
+    public final long getCompressedSizeLong() {
+        return uint32ToLong(mCompressedSize);
+    }
+
+    /**
      * Returns the format code for the MTP object's thumbnail
      * Will be zero for objects with no thumbnail
      *
@@ -116,60 +128,126 @@
      * @return the thumbnail size
      */
     public final int getThumbCompressedSize() {
+        Preconditions.checkState(mThumbCompressedSize >= 0);
         return mThumbCompressedSize;
     }
 
     /**
+     * Returns the size of the MTP object's thumbnail
+     * Will be zero for objects with no thumbnail
+     *
+     * @return the thumbnail size
+     */
+    public final long getThumbCompressedSizeLong() {
+        return uint32ToLong(mThumbCompressedSize);
+    }
+
+    /**
      * Returns the width of the MTP object's thumbnail in pixels
      * Will be zero for objects with no thumbnail
      *
      * @return the thumbnail width
      */
     public final int getThumbPixWidth() {
+        Preconditions.checkState(mThumbPixWidth >= 0);
         return mThumbPixWidth;
     }
 
     /**
+     * Returns the width of the MTP object's thumbnail in pixels
+     * Will be zero for objects with no thumbnail
+     *
+     * @return the thumbnail width
+     */
+    public final long getThumbPixWidthLong() {
+        return uint32ToLong(mThumbPixWidth);
+    }
+
+    /**
      * Returns the height of the MTP object's thumbnail in pixels
      * Will be zero for objects with no thumbnail
      *
      * @return the thumbnail height
      */
     public final int getThumbPixHeight() {
+        Preconditions.checkState(mThumbPixHeight >= 0);
         return mThumbPixHeight;
     }
 
     /**
+     * Returns the height of the MTP object's thumbnail in pixels
+     * Will be zero for objects with no thumbnail
+     *
+     * @return the thumbnail height
+     */
+    public final long getThumbPixHeightLong() {
+        return uint32ToLong(mThumbPixHeight);
+    }
+
+    /**
      * Returns the width of the MTP object in pixels
      * Will be zero for non-image objects
      *
      * @return the image width
      */
     public final int getImagePixWidth() {
+        Preconditions.checkState(mImagePixWidth >= 0);
         return mImagePixWidth;
     }
 
     /**
+     * Returns the width of the MTP object in pixels
+     * Will be zero for non-image objects
+     *
+     * @return the image width
+     */
+    public final long getImagePixWidthLong() {
+        return uint32ToLong(mImagePixWidth);
+    }
+
+    /**
      * Returns the height of the MTP object in pixels
      * Will be zero for non-image objects
      *
      * @return the image height
      */
     public final int getImagePixHeight() {
+        Preconditions.checkState(mImagePixHeight >= 0);
         return mImagePixHeight;
     }
 
     /**
+     * Returns the height of the MTP object in pixels
+     * Will be zero for non-image objects
+     *
+     * @return the image height
+     */
+    public final long getImagePixHeightLong() {
+        return uint32ToLong(mImagePixHeight);
+    }
+
+    /**
      * Returns the depth of the MTP object in bits per pixel
      * Will be zero for non-image objects
      *
      * @return the image depth
      */
     public final int getImagePixDepth() {
+        Preconditions.checkState(mImagePixDepth >= 0);
         return mImagePixDepth;
     }
 
     /**
+     * Returns the depth of the MTP object in bits per pixel
+     * Will be zero for non-image objects
+     *
+     * @return the image depth
+     */
+    public final long getImagePixDepthLong() {
+        return uint32ToLong(mImagePixDepth);
+    }
+
+    /**
      * Returns the object handle for the object's parent
      * Will be zero for the root directory of a storage unit
      *
@@ -203,7 +281,7 @@
         return mAssociationDesc;
     }
 
-   /**
+    /**
      * Returns the sequence number for the MTP object
      * This field is typically not used for MTP devices,
      * but is sometimes used to define a sequence of photos
@@ -212,9 +290,22 @@
      * @return the object's sequence number
      */
     public final int getSequenceNumber() {
+        Preconditions.checkState(mSequenceNumber >= 0);
         return mSequenceNumber;
     }
 
+    /**
+     * Returns the sequence number for the MTP object
+     * This field is typically not used for MTP devices,
+     * but is sometimes used to define a sequence of photos
+     * on PTP cameras.
+     *
+     * @return the object's sequence number
+     */
+    public final long getSequenceNumberLong() {
+        return uint32ToLong(mSequenceNumber);
+    }
+
    /**
      * Returns the name of the MTP object
      *
@@ -309,8 +400,8 @@
             return this;
         }
 
-        public Builder setCompressedSize(int value) {
-            mObjectInfo.mCompressedSize = value;
+        public Builder setCompressedSize(long value) {
+            mObjectInfo.mCompressedSize = longToUint32(value, "value");
             return this;
         }
 
@@ -329,18 +420,18 @@
             return this;
         }
 
-        public Builder setImagePixDepth(int value) {
-            mObjectInfo.mImagePixDepth = value;
+        public Builder setImagePixDepth(long value) {
+            mObjectInfo.mImagePixDepth = longToUint32(value, "value");
             return this;
         }
 
-        public Builder setImagePixHeight(int value) {
-            mObjectInfo.mImagePixHeight = value;
+        public Builder setImagePixHeight(long value) {
+            mObjectInfo.mImagePixHeight = longToUint32(value, "value");
             return this;
         }
 
-        public Builder setImagePixWidth(int value) {
-            mObjectInfo.mImagePixWidth = value;
+        public Builder setImagePixWidth(long value) {
+            mObjectInfo.mImagePixWidth = longToUint32(value, "value");
             return this;
         }
 
@@ -364,8 +455,8 @@
             return this;
         }
 
-        public Builder setSequenceNumber(int value) {
-            mObjectInfo.mSequenceNumber = value;
+        public Builder setSequenceNumber(long value) {
+            mObjectInfo.mSequenceNumber = longToUint32(value, "value");
             return this;
         }
 
@@ -374,8 +465,8 @@
             return this;
         }
 
-        public Builder setThumbCompressedSize(int value) {
-            mObjectInfo.mThumbCompressedSize = value;
+        public Builder setThumbCompressedSize(long value) {
+            mObjectInfo.mThumbCompressedSize = longToUint32(value, "value");
             return this;
         }
 
@@ -384,13 +475,13 @@
             return this;
         }
 
-        public Builder setThumbPixHeight(int value) {
-            mObjectInfo.mThumbPixHeight = value;
+        public Builder setThumbPixHeight(long value) {
+            mObjectInfo.mThumbPixHeight = longToUint32(value, "value");
             return this;
         }
 
-        public Builder setThumbPixWidth(int value) {
-            mObjectInfo.mThumbPixWidth = value;
+        public Builder setThumbPixWidth(long value) {
+            mObjectInfo.mThumbPixWidth = longToUint32(value, "value");
             return this;
         }
 
@@ -407,4 +498,13 @@
             return result;
         }
     }
+
+    private static long uint32ToLong(int value) {
+        return value < 0 ? 0x100000000L + value : value;
+    }
+
+    private static int longToUint32(long value, String valueName) {
+        Preconditions.checkArgumentInRange(value, 0, 0xffffffffL, valueName);
+        return (int) value;
+    }
 }
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 5108eb5..c08a5e3 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -81,7 +81,8 @@
 
 bool GetExifFromRawImage(
         FileStream* stream, const String8& filename, piex::PreviewImageData& image_data) {
-    memset(&image_data, 0, sizeof(image_data));
+    // Reset the PreviewImageData to its default.
+    image_data = piex::PreviewImageData();
 
     if (!stream->exists()) {
         // File is not exists.
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 8b7a926..0ecb750 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -26,6 +26,7 @@
 #include <fcntl.h>
 
 #include <memory>
+#include <string>
 
 #include "jni.h"
 #include "JNIHelp.h"
@@ -370,9 +371,26 @@
     return info;
 }
 
+bool check_uint32_arg(JNIEnv *env, const char* name, jlong value, uint32_t* out) {
+    if (value < 0 || 0xffffffff < value) {
+        jniThrowException(
+                env,
+                "java/lang/IllegalArgumentException",
+                (std::string("argument must be a 32-bit unsigned integer: ") + name).c_str());
+        return false;
+    }
+    *out = static_cast<uint32_t>(value);
+    return true;
+}
+
 static jbyteArray
-android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jint objectSize)
+android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jlong objectSizeLong)
 {
+    uint32_t objectSize;
+    if (!check_uint32_arg(env, "objectSize", objectSizeLong, &objectSize)) {
+        return nullptr;
+    }
+
     MtpDevice* device = get_device_from_object(env, thiz);
     if (!device) {
         return nullptr;
@@ -396,8 +414,8 @@
 android_mtp_MtpDevice_get_partial_object(JNIEnv *env,
                                          jobject thiz,
                                          jint objectID,
-                                         jlong offset,
-                                         jlong size,
+                                         jlong offsetLong,
+                                         jlong sizeLong,
                                          jbyteArray array)
 {
     if (!array) {
@@ -405,19 +423,10 @@
         return -1;
     }
 
-    if (offset < 0 || 0xffffffffL < offset) {
-        jniThrowException(
-                env,
-                "java/lang/IllegalArgumentException",
-                "Offset argument must be a 32-bit unsigned integer.");
-        return -1;
-    }
-
-    if (size < 0 || 0xffffffffL < size) {
-        jniThrowException(
-                env,
-                "java/lang/IllegalArgumentException",
-                "Size argument must be a 32-bit unsigned integer.");
+    uint32_t offset;
+    uint32_t size;
+    if (!check_uint32_arg(env, "offset", offsetLong, &offset) ||
+            !check_uint32_arg(env, "size", sizeLong, &size)) {
         return -1;
     }
 
@@ -438,6 +447,60 @@
     return static_cast<jlong>(written_size);
 }
 
+static jint
+android_mtp_MtpDevice_get_partial_object_64(JNIEnv *env,
+                                            jobject thiz,
+                                            jint objectID,
+                                            jlong offset,
+                                            jlong size,
+                                            jbyteArray array) {
+    if (!array) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Array must not be null.");
+        return -1;
+    }
+
+    if (offset < 0) {
+        jniThrowException(
+                env,
+                "java/lang/IllegalArgumentException",
+                "Offset argument must not be a negative value.");
+        return -1;
+    }
+
+    if (size < 0 || 0xffffffffL < size) {
+        jniThrowException(
+                env,
+                "java/lang/IllegalArgumentException",
+                "Size argument must be a 32-bit unsigned integer.");
+        return -1;
+    }
+
+    MtpDevice* const device = get_device_from_object(env, thiz);
+    if (!device) {
+        jniThrowException(env, "java/io/IOException", "Failed to obtain MtpDevice.");
+        return -1;
+    }
+
+    const uint32_t native_object_handle = static_cast<uint32_t>(objectID);
+    const uint64_t native_offset = static_cast<uint64_t>(offset);
+    const uint32_t native_size = static_cast<uint32_t>(size);
+
+    JavaArrayWriter writer(env, array);
+    uint32_t written_size;
+    const bool success = device->readPartialObject64(
+            native_object_handle,
+            native_offset,
+            native_size,
+            &written_size,
+            JavaArrayWriter::writeTo,
+            &writer);
+    if (!success) {
+        jniThrowException(env, "java/io/IOException", "Failed to read data.");
+        return -1;
+    }
+    return static_cast<jint>(written_size);
+}
+
 static jbyteArray
 android_mtp_MtpDevice_get_thumbnail(JNIEnv *env, jobject thiz, jint objectID)
 {
@@ -467,22 +530,22 @@
     }
 }
 
-static jlong
+static jint
 android_mtp_MtpDevice_get_parent(JNIEnv *env, jobject thiz, jint object_id)
 {
     MtpDevice* device = get_device_from_object(env, thiz);
     if (device)
-        return (jlong)device->getParent(object_id);
+        return static_cast<jint>(device->getParent(object_id));
     else
         return -1;
 }
 
-static jlong
+static jint
 android_mtp_MtpDevice_get_storage_id(JNIEnv *env, jobject thiz, jint object_id)
 {
     MtpDevice* device = get_device_from_object(env, thiz);
     if (device)
-        return (jlong)device->getStorageID(object_id);
+        return static_cast<jint>(device->getStorageID(object_id));
     else
         return -1;
 }
@@ -516,8 +579,13 @@
 }
 
 static jboolean
-android_mtp_MtpDevice_send_object(JNIEnv *env, jobject thiz, jint object_id, jint size, jint fd)
+android_mtp_MtpDevice_send_object(
+        JNIEnv *env, jobject thiz, jint object_id, jlong sizeLong, jint fd)
 {
+    uint32_t size;
+    if (!check_uint32_arg(env, "size", sizeLong, &size))
+        return JNI_FALSE;
+
     MtpDevice* device = get_device_from_object(env, thiz);
     if (!device)
         return JNI_FALSE;
@@ -647,16 +715,18 @@
                                         (void *)android_mtp_MtpDevice_get_object_handles},
     {"native_get_object_info",  "(I)Landroid/mtp/MtpObjectInfo;",
                                         (void *)android_mtp_MtpDevice_get_object_info},
-    {"native_get_object",       "(II)[B",(void *)android_mtp_MtpDevice_get_object},
+    {"native_get_object",       "(IJ)[B",(void *)android_mtp_MtpDevice_get_object},
     {"native_get_partial_object", "(IJJ[B)J", (void *)android_mtp_MtpDevice_get_partial_object},
+    {"native_get_partial_object_64", "(IJJ[B)I",
+                                        (void *)android_mtp_MtpDevice_get_partial_object_64},
     {"native_get_thumbnail",    "(I)[B",(void *)android_mtp_MtpDevice_get_thumbnail},
     {"native_delete_object",    "(I)Z", (void *)android_mtp_MtpDevice_delete_object},
-    {"native_get_parent",       "(I)J", (void *)android_mtp_MtpDevice_get_parent},
-    {"native_get_storage_id",   "(I)J", (void *)android_mtp_MtpDevice_get_storage_id},
+    {"native_get_parent",       "(I)I", (void *)android_mtp_MtpDevice_get_parent},
+    {"native_get_storage_id",   "(I)I", (void *)android_mtp_MtpDevice_get_storage_id},
     {"native_import_file",      "(ILjava/lang/String;)Z",
                                         (void *)android_mtp_MtpDevice_import_file},
     {"native_import_file",      "(II)Z",(void *)android_mtp_MtpDevice_import_file_to_fd},
-    {"native_send_object",      "(III)Z",(void *)android_mtp_MtpDevice_send_object},
+    {"native_send_object",      "(IJI)Z",(void *)android_mtp_MtpDevice_send_object},
     {"native_send_object_info", "(Landroid/mtp/MtpObjectInfo;)Landroid/mtp/MtpObjectInfo;",
                                         (void *)android_mtp_MtpDevice_send_object_info},
     {"native_submit_event_request",  "()I", (void *)android_mtp_MtpDevice_submit_event_request},
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index aefdc67..afe9336 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -181,6 +181,8 @@
     <string name="copy_failure_alert_content">These files weren\'t copied: <xliff:g id="list">%1$s</xliff:g></string>
     <!-- Contents of the moving failure alert dialog. [CHAR LIMIT=48] -->
     <string name="move_failure_alert_content">These files weren\'t moved: <xliff:g id="list">%1$s</xliff:g></string>
+    <!-- Contents of the copying warning dialog due to converted files. [CHAR LIMIT=64] -->
+    <string name="copy_converted_warning_content">These files were converted to another format: <xliff:g id="list" example="Document.pdf, Photo.jpg, Song.ogg">%1$s</xliff:g></string>
     <!-- Toast shown when a user copies files to clipboard. -->
     <plurals name="clipboard_files_clipped">
         <item quantity="one">Copied <xliff:g id="count" example="1">%1$d</xliff:g> file to clipboard.</item>
@@ -192,6 +194,9 @@
     <string name="menu_rename">Rename</string>
     <!-- Toast shown when renaming document failed with an error [CHAR LIMIT=48] -->
     <string name="rename_error">Failed to rename document</string>
+    <!-- First line for notifications saying that some files were converted to a different format
+         during a copy. [CHAR LIMIT=48] -->
+    <string name="notification_copy_files_converted_title">Some files were converted</string>
 
     <!--  DO NOT TRANSLATE - final phrase has not been decided yet (b/26750152) -->
     <string name="open_external_dialog_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index ad8b0d1..5ffc435 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -17,11 +17,13 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.MODE_GRID;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_SIDE;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_UP;
 import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.internal.util.Preconditions.checkState;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -51,8 +53,8 @@
 import android.widget.TextView;
 
 import com.android.documentsui.RecentsProvider.ResumeColumns;
-import com.android.documentsui.SearchManager;
 import com.android.documentsui.SearchManager.SearchManagerListener;
+import com.android.documentsui.State.ViewMode;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DocumentStack;
@@ -204,6 +206,8 @@
     void onStackRestored(boolean restored, boolean external) {}
 
     void onRootPicked(RootInfo root) {
+        mState.derivedMode = LocalPreferences.getViewMode(this, root, MODE_GRID);
+
         // Clear entire backstack and start in new root
         mState.onRootChanged(root);
         mSearchManager.update(root);
@@ -260,11 +264,11 @@
                 return true;
 
             case R.id.menu_grid:
-                setUserMode(State.MODE_GRID);
+                setViewMode(State.MODE_GRID);
                 return true;
 
             case R.id.menu_list:
-                setUserMode(State.MODE_LIST);
+                setViewMode(State.MODE_LIST);
                 return true;
 
             case R.id.menu_paste_from_clipboard:
@@ -419,24 +423,27 @@
         invalidateOptionsMenu();
     }
 
-    public void onStateChanged() {
-        invalidateOptionsMenu();
-    }
-
     /**
      * Set state sort order based on explicit user action.
      */
     void setUserSortOrder(int sortOrder) {
         mState.userSortOrder = sortOrder;
-        DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged();
+        DirectoryFragment.get(getFragmentManager()).onSortOrderChanged();
     }
 
     /**
-     * Set state mode based on explicit user action.
+     * Set mode based on explicit user action.
      */
-    void setUserMode(int mode) {
-        mState.userMode = mode;
-        DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
+    void setViewMode(@ViewMode int mode) {
+        checkState(mState.stack.root != null);
+        LocalPreferences.setViewMode(this, mState.stack.root, mode);
+        mState.derivedMode = mode;
+
+        // view icon needs to be updated, but we *could* do it
+        // in onOptionsItemSelected, and not do the full invalidation
+        // But! That's a larger refactoring we'll save for another day.
+        invalidateOptionsMenu();
+        DirectoryFragment.get(getFragmentManager()).onViewModeChanged();
     }
 
     public void setPending(boolean pending) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 6719b23..b0542b9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,11 +16,11 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.TAG;
 import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
 import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
 import static com.android.documentsui.State.SORT_ORDER_SIZE;
-import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 
 import android.content.AsyncTaskLoader;
 import android.content.ContentProviderClient;
@@ -35,7 +35,6 @@
 import android.provider.DocumentsContract.Document;
 import android.util.Log;
 
-import com.android.documentsui.RecentsProvider.StateColumns;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
@@ -52,10 +51,10 @@
 
     private final int mType;
     private final RootInfo mRoot;
-    private DocumentInfo mDoc;
     private final Uri mUri;
     private final int mUserSortOrder;
 
+    private DocumentInfo mDoc;
     private CancellationSignal mSignal;
     private DirectoryResult mResult;
 
@@ -64,9 +63,9 @@
         super(context, ProviderExecutor.forAuthority(root.authority));
         mType = type;
         mRoot = root;
-        mDoc = doc;
         mUri = uri;
         mUserSortOrder = userSortOrder;
+        mDoc = doc;
     }
 
     @Override
@@ -83,8 +82,6 @@
 
         final DirectoryResult result = new DirectoryResult();
 
-        int userMode = State.MODE_UNKNOWN;
-
         // Use default document when searching
         if (mType == DirectoryFragment.TYPE_SEARCH) {
             final Uri docUri = DocumentsContract.buildDocumentUri(
@@ -98,25 +95,6 @@
             }
         }
 
-        // Pick up any custom modes requested by user
-        Cursor cursor = null;
-        try {
-            final Uri stateUri = RecentsProvider.buildState(
-                    mRoot.authority, mRoot.rootId, mDoc.documentId);
-            cursor = resolver.query(stateUri, null, null, null, null);
-            if (cursor.moveToFirst()) {
-                userMode = getCursorInt(cursor, StateColumns.MODE);
-            }
-        } finally {
-            IoUtils.closeQuietly(cursor);
-        }
-
-        if (userMode != State.MODE_UNKNOWN) {
-            result.mode = userMode;
-        } else {
-            result.mode = State.MODE_GRID;
-        }
-
         if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
             result.sortOrder = mUserSortOrder;
         } else {
@@ -132,13 +110,13 @@
             result.sortOrder = State.SORT_ORDER_UNKNOWN;
         }
 
-        Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + mUserSortOrder + " --> mode="
-                + result.mode + ", sortOrder=" + result.sortOrder);
+        if (DEBUG)
+                Log.d(TAG, "userSortOrder=" + mUserSortOrder + ", sortOrder=" + result.sortOrder);
 
         ContentProviderClient client = null;
+        Cursor cursor = null;
         try {
             client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, authority);
-
             cursor = client.query(
                     mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal);
             if (cursor == null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
index e7e4f73..22e438a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
@@ -29,7 +29,6 @@
     public Cursor cursor;
     public Exception exception;
 
-    public int mode = MODE_UNKNOWN;
     public int sortOrder = SORT_ORDER_UNKNOWN;
 
     @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 6dcd472..c3395ae 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -346,11 +346,13 @@
             } else {
                 DirectoryFragment.showRecentsOpen(fm, anim);
 
-                // Start recents in grid when requesting visual things
-                final boolean visualMimes = MimePredicate.mimeMatches(
+                // In recents we pick layout mode based on the mimetype,
+                // picking GRID for visual types. We intentionally don't
+                // consult a user's saved preferences here since they are
+                // set per root (not per root and per mimetype).
+                boolean visualMimes = MimePredicate.mimeMatches(
                         MimePredicate.VISUAL_MIMES, mState.acceptMimes);
-                mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
-                mState.derivedMode = mState.userMode;
+                mState.derivedMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
             }
         } else {
             if (mSearchManager.isSearching()) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java b/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java
deleted file mode 100644
index b8ef5ac..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.documentsui;
-
-import static com.android.internal.util.Preconditions.checkArgument;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.text.Html;
-
-import com.android.documentsui.model.DocumentInfo;
-import com.android.documentsui.model.DocumentStack;
-import com.android.documentsui.services.FileOperationService;
-import com.android.documentsui.services.FileOperations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Alert dialog for failed operations.
- */
-public class FailureDialogFragment extends DialogFragment {
-    private static final String TAG = "FailureDialogFragment";
-
-    public static void show(FragmentManager fm, int failure,
-            ArrayList<DocumentInfo> failedSrcList, DocumentStack dstStack, int operationType) {
-        // TODO: Add support for other failures than copy.
-        if (failure != FileOperationService.FAILURE_COPY) {
-            return;
-        }
-
-        final Bundle args = new Bundle();
-        args.putInt(FileOperationService.EXTRA_FAILURE, failure);
-        args.putInt(FileOperationService.EXTRA_OPERATION, operationType);
-        args.putParcelableArrayList(FileOperationService.EXTRA_SRC_LIST, failedSrcList);
-
-        final FragmentTransaction ft = fm.beginTransaction();
-        final FailureDialogFragment fragment = new FailureDialogFragment();
-        fragment.setArguments(args);
-
-        ft.add(fragment, TAG);
-        ft.commitAllowingStateLoss();
-    }
-
-    @Override
-    public Dialog onCreateDialog(Bundle inState) {
-        super.onCreate(inState);
-
-        final int operationType = getArguments().getInt(FileOperationService.EXTRA_OPERATION);
-        final List<DocumentInfo> failedSrcList = getArguments().getParcelableArrayList(
-                FileOperationService.EXTRA_SRC_LIST);
-
-        final StringBuilder list = new StringBuilder("<p>");
-        for (DocumentInfo documentInfo : failedSrcList) {
-            list.append(String.format("&#8226; %s<br>", documentInfo.displayName));
-        }
-        list.append("</p>");
-
-        // TODO: Add support for other file operations.
-        checkArgument(
-                operationType == FileOperationService.OPERATION_COPY
-                || operationType == FileOperationService.OPERATION_MOVE);
-
-        int messageId = operationType == FileOperationService.OPERATION_COPY
-                ? R.string.copy_failure_alert_content
-                : R.string.move_failure_alert_content;
-
-        final String messageFormat = getString(
-                messageId);
-
-        final String message = String.format(messageFormat, list.toString());
-
-        return new AlertDialog.Builder(getActivity())
-                .setMessage(Html.fromHtml(message))
-                .setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int id) {
-                        dialog.dismiss();
-                    }
-                })
-                .create();
-    }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 5abe7f6..393fdcd 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -20,6 +20,8 @@
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkState;
+import static com.android.documentsui.OperationDialogFragment.DialogType;
+import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN;
 
 import android.app.Activity;
 import android.app.FragmentManager;
@@ -121,20 +123,20 @@
                     ProviderExecutor.forAuthority(homeUri.getAuthority()));
         }
 
-        final int failure = intent.getIntExtra(FileOperationService.EXTRA_FAILURE, 0);
-        final int opType = intent.getIntExtra(
-                FileOperationService.EXTRA_OPERATION,
-                FileOperationService.OPERATION_COPY);
-
+        final @DialogType int dialogType = intent.getIntExtra(
+                FileOperationService.EXTRA_DIALOG_TYPE, DIALOG_TYPE_UNKNOWN);
         // DialogFragment takes care of restoring the dialog on configuration change.
         // Only show it manually for the first time (icicle is null).
-        if (icicle == null && failure != 0) {
-            final ArrayList<DocumentInfo> failedSrcList =
+        if (icicle == null && dialogType != DIALOG_TYPE_UNKNOWN) {
+            final int opType = intent.getIntExtra(
+                    FileOperationService.EXTRA_OPERATION,
+                    FileOperationService.OPERATION_COPY);
+            final ArrayList<DocumentInfo> srcList =
                     intent.getParcelableArrayListExtra(FileOperationService.EXTRA_SRC_LIST);
-            FailureDialogFragment.show(
+            OperationDialogFragment.show(
                     getFragmentManager(),
-                    failure,
-                    failedSrcList,
+                    dialogType,
+                    srcList,
                     mState.stack,
                     opType);
         }
@@ -296,12 +298,6 @@
 
         if (cwd == null) {
             DirectoryFragment.showRecentsOpen(fm, anim);
-
-            // Start recents in grid when requesting visual things
-            final boolean visualMimes = MimePredicate.mimeMatches(
-                    MimePredicate.VISUAL_MIMES, mState.acceptMimes);
-            mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
-            mState.derivedMode = mState.userMode;
         } else {
             if (mState.currentSearch != null) {
                 // Ongoing search
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
index 113e9d7..4bffc49 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
@@ -16,12 +16,19 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.internal.util.Preconditions.checkArgument;
+
 import android.content.Context;
 import android.preference.PreferenceManager;
 
+import com.android.documentsui.State.ViewMode;
+import com.android.documentsui.model.RootInfo;
+
 public class LocalPreferences {
     private static final String KEY_ADVANCED_DEVICES = "advancedDevices";
     private static final String KEY_FILE_SIZE = "fileSize";
+    private static final String ROOT_VIEW_MODE_PREFIX = "rootViewMode-";
 
     public static boolean getDisplayAdvancedDevices(Context context) {
         boolean defaultAdvanced = context.getResources()
@@ -35,6 +42,12 @@
                 .getBoolean(KEY_FILE_SIZE, false);
     }
 
+    public static @ViewMode int getViewMode(
+            Context context, RootInfo root, @ViewMode int fallback) {
+        return PreferenceManager.getDefaultSharedPreferences(context)
+                .getInt(createKey(root), fallback);
+    }
+
     public static void setDisplayAdvancedDevices(Context context, boolean display) {
         PreferenceManager.getDefaultSharedPreferences(context).edit()
                 .putBoolean(KEY_ADVANCED_DEVICES, display).apply();
@@ -44,4 +57,14 @@
         PreferenceManager.getDefaultSharedPreferences(context).edit()
                 .putBoolean(KEY_FILE_SIZE, display).apply();
     }
+
+    public static void setViewMode(Context context, RootInfo root, @ViewMode int viewMode) {
+        checkArgument(viewMode != MODE_UNKNOWN);
+        PreferenceManager.getDefaultSharedPreferences(context).edit()
+                .putInt(createKey(root), viewMode).apply();
+    }
+
+    private static String createKey(RootInfo root) {
+        return ROOT_VIEW_MODE_PREFIX + root.authority + root.rootId;
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java b/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
new file mode 100644
index 0000000..85cc12b
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
@@ -0,0 +1,132 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.services.FileOperationService.OpType;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.annotation.IntDef;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.Html;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.services.FileOperationService;
+import com.android.documentsui.services.FileOperations;
+import com.android.documentsui.services.Job;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Alert dialog for operation dialogs.
+ */
+public class OperationDialogFragment extends DialogFragment {
+
+    public static final int DIALOG_TYPE_UNKNOWN = 0;
+    public static final int DIALOG_TYPE_FAILURE = 1;
+    public static final int DIALOG_TYPE_CONVERTED = 2;
+
+    @IntDef(flag = true, value = {
+        DIALOG_TYPE_UNKNOWN,
+        DIALOG_TYPE_FAILURE,
+        DIALOG_TYPE_CONVERTED
+    })
+
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DialogType {}
+
+    private static final String TAG = "OperationDialogFragment";
+
+    public static void show(FragmentManager fm, @DialogType int dialogType,
+            ArrayList<DocumentInfo> failedSrcList, DocumentStack dstStack,
+            @OpType int operationType) {
+        final Bundle args = new Bundle();
+        args.putInt(FileOperationService.EXTRA_DIALOG_TYPE, dialogType);
+        args.putInt(FileOperationService.EXTRA_OPERATION, operationType);
+        args.putParcelableArrayList(FileOperationService.EXTRA_SRC_LIST, failedSrcList);
+
+        final FragmentTransaction ft = fm.beginTransaction();
+        final OperationDialogFragment fragment = new OperationDialogFragment();
+        fragment.setArguments(args);
+
+        ft.add(fragment, TAG);
+        ft.commitAllowingStateLoss();
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle inState) {
+        super.onCreate(inState);
+
+        final @DialogType int dialogType =
+              getArguments().getInt(FileOperationService.EXTRA_DIALOG_TYPE);
+        final @OpType int operationType =
+              getArguments().getInt(FileOperationService.EXTRA_OPERATION);
+        final ArrayList<DocumentInfo> srcList = getArguments().getParcelableArrayList(
+                FileOperationService.EXTRA_SRC_LIST);
+
+        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        String messageFormat;
+
+        switch (dialogType) {
+            case DIALOG_TYPE_CONVERTED:
+                messageFormat = getString(R.string.copy_converted_warning_content);
+                break;
+
+            case DIALOG_TYPE_FAILURE:
+                switch (operationType) {
+                    case FileOperationService.OPERATION_COPY:
+                        messageFormat = getString(R.string.copy_failure_alert_content);
+                        break;
+                    case FileOperationService.OPERATION_MOVE:
+                        messageFormat = getString(R.string.move_failure_alert_content);
+                        break;
+                    default:
+                        throw new UnsupportedOperationException();
+                }
+                break;
+
+            default:
+                throw new UnsupportedOperationException();
+        }
+
+        final StringBuilder list = new StringBuilder("<p>");
+        for (DocumentInfo documentInfo : srcList) {
+            list.append(String.format("&#8226; %s<br>", documentInfo.displayName));
+        }
+        list.append("</p>");
+        builder.setMessage(Html.fromHtml(String.format(messageFormat, list.toString())));
+        builder.setPositiveButton(
+                R.string.close,
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int id) {
+                        dialog.dismiss();
+                    }
+                });
+
+        return builder.create();
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 82eb732..92ffb93 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -85,6 +85,8 @@
         public static final String AUTHORITY = "authority";
         public static final String ROOT_ID = Root.COLUMN_ROOT_ID;
         public static final String DOCUMENT_ID = Document.COLUMN_DOCUMENT_ID;
+
+        @Deprecated  // mode is tracked in local preferences now...by root only
         public static final String MODE = "mode";
         public static final String SORT_ORDER = "sortOrder";
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index 2f0224f..28f7432 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -16,6 +16,7 @@
 
 package com.android.documentsui;
 
+import android.annotation.IntDef;
 import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -26,18 +27,43 @@
 import com.android.documentsui.model.DurableUtils;
 import com.android.documentsui.model.RootInfo;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 
 public class State implements android.os.Parcelable {
+
+    public static final int ACTION_OPEN = 1;
+    public static final int ACTION_CREATE = 2;
+    public static final int ACTION_GET_CONTENT = 3;
+    public static final int ACTION_OPEN_TREE = 4;
+    public static final int ACTION_MANAGE = 5;
+    public static final int ACTION_BROWSE = 6;
+    public static final int ACTION_PICK_COPY_DESTINATION = 8;
+
+    @IntDef(flag = true, value = {
+            MODE_UNKNOWN,
+            MODE_LIST,
+            MODE_GRID
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ViewMode {}
+    public static final int MODE_UNKNOWN = 0;
+    public static final int MODE_LIST = 1;
+    public static final int MODE_GRID = 2;
+
+    public static final int SORT_ORDER_UNKNOWN = 0;
+    public static final int SORT_ORDER_DISPLAY_NAME = 1;
+    public static final int SORT_ORDER_LAST_MODIFIED = 2;
+    public static final int SORT_ORDER_SIZE = 3;
+
     public int action;
     public String[] acceptMimes;
 
-    /** Explicit user choice */
-    public int userMode = MODE_UNKNOWN;
-    /** Derived after loader */
-    public int derivedMode = MODE_GRID;
+    /** Derived from local preferences */
+    public @ViewMode int derivedMode = MODE_GRID;
 
     /** Explicit user choice */
     public int userSortOrder = SORT_ORDER_UNKNOWN;
@@ -58,6 +84,8 @@
 
     /** Current user navigation stack; empty implies recents. */
     public DocumentStack stack = new DocumentStack();
+    private boolean mStackTouched;
+
     /** Currently active search, overriding any stack. */
     public String currentSearch;
 
@@ -70,25 +98,6 @@
     /** Name of the package that started DocsUI */
     public List<String> excludedAuthorities = new ArrayList<>();
 
-    public static final int ACTION_OPEN = 1;
-    public static final int ACTION_CREATE = 2;
-    public static final int ACTION_GET_CONTENT = 3;
-    public static final int ACTION_OPEN_TREE = 4;
-    public static final int ACTION_MANAGE = 5;
-    public static final int ACTION_BROWSE = 6;
-    public static final int ACTION_PICK_COPY_DESTINATION = 8;
-
-    public static final int MODE_UNKNOWN = 0;
-    public static final int MODE_LIST = 1;
-    public static final int MODE_GRID = 2;
-
-    public static final int SORT_ORDER_UNKNOWN = 0;
-    public static final int SORT_ORDER_DISPLAY_NAME = 1;
-    public static final int SORT_ORDER_LAST_MODIFIED = 2;
-    public static final int SORT_ORDER_SIZE = 3;
-
-    private boolean mStackTouched;
-
     public void initAcceptMimes(Intent intent) {
         if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
             acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
@@ -131,7 +140,6 @@
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(action);
-        out.writeInt(userMode);
         out.writeStringArray(acceptMimes);
         out.writeInt(userSortOrder);
         out.writeInt(allowMultiple ? 1 : 0);
@@ -155,7 +163,6 @@
         public State createFromParcel(Parcel in) {
             final State state = new State();
             state.action = in.readInt();
-            state.userMode = in.readInt();
             state.acceptMimes = in.readStringArray();
             state.userSortOrder = in.readInt();
             state.allowMultiple = in.readInt() != 0;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 74fa8d0..f57aa4b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -20,7 +20,6 @@
 import static com.android.documentsui.State.ACTION_MANAGE;
 import static com.android.documentsui.State.MODE_GRID;
 import static com.android.documentsui.State.MODE_LIST;
-import static com.android.documentsui.State.MODE_UNKNOWN;
 import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -37,7 +36,6 @@
 import android.app.LoaderManager.LoaderCallbacks;
 import android.content.ClipData;
 import android.content.ContentResolver;
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.Loader;
@@ -91,9 +89,6 @@
 import com.android.documentsui.MimePredicate;
 import com.android.documentsui.R;
 import com.android.documentsui.RecentLoader;
-import com.android.documentsui.RecentsProvider;
-import com.android.documentsui.RecentsProvider.StateColumns;
-import com.android.documentsui.dirlist.RenameDocumentFragment;
 import com.android.documentsui.RootsCache;
 import com.android.documentsui.Shared;
 import com.android.documentsui.Snackbars;
@@ -155,7 +150,6 @@
     private int mType = TYPE_NORMAL;
     private String mStateKey;
 
-    private int mLastMode = MODE_UNKNOWN;
     private int mLastSortOrder = SORT_ORDER_UNKNOWN;
     private boolean mLastShowSize;
     private DocumentsAdapter mAdapter;
@@ -240,7 +234,7 @@
         final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
         final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
 
-        mIconHelper = new IconHelper(context, state.derivedMode);
+        mIconHelper = new IconHelper(context, MODE_GRID);
 
         mAdapter = new SectionBreakDocumentsAdapterWrapper(
                 this, new ModelBackedDocumentsAdapter(this, mIconHelper));
@@ -323,12 +317,6 @@
                 if (!isAdded()) return;
 
                 mModel.update(result);
-
-                // Push latest state up to UI
-                // TODO: if mode change was racing with us, don't overwrite it
-                if (result.mode != MODE_UNKNOWN) {
-                    state.derivedMode = result.mode;
-                }
                 state.derivedSortOrder = result.sortOrder;
 
                 updateDisplayState();
@@ -361,8 +349,6 @@
 
         // Kick off loader at least once
         getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
-
-        updateDisplayState();
     }
 
     @Override
@@ -425,61 +411,25 @@
         state.dirState.put(mStateKey, container);
     }
 
-    @Override
-    public void onResume() {
-        super.onResume();
-        updateDisplayState();
-    }
-
     public void onDisplayStateChanged() {
         updateDisplayState();
     }
 
-    public void onUserSortOrderChanged() {
-        // Sort order change always triggers reload; we'll trigger state change
-        // on the flip side.
+    public void onSortOrderChanged() {
+        // Sort order is implemented as a sorting wrapper around directory
+        // results. So when sort order changes, we force a reload of the directory.
         getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
     }
 
-    public void onUserModeChanged() {
-        final ContentResolver resolver = getActivity().getContentResolver();
-        final State state = getDisplayState();
-
-        final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
-        final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
-
-        if (root != null && doc != null) {
-            final Uri stateUri = RecentsProvider.buildState(
-                    root.authority, root.rootId, doc.documentId);
-            final ContentValues values = new ContentValues();
-            values.put(StateColumns.MODE, state.userMode);
-
-            new AsyncTask<Void, Void, Void>() {
-                @Override
-                protected Void doInBackground(Void... params) {
-                    resolver.insert(stateUri, values);
-                    return null;
-                }
-            }.execute();
-        }
-
-        // Mode change is just visual change; no need to kick loader, and
-        // deliver change event immediately.
-        state.derivedMode = state.userMode;
-        ((BaseActivity) getActivity()).onStateChanged();
-
+    public void onViewModeChanged() {
+        // Mode change is just visual change; no need to kick loader.
         updateDisplayState();
     }
 
     private void updateDisplayState() {
-        final State state = getDisplayState();
-
-        if (mLastMode == state.derivedMode && mLastShowSize == state.showSize) return;
-        mLastMode = state.derivedMode;
+        State state = getDisplayState();
         mLastShowSize = state.showSize;
-
         updateLayout(state.derivedMode);
-
         mRecView.setAdapter(mAdapter);
     }
 
@@ -506,7 +456,6 @@
                 }
                 layout = mListLayout;
                 break;
-            case MODE_UNKNOWN:
             default:
                 throw new IllegalArgumentException("Unsupported layout mode: " + mode);
         }
@@ -516,7 +465,7 @@
         // setting layout manager automatically invalidates existing ViewHolders.
         mRecView.setLayoutManager(layout);
         mSelectionManager.handleLayoutChanged();  // RecyclerView doesn't do this for us
-        mIconHelper.setMode(mode);
+        mIconHelper.setViewMode(mode);
     }
 
     private int calculateColumnCount() {
@@ -539,7 +488,6 @@
             case MODE_LIST:
                 return getResources().getDimensionPixelSize(
                         R.dimen.list_container_padding);
-            case MODE_UNKNOWN:
             default:
                 throw new IllegalArgumentException("Unsupported layout mode: " + mode);
         }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
index 0314077..c97c446 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
@@ -42,6 +42,8 @@
 import com.android.documentsui.ProviderExecutor;
 import com.android.documentsui.ProviderExecutor.Preemptable;
 import com.android.documentsui.R;
+import com.android.documentsui.State;
+import com.android.documentsui.State.ViewMode;
 import com.android.documentsui.ThumbnailCache;
 
 /**
@@ -64,7 +66,7 @@
      */
     public IconHelper(Context context, int mode) {
         mContext = context;
-        setMode(mode);
+        setViewMode(mode);
         mCache = DocumentsApplication.getThumbnailsCache(context, mThumbSize);
     }
 
@@ -82,7 +84,7 @@
      * Sets the current display mode.  This affects the thumbnail sizes that are loaded.
      * @param mode See {@link State.MODE_LIST} and {@link State.MODE_GRID}.
      */
-    public void setMode(int mode) {
+    public void setViewMode(@ViewMode int mode) {
         // TODO: Instead of exposing setMode, make the mode final, and make separate instances for
         // grid/list.
         int thumbSize;
@@ -94,7 +96,6 @@
                 thumbSize = mContext.getResources().getDimensionPixelSize(
                         R.dimen.list_item_thumbnail_size);
                 break;
-            case MODE_UNKNOWN:
             default:
                 throw new IllegalArgumentException("Unsupported layout mode: " + mode);
         }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
index 68756a3..880da9c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -19,7 +19,6 @@
 import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.State.MODE_GRID;
 import static com.android.documentsui.State.MODE_LIST;
-import static com.android.documentsui.State.MODE_UNKNOWN;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
@@ -92,7 +91,6 @@
             case MODE_LIST:
                 holder = new ListDocumentHolder(mEnv.getContext(), parent, mIconHelper);
                 break;
-            case MODE_UNKNOWN:
             default:
                 throw new IllegalStateException("Unsupported layout mode.");
         }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index 1d8eba5..e5e66f8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -21,17 +21,23 @@
 import static android.provider.DocumentsContract.buildDocumentUri;
 import static android.provider.DocumentsContract.getDocumentId;
 import static android.provider.DocumentsContract.isChildDocument;
+import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_CONVERTED;
 import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import static com.android.documentsui.services.FileOperationService.EXTRA_DIALOG_TYPE;
+import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
+import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
 import static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
 import static com.google.common.base.Preconditions.checkArgument;
 
 import android.annotation.StringRes;
 import android.app.Notification;
 import android.app.Notification.Builder;
+import android.app.PendingIntent;
 import android.content.ContentProviderClient;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
@@ -56,12 +62,14 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.text.NumberFormat;
+import java.util.ArrayList;
 import java.util.List;
 
 class CopyJob extends Job {
     private static final String TAG = "CopyJob";
     private static final int PROGRESS_INTERVAL_MILLIS = 1000;
     final List<DocumentInfo> mSrcs;
+    final ArrayList<DocumentInfo> convertedFiles = new ArrayList<>();
 
     private long mStartTime = -1;
     private long mBatchSize;
@@ -176,6 +184,29 @@
     }
 
     @Override
+    Notification getWarningNotification() {
+        final Intent navigateIntent = buildNavigateIntent();
+        navigateIntent.putExtra(EXTRA_DIALOG_TYPE, DIALOG_TYPE_CONVERTED);
+        navigateIntent.putExtra(EXTRA_OPERATION, operationType);
+
+        navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, convertedFiles);
+
+        // TODO: Consider adding a dialog on tapping the notification with a list of
+        // converted files.
+        final Notification.Builder warningBuilder = new Notification.Builder(service)
+                .setContentTitle(service.getResources().getString(
+                        R.string.notification_copy_files_converted_title))
+                .setContentText(service.getString(
+                        R.string.notification_touch_for_details))
+                .setContentIntent(PendingIntent.getActivity(appContext, 0, navigateIntent,
+                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT))
+                .setCategory(Notification.CATEGORY_ERROR)
+                .setSmallIcon(R.drawable.ic_menu_copy)
+                .setAutoCancel(true);
+        return warningBuilder.build();
+    }
+
+    @Override
     void start() throws RemoteException {
         mStartTime = elapsedRealtime();
 
@@ -203,6 +234,11 @@
         }
     }
 
+    @Override
+    boolean hasWarnings() {
+        return !convertedFiles.isEmpty();
+    }
+
     /**
      * Logs progress on the current copy operation. Displays/Updates the progress notification.
      *
@@ -425,6 +461,10 @@
             }
         }
 
+        if (src.isVirtualDocument() && success) {
+           convertedFiles.add(src);
+        }
+
         return success;
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
index eef696a..24eb987 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
@@ -75,6 +75,11 @@
     }
 
     @Override
+    Notification getWarningNotification() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     void start() throws RemoteException {
         for (DocumentInfo doc : mSrcs) {
             if (DEBUG) Log.d(TAG, "Deleting document @ " + doc.derivedUri);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
index 5d74cdc..3a025c2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
@@ -55,6 +55,7 @@
     private static final int POOL_SIZE = 2;  // "pool size", not *max* "pool size".
     private static final int NOTIFICATION_ID_PROGRESS = 0;
     private static final int NOTIFICATION_ID_FAILURE = 1;
+    private static final int NOTIFICATION_ID_WARNING = 2;
 
     public static final String TAG = "FileOperationService";
 
@@ -63,7 +64,7 @@
     public static final String EXTRA_OPERATION = "com.android.documentsui.OPERATION";
     public static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
     public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
-    public static final String EXTRA_FAILURE = "com.android.documentsui.FAILURE";
+    public static final String EXTRA_DIALOG_TYPE = "com.android.documentsui.DIALOG_TYPE";
 
     // This extra is used only for moving and deleting. Currently it's not the case,
     // but in the future those files may be from multiple different parents. In
@@ -306,6 +307,18 @@
         // Dismiss the ongoing copy notification when the copy is done.
         mNotificationManager.cancel(job.id, NOTIFICATION_ID_PROGRESS);
 
+        if (job.hasFailures()) {
+            Log.e(TAG, "Job failed on files: " + job.failedFiles.size() + ".");
+            mNotificationManager.notify(
+                job.id, NOTIFICATION_ID_FAILURE, job.getFailureNotification());
+        }
+
+        if (job.hasWarnings()) {
+            if (DEBUG) Log.d(TAG, "Job finished with warnings.");
+            mNotificationManager.notify(
+                    job.id, NOTIFICATION_ID_WARNING, job.getWarningNotification());
+        }
+
         synchronized (mRunning) {
             deleteJob(job);
         }
@@ -318,15 +331,6 @@
                 job.id, NOTIFICATION_ID_PROGRESS, job.getProgressNotification());
     }
 
-    @Override
-    public void onFailed(Job job) {
-        if (DEBUG) Log.d(TAG, "onFailed: " + job.id);
-        checkArgument(job.failed());
-        Log.e(TAG, "Job failed on files: " + job.failedFiles.size() + ".");
-        mNotificationManager.notify(job.id, NOTIFICATION_ID_FAILURE, job.getFailureNotification());
-        onFinished(job);  // Failed jobs don't call finished, so we do.
-    }
-
     private static final class JobRecord {
         private final Job job;
         private final ScheduledFuture<?> future;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index 9534d6c..7b8011a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -18,11 +18,10 @@
 
 import static com.android.documentsui.DocumentsApplication.acquireUnstableProviderOrThrow;
 import static com.android.documentsui.services.FileOperationService.EXTRA_CANCEL;
-import static com.android.documentsui.services.FileOperationService.EXTRA_FAILURE;
+import static com.android.documentsui.services.FileOperationService.EXTRA_DIALOG_TYPE;
 import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID;
 import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
 import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
-import static com.android.documentsui.services.FileOperationService.FAILURE_COPY;
 import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
@@ -42,6 +41,7 @@
 import android.util.Log;
 
 import com.android.documentsui.FilesActivity;
+import com.android.documentsui.OperationDialogFragment;
 import com.android.documentsui.R;
 import com.android.documentsui.Shared;
 import com.android.documentsui.model.DocumentInfo;
@@ -57,8 +57,7 @@
  * A mashup of work item and ui progress update factory. Used by {@link FileOperationService}
  * to do work and show progress relating to this work.
  */
-abstract class Job implements Runnable {
-
+abstract public class Job implements Runnable {
     private static final String TAG = "Job";
     final Context service;
     final Context appContext;
@@ -114,13 +113,9 @@
             // to resolve business in an orderly fashion. That'll
             // ensure the service is shut down and notifications
             // shown/closed.
-            listener.onFailed(this);
+            Log.e(TAG, "Operation failed due to an exception.", e);
         } finally {
-            if (failed()) {
-                listener.onFailed(this);
-            } else {
-                listener.onFinished(this);
-            }
+            listener.onFinished(this);
         }
     }
 
@@ -131,6 +126,8 @@
     // abstract Notification getProgressNotification(long bytesCopied);
     abstract Notification getFailureNotification();
 
+    abstract Notification getWarningNotification();
+
     ContentProviderClient getClient(DocumentInfo doc) throws RemoteException {
         ContentProviderClient client = mClients.get(doc.authority);
         if (client == null) {
@@ -167,10 +164,14 @@
         failedFiles.add(file);
     }
 
-    final boolean failed() {
+    final boolean hasFailures() {
         return !failedFiles.isEmpty();
     }
 
+    boolean hasWarnings() {
+        return false;
+    }
+
     final boolean deleteDocument(DocumentInfo doc) {
         try {
             DocumentsContract.deleteDocument(getClient(doc), doc.derivedUri);
@@ -190,7 +191,7 @@
 
     Notification getFailureNotification(@PluralsRes int titleId, @DrawableRes int icon) {
         final Intent navigateIntent = buildNavigateIntent();
-        navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY);
+        navigateIntent.putExtra(EXTRA_DIALOG_TYPE, OperationDialogFragment.DIALOG_TYPE_FAILURE);
         navigateIntent.putExtra(EXTRA_OPERATION, operationType);
 
         navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, failedFiles);
@@ -291,7 +292,6 @@
      */
     interface Listener {
         void onStart(Job job);
-        void onFailed(Job job);
         void onFinished(Job job);
         void onProgress(CopyJob job);
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
index 9c58780..a1c6dab 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
@@ -63,6 +63,11 @@
     }
 
     @Override
+    Notification getWarningNotification() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     Builder createProgressBuilder() {
         // the "copy" stuff was just convenient and available :)
         return super.createProgressBuilder(
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java
index 0110197..46b093d 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java
@@ -33,7 +33,6 @@
     private final CountDownLatch latch = new CountDownLatch(1);
     private final List<Job> progress = new ArrayList<>();
     @Nullable private Job started;
-    @Nullable private Job failed;
     @Nullable private Job finished;
 
     @Override
@@ -42,11 +41,6 @@
     }
 
     @Override
-    public void onFailed(Job job) {
-        failed = job;
-    }
-
-    @Override
     public void onFinished(Job job) {
         this.finished = job;
         latch.countDown();
@@ -70,28 +64,28 @@
     }
 
     public void assertFailed() {
-        if (failed == null) {
+        if (finished == null || !finished.hasFailures()) {
             fail("Job didn't fail. onFailed never called.");
         }
     }
 
     public void assertFilesFailed(ArrayList<String> names) {
-        if (failed == null) {
+        if (finished == null || !finished.hasFailures()) {
             fail("Can't test failed documetns. Job didn't fail.");
         }
 
-        assertEquals(failed.failedFiles.size(), names.size());
+        assertEquals(finished.failedFiles.size(), names.size());
         for (String name : names) {
             assertFileFailed(name);
         }
     }
 
     public void assertFileFailed(String name) {
-        if (failed == null) {
+        if (finished == null || !finished.hasFailures()) {
             fail("Can't test failed documetns. Job didn't fail.");
         }
 
-        for (DocumentInfo failed : failed.failedFiles) {
+        for (DocumentInfo failed : finished.failedFiles) {
             if (name.equals(failed.displayName)) {
                 return;
             }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index c7d17dc..409f6a7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -18,7 +18,6 @@
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.admin.DevicePolicyManager;
-import android.auditing.SecurityLog;
 import android.content.Context;
 import android.os.UserHandle;
 import android.util.AttributeSet;
@@ -424,11 +423,6 @@
         }
 
         public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
-            if (SecurityLog.isLoggingEnabled()) {
-                SecurityLog.writeEvent(SecurityLog.TAG_DEVICE_UNLOCK_ATTEMPT,
-                        (success ? 1 : 0),
-                        mCurrentSecuritySelection.name());
-            }
             KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
             if (success) {
                 monitor.clearFailedUnlockAttempts();
diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
index 7b57d89..2b44d51 100644
--- a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
+++ b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
@@ -50,7 +50,8 @@
 
 static jclass app_fuse_class;
 static jmethodID app_fuse_get_file_size;
-static jmethodID app_fuse_get_object_bytes;
+static jmethodID app_fuse_read_object_bytes;
+static jfieldID app_fuse_buffer;
 
 // NOTE:
 // FuseRequest and FuseResponse shares the same buffer to save memory usage, so the handlers must
@@ -282,7 +283,7 @@
         out->prepare_buffer(0);
         const int64_t result = get_object_bytes(it->second, offset, size, out->data());
         if (result < 0) {
-            return -EIO;
+            return result;
         }
         out->set_size(result);
         return 0;
@@ -332,20 +333,24 @@
             uint64_t offset,
             uint32_t size,
             void* buf) {
-        ScopedLocalRef<jbyteArray> array(env_, static_cast<jbyteArray>(env_->CallObjectMethod(
+        const jlong read_size = env_->CallLongMethod(
                 self_,
-                app_fuse_get_object_bytes,
-                inode,
-                offset,
-                size)));
+                app_fuse_read_object_bytes,
+                static_cast<jint>(inode),
+                static_cast<jlong>(offset),
+                static_cast<jlong>(size));
+        if (read_size <= 0) {
+            return read_size;
+        }
+        ScopedLocalRef<jbyteArray> array(
+                env_, static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
         if (array.get() == nullptr) {
-            return -1;
+            return -EFAULT;
         }
         ScopedByteArrayRO bytes(env_, array.get());
         if (bytes.get() == nullptr) {
-            return -1;
+            return -ENOMEM;
         }
-        const uint32_t read_size = std::min(static_cast<uint32_t>(bytes.size()), size);
         memcpy(buf, bytes.get(), read_size);
         return read_size;
     }
@@ -451,10 +456,16 @@
         return -1;
     }
 
-    app_fuse_get_object_bytes = env->GetMethodID(
-            app_fuse_class, "getObjectBytes", "(IJI)[B");
-    if (app_fuse_get_object_bytes == nullptr) {
-        ALOGE("Can't find getObjectBytes");
+    app_fuse_read_object_bytes = env->GetMethodID(
+            app_fuse_class, "readObjectBytes", "(IJJ)J");
+    if (app_fuse_read_object_bytes == nullptr) {
+        ALOGE("Can't find readObjectBytes");
+        return -1;
+    }
+
+    app_fuse_buffer = env->GetFieldID(app_fuse_class, "mBuffer", "[B");
+    if (app_fuse_buffer == nullptr) {
+        ALOGE("Can't find mBuffer");
         return -1;
     }
 
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
index 1300c47..6a98405 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
@@ -16,9 +16,11 @@
 
 package com.android.mtp;
 
+import android.annotation.WorkerThread;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.storage.StorageManager;
+import android.system.OsConstants;
 import android.util.Log;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
@@ -40,6 +42,13 @@
 
     private final String mName;
     private final Callback mCallback;
+
+    /**
+     * Buffer for read bytes request.
+     * Don't use the buffer from the out of AppFuseMessageThread.
+     */
+    private byte[] mBuffer = new byte[MAX_READ];
+
     private Thread mMessageThread;
     private ParcelFileDescriptor mDeviceFd;
 
@@ -82,28 +91,48 @@
     }
 
     static interface Callback {
+        /**
+         * Returns file size for the given inode.
+         * @param inode
+         * @return File size. Must not be negative.
+         * @throws FileNotFoundException
+         */
         long getFileSize(int inode) throws FileNotFoundException;
-        byte[] getObjectBytes(int inode, long offset, int size) throws IOException;
+
+        /**
+         * Returns flie bytes for the give inode.
+         * @param inode
+         * @param offset Offset for file bytes.
+         * @param size Size for file bytes.
+         * @param bytes Buffer to store file bytes.
+         * @return Number of read bytes. Must not be negative.
+         * @throws IOException
+         */
+        long readObjectBytes(int inode, long offset, long size, byte[] bytes) throws IOException;
     }
 
     @UsedByNative("com_android_mtp_AppFuse.cpp")
+    @WorkerThread
     private long getFileSize(int inode) {
         try {
             return mCallback.getFileSize(inode);
-        } catch (IOException e) {
-            return -1;
+        } catch (FileNotFoundException e) {
+            return -OsConstants.ENOENT;
         }
     }
 
     @UsedByNative("com_android_mtp_AppFuse.cpp")
-    private byte[] getObjectBytes(int inode, long offset, int size) {
+    @WorkerThread
+    private long readObjectBytes(int inode, long offset, long size) {
         if (offset < 0 || size < 0 || size > MAX_READ) {
-            return null;
+            return -OsConstants.EINVAL;
         }
         try {
-            return mCallback.getObjectBytes(inode, offset, size);
+            // It's OK to share the same mBuffer among requests because the requests are processed
+            // by AppFuseMessageThread sequentially.
+            return mCallback.readObjectBytes(inode, offset, size, mBuffer);
         } catch (IOException e) {
-            return null;
+            return -OsConstants.EIO;
         }
     }
 
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 3ac1b3d..6b5f16a 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -16,8 +16,6 @@
 
 package com.android.mtp;
 
-import static com.android.internal.util.Preconditions.checkArgument;
-
 import android.content.ContentResolver;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
@@ -40,7 +38,6 @@
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -391,16 +388,12 @@
     }
 
     private class AppFuseCallback implements AppFuse.Callback {
-        final byte[] mBytes = new byte[AppFuse.MAX_READ];
-
         @Override
-        public byte[] getObjectBytes(int inode, long offset, int size) throws IOException {
+        public long readObjectBytes(
+                int inode, long offset, long size, byte[] buffer) throws IOException {
             final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode));
-            final long readSize = mMtpManager.getPartialObject(
-                    identifier.mDeviceId, identifier.mObjectHandle, offset, size, mBytes);
-            // TODO: Change signature so that getObjectBytes can return read size without copying
-            // bytes.
-            return Arrays.copyOf(mBytes, (int) readSize);
+            return mMtpManager.getPartialObject(
+                    identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
         }
 
         @Override
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
index 6354880..c0973bd 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
@@ -77,30 +77,35 @@
 
     public void testReadFile() throws IOException {
         final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final byte[] BYTES = new byte[] { 'a', 'b', 'c', 'd', 'e' };
+        final int fileInode = 10;
+        final byte[] fileBytes = new byte[] { 'a', 'b', 'c', 'd', 'e' };
         final AppFuse appFuse = new AppFuse(
                 "test",
                 new TestCallback() {
                     @Override
                     public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode == INODE) {
-                            return BYTES.length;
+                        if (inode == fileInode) {
+                            return fileBytes.length;
                         }
                         return super.getFileSize(inode);
                     }
 
                     @Override
-                    public byte[] getObjectBytes(int inode, long offset, int size)
+                    public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
                             throws IOException {
-                        if (inode == INODE) {
-                            return Arrays.copyOfRange(BYTES, (int) offset, (int) offset + size);
+                        if (inode == fileInode) {
+                            int i = 0;
+                            while (i < size && i + offset < fileBytes.length)  {
+                                bytes[i] = fileBytes[(int) (i + offset)];
+                                i++;
+                            }
+                            return i;
                         }
-                        return super.getObjectBytes(inode, offset, size);
+                        return super.readObjectBytes(inode, offset, size, bytes);
                     }
                 });
         appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(INODE);
+        final ParcelFileDescriptor fd = appFuse.openFile(fileInode);
         try (final ParcelFileDescriptor.AutoCloseInputStream stream =
                 new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
             final byte[] buffer = new byte[1024];
@@ -117,7 +122,7 @@
         }
 
         @Override
-        public byte[] getObjectBytes(int inode, long offset, int size)
+        public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
                 throws IOException {
             throw new IOException();
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index d3c1364..ad567d3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -178,7 +178,7 @@
                     if (userInfo.isManagedProfile()) {
                         // If userInfo.id is a managed profile, we also need to look at
                         // the policies set on the parent.
-                        DevicePolicyManager parentDpm = dpm.getParentProfileInstance(admin);
+                        DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
                         if ((parentDpm.getKeyguardDisabledFeatures(admin, userInfo.id)
                                 & keyguardFeatures) != 0) {
                             if (enforcedAdmin == null) {
@@ -375,7 +375,7 @@
                     if (userInfo.isManagedProfile()) {
                         // If userInfo.id is a managed profile, we also need to look at
                         // the policies set on the parent.
-                        DevicePolicyManager parentDpm = dpm.getParentProfileInstance(admin);
+                        DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
                         if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
                             if (enforcedAdmin == null) {
                                 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 2ee4b12..5b8ed28 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -37,6 +37,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.support.annotation.NonNull;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
@@ -104,7 +105,8 @@
     private static final int PSK_WPA2 = 2;
     private static final int PSK_WPA_WPA2 = 3;
 
-    private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000;
+    public static final int SIGNAL_LEVELS = 4;
+
     private final Context mContext;
 
     private String ssid;
@@ -167,7 +169,7 @@
     }
 
     @Override
-    public int compareTo(AccessPoint other) {
+    public int compareTo(@NonNull AccessPoint other) {
         // Active one goes first.
         if (isActive() && !other.isActive()) return -1;
         if (!isActive() && other.isActive()) return 1;
@@ -182,8 +184,9 @@
         if (networkId == WifiConfiguration.INVALID_NETWORK_ID
                 && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
 
-        // Sort by signal strength.
-        int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
+        // Sort by signal strength, bucketed by level
+        int difference = WifiManager.calculateSignalLevel(other.mRssi, SIGNAL_LEVELS)
+                - WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
         if (difference != 0) {
             return difference;
         }
@@ -260,7 +263,7 @@
         if (mRssi == Integer.MAX_VALUE) {
             return -1;
         }
-        return WifiManager.calculateSignalLevel(mRssi, 4);
+        return WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
     }
 
     public int getRssi() {
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 2ea8c9c..d0c2d29 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -35,3 +35,4 @@
 }
 
 -keep class ** extends android.support.v14.preference.PreferenceFragment
+-keep class com.android.systemui.tuner.*
diff --git a/packages/SystemUI/res/drawable/clipboard_empty.xml b/packages/SystemUI/res/drawable/clipboard_empty.xml
new file mode 100644
index 0000000..14a5ad2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/clipboard_empty.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19.0,2.0l-4.18,0.0C14.0,0.84 13.3,0.0 12.0,0.0c-1.3,0.0 -2.0,0.84 -2.82,2.0L5.0,2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,16.0c0.0,1.0 0.9,2.0 2.0,2.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,0.0c0.55,0.0 1.0,0.45 1.0,1.0s-0.45,1.0 -1.0,1.0 -1.0,-0.45 -1.0,-1.0 0.45,-1.0 1.0,-1.0zm7.0,18.0L5.0,20.0L5.0,4.0l2.0,0.0l0.0,3.0l10.0,0.0L17.0,4.0l2.0,0.0l0.0,16.0z" />
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/clipboard_full.xml b/packages/SystemUI/res/drawable/clipboard_full.xml
new file mode 100644
index 0000000..2d46870
--- /dev/null
+++ b/packages/SystemUI/res/drawable/clipboard_full.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24.0dp"
+    android:height="24.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19.0,2.0l-4.18,0.0C14.0,0.84 13.3,0.0 12.0,0.0c-1.3,0.0 -2.0,0.84 -2.82,2.0L5.0,2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,16.0c0.0,1.0 0.9,2.0 2.0,2.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,0.0c0.55,0.0 1.0,0.45 1.0,1.0s-0.45,1.0 -1.0,1.0 -1.0,-0.45 -1.0,-1.0 0.45,-1.0 1.0,-1.0zm7.0,18.0L5.0,20.0L5.0,4.0l2.0,0.0l0.0,3.0l10.0,0.0L17.0,4.0l2.0,0.0l0.0,16.0z M 6,8 l 12,0 l 0,11 l -12,0 l 0,-11z" />
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/ic_drag_handle.xml b/packages/SystemUI/res/drawable/ic_drag_handle.xml
new file mode 100644
index 0000000..9b319f1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_drag_handle.xml
@@ -0,0 +1,24 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M20.0,9.0L4.0,9.0l0.0,2.0l16.0,0.0L20.0,9.0zM4.0,15.0l16.0,0.0l0.0,-2.0L4.0,13.0l0.0,2.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_width.xml b/packages/SystemUI/res/drawable/ic_width.xml
new file mode 100644
index 0000000..a302c81
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_width.xml
@@ -0,0 +1,28 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M7.77,6.76L6.23,5.4 0.82,12.0l5.41,6.52 1.54,-1.28L3.42,12.0l4.35,-5.24z
+        M17.77,5.48l-1.54,1.28L20.58,12.0l-4.35,5.24 1.54,1.28L23.18,12.0l-5.41,-6.52z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M2.0,13.0l20.0,0.0l0.0,-2.0l-20.0,0.0l0.0,2.0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml b/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml
new file mode 100644
index 0000000..6a417e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml
@@ -0,0 +1,54 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="16dp"
+    android:width="28dp"
+    android:viewportHeight="48"
+    android:viewportWidth="72" >
+    <group
+        android:name="dismiss_all"
+        android:translateX="48"
+        android:translateY="6" >
+        <group
+            android:name="3"
+            android:translateX="-24"
+            android:translateY="36" >
+            <path
+                android:name="rectangle_path_1_2"
+                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="1" />
+        </group>
+        <group
+            android:name="2"
+            android:translateX="-12"
+            android:translateY="18" >
+            <path
+                android:name="rectangle_path_1_1"
+                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="1" />
+        </group>
+        <group
+            android:name="1" >
+            <path
+                android:name="rectangle_path_1"
+                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="1" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/switchbar_background.xml b/packages/SystemUI/res/drawable/switchbar_background.xml
new file mode 100644
index 0000000..8d97c46
--- /dev/null
+++ b/packages/SystemUI/res/drawable/switchbar_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item android:drawable="@color/switch_bar_background" />
+</ripple>
+
diff --git a/packages/SystemUI/res/layout-land/nav_bar_tuner.xml b/packages/SystemUI/res/layout-land/nav_bar_tuner.xml
new file mode 100644
index 0000000..a430b73
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/nav_bar_tuner.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:elevation="4dp"
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
+        android:paddingStart="8dp"
+        android:paddingEnd="8dp"
+        android:background="@android:color/white"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/preview"
+            android:paddingStart="8dp"
+            android:paddingEnd="8dp"
+            android:textColor="?android:attr/colorAccent"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <FrameLayout
+            android:id="@+id/nav_preview_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml b/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml
new file mode 100644
index 0000000..5479157
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:elevation="4dp"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
+        android:paddingStart="12dp"
+        android:paddingEnd="12dp"
+        android:layout_gravity="bottom"
+        android:background="@android:color/white"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/preview"
+            android:paddingTop="8dp"
+            android:paddingBottom="8dp"
+            android:textColor="?android:attr/colorAccent"
+            android:textAppearance="?android:attr/textAppearanceLarge" />
+
+        <FrameLayout
+            android:id="@+id/nav_preview_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/clipboard.xml b/packages/SystemUI/res/layout/clipboard.xml
new file mode 100644
index 0000000..441d6737
--- /dev/null
+++ b/packages/SystemUI/res/layout/clipboard.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.systemui.tuner.ClipboardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/navigation_side_padding"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    android:scaleType="center"
+    android:contentDescription="@string/clipboard"
+    />
+
diff --git a/packages/SystemUI/res/layout/color_matrix_settings.xml b/packages/SystemUI/res/layout/color_matrix_settings.xml
new file mode 100644
index 0000000..3725e78
--- /dev/null
+++ b/packages/SystemUI/res/layout/color_matrix_settings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <include layout="@layout/switch_bar" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/custom_key.xml b/packages/SystemUI/res/layout/custom_key.xml
new file mode 100644
index 0000000..0b5cb72
--- /dev/null
+++ b/packages/SystemUI/res/layout/custom_key.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.systemui.statusbar.policy.KeyButtonView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/navigation_side_padding"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    android:scaleType="center"
+    android:tint="@android:color/white"
+    android:contentDescription="@string/accessibility_key" />
+
diff --git a/packages/SystemUI/res/layout/nav_bar_tuner.xml b/packages/SystemUI/res/layout/nav_bar_tuner.xml
new file mode 100644
index 0000000..5479157
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_bar_tuner.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:elevation="4dp"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
+        android:paddingStart="12dp"
+        android:paddingEnd="12dp"
+        android:layout_gravity="bottom"
+        android:background="@android:color/white"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/preview"
+            android:paddingTop="8dp"
+            android:paddingBottom="8dp"
+            android:textColor="?android:attr/colorAccent"
+            android:textAppearance="?android:attr/textAppearanceLarge" />
+
+        <FrameLayout
+            android:id="@+id/nav_preview_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml b/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml
new file mode 100644
index 0000000..b237633
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.systemui.tuner.PreviewNavInflater
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:background="@android:color/black"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/navigation_bar_size">
+
+    <include android:id="@+id/rot0" layout="@layout/navigation_layout" />
+
+    <include android:id="@+id/rot90" layout="@layout/navigation_layout_rot90" />
+
+</com.android.systemui.tuner.PreviewNavInflater>
diff --git a/packages/SystemUI/res/layout/nav_control_widget.xml b/packages/SystemUI/res/layout/nav_control_widget.xml
new file mode 100644
index 0000000..51dd68f
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_control_widget.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:gravity="center"
+    android:orientation="horizontal">
+
+    <ImageView
+        android:id="@+id/width"
+        android:layout_width="48dp"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_width"
+        android:clickable="true"
+        android:tint="?android:attr/textColorPrimary" />
+
+    <View
+        android:layout_width="1dp"
+        android:layout_height="match_parent"
+        android:background="?android:attr/listDivider" />
+
+    <ImageView
+        android:id="@+id/close"
+        android:layout_width="48dp"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_close"
+        android:clickable="true"
+        android:tint="?android:attr/textColorPrimary" />
+
+    <View
+        android:layout_width="1dp"
+        android:layout_height="match_parent"
+        android:background="?android:attr/listDivider" />
+
+    <ImageView
+        android:id="@+id/drag"
+        android:layout_width="48dp"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_drag_handle"
+        android:clickable="true"
+        android:tint="?android:attr/textColorPrimary" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/nav_width_view.xml b/packages/SystemUI/res/layout/nav_width_view.xml
new file mode 100644
index 0000000..6a72faf
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_width_view.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<SeekBar
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/seekbar"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:paddingTop="12dp"
+    android:paddingBottom="4dp" />
diff --git a/packages/SystemUI/res/layout/preference_matrix.xml b/packages/SystemUI/res/layout/preference_matrix.xml
index ebf486f..1f6066e 100644
--- a/packages/SystemUI/res/layout/preference_matrix.xml
+++ b/packages/SystemUI/res/layout/preference_matrix.xml
@@ -19,82 +19,86 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="horizontal">
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_weight="1" />
-    <GridLayout
-        android:id="@+id/edit_group"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:rowCount="5"
-        android:columnCount="5">
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:orientation="vertical">
 
-        <Space android:layout_width="40dp" />
+    <LinearLayout
+        android:id="@+id/r_group"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"
+        android:orientation="horizontal">
 
         <TextView
-            android:layout_width="40dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:text="@string/color_modification_r"
             android:gravity="center"
             android:textAppearance="?android:attr/textAppearanceMedium" />
 
+        <SeekBar android:id="@*android:id/seekbar"
+            android:layout_marginStart="16dp"
+            android:layout_gravity="center_vertical"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/g_group"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"
+        android:orientation="horizontal">
+
         <TextView
-            android:layout_width="40dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:text="@string/color_modification_g"
             android:gravity="center"
             android:textAppearance="?android:attr/textAppearanceMedium" />
 
+        <SeekBar android:id="@*android:id/seekbar"
+            android:layout_marginStart="16dp"
+            android:layout_gravity="center_vertical"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/b_group"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"
+        android:orientation="horizontal">
+
         <TextView
-            android:layout_width="40dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:text="@string/color_modification_b"
             android:gravity="center"
             android:textAppearance="?android:attr/textAppearanceMedium" />
 
-        <Space android:layout_width="40dp" />
+        <SeekBar android:id="@*android:id/seekbar"
+            android:layout_marginStart="16dp"
+            android:layout_gravity="center_vertical"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+    </LinearLayout>
 
-        <TextView
-            android:layout_width="40dp"
-            android:text="@string/color_modification_r"
-            android:gravity="center"
-            android:textAppearance="?android:attr/textAppearanceMedium" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-
-        <TextView
-            android:layout_width="40dp"
-            android:text="@string/color_modification_g"
-            android:gravity="center"
-            android:textAppearance="?android:attr/textAppearanceMedium" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-
-        <TextView
-            android:layout_width="40dp"
-            android:text="@string/color_modification_b"
-            android:gravity="center"
-            android:textAppearance="?android:attr/textAppearanceMedium" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-
-        <Space android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-        <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-
-    </GridLayout>
     <Button
         android:id="@+id/apply"
-        android:layout_width="0dp"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:layout_gravity="bottom"
+        android:layout_gravity="end"
         android:text="@string/color_apply" />
+
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents_history_clear_all_button.xml b/packages/SystemUI/res/layout/recents_history_clear_all_button.xml
new file mode 100644
index 0000000..05f0979
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_history_clear_all_button.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/button"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="start|center_vertical"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:paddingTop="14dp"
+    android:paddingBottom="14dp"
+    android:drawableStart="@drawable/recents_dismiss_all_history"
+    android:contentDescription="@string/recents_history_clear_all_button_label"
+    android:textSize="14sp"
+    android:textColor="#FFFFFF"
+    android:textAllCaps="true"
+    android:shadowColor="#99000000"
+    android:shadowDx="0"
+    android:shadowDy="2"
+    android:shadowRadius="5"
+    android:fontFamily="sans-serif-medium"
+    android:background="?android:selectableItemBackground"
+    android:visibility="invisible" />
diff --git a/packages/SystemUI/res/layout/switch_bar.xml b/packages/SystemUI/res/layout/switch_bar.xml
new file mode 100644
index 0000000..f98de96
--- /dev/null
+++ b/packages/SystemUI/res/layout/switch_bar.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/switch_bar"
+    android:layout_width="match_parent"
+    android:layout_height="?android:attr/actionBarSize"
+    android:background="@drawable/switchbar_background"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:clickable="true"
+    android:gravity="center">
+
+    <TextView android:id="@+id/switch_text"
+        android:layout_height="wrap_content"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_gravity="center_vertical"
+        android:paddingStart="48dp"
+        android:maxLines="2"
+        android:ellipsize="end"
+        android:textAppearance="@android:style/TextAppearance.Material.Title"
+        android:textColor="?android:attr/textColorPrimaryInverse"
+        android:textAlignment="viewStart"
+        android:text="@string/switch_bar_on" />
+
+    <Switch
+        android:id="@android:id/switch_widget"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:background="@null"
+        android:theme="@style/ThemeOverlay.SwitchBar" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5e25d2c..f0d9949 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -151,4 +151,7 @@
     <color name="qs_tile_tint_unavailable">#40ffffff</color>
     <color name="qs_tile_tint_inactive">#4dffffff</color>
     <color name="qs_tile_tint_active">#ffffffff</color>
+
+    <color name="switch_bar_background">#ff37474f</color>
+    <color name="switch_accent_color">#ff7fcac3</color>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b096934..32da3c6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -716,6 +716,8 @@
     <string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
     <!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
     <string name="recents_history_button_label">History</string>
+    <!-- Recents: History clear all string. [CHAR LIMIT=NONE] -->
+    <string name="recents_history_clear_all_button_label">Clear</string>
 
     <!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
     <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
@@ -1249,6 +1251,9 @@
     <!-- Label for custom color transform [CHAR LIMIT=30] -->
     <string name="color_matrix_custom">Custom colors</string>
 
+    <!-- Label for auto color transforms [CHAR LIMIT=30] -->
+    <string name="color_matrix_auto">Auto</string>
+
     <!-- Label for unknown color transform [CHAR LIMIT=30] -->
     <string name="color_matrix_unknown">Unknown colors</string>
 
@@ -1338,4 +1343,61 @@
     <!-- Accessibility description for data saver being off [CHAR LIMIT=NONE] -->
     <string name="accessibility_data_saver_off">Data Saver is off</string>
 
+    <!-- Label for feature switch [CHAR LIMIT=30] -->
+    <string name="switch_bar_on">On</string>
+
+    <!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
+    <string name="nav_bar">Navigation bar</string>
+
+    <!-- SysUI Tuner: Group of buttons that show on the start of the screen [CHAR LIMIT=30] -->
+    <string name="start">Start</string>
+    <!-- SysUI Tuner: Group of buttons that show on the center of the screen [CHAR LIMIT=30] -->
+    <string name="center">Center</string>
+    <!-- SysUI Tuner: Group of buttons that show on the end of the screen [CHAR LIMIT=30] -->
+    <string name="end">End</string>
+    <!-- SysUI Tuner: Name of space used in custom navigation bar layouts [CHAR LIMIT=30] -->
+    <string name="space">Spacer</string>
+    <!-- SysUI Tuner: Name of Combination Menu / Keyboard Switcher button [CHAR LIMIT=30] -->
+    <string name="menu_ime">Menu / Keyboard Switcher</string>
+    <!-- SysUI Tuner: Title for dialog to add a button [CHAR LIMIT=30] -->
+    <string name="select_button">Select button to add</string>
+    <!-- SysUI Tuner: Button to add a button [CHAR LIMIT=30] -->
+    <string name="add_button">Add button</string>
+    <!-- SysUI Tuner: Save the current settings [CHAR LIMIT=30] -->
+    <string name="save">Save</string>
+    <!-- SysUI Tuner: Reset to default settings [CHAR LIMIT=30] -->
+    <string name="reset">Reset</string>
+
+    <!-- SysUI Tuner: Title of no home warning dialog [CHAR LIMIT=30] -->
+    <string name="no_home_title">No home button found</string>
+    <!-- SysUI Tuner: Message of no home warning dialog [CHAR LIMIT=NONE] -->
+    <string name="no_home_message">A home button is required to be able to navigate this device. Please add a home button before saving.</string>
+
+    <!-- SysUI Tuner: Adjust button width dialog title [CHAR LIMIT=60] -->
+    <string name="adjust_button_width">Adjust button width</string>
+
+    <!-- SysUI Tuner: Nav bar button that holds the clipboard [CHAR LIMIT=30] -->
+    <string name="clipboard">Clipboard</string>
+
+    <!-- SysUI Tuner: Description of nav bar button that holds the clipboard [CHAR LIMIT=NONE] -->
+    <string name="clipboard_description">The Clipboard allows items to be dragged directly to the clipboard. Items can also be dragged directly out of the clipboard when present.</string>
+
+    <!-- SysUI Tuner: Accessibility description for custom nav key [CHAR LIMIT=NONE] -->
+    <string name="accessibility_key">Custom navigation button</string>
+
+    <!-- SysUI Tuner: Nav bar button that emulates a keycode [CHAR LIMIT=30] -->
+    <string name="keycode">Keycode</string>
+
+    <!-- SysUI Tuner: Description of nav bar button that emulates a keycode [CHAR LIMIT=NONE] -->
+    <string name="keycode_description">Keycode buttons allow keyboard keys to
+        be added to the Navigation Bar. When pressed they emulate the selected
+        keyboard key. First the key must be selected for the button, followed
+        by an image to be shown on the button.</string>
+
+    <!-- SysUI Tuner: Title of dialog to select which key to emulate [CHAR LIMIT=60] -->
+    <string name="select_keycode">Select Keyboard Button</string>
+
+    <!-- SysUI Tuner: Label for preview area in navigation bar tuner [CHAR LIMIT=NONE] -->
+    <string name="preview">Preview</string>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index d432a62..c64327d 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -18,15 +18,15 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Button to close PIP on PIP UI -->
-    <string name="pip_exit">Close PIP</string>
+    <string name="pip_exit" translatable="false">Close PIP</string>
     <!-- Button to move PIP screen to the fullscreen on PIP UI -->
-    <string name="pip_fullscreen">Full screen</string>
+    <string name="pip_fullscreen" translatable="false">Full screen</string>
     <!-- Button to play the current media on PIP UI -->
-    <string name="pip_play">Play</string>
+    <string name="pip_play" translatable="false">Play</string>
     <!-- Button to pause the current media on PIP UI -->
-    <string name="pip_pause">Pause</string>
+    <string name="pip_pause" translatable="false">Pause</string>
     <!-- Button to close PIP overlay menu on PIP UI -->
-    <string name="pip_cancel">Cancel</string>
+    <string name="pip_cancel" translatable="false">Cancel</string>
     <!-- Overlay text on PIP -->
-    <string name="pip_hold_home">Hold HOME to control PIP</string>
+    <string name="pip_hold_home" translatable="false">Hold HOME to control PIP</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e40a0f4..9931ab9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -310,6 +310,7 @@
     </style>
 
     <style name="TunerSettings" parent="@android:style/Theme.Material.Settings">
+        <item name="android:windowActionBar">false</item>
         <item name="preferenceTheme">@style/TunerPreferenceTheme</item>
     </style>
 
@@ -345,4 +346,8 @@
         <item name="android:textColor">@*android:color/material_deep_teal_500</item>
     </style>
 
+    <style name="ThemeOverlay.SwitchBar" parent="@android:style/ThemeOverlay">
+        <item name="android:colorAccent">@color/switch_accent_color</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 67a7a23..febe518 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -166,6 +166,11 @@
 
     </PreferenceScreen>
 
+    <Preference
+        android:key="nav_bar"
+        android:title="@string/nav_bar"
+        android:fragment="com.android.systemui.tuner.NavBarTuner" />
+
     <!-- Warning, this goes last. -->
     <Preference
         android:summary="@string/tuner_persistent_warning"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0475c72..958572f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -24,7 +24,6 @@
 import android.app.SearchManager;
 import android.app.StatusBarManager;
 import android.app.trust.TrustManager;
-import android.auditing.SecurityLog;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -1371,10 +1370,8 @@
      * @see #KEYGUARD_DONE
      */
     private void handleKeyguardDone(boolean authenticated) {
-        if (SecurityLog.isLoggingEnabled()
-                && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
-            SecurityLog.writeEvent(SecurityLog.TAG_DEVICE_UNLOCK_ATTEMPT,
-                    (authenticated ? 1 : 0), "Unknown");
+        if (mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
+            mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed();
         }
         if (DEBUG) Log.d(TAG, "handleKeyguardDone");
         synchronized (this) {
@@ -1487,9 +1484,8 @@
      * @see #SHOW
      */
     private void handleShow(Bundle options) {
-        if (SecurityLog.isLoggingEnabled()
-                && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
-            SecurityLog.writeEvent(SecurityLog.TAG_DEVICE_LOCKED, "");
+        if (mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
+            mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured();
         }
         synchronized (KeyguardViewMediator.this) {
             if (!mSystemReady) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 20e2fa4..789e72e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -35,6 +35,7 @@
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.DisplayController;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -389,6 +390,7 @@
         UserInfoController getUserInfoController();
         BatteryController getBatteryController();
         TileServices getTileServices();
+        DisplayController getDisplayController();
         void removeTile(String tileSpec);
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 8ae2d7b..3748a30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -72,8 +72,9 @@
             }
             mCurrentTiles = tileSpecs;
             final TileGroup group = new TileGroup("com.android.settings", mContext);
+            boolean hasColorMod = host.getDisplayController().isEnabled();
             String possible = mContext.getString(R.string.quick_settings_tiles_default)
-                    + ",hotspot,inversion,saver";
+                    + ",hotspot,inversion,saver" + (hasColorMod ? ",colors" : "");
             String[] possibleTiles = possible.split(",");
             for (int i = 0; i < possibleTiles.length; i++) {
                 final String spec = possibleTiles[i];
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index cd2c942..c3b794d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -34,7 +34,6 @@
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
-import android.view.ViewStub;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 
@@ -57,7 +56,6 @@
 import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
 import com.android.systemui.recents.events.activity.ShowHistoryEvent;
 import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
-import com.android.systemui.recents.events.activity.ToggleHistoryEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -71,7 +69,6 @@
 import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
-import com.android.systemui.recents.history.RecentsHistoryView;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsPackageMonitor;
@@ -83,8 +80,6 @@
 import com.android.systemui.recents.views.SystemBarScrimViews;
 import com.android.systemui.statusbar.BaseStatusBar;
 
-import java.util.ArrayList;
-
 /**
  * The main Recents activity that is started from AlternateRecentsComponent.
  */
diff --git a/location/java/android/location/IGpsStatusProvider.aidl b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java
similarity index 60%
copy from location/java/android/location/IGpsStatusProvider.aidl
copy to packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java
index cf277c8..98c0a69 100644
--- a/location/java/android/location/IGpsStatusProvider.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -14,16 +14,13 @@
  * limitations under the License.
  */
 
-package android.location;
+package com.android.systemui.recents.events.activity;
 
-import android.location.IGpsStatusListener;
+import com.android.systemui.recents.events.EventBus;
 
 /**
- * An interface for location providers that provide GPS status information.
- *
- * {@hide}
+ * This is sent when the history is to be cleared
  */
-interface IGpsStatusProvider {
-    void addGpsStatusListener(IGpsStatusListener listener);
-    void removeGpsStatusListener(IGpsStatusListener listener);
+public class ClearHistoryEvent extends EventBus.AnimatedEvent {
+    // Simple event
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
index 2c28c29..e288878 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
@@ -34,6 +34,7 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
 import com.android.systemui.recents.events.activity.HideHistoryEvent;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
@@ -76,6 +77,10 @@
             // This callback is only made for TaskRow view holders
             ImageView iv = (ImageView) content.findViewById(R.id.icon);
             iv.setImageDrawable(task.icon);
+            iv.animate()
+                    .alpha(1f)
+                    .setDuration(100)
+                    .start();
         }
 
         @Override
@@ -83,6 +88,7 @@
             // This callback is only made for TaskRow view holders
             ImageView iv = (ImageView) content.findViewById(R.id.icon);
             iv.setImageBitmap(null);
+            iv.animate().cancel();
         }
 
         @Override
@@ -210,6 +216,23 @@
     }
 
     /**
+     * Removes all historical tasks.
+     */
+    public void removeAllTasks() {
+        for (int i = mRows.size() - 1; i >= 0; i--) {
+            Row row = mRows.get(i);
+            if (row.getViewType() == TASK_ROW_VIEW_TYPE) {
+                TaskRow taskRow = (TaskRow) row;
+                Task task = taskRow.task;
+                mStack.removeTask(task, TaskViewAnimation.IMMEDIATE);
+                EventBus.getDefault().send(new DeleteTaskDataEvent(task));
+                i = removeTaskRow(i);
+            }
+        }
+        dismissHistory();
+    }
+
+    /**
      * Returns the row at the given {@param position}.
      */
     public Row getRow(int position) {
@@ -247,8 +270,10 @@
                 taskRow.task.addCallback(holder);
                 TextView tv = (TextView) holder.content.findViewById(R.id.description);
                 tv.setText(taskRow.task.title);
+                ImageView iv = (ImageView) holder.content.findViewById(R.id.icon);
+                iv.setAlpha(0f);
                 holder.content.setOnClickListener(taskRow);
-                loader.loadTaskData(taskRow.task);
+                loader.loadTaskData(taskRow.task, false /* fetchAndInvalidateThumbnails */);
                 break;
             }
         }
@@ -257,19 +282,25 @@
     @Override
     public void onViewRecycled(ViewHolder holder) {
         RecentsTaskLoader loader = Recents.getTaskLoader();
-
         int position = holder.getAdapterPosition();
         if (position != RecyclerView.NO_POSITION) {
             Row row = mRows.get(position);
             int viewType = row.getViewType();
             if (viewType == TASK_ROW_VIEW_TYPE) {
                 TaskRow taskRow = (TaskRow) row;
-                taskRow.task.removeCallback(holder);
                 loader.unloadTaskData(taskRow.task);
+                taskRow.task.removeCallback(holder);
             }
         }
     }
 
+    @Override
+    public boolean onFailedToRecycleView(ViewHolder holder) {
+        // Always recycle views, even if it is animating
+        onViewRecycled(holder);
+        return true;
+    }
+
     public void onTaskRemoved(Task task, int position) {
         // Since this is removed from the history, we need to update the stack as well to ensure
         // that the model is correct. Since the stack is hidden, we can update it immediately.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
index 6dd4b53..96b5cac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
@@ -37,13 +37,12 @@
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.ClearHistoryEvent;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent;
 import com.android.systemui.recents.events.ui.UpdateBackgroundScrimEvent;
-import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.AnimateableViewBounds;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 /**
  * A list of the recent tasks that are not in the stack.
@@ -96,7 +95,7 @@
     /**
      * Updates this history view with the recent tasks, and then shows it.
      */
-    public void show(TaskStack stack, int stackHeight) {
+    public void show(TaskStack stack, int stackHeight, View clearAllButton) {
         setVisibility(View.VISIBLE);
         setAlpha(0f);
         setTranslationY(-stackHeight * TRANSLATION_Y_PCT);
@@ -106,6 +105,13 @@
                 .setDuration(mHistoryTransitionDuration)
                 .setInterpolator(mFastOutSlowInInterpolator)
                 .setUpdateListener(this)
+                .start();
+        clearAllButton.setVisibility(View.VISIBLE);
+        clearAllButton.setAlpha(0f);
+        clearAllButton.animate()
+                .alpha(1f)
+                .setDuration(mHistoryTransitionDuration)
+                .setInterpolator(mFastOutSlowInInterpolator)
                 .withLayer()
                 .start();
         mAdapter.updateTasks(getContext(), stack);
@@ -118,7 +124,7 @@
     /**
      * Hides this history view.
      */
-    public void hide(boolean animate, int stackHeight) {
+    public void hide(boolean animate, int stackHeight, final View clearAllButton) {
         if (animate) {
             animate()
                     .alpha(0f)
@@ -132,11 +138,25 @@
                             setVisibility(View.INVISIBLE);
                         }
                     })
+                    .start();
+            clearAllButton.animate()
+                    .alpha(0f)
+                    .translationY(0f)
+                    .setDuration(mHistoryTransitionDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            clearAllButton.setVisibility(View.INVISIBLE);
+                        }
+                    })
                     .withLayer()
                     .start();
         } else {
             setAlpha(0f);
             setVisibility(View.INVISIBLE);
+            clearAllButton.setAlpha(0f);
+            clearAllButton.setVisibility(View.INVISIBLE);
         }
         mIsVisible = false;
         EventBus.getDefault().send(new ResetBackgroundScrimEvent());
@@ -222,9 +242,18 @@
         mViewBounds.setClipTop(top);
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
     /**** EventBus Events ****/
 
     public final void onBusEvent(PackagesChangedEvent event) {
         mAdapter.removeTasks(event.packageName, event.userId);
     }
+
+    public final void onBusEvent(ClearHistoryEvent event) {
+        mAdapter.removeAllTasks();
+    }
 }
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 44ad239..5c77d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -334,10 +334,19 @@
         }
     }
 
-    /** Acquires the task resource data directly from the pool. */
-    public void loadTaskData(Task t) {
+    /**
+     * Acquires the task resource data directly from the cache, loading if necessary.
+     *
+     * @param fetchAndInvalidateThumbnails If set, will try loading thumbnails, invalidating them
+     *                                     in the cache and loading if necessary. Otherwise, do not
+     *                                     load the thumbnail unless the icon also has to be loaded.
+     */
+    public void loadTaskData(Task t, boolean fetchAndInvalidateThumbnails) {
         Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
-        Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
+        Bitmap thumbnail = mDefaultThumbnail;
+        if (fetchAndInvalidateThumbnails) {
+            thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
+        }
 
         // Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and
         // use the default assets in their place until they load
@@ -360,6 +369,8 @@
         mLoadQueue.removeTask(t);
         mThumbnailCache.remove(t.key);
         mIconCache.remove(t.key);
+        mActivityLabelCache.remove(t.key);
+        mContentDescriptionCache.remove(t.key);
         mActivityInfoCache.remove(t.key.getComponent());
         if (notifyTaskDataUnloaded) {
             t.notifyTaskDataUnloaded(null, mDefaultIcon);
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 41739c4..b59ff30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -34,7 +34,6 @@
 import android.view.View;
 import android.view.ViewOutlineProvider;
 import android.view.ViewPropertyAnimator;
-import android.view.ViewStub;
 import android.view.WindowInsets;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -51,6 +50,7 @@
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.ClearHistoryEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
 import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
@@ -99,6 +99,7 @@
     private TaskStackView mTaskStackView;
     private RecentsAppWidgetHostView mSearchBar;
     private TextView mHistoryButton;
+    private TextView mHistoryClearAllButton;
     private View mEmptyView;
     private RecentsHistoryView mHistoryView;
 
@@ -154,6 +155,7 @@
                 EventBus.getDefault().send(new ToggleHistoryEvent());
             }
         });
+        addView(mHistoryButton);
         mHistoryButton.setClipToOutline(true);
         mHistoryButton.setOutlineProvider(new ViewOutlineProvider() {
             @Override
@@ -161,7 +163,6 @@
                 outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
             }
         });
-        addView(mHistoryButton);
         mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
         addView(mEmptyView);
 
@@ -406,6 +407,11 @@
         measureChild(mHistoryButton,
                 MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
                 MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
+        if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
+            measureChild(mHistoryClearAllButton,
+                    MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
+                    MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
+        }
 
         setMeasuredDimension(width, height);
     }
@@ -441,16 +447,33 @@
             mHistoryView.layout(left, top, right, bottom);
         }
 
-        // Layout the history button such that its drawable is left-aligned with the stack,
+        // Layout the history button such that its drawable is start-aligned with the stack,
         // vertically centered in the available space above the stack
         Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
-        int historyLeft = historyButtonRect.left - mHistoryButton.getPaddingStart();
+        int historyLeft = isLayoutRtl()
+                ? historyButtonRect.right + mHistoryButton.getPaddingStart()
+                        - mHistoryButton.getMeasuredWidth()
+                : historyButtonRect.left - mHistoryButton.getPaddingStart();
         int historyTop = historyButtonRect.top +
                 (historyButtonRect.height() - mHistoryButton.getMeasuredHeight()) / 2;
         mHistoryButton.layout(historyLeft, historyTop,
                 historyLeft + mHistoryButton.getMeasuredWidth(),
                 historyTop + mHistoryButton.getMeasuredHeight());
 
+        // Layout the history clear all button such that it is end-aligned with the stack,
+        // vertically centered in the available space above the stack
+        if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
+            int clearAllLeft = isLayoutRtl()
+                    ? historyButtonRect.left - mHistoryClearAllButton.getPaddingStart()
+                    : historyButtonRect.right + mHistoryClearAllButton.getPaddingStart()
+                            - mHistoryClearAllButton.getMeasuredWidth();
+            int clearAllTop = historyButtonRect.top +
+                    (historyButtonRect.height() - mHistoryClearAllButton.getMeasuredHeight()) / 2;
+            mHistoryClearAllButton.layout(clearAllLeft, clearAllTop,
+                    clearAllLeft + mHistoryClearAllButton.getMeasuredWidth(),
+                    clearAllTop + mHistoryClearAllButton.getMeasuredHeight());
+        }
+
         if (mAwaitingFirstLayout) {
             mAwaitingFirstLayout = false;
 
@@ -665,16 +688,37 @@
 
     public final void onBusEvent(ShowHistoryEvent event) {
         if (mHistoryView == null) {
-            mHistoryView = (RecentsHistoryView) LayoutInflater.from(getContext()).inflate(
-                    R.layout.recents_history, this, false);
+            LayoutInflater inflater = LayoutInflater.from(getContext());
+            mHistoryView = (RecentsHistoryView) inflater.inflate(R.layout.recents_history, this,
+                    false);
             addView(mHistoryView);
 
+            final float cornerRadius = getResources().getDimensionPixelSize(
+                    R.dimen.recents_task_view_rounded_corners_radius);
+            mHistoryClearAllButton = (TextView) inflater.inflate(
+                    R.layout.recents_history_clear_all_button, this, false);
+            mHistoryClearAllButton.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    EventBus.getDefault().send(new ClearHistoryEvent());
+                }
+            });
+            mHistoryClearAllButton.setClipToOutline(true);
+            mHistoryClearAllButton.setOutlineProvider(new ViewOutlineProvider() {
+                @Override
+                public void getOutline(View view, Outline outline) {
+                    outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
+                }
+            });
+            addView(mHistoryClearAllButton);
+
             // Since this history view is inflated by a view stub after the insets have already
             // been applied, we have to set them ourselves initial from the insets that were last
             // provided.
             mHistoryView.setSystemInsets(mSystemInsets);
             mHistoryView.setHeaderHeight(mHistoryButton.getMeasuredHeight());
             mHistoryButton.bringToFront();
+            mHistoryClearAllButton.bringToFront();
         }
 
         // Animate the empty view in parallel with the history view (the task view animations are
@@ -685,7 +729,7 @@
                     R.integer.recents_history_transition_duration);
             mEmptyView.animate()
                     .alpha(0f)
-                    .translationY(stackRect.bottom)
+                    .translationY(stackRect.height() / 2)
                     .setDuration(historyTransitionDuration)
                     .setInterpolator(mFastOutSlowInInterpolator)
                     .withEndAction(new Runnable() {
@@ -697,7 +741,7 @@
                     .start();
         }
 
-        mHistoryView.show(mStack, stackRect.height());
+        mHistoryView.show(mStack, stackRect.height(), mHistoryClearAllButton);
     }
 
     public final void onBusEvent(HideHistoryEvent event) {
@@ -716,7 +760,7 @@
                     .start();
         }
 
-        mHistoryView.hide(event.animate, stackRect.height());
+        mHistoryView.hide(event.animate, stackRect.height(), mHistoryClearAllButton);
     }
 
     public final void onBusEvent(ShowHistoryButtonEvent event) {
@@ -737,6 +781,8 @@
             mHistoryButton.setAlpha(0f);
             if (translate) {
                 mHistoryButton.setTranslationY(-mHistoryButton.getMeasuredHeight() * 0.25f);
+            } else {
+                mHistoryButton.setTranslationY(0f);
             }
             postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
                 @Override
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 1c545c8..79f6381 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -64,7 +64,6 @@
 import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
-import com.android.systemui.recents.events.ui.UpdateBackgroundScrimEvent;
 import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
 import com.android.systemui.recents.events.ui.UserInteractionEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
@@ -81,7 +80,6 @@
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 
-import java.lang.ref.Reference;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -1419,7 +1417,7 @@
         tv.onTaskBound(task);
 
         // Load the task data
-        Recents.getTaskLoader().loadTaskData(task);
+        Recents.getTaskLoader().loadTaskData(task, true /* fetchAndInvalidateThumbnails */);
 
         // If the doze trigger has already fired, then update the state for this task view
         tv.setNoUserInteractionState();
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 d5aea9d..36760f7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -47,7 +47,6 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
 import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
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 de96d9d..c3a0ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -27,8 +27,6 @@
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.util.AttributeSet;
-import android.util.FloatProperty;
-import android.util.Property;
 import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 67bb58a..24ab506 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -97,7 +97,8 @@
         @Override
         public void run() {
             try {
-                ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true);
+                ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true, false,
+                        false);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed to resize stack: " + e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 5359dd2..240d32e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1225,10 +1225,7 @@
             final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
                     mContext.getContentResolver(),
                     Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
-            final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
-                    userHandle);
-            final boolean allowedByDpm = (dpmFlags
-                    & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
+            final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
             final boolean allowed = allowedByUser && allowedByDpm;
             mUsersAllowingPrivateNotifications.append(userHandle, allowed);
             return allowed;
@@ -1237,6 +1234,15 @@
         return mUsersAllowingPrivateNotifications.get(userHandle);
     }
 
+    private boolean adminAllowsUnredactedNotifications(int userHandle) {
+        if (userHandle == UserHandle.USER_ALL) {
+            return true;
+        }
+        final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
+                    userHandle);
+        return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
+    }
+
     /**
      * Returns true if we're on a secure lockscreen and the user wants to hide "sensitive"
      * notification data. If so, private notifications should show their (possibly
@@ -2047,6 +2053,21 @@
         entry.row.resetHeight();
     }
 
+    protected void updatePublicContentView(Entry entry,
+            StatusBarNotification sbn) {
+        final RemoteViews publicContentView = entry.cachedPublicContentView;
+        if (publicContentView != null && entry.getPublicContentView() != null) {
+            final boolean disabledByPolicy =
+                    !adminAllowsUnredactedNotifications(entry.notification.getUserId());
+            publicContentView.setTextViewText(android.R.id.title,
+                    mContext.getString(disabledByPolicy
+                            ? com.android.internal.R.string.notification_hidden_by_policy_text
+                            : com.android.internal.R.string.notification_hidden_text));
+            publicContentView.reapply(sbn.getPackageContext(mContext),
+                    entry.getPublicContentView(), mOnClickHandler);
+        }
+    }
+
     protected void notifyHeadsUpScreenOff() {
         maybeEscalateHeadsUp();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index ba08ee7..6cfd715 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -18,7 +18,10 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -28,8 +31,10 @@
 import android.widget.LinearLayout;
 import android.widget.Space;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.KeyButtonView;
 import com.android.systemui.tuner.TunerService;
 
+import java.io.File;
 import java.util.Objects;
 
 public class NavigationBarInflaterView extends FrameLayout implements TunerService.Tunable {
@@ -38,20 +43,30 @@
 
     public static final String NAV_BAR_VIEWS = "sysui_nav_bar";
 
-    protected static final String MENU_IME = "menu_ime";
-    protected static final String BACK = "back";
-    protected static final String HOME = "home";
-    protected static final String RECENT = "recent";
-    protected static final String NAVSPACE = "space";
+    public static final String MENU_IME = "menu_ime";
+    public static final String BACK = "back";
+    public static final String HOME = "home";
+    public static final String RECENT = "recent";
+    public static final String NAVSPACE = "space";
+    public static final String CLIPBOARD = "clipboard";
+    public static final String KEY = "key";
 
     public static final String GRAVITY_SEPARATOR = ";";
     public static final String BUTTON_SEPARATOR = ",";
 
+    public static final String SIZE_MOD_START = "[";
+    public static final String SIZE_MOD_END = "]";
+
+    public static final String KEY_CODE_START = "(";
+    public static final String KEY_IMAGE_DELIM = ":";
+    public static final String KEY_CODE_END = ")";
+
     protected final LayoutInflater mLayoutInflater;
     protected final LayoutInflater mLandscapeInflater;
 
     protected FrameLayout mRot0;
     protected FrameLayout mRot90;
+
     private SparseArray<ButtonDispatcher> mButtonDispatchers;
     private String mCurrentLayout;
 
@@ -206,9 +221,11 @@
     }
 
     @Nullable
-    protected View inflateButton(String button, ViewGroup parent, boolean landscape) {
-        View v;
+    protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape) {
         LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
+        float size = extractSize(buttonSpec);
+        String button = extractButton(buttonSpec);
+        View v = null;
         if (HOME.equals(button)) {
             v = inflater.inflate(R.layout.home, parent, false);
             if (landscape && isSw600Dp()) {
@@ -228,15 +245,63 @@
             v = inflater.inflate(R.layout.menu_ime, parent, false);
         } else if (NAVSPACE.equals(button)) {
             v = inflater.inflate(R.layout.nav_key_space, parent, false);
+        } else if (CLIPBOARD.equals(button)) {
+            v = inflater.inflate(R.layout.clipboard, parent, false);
+        } else if (button.startsWith(KEY)) {
+            String uri = extractImage(button);
+            int code = extractKeycode(button);
+            v = inflater.inflate(R.layout.custom_key, parent, false);
+            ((KeyButtonView) v).setCode(code);
+            if (uri != null) {
+                ((KeyButtonView) v).loadAsync(uri);
+            }
         } else {
             return null;
         }
 
+        if (size != 0) {
+            ViewGroup.LayoutParams params = v.getLayoutParams();
+            params.width = (int) (params.width * size);
+        }
         parent.addView(v);
         addToDispatchers(v);
         return v;
     }
 
+    public static String extractImage(String buttonSpec) {
+        if (!buttonSpec.contains(KEY_IMAGE_DELIM)) {
+            return null;
+        }
+        final int start = buttonSpec.indexOf(KEY_IMAGE_DELIM);
+        String subStr = buttonSpec.substring(start + 1, buttonSpec.indexOf(KEY_CODE_END));
+        return subStr;
+    }
+
+    public static int extractKeycode(String buttonSpec) {
+        if (!buttonSpec.contains(KEY_CODE_START)) {
+            return 1;
+        }
+        final int start = buttonSpec.indexOf(KEY_CODE_START);
+        String subStr = buttonSpec.substring(start + 1, buttonSpec.indexOf(KEY_IMAGE_DELIM));
+        return Integer.parseInt(subStr);
+    }
+
+    public static float extractSize(String buttonSpec) {
+        if (!buttonSpec.contains(SIZE_MOD_START)) {
+            return 1;
+        }
+        final int sizeStart = buttonSpec.indexOf(SIZE_MOD_START);
+        String sizeStr = buttonSpec.substring(sizeStart + 1, buttonSpec.indexOf(SIZE_MOD_END));
+        return Float.parseFloat(sizeStr);
+    }
+
+    public static String extractButton(String buttonSpec) {
+        if (!buttonSpec.contains(SIZE_MOD_START)) {
+            return buttonSpec;
+        }
+        return buttonSpec.substring(0, buttonSpec.indexOf(SIZE_MOD_START));
+    }
+
     private void addToDispatchers(View v) {
         if (mButtonDispatchers != null) {
             final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId());
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 f2dea3c..a6ebab3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1373,6 +1373,9 @@
             boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
             boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage;
             boolean showingPublic = sensitive && isLockscreenPublicMode();
+            if (showingPublic) {
+                updatePublicContentView(ent, ent.notification);
+            }
             ent.row.setSensitive(sensitive);
             if (ent.autoRedacted && ent.legacy) {
                 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 9c2159be..b8cd7fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -51,6 +51,7 @@
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.DisplayController;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -101,6 +102,7 @@
     private final TileServices mServices;
 
     private final List<Callback> mCallbacks = new ArrayList<>();
+    private final DisplayController mDisplayController;
     private View mHeader;
 
     public QSTileHost(Context context, PhoneStatusBar statusBar,
@@ -127,6 +129,7 @@
         mSecurity = security;
         mBattery = battery;
         mIconController = iconController;
+        mDisplayController = new DisplayController(mContext);
 
         final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
                 Process.THREAD_PRIORITY_BACKGROUND);
@@ -277,6 +280,10 @@
         return mIconController;
     }
 
+    public DisplayController getDisplayController() {
+        return mDisplayController;
+    }
+
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (!TILES_SETTING.equals(key)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
new file mode 100644
index 0000000..e5d244f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
@@ -0,0 +1,191 @@
+/*
+ * 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.policy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.provider.Settings;
+import com.android.systemui.R;
+import com.android.systemui.tuner.TunerService;
+import libcore.util.Objects;
+
+import java.util.ArrayList;
+
+public class DisplayController implements TunerService.Tunable {
+
+    public static final String COLOR_MATRIX_CUSTOM_ENABLED = "tuner_color_custom_enabled";
+    public static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
+
+    public static final String COLOR_STATE = "sysui_color_matrix_state";
+
+    public static final int COLOR_STATE_DISABLED = 0;
+    public static final int COLOR_STATE_ENABLED = 1;
+    public static final int COLOR_STATE_AUTO = 2;
+
+    public static final String AUTO_STRING = "auto_mode";
+    public static final String NONE_STRING = "none";
+
+    public static final int AUTO_INDEX = 2;
+    public static final int CUSTOM_INDEX = 3;
+
+    // Night mode ~= 3400 K
+    private static final float[] NIGHT_VALUES = new float[] {
+        1, 0,     0,     0,
+        0, .754f, 0,     0,
+        0, 0,     .516f, 0,
+        0, 0,     0,     1,
+    };
+    public static final float[] IDENTITY_MATRIX = new float[] {
+        1, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 1, 0,
+        0, 0, 0, 1,
+    };
+
+    private final ArrayList<Listener> mListeners = new ArrayList<>();
+
+    private final Context mContext;
+
+    private String mCurrentValue;
+    private boolean mListening;
+
+    public DisplayController(Context context) {
+        mContext = context;
+        TunerService.get(mContext).addTunable(this, COLOR_STATE,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+    }
+
+    public void addListener(Listener listener) {
+        mListeners.add(listener);
+        listener.onCurrentMatrixChanged();
+    }
+
+    public void removeListener(Listener listener) {
+        mListeners.remove(listener);
+    }
+
+    public boolean isEnabled() {
+        return TunerService.get(mContext).getValue(COLOR_STATE, COLOR_STATE_DISABLED)
+                != COLOR_STATE_DISABLED;
+    }
+
+    public boolean isAuto() {
+        return mListening;
+    }
+
+    public void setAuto(boolean auto) {
+        TunerService.get(mContext).setValue(COLOR_STATE, auto ? COLOR_STATE_AUTO
+                : COLOR_STATE_DISABLED);
+    }
+
+    public boolean isCustomSet() {
+        return isCustomEnabled() && Objects.equal(getCurrentMatrix(), getCustomValues());
+    }
+
+    public String getCurrentMatrix() {
+        return mCurrentValue;
+    }
+
+    public String getCustomValues() {
+        return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_VALUES);
+    }
+
+    public boolean isCustomEnabled() {
+        return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_ENABLED, 0) != 0;
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX.equals(key)) {
+            mCurrentValue = newValue;
+            for (int i = 0; i < mListeners.size(); i++) {
+                mListeners.get(i).onCurrentMatrixChanged();
+            }
+        } else if (COLOR_STATE.equals(key)) {
+            final boolean listening = newValue != null
+                    && Integer.parseInt(newValue) == COLOR_STATE_AUTO;
+            if (listening && !mListening) {
+                mListening = true;
+                mContext.registerReceiver(mReceiver,
+                        new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
+                updateNightMode();
+            } else if (!listening && mListening) {
+                mListening = false;
+                mContext.unregisterReceiver(mReceiver);
+            }
+            for (int i = 0; i < mListeners.size(); i++) {
+                mListeners.get(i).onCurrentMatrixChanged();
+            }
+        }
+    }
+
+    private void updateNightMode() {
+        final int uiMode = mContext.getResources().getConfiguration().uiMode;
+        final boolean isNightMode = (uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+        String value = null;
+        if (isNightMode) {
+            value = toString(NIGHT_VALUES);
+        }
+        TunerService.get(mContext).setValue(Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+                value);
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
+                updateNightMode();
+            }
+        }
+    };
+
+    public interface Listener {
+        void onCurrentMatrixChanged();
+    }
+
+    public static String[] getColorTransforms(Context context) {
+        return new String[] {
+                NONE_STRING,
+                toString(NIGHT_VALUES),
+                AUTO_STRING, // Blank spot for auto values
+                null, // Blank spot for custom values
+        };
+    }
+
+    public static CharSequence[] getColorTitles(Context context) {
+        // TODO: Move to string array resource.
+        return new CharSequence[]{
+                context.getString(R.string.color_matrix_none),
+                context.getString(R.string.color_matrix_night),
+                context.getString(R.string.color_matrix_auto),
+                context.getString(R.string.color_matrix_custom),
+        };
+    }
+
+    public static String toString(float[] values) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < values.length; i++) {
+            if (builder.length() != 0) {
+                builder.append(',');
+            }
+            builder.append(values[i]);
+        }
+        return builder.toString();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index ba284c9..6e7cf19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -20,8 +20,12 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.hardware.input.InputManager;
 import android.media.AudioManager;
+import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.util.AttributeSet;
@@ -99,6 +103,24 @@
         setBackground(new KeyButtonRipple(context, this));
     }
 
+    public void setCode(int code) {
+        mCode = code;
+    }
+
+    public void loadAsync(String uri) {
+        new AsyncTask<String, Void, Drawable>() {
+            @Override
+            protected Drawable doInBackground(String... params) {
+                return Icon.createWithContentUri(params[0]).loadDrawable(mContext);
+            }
+
+            @Override
+            protected void onPostExecute(Drawable drawable) {
+                setImageDrawable(drawable);
+            }
+        }.execute(uri);
+    }
+
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java b/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java
new file mode 100644
index 0000000..63ed912
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java
@@ -0,0 +1,100 @@
+/*
+ * 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.tuner;
+
+import com.android.systemui.R;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.ClipboardManager.OnPrimaryClipChangedListener;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.DragEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ImageView;
+
+public class ClipboardView extends ImageView implements OnPrimaryClipChangedListener {
+
+    private static final int TARGET_COLOR = 0x4dffffff;
+    private final ClipboardManager mClipboardManager;
+    private ClipData mCurrentClip;
+
+    public ClipboardView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mClipboardManager = context.getSystemService(ClipboardManager.class);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        startListening();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        stopListening();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN && mCurrentClip != null) {
+            startPocketDrag();
+        }
+        return super.onTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onDragEvent(DragEvent event) {
+        switch (event.getAction()) {
+            case DragEvent.ACTION_DRAG_ENTERED:
+                setBackgroundDragTarget(true);
+                break;
+            case DragEvent.ACTION_DROP:
+                mClipboardManager.setPrimaryClip(event.getClipData());
+            case DragEvent.ACTION_DRAG_EXITED:
+            case DragEvent.ACTION_DRAG_ENDED:
+                setBackgroundDragTarget(false);
+                break;
+        }
+        return true;
+    }
+
+    private void setBackgroundDragTarget(boolean isTarget) {
+        setBackgroundColor(isTarget ? TARGET_COLOR : 0);
+    }
+
+    public void startPocketDrag() {
+        startDragAndDrop(mCurrentClip, new View.DragShadowBuilder(this), null,
+                View.DRAG_FLAG_GLOBAL);
+    }
+
+    public void startListening() {
+        mClipboardManager.addPrimaryClipChangedListener(this);
+        onPrimaryClipChanged();
+    }
+
+    public void stopListening() {
+        mClipboardManager.removePrimaryClipChangedListener(this);
+    }
+
+    @Override
+    public void onPrimaryClipChanged() {
+        mCurrentClip = mClipboardManager.getPrimaryClip();
+        setImageResource(mCurrentClip != null
+                ? R.drawable.clipboard_full : R.drawable.clipboard_empty);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
index 8ed1b06..dfacd03 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
@@ -19,6 +19,7 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.DialogFragment;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.os.Bundle;
@@ -28,15 +29,15 @@
 import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceViewHolder;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.EditText;
+import android.widget.SeekBar;
+import android.widget.Switch;
+
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.policy.DisplayController;
 
 import java.util.Objects;
 
@@ -44,21 +45,6 @@
 
     private static final String TAG = "ColorMatrixFragment";
 
-    public static final int CUSTOM_INDEX = 2;
-
-    // Night mode ~= 3400 K
-    private static final float[] NIGHT_VALUES = new float[] {
-        1, 0,     0,     0,
-        0, .754f, 0,     0,
-        0, 0,     .516f, 0,
-        0, 0,     0,     1,
-    };
-    public static final float[] IDENTITY_MATRIX = new float[]{
-            1, 0, 0, 0,
-            0, 1, 0, 0,
-            0, 0, 1, 0,
-            0, 0, 0, 1,
-    };
     private static final long RESET_DELAY = 10000;
 
     private boolean mCustomEnabled;
@@ -67,20 +53,29 @@
     private String mCustomValues;
     private SwitchPreference mEnableCustomPreference;
     private MatrixPreference mCustomPreference;
-    private SwitchPreference mShowQs;
-    private String mTiles;
+    private int mState;
+    private Switch mSwitch;
 
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         Context context = getContext();
-        TunerService.get(context).addTunable(this, ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED,
-                ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES, QSTileHost.TILES_SETTING,
+        TunerService.get(context).addTunable(this, DisplayController.COLOR_MATRIX_CUSTOM_ENABLED,
+                DisplayController.COLOR_MATRIX_CUSTOM_VALUES, DisplayController.COLOR_STATE,
                 Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
     }
 
     @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        final View view = LayoutInflater.from(getContext()).inflate(
+                R.layout.color_matrix_settings, container, false);
+        ((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
+        return view;
+    }
+
+    @Override
     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
         final Context context = getPreferenceManager().getContext();
         setPreferenceScreen(getPreferenceManager().createPreferenceScreen(context));
@@ -88,40 +83,33 @@
         mSelectPreference = new DropDownPreference(context);
         mSelectPreference.setTitle(R.string.color_transform);
         mSelectPreference.setSummary("%s");
-        mSelectPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+        mSelectPreference.setOnPreferenceChangeListener(
+                new Preference.OnPreferenceChangeListener() {
             @Override
             public boolean onPreferenceChange(Preference preference, Object newValue) {
-                int index = Integer.parseInt((String) newValue);
+                if (Objects.equals(newValue, DisplayController.AUTO_STRING)) {
+                    Settings.Secure.putInt(context.getContentResolver(),
+                            DisplayController.COLOR_STATE,
+                            DisplayController.COLOR_STATE_AUTO);
+                    return true;
+                }
+                if (Objects.equals(newValue, DisplayController.NONE_STRING)) {
+                    Settings.Secure.putString(context.getContentResolver(),
+                            Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+                    return true;
+                }
+                Settings.Secure.putInt(context.getContentResolver(),
+                        DisplayController.COLOR_STATE,
+                        DisplayController.COLOR_STATE_ENABLED);
+                final String value = (String) newValue;
                 Settings.Secure.putString(context.getContentResolver(),
-                        Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, getValues()[index]);
+                        Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+                        value);
                 return true;
             }
         });
         getPreferenceScreen().addPreference(mSelectPreference);
 
-        mShowQs = new SwitchPreference(context);
-        mShowQs.setTitle(R.string.color_matrix_show_qs);
-        mShowQs.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
-            @Override
-            public boolean onPreferenceChange(Preference preference, Object newValue) {
-                boolean showTile = (Boolean) newValue;
-                String newTiles;
-                if (showTile) {
-                    newTiles = mTiles != null ? mTiles + "," + ColorMatrixTile.COLOR_MATRIX_SPEC
-                            : "default," + ColorMatrixTile.COLOR_MATRIX_SPEC;
-                } else {
-                    newTiles =
-                            mTiles.replace(mTiles.contains(ColorMatrixTile.COLOR_MATRIX_SPEC+ ",")
-                            ? ColorMatrixTile.COLOR_MATRIX_SPEC + ","
-                            : "," + ColorMatrixTile.COLOR_MATRIX_SPEC, "");
-                }
-                Settings.Secure.putString(context.getContentResolver(), QSTileHost.TILES_SETTING,
-                        newTiles);
-                return true;
-            }
-        });
-        getPreferenceScreen().addPreference(mShowQs);
-
         mEnableCustomPreference = new SwitchPreference(context);
         mEnableCustomPreference.setTitle(R.string.color_enable_custom);
         mEnableCustomPreference.setOnPreferenceChangeListener(
@@ -129,8 +117,12 @@
             @Override
             public boolean onPreferenceChange(Preference preference, Object newValue) {
                 boolean enabled = (Boolean) newValue;
+                if (!enabled && Objects.equals(mCurrentValue, mCustomValues)) {
+                    Settings.Secure.putString(context.getContentResolver(),
+                            Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+                }
                 Settings.Secure.putInt(context.getContentResolver(),
-                        ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED, enabled ? 1 : 0);
+                        DisplayController.COLOR_MATRIX_CUSTOM_ENABLED, enabled ? 1 : 0);
                 return true;
             }
         });
@@ -141,6 +133,38 @@
     }
 
     @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        View switchBar = view.findViewById(R.id.switch_bar);
+        mSwitch = (Switch) switchBar.findViewById(android.R.id.switch_widget);
+        mSwitch.setChecked(mState != DisplayController.COLOR_STATE_DISABLED);
+        switchBar.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                int newState = mState != DisplayController.COLOR_STATE_DISABLED
+                        ? DisplayController.COLOR_STATE_DISABLED
+                        : DisplayController.COLOR_STATE_ENABLED;
+                ContentResolver contentResolver = getContext().getContentResolver();
+                if (newState == DisplayController.COLOR_STATE_DISABLED) {
+                    String tiles = Settings.Secure.getString(contentResolver,
+                            QSTileHost.TILES_SETTING);
+                    if (tiles != null) {
+                        if (tiles.contains(",colors")) {
+                            tiles = tiles.replace(",colors", "");
+                        } else if (tiles.contains("colors,")) {
+                            tiles = tiles.replace("colors,", "");
+                        }
+                        Settings.Secure.putString(contentResolver, QSTileHost.TILES_SETTING,
+                                tiles);
+                    }
+                }
+                Settings.Secure.putInt(contentResolver,
+                        DisplayController.COLOR_STATE, newState);
+            }
+        });
+    }
+
+    @Override
     public void onDestroy() {
         super.onDestroy();
         TunerService.get(getContext()).removeTunable(this);
@@ -148,20 +172,28 @@
 
     @Override
     public void onTuningChanged(String key, String newValue) {
-        if (ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
+        if (DisplayController.COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
             mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
             mEnableCustomPreference.setChecked(mCustomEnabled);
-            mCustomPreference.setEnabled(mCustomEnabled);
+            mCustomPreference.setEnabled(mCustomEnabled
+                    && mState != DisplayController.COLOR_STATE_DISABLED);
             updateSelectOptions();
-        } else if (ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
+        } else if (DisplayController.COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
             mCustomValues = newValue;
+            if (mCustomValues == null) {
+                mCustomValues = DisplayController.toString(DisplayController.IDENTITY_MATRIX);
+            }
             mCustomPreference.setValues(mCustomValues);
             updateSelectOptions();
-        } else if (QSTileHost.TILES_SETTING.equals(key)) {
-            mTiles = newValue;
-            boolean hasTile = newValue != null
-                    && newValue.contains(ColorMatrixTile.COLOR_MATRIX_SPEC);
-            mShowQs.setChecked(hasTile);
+        } else if (DisplayController.COLOR_STATE.equals(key)) {
+            mState = newValue != null ? Integer.parseInt(newValue) : 0;
+            if (mSwitch != null) {
+                mSwitch.setChecked(mState != DisplayController.COLOR_STATE_DISABLED);
+            }
+            mSelectPreference.setEnabled(mState != DisplayController.COLOR_STATE_DISABLED);
+            mEnableCustomPreference.setEnabled(mState != DisplayController.COLOR_STATE_DISABLED);
+            mCustomPreference.setEnabled(mCustomEnabled
+                    && mState != DisplayController.COLOR_STATE_DISABLED);
         } else {
             mCurrentValue = newValue;
             updateSelectOptions();
@@ -169,41 +201,38 @@
     }
 
     private void updateSelectOptions() {
-        final int N = CUSTOM_INDEX + (mCustomEnabled ? 1 : 0);
+        final int N = DisplayController.CUSTOM_INDEX + (mCustomEnabled ? 1 : 0);
         String[] values = new String[N];
-        CharSequence[] totalNames = getColorTitles(getContext());
         CharSequence[] names = new CharSequence[N];
+        CharSequence[] totalNames = DisplayController.getColorTitles(getContext());
+        String[] entries = DisplayController.getColorTransforms(getContext());
+        entries[DisplayController.CUSTOM_INDEX] = mCustomValues != null ? mCustomValues : "";
         for (int i = 0; i < N; i++) {
-            values[i] = String.valueOf(i);
+            values[i] = entries[i];
             names[i] = totalNames[i];
         }
         mSelectPreference.setEntries(names);
         mSelectPreference.setEntryValues(values);
-        String[] entries = getValues();
-        for (int i = 0; i < values.length; i++) {
-            if (Objects.equals(entries[i], mCurrentValue)) {
-                mSelectPreference.setValueIndex(i);
-                return;
-            }
+        int index = 0;
+        if (mState == DisplayController.COLOR_STATE_AUTO) {
+            index = DisplayController.AUTO_INDEX;
+        } else if (mCustomValues != null && Objects.equals(mCurrentValue, mCustomValues)) {
+            index = DisplayController.CUSTOM_INDEX;
+        } else if (Objects.equals(mCurrentValue, entries[1])) {
+            index = 1;
         }
-        mSelectPreference.setSummary(R.string.color_matrix_unknown);
+        mSelectPreference.setValueIndex(index);
+        mSelectPreference.setSummary("%s");
         return;
     }
 
-    private String[] getValues() {
-        String[] ret = getColorTransforms();
-        // Fill in custom based on tuner settings.
-        ret[CUSTOM_INDEX] = mCustomValues;
-        return ret;
-    }
-
     private void startRevertTimer() {
         getView().postDelayed(mResetColorMatrix, RESET_DELAY);
     }
 
     private void onApply() {
         Settings.Secure.putString(getContext().getContentResolver(),
-                ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES, mCurrentValue);
+                DisplayController.COLOR_MATRIX_CUSTOM_VALUES, mCurrentValue);
         getView().removeCallbacks(mResetColorMatrix);
     }
 
@@ -212,35 +241,6 @@
         mResetColorMatrix.run();
     }
 
-    public static String[] getColorTransforms() {
-        return new String[] {
-                null,
-                toString(NIGHT_VALUES),
-                null, // Blank spot for custom values
-                null, // Unknown
-        };
-    }
-
-    public static CharSequence[] getColorTitles(Context context) {
-        return new CharSequence[] {
-                context.getString(R.string.color_matrix_none),
-                context.getString(R.string.color_matrix_night),
-                context.getString(R.string.color_matrix_custom),
-                context.getString(R.string.color_matrix_unknown),
-        };
-    }
-
-    private static String toString(float[] values) {
-        StringBuilder builder = new StringBuilder();
-        for (int i = 0; i < values.length; i++) {
-            if (builder.length() != 0) {
-                builder.append(',');
-            }
-            builder.append(values[i]);
-        }
-        return builder.toString();
-    }
-
     private final Runnable mResetColorMatrix = new Runnable() {
         @Override
         public void run() {
@@ -259,14 +259,10 @@
         }
 
         public void setValues(String customValues) {
-            if (customValues == null) {
-                mValues = IDENTITY_MATRIX;
-            } else {
-                String[] strValues = customValues.split(",");
-                mValues = new float[strValues.length];
-                for (int i = 0; i < mValues.length; i++) {
-                    mValues[i] = Float.parseFloat(strValues[i]);
-                }
+            String[] strValues = customValues.split(",");
+            mValues = new float[strValues.length];
+            for (int i = 0; i < mValues.length; i++) {
+                mValues[i] = Float.parseFloat(strValues[i]);
             }
             notifyChanged();
         }
@@ -274,48 +270,38 @@
         @Override
         public void onBindViewHolder(PreferenceViewHolder holder) {
             super.onBindViewHolder(holder);
-            ViewGroup vg = (ViewGroup) holder.itemView.findViewById(R.id.edit_group);
-            if (mValues == null) {
-                return;
-            }
-            int childIndex = 0;
-            for (int i = 0; i < mValues.length; i++) {
-                final int index = i;
-                while (!(vg.getChildAt(childIndex) instanceof EditText)) {
-                    childIndex++;
+            bindView(holder.findViewById(R.id.r_group), 0);
+            bindView(holder.findViewById(R.id.g_group), 5);
+            bindView(holder.findViewById(R.id.b_group), 10);
+            holder.findViewById(R.id.apply).setOnClickListener(this);
+        }
+
+        private void bindView(View view, final int index) {
+            SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
+            seekBar.setMax(1000);
+            seekBar.setProgress((int) (1000 * mValues[index]));
+            seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+                @Override
+                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                    mValues[index] = progress / 1000f;
                 }
-                final EditText editText = (EditText) vg.getChildAt(childIndex++);
-                editText.setText(String.valueOf(mValues[i]));
-                editText.addTextChangedListener(new TextWatcher() {
-                    @Override
-                    public void afterTextChanged(Editable s) {
-                        if (TextUtils.isEmpty(s.toString())) {
-                            return;
-                        }
-                        try {
-                            mValues[index] = Float.parseFloat(s.toString());
-                        } catch (NumberFormatException e) {
-                            mValues[index] = 0;
-                        }
-                    }
 
-                    @Override
-                    public void onTextChanged(CharSequence s, int start, int before, int count) {
-                    }
+                @Override
+                public void onStartTrackingTouch(SeekBar seekBar) {
+                }
 
-                    @Override
-                    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-                    }
-                });
-            }
-            ((Button) holder.itemView.findViewById(R.id.apply)).setOnClickListener(this);
+                @Override
+                public void onStopTrackingTouch(SeekBar seekBar) {
+                }
+            });
         }
 
         @Override
         public void onClick(View v) {
+            startRevertTimer();
             Settings.Secure.putString(getContext().getContentResolver(),
                     Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
-                    ColorMatrixFragment.toString(mValues));
+                    DisplayController.toString(mValues));
             RevertWarning.show(ColorMatrixFragment.this);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
index 3206882..1933c15 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
@@ -20,15 +20,17 @@
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
-import libcore.util.Objects;
+import com.android.systemui.statusbar.policy.DisplayController;
 
-public class ColorMatrixTile extends QSTile<QSTile.State> implements TunerService.Tunable {
+import java.util.Objects;
 
-    public static final String COLOR_MATRIX_CUSTOM_ENABLED = "tuner_color_custom_enabled";
-    public static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
+
+public class ColorMatrixTile extends QSTile<QSTile.State> implements DisplayController.Listener {
 
     public static final String COLOR_MATRIX_SPEC = "colors";
 
+    private final DisplayController mDisplayController;
+
     private int mIndex;
     private String mCurrentValue;
 
@@ -38,18 +40,17 @@
 
     public ColorMatrixTile(Host host) {
         super(host);
+        mDisplayController = host.getDisplayController();
     }
 
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            mValues = ColorMatrixFragment.getColorTransforms();
-            mValueTitles = ColorMatrixFragment.getColorTitles(mContext);
-            TunerService.get(mContext).addTunable(this, COLOR_MATRIX_CUSTOM_ENABLED,
-                    COLOR_MATRIX_CUSTOM_VALUES,
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+            mValues = DisplayController.getColorTransforms(mContext);
+            mValueTitles = DisplayController.getColorTitles(mContext);
+            mDisplayController.addListener(this);
         } else {
-            TunerService.get(mContext).removeTunable(this);
+            mDisplayController.removeListener(this);
         }
     }
 
@@ -61,46 +62,44 @@
     @Override
     protected void handleClick() {
         mIndex++;
-        if (!mCustomEnabled && (mIndex == ColorMatrixFragment.CUSTOM_INDEX)) {
-            mIndex++;
-        }
-        if (mIndex == mValues.length - 1) {
-            mIndex = 0;
-        }
-        Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, mValues[mIndex],
-                ActivityManager.getCurrentUser());
-        refreshState();
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
-            mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
-        } else if (COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
-            mValues[ColorMatrixFragment.CUSTOM_INDEX] = newValue;
+        if (mIndex == DisplayController.AUTO_INDEX) {
+            mDisplayController.setAuto(true);
         } else {
-            mCurrentValue = newValue;
-        }
-        // Last value is unknown, default to that.
-        mIndex = mValues.length - 1;
-        for (int i = 0; i < mValues.length - 1; i++) {
-            if (Objects.equal(mCurrentValue, mValues[i])) {
-                mIndex = i;
-                break;
+            mDisplayController.setAuto(false);
+            if (!mDisplayController.isCustomEnabled()
+                    && (mIndex == DisplayController.CUSTOM_INDEX)) {
+                mIndex++;
             }
+            if (mIndex == mValues.length - 1) {
+                mIndex = 0;
+            }
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, mValues[mIndex],
+                    ActivityManager.getCurrentUser());
         }
         refreshState();
     }
 
     @Override
     protected void handleUpdateState(State state, Object arg) {
+        if (mDisplayController.isAuto()) {
+            mIndex = DisplayController.AUTO_INDEX;
+        } else if (mDisplayController.isCustomSet()) {
+            mIndex = DisplayController.CUSTOM_INDEX;
+        } else {
+            mIndex = Objects.equals(mDisplayController.getCurrentMatrix(), mValues[1]) ? 1 : 0;
+        }
         state.icon = ResourceIcon.get(R.drawable.ic_colorize);
         state.label = mValueTitles[mIndex];
         state.contentDescription = mValueTitles[mIndex];
     }
 
     @Override
+    public void onCurrentMatrixChanged() {
+        refreshState();
+    }
+
+    @Override
     public int getMetricsCategory() {
         return MetricsEvent.QS_COLOR_MATRIX;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java b/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
new file mode 100644
index 0000000..e6073ae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
@@ -0,0 +1,84 @@
+/*
+ * 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.tuner;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.util.Pair;
+import android.view.KeyEvent;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import com.android.systemui.R;
+
+public class KeycodeSelectionHelper {
+
+    private static final ArrayList<String> mKeycodeStrings = new ArrayList<>();
+    private static final ArrayList<Integer> mKeycodes = new ArrayList<>();
+
+    private static final String KEYCODE_STRING = "KEYCODE_";
+
+    static {
+        Class<KeyEvent> cls = KeyEvent.class;
+        for (Field field : cls.getDeclaredFields()) {
+            if (Modifier.isStatic(field.getModifiers())
+                    && field.getName().startsWith(KEYCODE_STRING)
+                    && field.getType().equals(int.class)) {
+                try {
+                    mKeycodeStrings.add(formatString(field.getName()));
+                    mKeycodes.add((Integer) field.get(null));
+                } catch (IllegalAccessException e) {
+                }
+            }
+        }
+    }
+
+    // Force the string into something somewhat readable.
+    private static String formatString(String name) {
+        StringBuilder str = new StringBuilder(name.replace(KEYCODE_STRING, "").replace("_", " ")
+                .toLowerCase());
+        for (int i = 0; i < str.length(); i++) {
+            if (i == 0 || str.charAt(i - 1) == ' ') {
+                str.setCharAt(i, Character.toUpperCase(str.charAt(i)));
+            }
+        }
+        return str.toString();
+    }
+
+    public static void showKeycodeSelect(Context context, final OnSelectionComplete listener) {
+        new AlertDialog.Builder(context)
+                .setTitle(R.string.select_keycode)
+                .setItems(mKeycodeStrings.toArray(new String[0]),
+                        new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        listener.onSelectionComplete(mKeycodes.get(which));
+                    }
+                }).show();
+    }
+
+    public static Intent getSelectImageIntent() {
+        return new Intent(Intent.ACTION_OPEN_DOCUMENT).addCategory(Intent.CATEGORY_OPENABLE)
+                .setType("image/*");
+    }
+
+    public interface OnSelectionComplete {
+        void onSelectionComplete(int code);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
new file mode 100644
index 0000000..6fba9dc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -0,0 +1,608 @@
+/*
+ * 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.tuner;
+
+import com.android.systemui.R;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.CLIPBOARD;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_END;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_START;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_IMAGE_DELIM;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_END;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_START;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractButton;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractSize;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BACK;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BUTTON_SEPARATOR;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.GRAVITY_SEPARATOR;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.HOME;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.MENU_IME;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAVSPACE;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_VIEWS;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.RECENT;
+
+public class NavBarTuner extends Fragment implements TunerService.Tunable {
+
+    private static final int SAVE = Menu.FIRST + 1;
+    private static final int RESET = Menu.FIRST + 2;
+    private static final int READ_REQUEST = 42;
+
+    private static final float PREVIEW_SCALE = .95f;
+    private static final float PREVIEW_SCALE_LANDSCAPE = .75f;
+
+    private NavBarAdapter mNavBarAdapter;
+    private PreviewNavInflater mPreview;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            Bundle savedInstanceState) {
+        final View view = inflater.inflate(R.layout.nav_bar_tuner, container, false);
+        inflatePreview((ViewGroup) view.findViewById(R.id.nav_preview_frame));
+        return view;
+    }
+
+    private void inflatePreview(ViewGroup view) {
+        Display display = getActivity().getWindowManager().getDefaultDisplay();
+        boolean isRotated = display.getRotation() == Surface.ROTATION_90
+                || display.getRotation() == Surface.ROTATION_270;
+
+        Configuration config = new Configuration(getContext().getResources().getConfiguration());
+        boolean isPhoneLandscape = isRotated && (config.smallestScreenWidthDp < 600);
+        final float scale = isPhoneLandscape ? PREVIEW_SCALE_LANDSCAPE : PREVIEW_SCALE;
+        config.densityDpi = (int) (config.densityDpi * scale);
+
+        mPreview = (PreviewNavInflater) LayoutInflater.from(getContext().createConfigurationContext(
+                config)).inflate(R.layout.nav_bar_tuner_inflater, view, false);
+        final ViewGroup.LayoutParams layoutParams = mPreview.getLayoutParams();
+        layoutParams.width = (int) ((isPhoneLandscape ? display.getHeight() : display.getWidth())
+                * scale);
+        // Not sure why, but the height dimen is not being scaled with the dp, set it manually
+        // for now.
+        layoutParams.height = (int) (layoutParams.height * scale);
+        if (isPhoneLandscape) {
+            int width = layoutParams.width;
+            layoutParams.width = layoutParams.height;
+            layoutParams.height = width;
+        }
+        view.addView(mPreview);
+
+        if (isRotated) {
+            mPreview.findViewById(R.id.rot0).setVisibility(View.GONE);
+            final View rot90 = mPreview.findViewById(R.id.rot90);
+            rot90.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
+            rot90.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
+        } else {
+            mPreview.findViewById(R.id.rot90).setVisibility(View.GONE);
+            final View rot0 = mPreview.findViewById(R.id.rot0);
+            rot0.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
+            rot0.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
+        }
+    }
+
+    private void notifyChanged() {
+        mPreview.onTuningChanged(NAV_BAR_VIEWS, mNavBarAdapter.getNavString());
+    }
+
+    @Override
+    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        RecyclerView recyclerView = (RecyclerView) view.findViewById(android.R.id.list);
+        final Context context = getContext();
+        recyclerView.setLayoutManager(new LinearLayoutManager(context));
+        mNavBarAdapter = new NavBarAdapter(context);
+        recyclerView.setAdapter(mNavBarAdapter);
+        recyclerView.addItemDecoration(new Dividers(context));
+        final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(mNavBarAdapter.mCallbacks);
+        mNavBarAdapter.setTouchHelper(itemTouchHelper);
+        itemTouchHelper.attachToRecyclerView(recyclerView);
+
+        TunerService.get(getContext()).addTunable(this, NAV_BAR_VIEWS);
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        TunerService.get(getContext()).removeTunable(this);
+    }
+
+    @Override
+    public void onTuningChanged(String key, String navLayout) {
+        if (!NAV_BAR_VIEWS.equals(key)) return;
+        Context context = getContext();
+        if (navLayout == null) {
+            navLayout = context.getString(R.string.config_navBarLayout);
+        }
+        String[] views = navLayout.split(GRAVITY_SEPARATOR);
+        String[] groups = new String[] { NavBarAdapter.START, NavBarAdapter.CENTER,
+                NavBarAdapter.END};
+        CharSequence[] groupLabels = new String[] { getString(R.string.start),
+                getString(R.string.center), getString(R.string.end) };
+        mNavBarAdapter.clear();
+        for (int i = 0; i < 3; i++) {
+            mNavBarAdapter.addButton(groups[i], groupLabels[i]);
+            for (String button : views[i].split(BUTTON_SEPARATOR)) {
+                mNavBarAdapter.addButton(button, getLabel(button, context));
+            }
+        }
+        mNavBarAdapter.addButton(NavBarAdapter.ADD, getString(R.string.add_button));
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+        // TODO: Show save button conditionally, only when there are changes.
+        menu.add(Menu.NONE, SAVE, Menu.NONE, getString(R.string.save))
+                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        menu.add(Menu.NONE, RESET, Menu.NONE, getString(R.string.reset));
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == SAVE) {
+            if (!mNavBarAdapter.hasHomeButton()) {
+                new AlertDialog.Builder(getContext())
+                        .setTitle(R.string.no_home_title)
+                        .setMessage(R.string.no_home_message)
+                        .setPositiveButton(android.R.string.ok, null)
+                        .show();
+            } else {
+                Settings.Secure.putString(getContext().getContentResolver(),
+                        NAV_BAR_VIEWS, mNavBarAdapter.getNavString());
+            }
+            return true;
+        } else if (item.getItemId() == RESET) {
+            Settings.Secure.putString(getContext().getContentResolver(),
+                    NAV_BAR_VIEWS, null);
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    private static CharSequence getLabel(String button, Context context) {
+        if (button.startsWith(HOME)) {
+            return context.getString(R.string.accessibility_home);
+        } else if (button.startsWith(BACK)) {
+            return context.getString(R.string.accessibility_back);
+        } else if (button.startsWith(RECENT)) {
+            return context.getString(R.string.accessibility_recent);
+        } else if (button.startsWith(NAVSPACE)) {
+            return context.getString(R.string.space);
+        } else if (button.startsWith(MENU_IME)) {
+            return context.getString(R.string.menu_ime);
+        } else if (button.startsWith(CLIPBOARD)) {
+            return context.getString(R.string.clipboard);
+        } else if (button.startsWith(KEY)) {
+            return context.getString(R.string.keycode);
+        }
+        return button;
+    }
+
+    private static class Holder extends RecyclerView.ViewHolder {
+        private TextView title;
+
+        public Holder(View itemView) {
+            super(itemView);
+            title = (TextView) itemView.findViewById(android.R.id.title);
+        }
+    }
+
+    private static class Dividers extends RecyclerView.ItemDecoration {
+        private final Drawable mDivider;
+
+        public Dividers(Context context) {
+            TypedValue value = new TypedValue();
+            context.getTheme().resolveAttribute(android.R.attr.listDivider, value, true);
+            mDivider = context.getDrawable(value.resourceId);
+        }
+
+        @Override
+        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+            super.onDraw(c, parent, state);
+            final int left = parent.getPaddingLeft();
+            final int right = parent.getWidth() - parent.getPaddingRight();
+
+            final int childCount = parent.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = parent.getChildAt(i);
+                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
+                        .getLayoutParams();
+                final int top = child.getBottom() + params.bottomMargin;
+                final int bottom = top + mDivider.getIntrinsicHeight();
+                mDivider.setBounds(left, top, right, bottom);
+                mDivider.draw(c);
+            }
+        }
+    }
+
+    private void selectImage() {
+        startActivityForResult(KeycodeSelectionHelper.getSelectImageIntent(), READ_REQUEST);
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == READ_REQUEST && resultCode == Activity.RESULT_OK && data != null) {
+            final Uri uri = data.getData();
+            final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            getContext().getContentResolver().takePersistableUriPermission(uri, takeFlags);
+            mNavBarAdapter.onImageSelected(uri);
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+
+    private class NavBarAdapter extends RecyclerView.Adapter<Holder>
+            implements View.OnClickListener {
+
+        private static final String START = "start";
+        private static final String CENTER = "center";
+        private static final String END = "end";
+        private static final String ADD = "add";
+
+        private static final int ADD_ID = 0;
+        private static final int BUTTON_ID = 1;
+        private static final int CATEGORY_ID = 2;
+
+        private List<String> mButtons = new ArrayList<>();
+        private List<CharSequence> mLabels = new ArrayList<>();
+        private int mCategoryLayout;
+        private int mButtonLayout;
+        private ItemTouchHelper mTouchHelper;
+
+        // Stored keycode while we wait for image selection on a KEY.
+        private int mKeycode;
+
+        public NavBarAdapter(Context context) {
+            TypedArray attrs = context.getTheme().obtainStyledAttributes(null,
+                    android.R.styleable.Preference, android.R.attr.preferenceStyle, 0);
+            mButtonLayout = attrs.getResourceId(android.R.styleable.Preference_layout, 0);
+            attrs = context.getTheme().obtainStyledAttributes(null,
+                    android.R.styleable.Preference, android.R.attr.preferenceCategoryStyle, 0);
+            mCategoryLayout = attrs.getResourceId(android.R.styleable.Preference_layout, 0);
+        }
+
+        public void setTouchHelper(ItemTouchHelper itemTouchHelper) {
+            mTouchHelper = itemTouchHelper;
+        }
+
+        public void clear() {
+            mButtons.clear();
+            mLabels.clear();
+            notifyDataSetChanged();
+        }
+
+        public void addButton(String button, CharSequence label) {
+            mButtons.add(button);
+            mLabels.add(label);
+            notifyItemInserted(mLabels.size() - 1);
+            notifyChanged();
+        }
+
+        public boolean hasHomeButton() {
+            final int N = mButtons.size();
+            for (int i = 0; i < N; i++) {
+                if (mButtons.get(i).startsWith(HOME)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public String getNavString() {
+            StringBuilder builder = new StringBuilder();
+            for (int i = 1; i < mButtons.size() - 1; i++) {
+                String button = mButtons.get(i);
+                if (button.equals(CENTER) || button.equals(END)) {
+                    if (builder.length() == 0 || builder.toString().endsWith(GRAVITY_SEPARATOR)) {
+                        // No start or center buttons, fill with a space.
+                        builder.append(NAVSPACE);
+                    }
+                    builder.append(GRAVITY_SEPARATOR);
+                    continue;
+                } else if (builder.length() != 0 && !builder.toString().endsWith(
+                        GRAVITY_SEPARATOR)) {
+                    builder.append(BUTTON_SEPARATOR);
+                }
+                builder.append(button);
+            }
+            if (builder.toString().endsWith(GRAVITY_SEPARATOR)) {
+                // No end buttons, fill with space.
+                builder.append(NAVSPACE);
+            }
+            return builder.toString();
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            String button = mButtons.get(position);
+            if (button.equals(START) || button.equals(CENTER) || button.equals(END)) {
+                return CATEGORY_ID;
+            }
+            if (button.equals(ADD)) {
+                return ADD_ID;
+            }
+            return BUTTON_ID;
+        }
+
+        @Override
+        public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
+            final Context context = parent.getContext();
+            final LayoutInflater inflater = LayoutInflater.from(context);
+            final View view = inflater.inflate(getLayoutId(viewType), parent, false);
+            if (viewType == BUTTON_ID) {
+                inflater.inflate(R.layout.nav_control_widget,
+                        (ViewGroup) view.findViewById(android.R.id.widget_frame));
+            }
+            return new Holder(view);
+        }
+
+        private int getLayoutId(int viewType) {
+            if (viewType == CATEGORY_ID) {
+                return mCategoryLayout;
+            }
+            return mButtonLayout;
+        }
+
+        @Override
+        public void onBindViewHolder(Holder holder, int position) {
+            holder.title.setText(mLabels.get(position));
+            if (holder.getItemViewType() == BUTTON_ID) {
+                bindButton(holder, position);
+            } else if (holder.getItemViewType() == ADD_ID) {
+                bindAdd(holder);
+            }
+        }
+
+        private void bindAdd(Holder holder) {
+            TypedValue value = new TypedValue();
+            final Context context = holder.itemView.getContext();
+            context.getTheme().resolveAttribute(android.R.attr.colorAccent, value, true);
+            final ImageView icon = (ImageView) holder.itemView.findViewById(android.R.id.icon);
+            icon.setImageResource(R.drawable.ic_add);
+            icon.setImageTintList(ColorStateList.valueOf(context.getColor(value.resourceId)));
+            holder.itemView.findViewById(android.R.id.summary).setVisibility(View.GONE);
+            holder.itemView.setClickable(true);
+            holder.itemView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    showAddDialog(v.getContext());
+                }
+            });
+        }
+
+        private void bindButton(final Holder holder, int position) {
+            holder.itemView.findViewById(android.R.id.icon_frame).setVisibility(View.GONE);
+            holder.itemView.findViewById(android.R.id.summary).setVisibility(View.GONE);
+            bindClick(holder.itemView.findViewById(R.id.close), holder);
+            bindClick(holder.itemView.findViewById(R.id.width), holder);
+            holder.itemView.findViewById(R.id.drag).setOnTouchListener(new View.OnTouchListener() {
+                @Override
+                public boolean onTouch(View v, MotionEvent event) {
+                    mTouchHelper.startDrag(holder);
+                    return true;
+                }
+            });
+        }
+
+        private void showAddDialog(final Context context) {
+            final String[] options = new String[] {
+                    BACK, HOME, RECENT, MENU_IME, NAVSPACE, CLIPBOARD, KEY,
+            };
+            final CharSequence[] labels = new CharSequence[options.length];
+            for (int i = 0; i < options.length; i++) {
+                labels[i] = getLabel(options[i], context);
+            }
+            new AlertDialog.Builder(context)
+                    .setTitle(R.string.select_button)
+                    .setItems(labels, new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            if (KEY.equals(options[which])) {
+                                showKeyDialogs(context);
+                            } else {
+                                int index = mButtons.size() - 1;
+                                showAddedMessage(context, options[which]);
+                                mButtons.add(index, options[which]);
+                                mLabels.add(index, labels[which]);
+
+                                notifyItemInserted(index);
+                                notifyChanged();
+                            }
+                        }
+                    }).setNegativeButton(android.R.string.cancel, null)
+                    .show();
+        }
+
+        private void onImageSelected(Uri uri) {
+            int index = mButtons.size() - 1;
+            mButtons.add(index, KEY + KEY_CODE_START + mKeycode + KEY_IMAGE_DELIM + uri.toString()
+                    + KEY_CODE_END);
+            mLabels.add(index, getLabel(KEY, getContext()));
+
+            notifyItemInserted(index);
+            notifyChanged();
+        }
+
+        private void showKeyDialogs(final Context context) {
+            final KeycodeSelectionHelper.OnSelectionComplete listener =
+                    new KeycodeSelectionHelper.OnSelectionComplete() {
+                        @Override
+                        public void onSelectionComplete(int code) {
+                            mKeycode = code;
+                            selectImage();
+                        }
+                    };
+            new AlertDialog.Builder(context)
+                    .setTitle(R.string.keycode)
+                    .setMessage(R.string.keycode_description)
+                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            KeycodeSelectionHelper.showKeycodeSelect(context, listener);
+                        }
+                    }).show();
+        }
+
+        private void showAddedMessage(Context context, String button) {
+            if (CLIPBOARD.equals(button)) {
+                new AlertDialog.Builder(context)
+                        .setTitle(R.string.clipboard)
+                        .setMessage(R.string.clipboard_description)
+                        .setPositiveButton(android.R.string.ok, null)
+                        .show();
+            }
+        }
+
+        private void bindClick(View view, Holder holder) {
+            view.setOnClickListener(this);
+            view.setTag(holder);
+        }
+
+        @Override
+        public void onClick(View v) {
+            Holder holder = (Holder) v.getTag();
+            if (v.getId() == R.id.width) {
+                showWidthDialog(holder, v.getContext());
+            } else if (v.getId() == R.id.close) {
+                int position = holder.getAdapterPosition();
+                mButtons.remove(position);
+                mLabels.remove(position);
+                notifyItemRemoved(position);
+                notifyChanged();
+            }
+        }
+
+        private void showWidthDialog(final Holder holder, Context context) {
+            final String buttonSpec = mButtons.get(holder.getAdapterPosition());
+            float amount = extractSize(buttonSpec);
+            final AlertDialog dialog = new AlertDialog.Builder(context)
+                    .setTitle(R.string.adjust_button_width)
+                    .setView(R.layout.nav_width_view)
+                    .setNegativeButton(android.R.string.cancel, null).create();
+            dialog.setButton(DialogInterface.BUTTON_POSITIVE,
+                    context.getString(android.R.string.ok),
+                    new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface d, int which) {
+                            final String button = extractButton(buttonSpec);
+                            SeekBar seekBar = (SeekBar) dialog.findViewById(R.id.seekbar);
+                            if (seekBar.getProgress() == 75) {
+                                mButtons.set(holder.getAdapterPosition(), button);
+                            } else {
+                                float amount = (seekBar.getProgress() + 25) / 100f;
+                                mButtons.set(holder.getAdapterPosition(), button
+                                        + SIZE_MOD_START + amount + SIZE_MOD_END);
+                            }
+                            notifyChanged();
+                        }
+                    });
+            dialog.show();
+            SeekBar seekBar = (SeekBar) dialog.findViewById(R.id.seekbar);
+            // Range is .25 - 1.75.
+            seekBar.setMax(150);
+            seekBar.setProgress((int) ((amount - .25f) * 100));
+        }
+
+        @Override
+        public int getItemCount() {
+            return mButtons.size();
+        }
+
+        private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
+            @Override
+            public boolean isLongPressDragEnabled() {
+                return false;
+            }
+
+            @Override
+            public boolean isItemViewSwipeEnabled() {
+                return false;
+            }
+
+            @Override
+            public int getMovementFlags(RecyclerView recyclerView,
+                    RecyclerView.ViewHolder viewHolder) {
+                if (viewHolder.getItemViewType() != BUTTON_ID) {
+                    return makeMovementFlags(0, 0);
+                }
+                int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
+                return makeMovementFlags(dragFlags, 0);
+            }
+
+            @Override
+            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
+                    RecyclerView.ViewHolder target) {
+                int from = viewHolder.getAdapterPosition();
+                int to = target.getAdapterPosition();
+                if (to == 0) {
+                    // Can't go above the top.
+                    return false;
+                }
+                move(from, to, mButtons);
+                move(from, to, mLabels);
+                notifyChanged();
+                notifyItemMoved(from, to);
+                return true;
+            }
+
+            private <T> void move(int from, int to, List<T> list) {
+                list.add(from > to ? to : to + 1, list.get(from));
+                list.remove(from > to ? from + 1 : from);
+            }
+
+            @Override
+            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+                // Don't care.
+            }
+        };
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java b/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
new file mode 100644
index 0000000..b30ca5c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
@@ -0,0 +1,73 @@
+/*
+ * 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.tuner;
+
+import com.android.systemui.statusbar.phone.NavigationBarInflaterView;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+public class PreviewNavInflater extends NavigationBarInflaterView {
+
+    public PreviewNavInflater(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        // Immediately remove tuner listening, since this is a preview, all values will be injected
+        // manually.
+        TunerService.get(getContext()).removeTunable(this);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        // Only a preview, not interactable.
+        return true;
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (NAV_BAR_VIEWS.equals(key)) {
+            // Since this is a preview we might get a bunch of random stuff, validate before sending
+            // for inflation.
+            if (isValidLayout(newValue)) {
+                super.onTuningChanged(key, newValue);
+            }
+        } else {
+            super.onTuningChanged(key, newValue);
+        }
+    }
+
+    private boolean isValidLayout(String newValue) {
+        if (newValue == null) {
+            return true;
+        }
+        int separatorCount = 0;
+        int lastGravitySeparator = 0;
+        for (int i = 0; i < newValue.length(); i++) {
+            if (newValue.charAt(i) == GRAVITY_SEPARATOR.charAt(0)) {
+                if (i == 0 || (i - lastGravitySeparator) == 1) {
+                    return false;
+                }
+                lastGravitySeparator = i;
+                separatorCount++;
+            }
+        }
+        return separatorCount == 2 && (newValue.length() - lastGravitySeparator) != 1;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 4173ecc..4225b48 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -30,11 +30,15 @@
         PreferenceFragment.OnPreferenceStartFragmentCallback,
         PreferenceFragment.OnPreferenceStartScreenCallback {
 
+    private static final String TAG_TUNER = "tuner";
+
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        getFragmentManager().beginTransaction().replace(R.id.content_frame, new TunerFragment())
-                .commit();
+        if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) {
+            getFragmentManager().beginTransaction().replace(R.id.content_frame, new TunerFragment(),
+                    TAG_TUNER).commit();
+        }
     }
 
     @Override
@@ -43,6 +47,7 @@
             Class<?> cls = Class.forName(pref.getFragment());
             Fragment fragment = (Fragment) cls.newInstance();
             FragmentTransaction transaction = getFragmentManager().beginTransaction();
+            setTitle(pref.getTitle());
             transaction.replace(R.id.content_frame, fragment);
             transaction.addToBackStack("PreferenceFragment");
             transaction.commit();
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 427b5e8..e4d7be7 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -61,11 +61,16 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
         setHasOptionsMenu(true);
     }
 
     @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
+    }
+
+    @Override
     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
         addPreferencesFromResource(R.xml.tuner_prefs);
 
@@ -81,6 +86,7 @@
     @Override
     public void onResume() {
         super.onResume();
+        getActivity().setTitle(R.string.system_ui_tuner);
         updateBatteryPct();
         getContext().getContentResolver().registerContentObserver(
                 System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 47a4667..abaa628 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -76,6 +76,22 @@
         mUserTracker.startTracking();
     }
 
+    public String getValue(String setting) {
+        return Settings.Secure.getStringForUser(mContentResolver, setting, mCurrentUser);
+    }
+
+    public void setValue(String setting, String value) {
+         Settings.Secure.putStringForUser(mContentResolver, setting, value, mCurrentUser);
+    }
+
+    public int getValue(String setting, int def) {
+        return Settings.Secure.getIntForUser(mContentResolver, setting, def, mCurrentUser);
+    }
+
+    public void setValue(String setting, int value) {
+         Settings.Secure.putIntForUser(mContentResolver, setting, value, mCurrentUser);
+    }
+
     public void addTunable(Tunable tunable, String... keys) {
         for (String key : keys) {
             addTunable(tunable, key);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index e6e69b1..a4455e9 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1181,6 +1181,9 @@
                             } else if ("audioserver".equals(packageName)) {
                                 pkgUid = Process.AUDIOSERVER_UID;
                                 isPrivileged = false;
+                            } else if ("cameraserver".equals(packageName)) {
+                                pkgUid = Process.CAMERASERVER_UID;
+                                isPrivileged = false;
                             }
                         }
                     } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 9405d8e0..c55c5b6 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -24,10 +24,10 @@
 import com.android.server.location.ActivityRecognitionProxy;
 import com.android.server.location.FlpHardwareProvider;
 import com.android.server.location.FusedProxy;
+import com.android.server.location.GnssLocationProvider;
 import com.android.server.location.GeocoderProxy;
 import com.android.server.location.GeofenceManager;
 import com.android.server.location.GeofenceProxy;
-import com.android.server.location.GpsLocationProvider;
 import com.android.server.location.GpsMeasurementsProvider;
 import com.android.server.location.GpsNavigationMessageProvider;
 import com.android.server.location.LocationBlacklist;
@@ -61,11 +61,11 @@
 import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.Geofence;
+import android.location.IGnssStatusListener;
+import android.location.IGnssStatusProvider;
 import android.location.IGpsGeofenceHardware;
 import android.location.IGpsMeasurementsListener;
 import android.location.IGpsNavigationMessageListener;
-import android.location.IGpsStatusListener;
-import android.location.IGpsStatusProvider;
 import android.location.ILocationListener;
 import android.location.ILocationManager;
 import android.location.INetInitiatedListener;
@@ -157,7 +157,7 @@
     private PowerManager mPowerManager;
     private UserManager mUserManager;
     private GeocoderProxy mGeocodeProvider;
-    private IGpsStatusProvider mGpsStatusProvider;
+    private IGnssStatusProvider mGnssStatusProvider;
     private INetInitiatedListener mNetInitiatedListener;
     private LocationWorkerHandler mLocationHandler;
     private PassiveProvider mPassiveProvider;  // track passive provider for special cases
@@ -214,6 +214,8 @@
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
     private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
 
+    private GnssLocationProvider.GpsSystemInfoProvider mGpsSystemInfoProvider;
+
     public LocationManagerService(Context context) {
         super();
         mContext = context;
@@ -456,17 +458,18 @@
         mEnabledProviders.add(passiveProvider.getName());
         mPassiveProvider = passiveProvider;
 
-        if (GpsLocationProvider.isSupported()) {
+        if (GnssLocationProvider.isSupported()) {
             // Create a gps location provider
-            GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
+            GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
                     mLocationHandler.getLooper());
-            mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
-            mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
-            addProviderLocked(gpsProvider);
-            mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
-            mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
-            mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
-            mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
+            mGpsSystemInfoProvider = gnssProvider.getGpsSystemInfoProvider();
+            mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
+            mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
+            addProviderLocked(gnssProvider);
+            mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
+            mGpsMeasurementsProvider = gnssProvider.getGpsMeasurementsProvider();
+            mGpsNavigationMessageProvider = gnssProvider.getGpsNavigationMessageProvider();
+            mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
         }
 
         /*
@@ -986,6 +989,18 @@
         }
     }
 
+    /**
+     * Returns the system information of the GPS hardware.
+     */
+    @Override
+    public int getGpsYearOfHardware() {
+        if (mGpsNavigationMessageProvider != null) {
+            return mGpsSystemInfoProvider.getGpsYearOfHardware();
+        } else {
+            return 0;
+        }
+    }
+
     private void addProviderLocked(LocationProviderInterface provider) {
         mProviders.add(provider);
         mProvidersByName.put(provider.getName(), provider);
@@ -1867,7 +1882,7 @@
 
 
     @Override
-    public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
+    public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
                 LocationManager.GPS_PROVIDER);
@@ -1883,26 +1898,26 @@
             Binder.restoreCallingIdentity(ident);
         }
 
-        if (mGpsStatusProvider == null) {
+        if (mGnssStatusProvider == null) {
             return false;
         }
 
         try {
-            mGpsStatusProvider.addGpsStatusListener(listener);
+            mGnssStatusProvider.registerGnssStatusCallback(callback);
         } catch (RemoteException e) {
-            Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
+            Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
             return false;
         }
         return true;
     }
 
     @Override
-    public void removeGpsStatusListener(IGpsStatusListener listener) {
+    public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
         synchronized (mLock) {
             try {
-                mGpsStatusProvider.removeGpsStatusListener(listener);
+                mGnssStatusProvider.unregisterGnssStatusCallback(callback);
             } catch (Exception e) {
-                Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
+                Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
             }
         }
     }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index f6f05fe..e9f0a7a 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -17,11 +17,12 @@
 package com.android.server;
 
 import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.app.backup.BackupManager;
 import android.app.trust.IStrongAuthTracker;
-import android.app.trust.ITrustManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -30,6 +31,8 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
+
 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
 import static android.content.Context.USER_SERVICE;
 import static android.Manifest.permission.READ_CONTACTS;
@@ -40,7 +43,6 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.storage.IMountService;
-import android.os.storage.StorageManager;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -70,19 +72,27 @@
  * @hide
  */
 public class LockSettingsService extends ILockSettings.Stub {
-
-    private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
-
     private static final String TAG = "LockSettingsService";
+    private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
+    private static final Intent ACTION_NULL; // hack to ensure notification shows the bouncer
+    private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
+    private static final boolean DEBUG = false;
 
     private final Context mContext;
-
     private final LockSettingsStorage mStorage;
     private final LockSettingsStrongAuth mStrongAuth;
 
     private LockPatternUtils mLockPatternUtils;
     private boolean mFirstCallToVold;
     private IGateKeeperService mGateKeeperService;
+    private NotificationManager mNotificationManager;
+    private UserManager mUserManager;
+
+    static {
+        // Just launch the home screen, which happens anyway
+        ACTION_NULL = new Intent(Intent.ACTION_MAIN);
+        ACTION_NULL.addCategory(Intent.CATEGORY_HOME);
+    }
 
     private interface CredentialUtil {
         void setCredential(String credential, String savedCredential, int userId)
@@ -91,6 +101,42 @@
         String adjustForKeystore(String credential);
     }
 
+    // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
+    // devices. The most basic of these is to show/hide notifications about missing features until
+    // the user unlocks the account and credential-encrypted storage is available.
+    public static final class Lifecycle extends SystemService {
+        private LockSettingsService mLockSettingsService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mLockSettingsService = new LockSettingsService(getContext());
+            publishBinderService("lock_settings", mLockSettingsService);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+                mLockSettingsService.maybeShowEncryptionNotification(UserHandle.ALL);
+            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
+                // TODO
+            }
+        }
+
+        @Override
+        public void onUnlockUser(int userHandle) {
+            mLockSettingsService.onUnlockUser(userHandle);
+        }
+
+        @Override
+        public void onCleanupUser(int userHandle) {
+            mLockSettingsService.onCleanupUser(userHandle);
+        }
+    }
+
     public LockSettingsService(Context context) {
         mContext = context;
         mStrongAuth = new LockSettingsStrongAuth(context);
@@ -117,6 +163,71 @@
                 }
             }
         });
+        mNotificationManager = (NotificationManager)
+                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+    }
+
+    /**
+     * 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);
+                }
+            }
+        } else if (!mUserManager.isUserUnlocked(userHandle)){
+            showEncryptionNotification(userHandle);
+        }
+    }
+
+    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);
+        CharSequence message = r.getText(
+                com.android.internal.R.string.user_encrypted_message);
+        CharSequence detail = r.getText(
+                com.android.internal.R.string.user_encrypted_detail);
+
+        PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
+                PendingIntent.FLAG_UPDATE_CURRENT);
+
+        Notification notification = new Notification.Builder(mContext)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
+                .setWhen(0)
+                .setOngoing(true)
+                .setTicker(title)
+                .setDefaults(0)  // please be quiet
+                .setPriority(Notification.PRIORITY_MAX)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentText(message)
+                .setContentInfo(detail)
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setContentIntent(intent)
+                .build();
+        mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
+    }
+
+    public void hideEncryptionNotification(UserHandle userHandle) {
+        if (DEBUG) Slog.v(TAG, "hide encryption notification, user: "+ userHandle.getIdentifier());
+        mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
+    }
+
+    public void onCleanupUser(int userId) {
+        hideEncryptionNotification(new UserHandle(userId));
+    }
+
+    public void onUnlockUser(int userHandle) {
+        hideEncryptionNotification(new UserHandle(userHandle));
     }
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -144,6 +255,7 @@
         }
     };
 
+    @Override // binder interface
     public void systemReady() {
         migrateOldData();
         try {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2c55ee2..76fbebf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9411,14 +9411,24 @@
     }
 
     @Override
-    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) {
+    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
+            boolean preserveWindows, boolean animate) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                mStackSupervisor.resizeStackLocked(
-                        stackId, bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
-                        !PRESERVE_WINDOWS, allowResizeInDockedMode);
+                if (animate) {
+                    if (stackId == PINNED_STACK_ID) {
+                        mWindowManager.animateResizePinnedStack(bounds);
+                    } else {
+                        throw new IllegalArgumentException("Stack: " + stackId
+                                + " doesn't support animated resize.");
+                    }
+                } else {
+                    mStackSupervisor.resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
+                            null /* tempTaskInsetBounds */, preserveWindows,
+                            allowResizeInDockedMode);
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 71008a9..d1fcd3b 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -19,8 +19,9 @@
 import static android.app.ActivityManager.StackId;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE;
-import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
@@ -355,6 +356,9 @@
         if (connections != null) {
             pw.print(prefix); pw.print("connections="); pw.println(connections);
         }
+        if (info != null) {
+            pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
+        }
     }
 
     public boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
@@ -754,11 +758,16 @@
     }
 
     boolean isResizeable() {
-        return (info.flags & FLAG_RESIZEABLE) != 0;
+        return !isHomeActivity() && (info.resizeMode == RESIZE_MODE_RESIZEABLE
+                || info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE);
     }
 
     boolean supportsPictureInPicture() {
-        return (info.flags & FLAG_SUPPORTS_PICTURE_IN_PICTURE) != 0;
+        return !isHomeActivity() && info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+    }
+
+    boolean cropAppWindows() {
+        return !isHomeActivity() && info.resizeMode == RESIZE_MODE_CROP_WINDOWS;
     }
 
     boolean isAlwaysFocusable() {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ef8d230..3e99558 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1410,14 +1410,11 @@
         }
 
         if (mStackId == DOCKED_STACK_ID) {
-            // Docked stack is always visible, except in the case where the home activity
-            // is the top running activity in the focused home stack.
-            if (focusedStackId != HOME_STACK_ID) {
-                return STACK_VISIBLE;
-            }
-            ActivityRecord topHomeActivity = focusedStack.topRunningActivityLocked();
-            return topHomeActivity == null || !topHomeActivity.isHomeActivity() ?
-                    STACK_VISIBLE : STACK_INVISIBLE;
+            // Docked stack is always visible, except in the case where the top running activity in
+            // the focus stack doesn't support any form of resizing.
+            final ActivityRecord r = focusedStack.topRunningActivityLocked();
+            return r == null || r.isResizeable() || r.cropAppWindows()
+                    ? STACK_VISIBLE : STACK_INVISIBLE;
         }
 
         // Find the first stack below focused stack that actually got something visible.
@@ -4819,7 +4816,7 @@
                 r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                 (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
                 task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
-                !r.isHomeActivity(), r.isAlwaysFocusable());
+                r.cropAppWindows() | r.isResizeable(), r.isAlwaysFocusable());
         mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
         r.taskConfigOverride = task.mOverrideConfig;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8db2f8f..11dd8a3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -98,6 +98,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 import static android.Manifest.permission.START_ANY_ACTIVITY;
@@ -2019,7 +2020,7 @@
         // If this is a forced resize, let it go through even if the bounds is not changing,
         // as we might need a relayout due to surface size change (to/from fullscreen).
         final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
-        if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) {
+        if (Objects.equals(task.mBounds, bounds) && !forced) {
             // Nothing to do here...
             return true;
         }
@@ -2257,10 +2258,7 @@
             // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
             // window), we need to clear the replace window settings. Otherwise, we schedule a
             // timeout to remove the old window if the replacing window is not coming in time.
-            // In case of the pinned stack we don't resize the task during the move, but we will
-            // resize the stack soon after so we want to retain the replacing window.
-            mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken,
-                    !kept || stackId == PINNED_STACK_ID);
+            mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept);
         }
 
         // The task might have already been running and its visibility needs to be synchronized with
@@ -2294,7 +2292,8 @@
             return false;
         }
 
-        moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", bounds);
+        moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", null);
+        mWindowManager.animateResizePinnedStack(bounds);
         return true;
     }
 
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index fd787df..c9d4595 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -24,7 +24,8 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
@@ -447,7 +448,9 @@
         } else {
             autoRemoveRecents = false;
         }
-        mResizeable = (info.flags & FLAG_RESIZEABLE) != 0 || mService.mForceResizableActivities;
+        mResizeable = info.resizeMode == RESIZE_MODE_RESIZEABLE
+                || info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE
+                || mService.mForceResizableActivities;
         mLockTaskMode = info.lockTaskLaunchMode;
         mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
         setLockTaskAuth();
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 0029279..c5d38cb 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -248,10 +248,10 @@
     }
 
     public String toString() {
-        return "NetworkAgentInfo{ ni{" + networkInfo + "}  network{" +
-                network + "}  lp{" +
-                linkProperties + "}  nc{" +
-                networkCapabilities + "}  Score{" + getCurrentScore() + "}  " +
+        return "NetworkAgentInfo{ ni{" + networkInfo + "}  " +
+                "network{" + network + "}  nethandle{" + network.getNetworkHandle() + "}  " +
+                "lp{" + linkProperties + "}  " +
+                "nc{" + networkCapabilities + "}  Score{" + getCurrentScore() + "}  " +
                 "everValidated{" + everValidated + "}  lastValidated{" + lastValidated + "}  " +
                 "created{" + created + "} lingering{" + lingering + "} " +
                 "explicitlySelected{" + networkMisc.explicitlySelected + "} " +
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
similarity index 96%
rename from services/core/java/com/android/server/location/GpsLocationProvider.java
rename to services/core/java/com/android/server/location/GnssLocationProvider.java
index 88ab2c6..9798e56 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -35,11 +35,12 @@
 import android.hardware.location.GeofenceHardwareImpl;
 import android.location.Criteria;
 import android.location.FusedBatchOptions;
+import android.location.GnssStatus;
+import android.location.IGnssStatusListener;
+import android.location.IGnssStatusProvider;
 import android.location.GpsMeasurementsEvent;
 import android.location.GpsNavigationMessageEvent;
 import android.location.IGpsGeofenceHardware;
-import android.location.IGpsStatusListener;
-import android.location.IGpsStatusProvider;
 import android.location.ILocationManager;
 import android.location.INetInitiatedListener;
 import android.location.Location;
@@ -100,9 +101,9 @@
  *
  * {@hide}
  */
-public class GpsLocationProvider implements LocationProviderInterface {
+public class GnssLocationProvider implements LocationProviderInterface {
 
-    private static final String TAG = "GpsLocationProvider";
+    private static final String TAG = "GnssLocationProvider";
 
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
@@ -366,7 +367,7 @@
     private final ILocationManager mILocationManager;
     private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
     private Bundle mLocationExtras = new Bundle();
-    private final GpsStatusListenerHelper mListenerHelper;
+    private final GnssStatusListenerHelper mListenerHelper;
     private final GpsMeasurementsProvider mGpsMeasurementsProvider;
     private final GpsNavigationMessageProvider mGpsNavigationMessageProvider;
 
@@ -382,7 +383,7 @@
     private final GpsNetInitiatedHandler mNIHandler;
 
     // Wakelocks
-    private final static String WAKELOCK_KEY = "GpsLocationProvider";
+    private final static String WAKELOCK_KEY = "GnssLocationProvider";
     private final PowerManager.WakeLock mWakeLock;
 
     // Alarms
@@ -405,20 +406,22 @@
 
     private GeofenceHardwareImpl mGeofenceHardwareImpl;
 
-    private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
+    private int mYearOfHardware = 0;
+
+    private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
         @Override
-        public void addGpsStatusListener(IGpsStatusListener listener) {
-            mListenerHelper.addListener(listener);
+        public void registerGnssStatusCallback(IGnssStatusListener callback) {
+            mListenerHelper.addListener(callback);
         }
 
         @Override
-        public void removeGpsStatusListener(IGpsStatusListener listener) {
-            mListenerHelper.removeListener(listener);
+        public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
+            mListenerHelper.removeListener(callback);
         }
     };
 
-    public IGpsStatusProvider getGpsStatusProvider() {
-        return mGpsStatusProvider;
+    public IGnssStatusProvider getGnssStatusProvider() {
+        return mGnssStatusProvider;
     }
 
     public IGpsGeofenceHardware getGpsGeofenceProxy() {
@@ -655,7 +658,7 @@
         return true;
     }
 
-    public GpsLocationProvider(Context context, ILocationManager ilocationManager,
+    public GnssLocationProvider(Context context, ILocationManager ilocationManager,
             Looper looper) {
         mContext = context;
         mNtpTime = NtpTrustedTime.getInstance(context);
@@ -698,7 +701,7 @@
                                                 mNetInitiatedListener,
                                                 mSuplEsEnabled);
 
-        mListenerHelper = new GpsStatusListenerHelper(mHandler) {
+        mListenerHelper = new GnssStatusListenerHelper(mHandler) {
             @Override
             protected boolean isAvailableInPlatform() {
                 return isSupported();
@@ -1554,34 +1557,40 @@
      * called from native code to update SV info
      */
     private void reportSvStatus() {
-        int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
+        int svCount = native_read_sv_status(mPrnWithFlags, mSnrs, mSvElevations, mSvAzimuths,
+                mConstellationTypes);
         mListenerHelper.onSvStatusChanged(
                 svCount,
-                mSvs,
+                mPrnWithFlags,
                 mSnrs,
                 mSvElevations,
                 mSvAzimuths,
-                mSvMasks[EPHEMERIS_MASK],
-                mSvMasks[ALMANAC_MASK],
-                mSvMasks[USED_FOR_FIX_MASK]);
+                mConstellationTypes);
 
         if (VERBOSE) {
-            Log.v(TAG, "SV count: " + svCount +
-                    " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
-                    " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
-            for (int i = 0; i < svCount; i++) {
-                Log.v(TAG, "sv: " + mSvs[i] +
+            Log.v(TAG, "SV count: " + svCount);
+        }
+        // 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) {
+                ++usedInFixCount;
+            }
+            if (VERBOSE) {
+                Log.v(TAG, "prn: " + (mPrnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH) +
                         " snr: " + mSnrs[i]/10 +
                         " elev: " + mSvElevations[i] +
                         " azimuth: " + mSvAzimuths[i] +
-                        ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "  " : " E") +
-                        ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "  " : " A") +
-                        ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
+                        ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
+                                ? "  " : " E") +
+                        ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
+                                ? "  " : " A") +
+                        ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
+                                ? "" : "U"));
             }
         }
-
         // return number of sets used in fix instead of total
-        updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]));
+        updateStatus(mStatus, usedInFixCount);
 
         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
             System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
@@ -1675,6 +1684,33 @@
     }
 
     /**
+     * Called from native code to inform us the hardware information.
+     */
+    private void setGpsYearOfHardware(int yearOfHardware) {
+        if (DEBUG) Log.d(TAG, "setGpsYearOfHardware called with " + yearOfHardware);
+        mYearOfHardware = yearOfHardware;
+    }
+
+    public interface GpsSystemInfoProvider {
+        /**
+         * Returns the year of GPS hardware.
+         */
+        int getGpsYearOfHardware();
+    }
+
+    /**
+     * @hide
+     */
+    public GpsSystemInfoProvider getGpsSystemInfoProvider() {
+        return new GpsSystemInfoProvider() {
+            @Override
+            public int getGpsYearOfHardware() {
+                return mYearOfHardware;
+            }
+        };
+    }
+
+    /**
      * called from native code to request XTRA data
      */
     private void xtraDownloadRequest() {
@@ -2067,7 +2103,7 @@
         }
 
         /**
-         * This method is bound to {@link #GpsLocationProvider(Context, ILocationManager, Looper)}.
+         * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
          * It is in charge of loading properties and registering for events that will be posted to
          * this handler.
          */
@@ -2362,17 +2398,14 @@
     }
 
     // for GPS SV statistics
-    private static final int MAX_SVS = 32;
-    private static final int EPHEMERIS_MASK = 0;
-    private static final int ALMANAC_MASK = 1;
-    private static final int USED_FOR_FIX_MASK = 2;
+    private static final int MAX_SVS = 512;
 
     // preallocated arrays, to avoid memory allocation in reportStatus()
-    private int mSvs[] = new int[MAX_SVS];
+    private int mPrnWithFlags[] = 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 mSvMasks[] = new int[3];
+    private int mConstellationTypes[] = new int[MAX_SVS];
     private int mSvCount;
     // preallocated to avoid memory allocation in reportNmea()
     private byte[] mNmeaBuffer = new byte[120];
@@ -2392,8 +2425,8 @@
     private native void native_delete_aiding_data(int flags);
     // returns number of SVs
     // mask[0] is ephemeris mask and mask[1] is almanac mask
-    private native int native_read_sv_status(int[] svs, float[] snrs,
-            float[] elevations, float[] azimuths, int[] masks);
+    private native int native_read_sv_status(int[] prnWithFlags, float[] snrs, float[] elevations,
+            float[] azimuths, int[] constellationTypes);
     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/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
similarity index 63%
rename from services/core/java/com/android/server/location/GpsStatusListenerHelper.java
rename to services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index 53ff6c2..9840c61 100644
--- a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -16,17 +16,17 @@
 
 package com.android.server.location;
 
-import android.location.IGpsStatusListener;
+import android.location.IGnssStatusListener;
 import android.os.Handler;
 import android.os.RemoteException;
 
 /**
- * Implementation of a handler for {@link IGpsStatusListener}.
+ * Implementation of a handler for {@link IGnssStatusListener}.
  */
-abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
-    protected GpsStatusListenerHelper(Handler handler) {
-        super(handler, "GpsStatusListenerHelper");
-        setSupported(GpsLocationProvider.isSupported());
+abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatusListener> {
+    protected GnssStatusListenerHelper(Handler handler) {
+        super(handler, "GnssStatusListenerHelper");
+        setSupported(GnssLocationProvider.isSupported());
     }
 
     @Override
@@ -38,7 +38,7 @@
     protected void unregisterFromService() {}
 
     @Override
-    protected ListenerOperation<IGpsStatusListener> getHandlerOperation(int result) {
+    protected ListenerOperation<IGnssStatusListener> getHandlerOperation(int result) {
         return null;
     }
 
@@ -47,15 +47,15 @@
         if (isNavigating) {
             operation = new Operation() {
                 @Override
-                public void execute(IGpsStatusListener listener) throws RemoteException {
-                    listener.onGpsStarted();
+                public void execute(IGnssStatusListener listener) throws RemoteException {
+                    listener.onGnssStarted();
                 }
             };
         } else {
             operation = new Operation() {
                 @Override
-                public void execute(IGpsStatusListener listener) throws RemoteException {
-                    listener.onGpsStopped();
+                public void execute(IGnssStatusListener listener) throws RemoteException {
+                    listener.onGnssStopped();
                 }
             };
         }
@@ -65,7 +65,7 @@
     public void onFirstFix(final int timeToFirstFix) {
         Operation operation = new Operation() {
             @Override
-            public void execute(IGpsStatusListener listener) throws RemoteException {
+            public void execute(IGnssStatusListener listener) throws RemoteException {
                 listener.onFirstFix(timeToFirstFix);
             }
         };
@@ -74,25 +74,21 @@
 
     public void onSvStatusChanged(
             final int svCount,
-            final int[] prns,
+            final int[] prnWithFlags,
             final float[] snrs,
             final float[] elevations,
             final float[] azimuths,
-            final int ephemerisMask,
-            final int almanacMask,
-            final int usedInFixMask) {
+            final int[] constellationTypes) {
         Operation operation = new Operation() {
             @Override
-            public void execute(IGpsStatusListener listener) throws RemoteException {
+            public void execute(IGnssStatusListener listener) throws RemoteException {
                 listener.onSvStatusChanged(
                         svCount,
-                        prns,
+                        prnWithFlags,
                         snrs,
                         elevations,
                         azimuths,
-                        ephemerisMask,
-                        almanacMask,
-                        usedInFixMask);
+                        constellationTypes);
             }
         };
         foreach(operation);
@@ -101,12 +97,12 @@
     public void onNmeaReceived(final long timestamp, final String nmea) {
         Operation operation = new Operation() {
             @Override
-            public void execute(IGpsStatusListener listener) throws RemoteException {
+            public void execute(IGnssStatusListener listener) throws RemoteException {
                 listener.onNmeaReceived(timestamp, nmea);
             }
         };
         foreach(operation);
     }
 
-    private interface Operation extends ListenerOperation<IGpsStatusListener> {}
+    private interface Operation extends ListenerOperation<IGnssStatusListener> {}
 }
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
index 53ba718..479b065 100644
--- a/services/core/java/com/android/server/net/NetworkStatsAccess.java
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -66,15 +66,26 @@
          *
          * <p>Granted to:
          * <ul>
-         * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit
-         * so it is not necessarily sufficient to declare this in the manifest.
-         * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission.
          * <li>Profile owners.
          * </ul>
          */
         int USER = 1;
 
         /**
+         * Access level for apps which can access usage summary of device. Device summary includes
+         * usage by apps running in any profiles/users, however this access level does not
+         * allow querying usage of individual apps running in other profiles/users.
+         *
+         * <p>Granted to:
+         * <ul>
+         * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit
+         * so it is not necessarily sufficient to declare this in the manifest.
+         * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission.
+         * </ul>
+         */
+        int DEVICESUMMARY = 2;
+
+        /**
          * Access level for apps which can access usage for any app on the device, including apps
          * running on other users/profiles.
          *
@@ -85,7 +96,7 @@
          * <li>The system UID.
          * </ul>
          */
-        int DEVICE = 2;
+        int DEVICE = 3;
     }
 
     /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
@@ -107,11 +118,15 @@
             return NetworkStatsAccess.Level.DEVICE;
         }
 
+        boolean hasAppOpsPermission = hasAppOpsPermission(context, callingUid, callingPackage);
+        if (hasAppOpsPermission || context.checkCallingOrSelfPermission(
+                READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) {
+            return NetworkStatsAccess.Level.DEVICESUMMARY;
+        }
+
         boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
                 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-        if (hasAppOpsPermission(context, callingUid, callingPackage) || isProfileOwner
-                || context.checkCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY) ==
-                PackageManager.PERMISSION_GRANTED) {
+        if (isProfileOwner) {
             // Apps with the AppOps permission, profile owners, and apps with the privileged
             // permission can access data usage for all apps in this user/profile.
             return NetworkStatsAccess.Level.USER;
@@ -131,6 +146,7 @@
             case NetworkStatsAccess.Level.DEVICE:
                 // Device-level access - can access usage for any uid.
                 return true;
+            case NetworkStatsAccess.Level.DEVICESUMMARY:
             case NetworkStatsAccess.Level.USER:
                 // User-level access - can access usage for any app running in the same user, along
                 // with some special uids (system, removed, or tethering).
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index b1d6f89..3aeceef 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -484,15 +484,19 @@
             public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start,
                     long end) {
                 @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
-                if (accessLevel < NetworkStatsAccess.Level.DEVICE) {
+                if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) {
                     throw new SecurityException("Calling package " + mCallingPackage
-                            + " cannot access device-level network stats");
+                            + " cannot access device summary network stats");
                 }
                 NetworkStats result = new NetworkStats(end - start, 1);
                 final long ident = Binder.clearCallingIdentity();
                 try {
+                    // Using access level higher than the one we checked for above.
+                    // Reason is that we are combining usage data in a way that is not PII
+                    // anymore.
                     result.combineAllValues(
-                            internalGetSummaryForNetwork(template, start, end, accessLevel));
+                            internalGetSummaryForNetwork(template, start, end,
+                                    NetworkStatsAccess.Level.DEVICE));
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index bce7223..4d66e10 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -70,8 +70,7 @@
     }
 
     static boolean canOptimizePackage(PackageParser.Package pkg) {
-        return pkg.canHaveOatDir() &&
-                ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0);
+        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 552af03..43a17c9 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -134,7 +134,7 @@
     /** Fraction of animation at which the recents thumbnail becomes completely transparent */
     private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
 
-    private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+    static final int DEFAULT_APP_TRANSITION_DURATION = 336;
     private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
     private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336;
     private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
new file mode 100644
index 0000000..5f97478
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -0,0 +1,142 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.animation.LinearInterpolator;
+
+/**
+ * Enables animating bounds of objects.
+ *
+ * In multi-window world bounds of both stack and tasks can change. When we need these bounds to
+ * change smoothly and not require the app to relaunch (e.g. because it handles resizes and
+ * relaunching it would cause poorer experience), these class provides a way to directly animate
+ * the bounds of the resized object.
+ *
+ * The object that is resized needs to implement {@link AnimateBoundsUser} interface.
+ */
+public class BoundsAnimationController {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "BoundsAnimationController" : TAG_WM;
+
+    // Only acccessed on UI thread.
+    private ArrayMap<AnimateBoundsUser, BoundsAnimator> mRunningAnimations = new ArrayMap<>();
+
+    private final class BoundsAnimator extends ValueAnimator
+            implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
+        private final AnimateBoundsUser mTarget;
+        private final Rect mFrom;
+        private final Rect mTo;
+        private final Rect mTmpRect;
+
+        BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to) {
+            super();
+            mTarget = target;
+            mFrom = from;
+            mTo = to;
+            mTmpRect = new Rect();
+            addUpdateListener(this);
+            addListener(this);
+        }
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            final float value = (Float) animation.getAnimatedValue();
+            final float remains = 1 - value;
+            mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value);
+            mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value);
+            mTmpRect.right = (int) (mFrom.right * remains + mTo.right * value);
+            mTmpRect.bottom = (int) (mFrom.bottom * remains + mTo.bottom * value);
+            if (DEBUG_ANIM) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + ", mBounds="
+                    + mTmpRect + ", from=" + mFrom + ", mTo=" + mTo + ", value=" + value
+                    + ", remains=" + remains);
+            if (!mTarget.setSize(mTmpRect)) {
+                // Whoops, the target doesn't feel like animating anymore. Let's immediately finish
+                // any further animation.
+                animation.cancel();
+            }
+        }
+
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            finishAnimation();
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            finishAnimation();
+        }
+
+        private void finishAnimation() {
+            mTarget.finishBoundsAnimation();
+            removeListener(this);
+            removeUpdateListener(this);
+            mRunningAnimations.remove(mTarget);
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+
+        }
+    }
+
+    public interface AnimateBoundsUser {
+        /**
+         * Asks the target to directly (without any intermediate steps, like scheduling animation)
+         * resize its bounds.
+         *
+         * @return Whether the target still wants to be animated and successfully finished the
+         * operation. If it returns false, the animation will immediately be cancelled. The target
+         * should return false when something abnormal happened, e.g. it was completely removed
+         * from the hierarchy and is not valid anymore.
+         */
+        boolean setSize(Rect bounds);
+
+        /**
+         * Callback for the target to inform it that the animation is finished, so it can do some
+         * necessary cleanup.
+         */
+        void finishBoundsAnimation();
+    }
+
+    void animateBounds(AnimateBoundsUser target, Rect from, Rect to) {
+        final BoundsAnimator existing = mRunningAnimations.get(target);
+        if (existing != null) {
+            existing.cancel();
+        }
+        BoundsAnimator animator = new BoundsAnimator(target, from, to);
+        mRunningAnimations.put(target, animator);
+        animator.setFloatValues(0f, 1f);
+        animator.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+        animator.setInterpolator(new LinearInterpolator());
+        animator.start();
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index f02e49e..e0880ad 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -20,6 +20,7 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Debug;
+import android.os.RemoteException;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -47,7 +48,8 @@
 import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
-public class TaskStack implements DimLayer.DimLayerUser {
+public class TaskStack implements DimLayer.DimLayerUser,
+        BoundsAnimationController.AnimateBoundsUser {
 
     // If the stack should be resized to fullscreen.
     private static final boolean FULLSCREEN = true;
@@ -804,4 +806,32 @@
         }
         return false;
     }
+
+    @Override  // AnimatesBounds
+    public boolean setSize(Rect bounds) {
+        synchronized (mService.mWindowMap) {
+            if (mDisplayContent == null) {
+                return false;
+            }
+        }
+        try {
+            mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false);
+        } catch (RemoteException e) {
+        }
+        return true;
+    }
+
+    @Override  // AnimatesBounds
+    public void finishBoundsAnimation() {
+        synchronized (mService.mWindowMap) {
+            if (mTasks.isEmpty()) {
+                return;
+            }
+            final Task task = mTasks.get(mTasks.size() - 1);
+            if (task != null) {
+                task.setDragResizing(false);
+                mService.requestTraversal();
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 93a1015..2b88af4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -157,6 +157,7 @@
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 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.PINNED_STACK_ID;
 import static android.app.StatusBarManager.DISABLE_MASK;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -643,6 +644,9 @@
 
     final WindowAnimator mAnimator;
 
+    private final BoundsAnimationController mBoundsAnimationController =
+            new BoundsAnimationController();
+
     SparseArray<Task> mTaskIdToTask = new SparseArray<>();
 
     /** All of the TaskStacks in the window manager, unordered. For an ordered list call
@@ -2848,11 +2852,12 @@
         if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
             win.prepareWindowToDisplayDuringRelayout(outConfig);
         }
-        if ((attrChanges& LayoutParams.FORMAT_CHANGED) != 0) {
-            // If the format can be changed in place yaay!
-            // If not, fall back to a surface re-build
+        if ((attrChanges & LayoutParams.FORMAT_CHANGED) != 0) {
+            // If the format can't be changed in place, preserve the old surface until the app draws
+            // on the new one. This prevents blinking when we change elevation of freeform and
+            // pinned windows.
             if (!winAnimator.tryChangeFormatInPlaceLocked()) {
-                winAnimator.destroySurfaceLocked();
+                winAnimator.preserveSurfaceLocked();
                 result |= RELAYOUT_RES_SURFACE_CHANGED
                         | WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
             }
@@ -8085,7 +8090,8 @@
                 break;
                 case RESIZE_STACK: {
                     try {
-                        mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1);
+                        mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1, false,
+                                false);
                     } catch (RemoteException e) {
                         // This will not happen since we are in the same process.
                     }
@@ -10273,6 +10279,31 @@
         }
     }
 
+    public void animateResizePinnedStack(final Rect bounds) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+            if (stack == null) {
+                Slog.w(TAG, "animateResizePinnedStack: stackId " + PINNED_STACK_ID + " not found.");
+                return;
+            }
+            final ArrayList<Task> tasks = stack.getTasks();
+            if (tasks.isEmpty()) {
+                Slog.w(TAG, "animateResizePinnedStack: pinned stack doesn't have any tasks.");
+                return;
+            }
+            final Task task = tasks.get(tasks.size() - 1);
+            task.setDragResizing(true);
+            final Rect originalBounds = new Rect();
+            stack.getBounds(originalBounds);
+            UiThread.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    mBoundsAnimationController.animateBounds(stack, originalBounds, bounds);
+                }
+            });
+        }
+    }
+
     public void setTaskResizeable(int taskId, boolean resizeable) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c541b3f..1214948 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -57,6 +57,7 @@
 import java.util.ArrayList;
 
 import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
@@ -2051,10 +2052,21 @@
         // until the window to small size, otherwise the multithread renderer will shift last
         // one or more frame to wrong offset. So here we send fullscreen backdrop if either
         // isDragResizing() or isDragResizeChanged() is true.
+        boolean resizing = isDragResizing() || isDragResizeChanged();
+        if (StackId.useWindowFrameForBackdrop(getStackId()) || !resizing) {
+            return frame;
+        }
         DisplayInfo displayInfo = getDisplayInfo();
         mTmpRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
-        boolean resizing = isDragResizing() || isDragResizeChanged();
-        return (inFreeformWorkspace() || !resizing) ? frame : mTmpRect;
+        return mTmpRect;
+    }
+
+    private int getStackId() {
+        final TaskStack stack = getStack();
+        if (stack == null) {
+            return INVALID_STACK_ID;
+        }
+        return stack.mStackId;
     }
 
     private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 98d8d08..d1b8648 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -22,7 +22,7 @@
     $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
     $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \
-    $(LOCAL_REL_DIR)/com_android_server_location_GpsLocationProvider.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_location_GnssLocationProvider.cpp \
     $(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \
     $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
similarity index 79%
rename from services/core/jni/com_android_server_location_GpsLocationProvider.cpp
rename to services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index b8d4196..0c85a15 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "GpsLocationProvider"
+#define LOG_TAG "GnssLocationProvider"
 
 #define LOG_NDEBUG 0
 
 #include "JNIHelp.h"
 #include "jni.h"
 #include "hardware/hardware.h"
-#include "hardware/gps.h"
+#include "hardware/gps_internal.h"
 #include "hardware_legacy/power.h"
 #include "utils/Log.h"
 #include "utils/misc.h"
@@ -42,6 +42,7 @@
 static jmethodID method_reportAGpsStatus;
 static jmethodID method_reportNmea;
 static jmethodID method_setEngineCapabilities;
+static jmethodID method_setGpsYearOfHardware;
 static jmethodID method_xtraDownloadRequest;
 static jmethodID method_reportNiNotification;
 static jmethodID method_requestRefLocation;
@@ -67,8 +68,14 @@
 static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
 static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;
 
+#define MAX_SATELLITE_COUNT 512
+#define MAX_GPS_SATELLITE_COUNT 512
+
+#define PRN_SHIFT_WIDTH 3
+
 // temporary storage for GPS callbacks
-static GpsSvStatus  sGpsSvStatus;
+static GnssSvInfo sGnssSvList[MAX_SATELLITE_COUNT];
+static size_t sGnssSvListSize;
 static const char* sNmeaString;
 static int sNmeaStringLength;
 
@@ -105,7 +112,57 @@
 static void sv_status_callback(GpsSvStatus* sv_status)
 {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus));
+    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.
+    if (status_size == 0) {
+        status_size = sizeof(GpsSvStatus_v1);
+    }
+    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];
+            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) {
+                info.flags |= GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA;
+              }
+              if ((almanac_mask & this_prn_mask) != 0) {
+                info.flags |= GNSS_SV_FLAGS_HAS_ALMANAC_DATA;
+              }
+              if ((used_in_fix_mask & this_prn_mask) != 0) {
+                info.flags |= GNSS_SV_FLAGS_USED_IN_FIX;
+              }
+            }
+        }
+    } else {
+        sGnssSvListSize = 0;
+        ALOGE("Invalid size of GpsSvStatus found: %zd.", status_size);
+        return;
+    }
     env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
@@ -121,6 +178,14 @@
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
+static void set_system_info_callback(const GpsSystemInfo* info) {
+    ALOGD("set_system_info_callback: year_of_hw=%d\n", info->year_of_hw);
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setGpsYearOfHardware,
+                        info->year_of_hw);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
 static void set_capabilities_callback(uint32_t capabilities)
 {
     ALOGD("set_capabilities_callback: %du\n", capabilities);
@@ -162,6 +227,7 @@
     release_wakelock_callback,
     create_thread_callback,
     request_utc_time_callback,
+    set_system_info_callback,
 };
 
 static void xtra_download_request_callback()
@@ -213,7 +279,7 @@
     bool isSupported = false;
 
     size_t status_size = agps_status->size;
-    if (status_size == sizeof(AGpsStatus_v3)) {
+    if (status_size == sizeof(AGpsStatus)) {
       ALOGV("AGpsStatus is V3: %zd", status_size);
       switch (agps_status->addr.ss_family)
       {
@@ -439,7 +505,7 @@
     create_thread_callback,
 };
 
-static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
+static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
     int err;
     hw_module_t* module;
 
@@ -449,6 +515,7 @@
     method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
     method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
     method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
+    method_setGpsYearOfHardware = env->GetMethodID(clazz, "setGpsYearOfHardware", "(I)V");
     method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
     method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
             "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
@@ -509,13 +576,13 @@
     }
 }
 
-static jboolean android_location_GpsLocationProvider_is_supported(
+static jboolean android_location_GnssLocationProvider_is_supported(
         JNIEnv* /* env */, jclass /* clazz */)
 {
     return (sGpsInterface != NULL) ?  JNI_TRUE : JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_is_agps_ril_supported(
+static jboolean android_location_GnssLocationProvider_is_agps_ril_supported(
         JNIEnv* /* env */, jclass /* clazz */)
 {
     return (sAGpsRilInterface != NULL) ? JNI_TRUE : JNI_FALSE;
@@ -527,7 +594,7 @@
     return (sGnssConfigurationInterface != NULL) ? JNI_TRUE : JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
+static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj)
 {
     // this must be set before calling into the HAL library
     if (!mCallbacksObj)
@@ -553,13 +620,13 @@
     return JNI_TRUE;
 }
 
-static void android_location_GpsLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */)
+static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */)
 {
     if (sGpsInterface)
         sGpsInterface->cleanup();
 }
 
-static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* /* env */,
+static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
         jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
         jint preferred_time)
 {
@@ -575,7 +642,7 @@
         return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_start(JNIEnv* /* env */, jobject /* obj */)
+static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */)
 {
     if (sGpsInterface) {
         if (sGpsInterface->start() == 0) {
@@ -588,7 +655,7 @@
         return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */)
+static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */)
 {
     if (sGpsInterface) {
         if (sGpsInterface->stop() == 0) {
@@ -601,7 +668,7 @@
         return JNI_FALSE;
 }
 
-static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* /* env */,
+static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */,
                                                                     jobject /* obj */,
                                                                     jint flags)
 {
@@ -609,38 +676,36 @@
         sGpsInterface->delete_aiding_data(flags);
 }
 
-static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
-        jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
-        jintArray maskArray)
+static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
+        jintArray prnWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
+        jfloatArray azumArray, jintArray constellationTypeArray)
 {
     // this should only be called from within a call to reportSvStatus
-
-    jint* prns = env->GetIntArrayElements(prnArray, 0);
+    jint* prnWithFlags = env->GetIntArrayElements(prnWithFlagArray, 0);
     jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
     jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
     jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
-    jint* mask = env->GetIntArrayElements(maskArray, 0);
+    jint* constellationTypes = env->GetIntArrayElements(constellationTypeArray, 0);
 
-    int num_svs = sGpsSvStatus.num_svs;
-    for (int i = 0; i < num_svs; i++) {
-        prns[i] = sGpsSvStatus.sv_list[i].prn;
-        snrs[i] = sGpsSvStatus.sv_list[i].snr;
-        elev[i] = sGpsSvStatus.sv_list[i].elevation;
-        azim[i] = sGpsSvStatus.sv_list[i].azimuth;
+    // 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;
+        snrs[i] = info.snr;
+        elev[i] = info.elevation;
+        azim[i] = info.azimuth;
     }
-    mask[0] = sGpsSvStatus.ephemeris_mask;
-    mask[1] = sGpsSvStatus.almanac_mask;
-    mask[2] = sGpsSvStatus.used_in_fix_mask;
 
-    env->ReleaseIntArrayElements(prnArray, prns, 0);
+    env->ReleaseIntArrayElements(prnWithFlagArray, prnWithFlags, 0);
     env->ReleaseFloatArrayElements(snrArray, snrs, 0);
     env->ReleaseFloatArrayElements(elevArray, elev, 0);
     env->ReleaseFloatArrayElements(azumArray, azim, 0);
-    env->ReleaseIntArrayElements(maskArray, mask, 0);
-    return (jint) num_svs;
+    env->ReleaseIntArrayElements(constellationTypeArray, constellationTypes, 0);
+    return (jint) sGnssSvListSize;
 }
 
-static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(
+static void android_location_GnssLocationProvider_agps_set_reference_location_cellid(
         JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid)
 {
     AGpsRefLocation location;
@@ -667,7 +732,7 @@
     sAGpsRilInterface->set_ref_location(&location, sizeof(location));
 }
 
-static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env,
+static void android_location_GnssLocationProvider_agps_send_ni_message(JNIEnv* env,
         jobject /* obj */, jbyteArray ni_msg, jint size)
 {
     size_t sz;
@@ -684,7 +749,7 @@
     env->ReleaseByteArrayElements(ni_msg,b,0);
 }
 
-static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
+static void android_location_GnssLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
                                                              jint type, jstring  setid_string)
 {
     if (!sAGpsRilInterface) {
@@ -697,7 +762,7 @@
     env->ReleaseStringUTFChars(setid_string, setid);
 }
 
-static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
+static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
                                             jbyteArray nmeaArray, jint buffer_size)
 {
     // this should only be called from within a call to reportNmea
@@ -710,27 +775,27 @@
     return (jint) length;
 }
 
-static void android_location_GpsLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
+static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
         jlong time, jlong timeReference, jint uncertainty)
 {
     if (sGpsInterface)
         sGpsInterface->inject_time(time, timeReference, uncertainty);
 }
 
-static void android_location_GpsLocationProvider_inject_location(JNIEnv* /* env */,
+static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
         jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy)
 {
     if (sGpsInterface)
         sGpsInterface->inject_location(latitude, longitude, accuracy);
 }
 
-static jboolean android_location_GpsLocationProvider_supports_xtra(
+static jboolean android_location_GnssLocationProvider_supports_xtra(
         JNIEnv* /* env */, jobject /* obj */)
 {
     return (sGpsXtraInterface != NULL) ? JNI_TRUE : JNI_FALSE;
 }
 
-static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
+static void android_location_GnssLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
         jbyteArray data, jint length)
 {
     if (!sGpsXtraInterface) {
@@ -743,7 +808,7 @@
     env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
 }
 
-static void android_location_GpsLocationProvider_agps_data_conn_open(
+static void android_location_GnssLocationProvider_agps_data_conn_open(
         JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType)
 {
     if (!sAGpsInterface) {
@@ -758,7 +823,7 @@
     const char *apnStr = env->GetStringUTFChars(apn, NULL);
 
     size_t interface_size = sAGpsInterface->size;
-    if (interface_size == sizeof(AGpsInterface_v2)) {
+    if (interface_size == sizeof(AGpsInterface)) {
         sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType);
     } else if (interface_size == sizeof(AGpsInterface_v1)) {
         sAGpsInterface->data_conn_open(apnStr);
@@ -769,7 +834,7 @@
     env->ReleaseStringUTFChars(apn, apnStr);
 }
 
-static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
+static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
                                                                        jobject /* obj */)
 {
     if (!sAGpsInterface) {
@@ -779,7 +844,7 @@
     sAGpsInterface->data_conn_closed();
 }
 
-static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
+static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
                                                                        jobject /* obj */)
 {
     if (!sAGpsInterface) {
@@ -789,7 +854,7 @@
     sAGpsInterface->data_conn_failed();
 }
 
-static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
+static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
         jint type, jstring hostname, jint port)
 {
     if (!sAGpsInterface) {
@@ -801,7 +866,7 @@
     env->ReleaseStringUTFChars(hostname, c_hostname);
 }
 
-static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* /* env */,
+static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */,
       jobject /* obj */, jint notifId, jint response)
 {
     if (!sGpsNiInterface) {
@@ -812,7 +877,7 @@
     sGpsNiInterface->respond(notifId, response);
 }
 
-static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env,
+static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
                                                                        jobject /* obj */) {
     jstring result = NULL;
     if (sGpsDebugInterface) {
@@ -826,7 +891,7 @@
     return result;
 }
 
-static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */,
+static void android_location_GnssLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */,
         jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
 {
 
@@ -849,13 +914,13 @@
     }
 }
 
-static jboolean android_location_GpsLocationProvider_is_geofence_supported(
+static jboolean android_location_GnssLocationProvider_is_geofence_supported(
         JNIEnv* /* env */, jobject /* obj */)
 {
     return (sGpsGeofencingInterface != NULL) ? JNI_TRUE : JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_add_geofence(JNIEnv* /* env */,
+static jboolean android_location_GnssLocationProvider_add_geofence(JNIEnv* /* env */,
         jobject /* obj */, jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
         jint last_transition, jint monitor_transition, jint notification_responsiveness,
         jint unknown_timer) {
@@ -870,7 +935,7 @@
     return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_remove_geofence(JNIEnv* /* env */,
+static jboolean android_location_GnssLocationProvider_remove_geofence(JNIEnv* /* env */,
         jobject /* obj */, jint geofence_id) {
     if (sGpsGeofencingInterface != NULL) {
         sGpsGeofencingInterface->remove_geofence_area(geofence_id);
@@ -881,7 +946,7 @@
     return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_pause_geofence(JNIEnv* /* env */,
+static jboolean android_location_GnssLocationProvider_pause_geofence(JNIEnv* /* env */,
         jobject /* obj */, jint geofence_id) {
     if (sGpsGeofencingInterface != NULL) {
         sGpsGeofencingInterface->pause_geofence(geofence_id);
@@ -892,7 +957,7 @@
     return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* /* env */,
+static jboolean android_location_GnssLocationProvider_resume_geofence(JNIEnv* /* env */,
         jobject /* obj */, jint geofence_id, jint monitor_transition) {
     if (sGpsGeofencingInterface != NULL) {
         sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
@@ -903,10 +968,12 @@
     return JNI_FALSE;
 }
 
-static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
+static jobject translate_gps_clock(JNIEnv* env, void* data, size_t size) {
     const char* doubleSignature = "(D)V";
     const char* longSignature = "(J)V";
 
+    GpsClock* clock = reinterpret_cast<GpsClock*>(data);
+
     jclass gpsClockClass = env->FindClass("android/location/GpsClock");
     jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
 
@@ -958,11 +1025,23 @@
         env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
     }
 
+    if (flags & GPS_CLOCK_TYPE_LOCAL_HW_TIME) {
+        if (size == sizeof(GpsClock)) {
+            jmethodID setterMethod =
+                    env->GetMethodID(gpsClockClass,
+                                     "setTimeOfLastHwClockDiscontinuityInNs",
+                                     longSignature);
+            env->CallVoidMethod(gpsClockObject,
+                                setterMethod,
+                                clock->time_of_last_hw_clock_discontinuity_ns);
+        }
+    }
+
     env->DeleteLocalRef(gpsClockClass);
     return gpsClockObject;
 }
 
-static jobject translate_gps_measurement(JNIEnv* env, GpsMeasurement* measurement) {
+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";
@@ -972,6 +1051,7 @@
 
     jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
     jmethodID gpsMeasurementCtor = env->GetMethodID(gpsMeasurementClass, "<init>", "()V");
+    GpsMeasurement* measurement = reinterpret_cast<GpsMeasurement*>(data);
 
     jobject gpsMeasurementObject = env->NewObject(gpsMeasurementClass, gpsMeasurementCtor);
     GpsMeasurementFlags flags = measurement->flags;
@@ -1205,12 +1285,38 @@
             usedInFixSetterMethod,
             (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
 
+    if (size == sizeof(GpsMeasurement)) {
+      jmethodID setterMethod =
+          env->GetMethodID(gpsMeasurementClass,
+                           "setPseudorangeRateCarrierInMetersPerSec",
+                           doubleSignature);
+      env->CallVoidMethod(
+          gpsMeasurementObject,
+          setterMethod,
+          measurement->pseudorange_rate_carrier_mps);
+
+      setterMethod =
+          env->GetMethodID(gpsMeasurementClass,
+                           "setPseudorangeRateCarrierUncertaintyInMetersPerSec",
+                           doubleSignature);
+      env->CallVoidMethod(
+          gpsMeasurementObject,
+          setterMethod,
+          measurement->pseudorange_rate_carrier_uncertainty_mps);
+    }
+
     env->DeleteLocalRef(gpsMeasurementClass);
     return gpsMeasurementObject;
 }
 
-static jobjectArray translate_gps_measurements(JNIEnv* env, GpsData* data) {
-    size_t measurementCount = data->measurement_count;
+/**
+ * <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) {
         return NULL;
     }
@@ -1221,9 +1327,11 @@
             gpsMeasurementClass,
             NULL /* initialElement */);
 
-    GpsMeasurement* gpsMeasurements = data->measurements;
     for (uint16_t i = 0; i < measurementCount; ++i) {
-        jobject gpsMeasurement = translate_gps_measurement(env, &gpsMeasurements[i]);
+        jobject gpsMeasurement = translate_gps_measurement(
+            env,
+            &(gps_data->measurements[i]),
+            sizeof(gps_data->measurements[0]));
         env->SetObjectArrayElement(gpsMeasurementArray, i, gpsMeasurement);
         env->DeleteLocalRef(gpsMeasurement);
     }
@@ -1238,33 +1346,39 @@
         ALOGE("Invalid data provided to gps_measurement_callback");
         return;
     }
-
-    if (data->size == sizeof(GpsData)) {
-        jobject gpsClock = translate_gps_clock(env, &data->clock);
-        jobjectArray measurementArray = translate_gps_measurements(env, data);
-
-        jclass gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
-        jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
-                gpsMeasurementsEventClass,
-                "<init>",
-                "(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
-
-        jobject gpsMeasurementsEvent = env->NewObject(
-                gpsMeasurementsEventClass,
-                gpsMeasurementsEventCtor,
-                gpsClock,
-                measurementArray);
-
-        env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
-        checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
-        env->DeleteLocalRef(gpsClock);
-        env->DeleteLocalRef(measurementArray);
-        env->DeleteLocalRef(gpsMeasurementsEventClass);
-        env->DeleteLocalRef(gpsMeasurementsEvent);
-    } else {
+    if (data->size != sizeof(GpsData) && data->size != sizeof(GpsData_v1)) {
         ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%zd", data->size);
+        return;
     }
+
+    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 gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
+    jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
+        gpsMeasurementsEventClass,
+        "<init>",
+        "(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
+
+    jobject gpsMeasurementsEvent = env->NewObject(
+        gpsMeasurementsEventClass,
+        gpsMeasurementsEventCtor,
+        gpsClock,
+        measurementArray);
+
+    env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+    env->DeleteLocalRef(gpsClock);
+    env->DeleteLocalRef(measurementArray);
+    env->DeleteLocalRef(gpsMeasurementsEventClass);
+    env->DeleteLocalRef(gpsMeasurementsEvent);
 }
 
 GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
@@ -1272,7 +1386,7 @@
     measurement_callback,
 };
 
-static jboolean android_location_GpsLocationProvider_is_measurement_supported(
+static jboolean android_location_GnssLocationProvider_is_measurement_supported(
         JNIEnv* env,
         jclass clazz) {
     if (sGpsMeasurementInterface != NULL) {
@@ -1281,7 +1395,7 @@
     return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_start_measurement_collection(
+static jboolean android_location_GnssLocationProvider_start_measurement_collection(
         JNIEnv* env,
         jobject obj) {
     if (sGpsMeasurementInterface == NULL) {
@@ -1298,7 +1412,7 @@
     return JNI_TRUE;
 }
 
-static jboolean android_location_GpsLocationProvider_stop_measurement_collection(
+static jboolean android_location_GnssLocationProvider_stop_measurement_collection(
         JNIEnv* env,
         jobject obj) {
     if (sGpsMeasurementInterface == NULL) {
@@ -1382,7 +1496,7 @@
     navigation_message_callback,
 };
 
-static jboolean android_location_GpsLocationProvider_is_navigation_message_supported(
+static jboolean android_location_GnssLocationProvider_is_navigation_message_supported(
         JNIEnv* env,
         jclass clazz) {
     if(sGpsNavigationMessageInterface != NULL) {
@@ -1391,7 +1505,7 @@
     return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_start_navigation_message_collection(
+static jboolean android_location_GnssLocationProvider_start_navigation_message_collection(
         JNIEnv* env,
         jobject obj) {
     if (sGpsNavigationMessageInterface == NULL) {
@@ -1408,7 +1522,7 @@
     return JNI_TRUE;
 }
 
-static jboolean android_location_GpsLocationProvider_stop_navigation_message_collection(
+static jboolean android_location_GnssLocationProvider_stop_navigation_message_collection(
         JNIEnv* env,
         jobject obj) {
     if (sGpsNavigationMessageInterface == NULL) {
@@ -1420,7 +1534,7 @@
     return JNI_TRUE;
 }
 
-static void android_location_GpsLocationProvider_configuration_update(JNIEnv* env, jobject obj,
+static void android_location_GnssLocationProvider_configuration_update(JNIEnv* env, jobject obj,
         jstring config_content)
 {
     if (!sGnssConfigurationInterface) {
@@ -1436,105 +1550,105 @@
 
 static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
-    {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
-    {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
+    {"class_init_native", "()V", (void *)android_location_GnssLocationProvider_class_init_native},
+    {"native_is_supported", "()Z", (void*)android_location_GnssLocationProvider_is_supported},
     {"native_is_agps_ril_supported", "()Z",
-            (void*)android_location_GpsLocationProvider_is_agps_ril_supported},
+            (void*)android_location_GnssLocationProvider_is_agps_ril_supported},
     {"native_is_gnss_configuration_supported", "()Z",
             (void*)android_location_gpsLocationProvider_is_gnss_configuration_supported},
-    {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
-    {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
+    {"native_init", "()Z", (void*)android_location_GnssLocationProvider_init},
+    {"native_cleanup", "()V", (void*)android_location_GnssLocationProvider_cleanup},
     {"native_set_position_mode",
             "(IIIII)Z",
-            (void*)android_location_GpsLocationProvider_set_position_mode},
-    {"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
-    {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
+            (void*)android_location_GnssLocationProvider_set_position_mode},
+    {"native_start", "()Z", (void*)android_location_GnssLocationProvider_start},
+    {"native_stop", "()Z", (void*)android_location_GnssLocationProvider_stop},
     {"native_delete_aiding_data",
             "(I)V",
-            (void*)android_location_GpsLocationProvider_delete_aiding_data},
+            (void*)android_location_GnssLocationProvider_delete_aiding_data},
     {"native_read_sv_status",
             "([I[F[F[F[I)I",
-            (void*)android_location_GpsLocationProvider_read_sv_status},
-    {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
-    {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
+            (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},
     {"native_inject_location",
             "(DDF)V",
-            (void*)android_location_GpsLocationProvider_inject_location},
-    {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
+            (void*)android_location_GnssLocationProvider_inject_location},
+    {"native_supports_xtra", "()Z", (void*)android_location_GnssLocationProvider_supports_xtra},
     {"native_inject_xtra_data",
             "([BI)V",
-            (void*)android_location_GpsLocationProvider_inject_xtra_data},
+            (void*)android_location_GnssLocationProvider_inject_xtra_data},
     {"native_agps_data_conn_open",
             "(Ljava/lang/String;I)V",
-            (void*)android_location_GpsLocationProvider_agps_data_conn_open},
+            (void*)android_location_GnssLocationProvider_agps_data_conn_open},
     {"native_agps_data_conn_closed",
             "()V",
-            (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
+            (void*)android_location_GnssLocationProvider_agps_data_conn_closed},
     {"native_agps_data_conn_failed",
             "()V",
-            (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
+            (void*)android_location_GnssLocationProvider_agps_data_conn_failed},
     {"native_agps_set_id",
             "(ILjava/lang/String;)V",
-            (void*)android_location_GpsLocationProvider_agps_set_id},
+            (void*)android_location_GnssLocationProvider_agps_set_id},
     {"native_agps_set_ref_location_cellid",
             "(IIIII)V",
-            (void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
+            (void*)android_location_GnssLocationProvider_agps_set_reference_location_cellid},
     {"native_set_agps_server",
             "(ILjava/lang/String;I)V",
-            (void*)android_location_GpsLocationProvider_set_agps_server},
+            (void*)android_location_GnssLocationProvider_set_agps_server},
     {"native_send_ni_response",
             "(II)V",
-            (void*)android_location_GpsLocationProvider_send_ni_response},
+            (void*)android_location_GnssLocationProvider_send_ni_response},
     {"native_agps_ni_message",
             "([BI)V",
-            (void *)android_location_GpsLocationProvider_agps_send_ni_message},
+            (void *)android_location_GnssLocationProvider_agps_send_ni_message},
     {"native_get_internal_state",
             "()Ljava/lang/String;",
-            (void*)android_location_GpsLocationProvider_get_internal_state},
+            (void*)android_location_GnssLocationProvider_get_internal_state},
     {"native_update_network_state",
             "(ZIZZLjava/lang/String;Ljava/lang/String;)V",
-            (void*)android_location_GpsLocationProvider_update_network_state },
+            (void*)android_location_GnssLocationProvider_update_network_state },
     {"native_is_geofence_supported",
             "()Z",
-            (void*) android_location_GpsLocationProvider_is_geofence_supported},
+            (void*) android_location_GnssLocationProvider_is_geofence_supported},
     {"native_add_geofence",
             "(IDDDIIII)Z",
-            (void *)android_location_GpsLocationProvider_add_geofence},
+            (void *)android_location_GnssLocationProvider_add_geofence},
     {"native_remove_geofence",
             "(I)Z",
-            (void *)android_location_GpsLocationProvider_remove_geofence},
-    {"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
+            (void *)android_location_GnssLocationProvider_remove_geofence},
+    {"native_pause_geofence", "(I)Z", (void *)android_location_GnssLocationProvider_pause_geofence},
     {"native_resume_geofence",
             "(II)Z",
-            (void *)android_location_GpsLocationProvider_resume_geofence},
+            (void *)android_location_GnssLocationProvider_resume_geofence},
     {"native_is_measurement_supported",
             "()Z",
-            (void*) android_location_GpsLocationProvider_is_measurement_supported},
+            (void*) android_location_GnssLocationProvider_is_measurement_supported},
     {"native_start_measurement_collection",
             "()Z",
-            (void*) android_location_GpsLocationProvider_start_measurement_collection},
+            (void*) android_location_GnssLocationProvider_start_measurement_collection},
     {"native_stop_measurement_collection",
             "()Z",
-            (void*) android_location_GpsLocationProvider_stop_measurement_collection},
+            (void*) android_location_GnssLocationProvider_stop_measurement_collection},
     {"native_is_navigation_message_supported",
             "()Z",
-            (void*) android_location_GpsLocationProvider_is_navigation_message_supported},
+            (void*) android_location_GnssLocationProvider_is_navigation_message_supported},
     {"native_start_navigation_message_collection",
             "()Z",
-            (void*) android_location_GpsLocationProvider_start_navigation_message_collection},
+            (void*) android_location_GnssLocationProvider_start_navigation_message_collection},
     {"native_stop_navigation_message_collection",
             "()Z",
-            (void*) android_location_GpsLocationProvider_stop_navigation_message_collection},
+            (void*) android_location_GnssLocationProvider_stop_navigation_message_collection},
     {"native_configuration_update",
             "(Ljava/lang/String;)V",
-            (void*)android_location_GpsLocationProvider_configuration_update},
+            (void*)android_location_GnssLocationProvider_configuration_update},
 };
 
-int register_android_server_location_GpsLocationProvider(JNIEnv* env)
+int register_android_server_location_GnssLocationProvider(JNIEnv* env)
 {
     return jniRegisterNativeMethods(
             env,
-            "com/android/server/location/GpsLocationProvider",
+            "com/android/server/location/GnssLocationProvider",
             sMethods,
             NELEM(sMethods));
 }
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 1f3fde6..a7010bc 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -36,7 +36,7 @@
 int register_android_server_UsbMidiDevice(JNIEnv* env);
 int register_android_server_UsbHostManager(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
-int register_android_server_location_GpsLocationProvider(JNIEnv* env);
+int register_android_server_location_GnssLocationProvider(JNIEnv* env);
 int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
@@ -71,7 +71,7 @@
     register_android_server_UsbHostManager(env);
     register_android_server_VibratorService(env);
     register_android_server_SystemServer(env);
-    register_android_server_location_GpsLocationProvider(env);
+    register_android_server_location_GnssLocationProvider(env);
     register_android_server_location_FlpHardwareProvider(env);
     register_android_server_connectivity_Vpn(env);
     register_android_server_AssetAtlasService(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b94e6d6..236ae68e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -49,6 +49,7 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.backup.IBackupManager;
+import android.auditing.SecurityLog;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -4401,6 +4402,10 @@
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
+
+        if (SecurityLog.isLoggingEnabled()) {
+            SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0);
+        }
     }
 
     @Override
@@ -4427,6 +4432,28 @@
                 }
             }
         }
+
+        if (SecurityLog.isLoggingEnabled()) {
+            SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1);
+        }
+    }
+
+    @Override
+    public void reportKeyguardDismissed() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        if (SecurityLog.isLoggingEnabled()) {
+            SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISSED);
+        }
+    }
+
+    @Override
+    public void reportKeyguardSecured() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        if (SecurityLog.isLoggingEnabled()) {
+            SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_SECURED);
+        }
     }
 
     @Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9f320e4..254a37a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -68,6 +68,7 @@
 import com.android.server.input.InputManagerService;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.lights.LightsService;
+import com.android.internal.widget.ILockSettings;
 import com.android.server.media.MediaRouterService;
 import com.android.server.media.MediaSessionService;
 import com.android.server.media.MediaResourceMonitorService;
@@ -143,6 +144,8 @@
             "com.android.server.ethernet.EthernetService";
     private static final String JOB_SCHEDULER_SERVICE_CLASS =
             "com.android.server.job.JobSchedulerService";
+    private static final String LOCK_SETTINGS_SERVICE_CLASS =
+            "com.android.server.LockSettingsService$Lifecycle";
     private static final String MOUNT_SERVICE_CLASS =
             "com.android.server.MountService$Lifecycle";
     private static final String SEARCH_MANAGER_SERVICE_CLASS =
@@ -607,7 +610,7 @@
         LocationManagerService location = null;
         CountryDetectorService countryDetector = null;
         TextServicesManagerService tsms = null;
-        LockSettingsService lockSettings = null;
+        ILockSettings lockSettings = null;
         AssetAtlasService atlas = null;
         MediaRouterService mediaRouter = null;
 
@@ -680,8 +683,9 @@
             if (!disableNonCoreServices) {
                 traceBeginAndSlog("StartLockSettingsService");
                 try {
-                    lockSettings = new LockSettingsService(context);
-                    ServiceManager.addService("lock_settings", lockSettings);
+                    mSystemServiceManager.startService(LOCK_SETTINGS_SERVICE_CLASS);
+                    lockSettings = ILockSettings.Stub.asInterface(
+                            ServiceManager.getService("lock_settings"));
                 } catch (Throwable e) {
                     reportWtf("starting LockSettingsService service", e);
                 }
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 1b6e162..f62b170 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -89,7 +89,7 @@
     /*
      * Information about how to respond to an incoming call.
      */
-    public class CallResponse {
+    public static class CallResponse {
         private final boolean mShouldDisallowCall;
         private final boolean mShouldRejectCall;
         private final boolean mShouldSkipCallLog;
@@ -140,7 +140,7 @@
             return mShouldSkipNotification;
         }
 
-        public class Builder {
+        public static class Builder {
             private boolean mShouldDisallowCall;
             private boolean mShouldRejectCall;
             private boolean mShouldSkipCallLog;
diff --git a/test-runner/src/android/test/ActivityInstrumentationTestCase.java b/test-runner/src/android/test/ActivityInstrumentationTestCase.java
index a59ee35..aca1c16 100644
--- a/test-runner/src/android/test/ActivityInstrumentationTestCase.java
+++ b/test-runner/src/android/test/ActivityInstrumentationTestCase.java
@@ -23,15 +23,15 @@
  * be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity())
  * and you will then be able to manipulate your Activity directly.  Most of the work is handled
  * automatically here by {@link #setUp} and {@link #tearDown}.
- * 
+ *
  * <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}.
- * 
- * @deprecated new tests should be written using 
+ *
+ * @deprecated new tests should be written using
  * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
  * configuring the Activity under test
  */
 @Deprecated
-public abstract class ActivityInstrumentationTestCase<T extends Activity> 
+public abstract class ActivityInstrumentationTestCase<T extends Activity>
         extends ActivityTestCase {
     String mPackage;
     Class<T> mActivityClass;
@@ -39,7 +39,7 @@
 
     /**
      * Creates an {@link ActivityInstrumentationTestCase} in non-touch mode.
-     * 
+     *
      * @param pkg ignored - no longer in use.
      * @param activityClass The activity to test. This must be a class in the instrumentation
      * targetPackage specified in the AndroidManifest.xml
@@ -56,7 +56,7 @@
      * targetPackage specified in the AndroidManifest.xml
      * @param initialTouchMode true = in touch mode
      */
-    public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass, 
+    public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass,
             boolean initialTouchMode) {
         mActivityClass = activityClass;
         mInitialTouchMode = initialTouchMode;
@@ -80,8 +80,8 @@
     protected void tearDown() throws Exception {
         getActivity().finish();
         setActivity(null);
-        
-        // Scrub out members - protects against memory leaks in the case where someone 
+
+        // Scrub out members - protects against memory leaks in the case where someone
         // creates a non-static inner class (thus referencing the test case) and gives it to
         // someone else to hold onto
         scrubClass(ActivityInstrumentationTestCase.class);
diff --git a/test-runner/src/android/test/ActivityInstrumentationTestCase2.java b/test-runner/src/android/test/ActivityInstrumentationTestCase2.java
index c4bcf31..0e61ce7 100644
--- a/test-runner/src/android/test/ActivityInstrumentationTestCase2.java
+++ b/test-runner/src/android/test/ActivityInstrumentationTestCase2.java
@@ -25,26 +25,26 @@
  * This class provides functional testing of a single activity.  The activity under test will
  * be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity())
  * and you will then be able to manipulate your Activity directly.
- * 
+ *
  * <p>Other options supported by this test case include:
  * <ul>
  * <li>You can run any test method on the UI thread (see {@link android.test.UiThreadTest}).</li>
- * <li>You can inject custom Intents into your Activity (see 
+ * <li>You can inject custom Intents into your Activity (see
  * {@link #setActivityIntent(Intent)}).</li>
  * </ul>
- * 
+ *
  * <p>This class replaces {@link android.test.ActivityInstrumentationTestCase}, which is deprecated.
  * New tests should be written using this base class.
- * 
+ *
  * <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}.
  *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about application testing, read the
- * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p>
- * </div>
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+ * ActivityTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
-public abstract class ActivityInstrumentationTestCase2<T extends Activity> 
+@Deprecated
+public abstract class ActivityInstrumentationTestCase2<T extends Activity>
         extends ActivityTestCase {
     Class<T> mActivityClass;
     boolean mInitialTouchMode = false;
@@ -78,18 +78,18 @@
      * Get the Activity under test, starting it if necessary.
      *
      * For each test method invocation, the Activity will not actually be created until the first
-     * time this method is called. 
-     * 
-     * <p>If you wish to provide custom setup values to your Activity, you may call 
-     * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)} 
-     * before your first call to getActivity().  Calling them after your Activity has 
+     * time this method is called.
+     *
+     * <p>If you wish to provide custom setup values to your Activity, you may call
+     * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)}
+     * before your first call to getActivity().  Calling them after your Activity has
      * started will have no effect.
      *
      * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
      * If your test method is annotated with {@link android.test.UiThreadTest}, then your Activity
      * will be started automatically just before your test method is run.  You still call this
      * method in order to get the Activity under test.
-     * 
+     *
      * @return the Activity under test
      */
     @Override
@@ -113,10 +113,10 @@
     /**
      * Call this method before the first call to {@link #getActivity} to inject a customized Intent
      * into the Activity under test.
-     * 
+     *
      * <p>If you do not call this, the default intent will be provided.  If you call this after
      * your Activity has been started, it will have no effect.
-     * 
+     *
      * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
      * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call
      * {@link #setActivityIntent(Intent)} from {@link #setUp()}.
@@ -131,28 +131,28 @@
     public void setActivityIntent(Intent i) {
         mActivityIntent = i;
     }
-    
+
     /**
      * Call this method before the first call to {@link #getActivity} to set the initial touch
      * mode for the Activity under test.
-     * 
+     *
      * <p>If you do not call this, the touch mode will be false.  If you call this after
      * your Activity has been started, it will have no effect.
-     * 
+     *
      * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
      * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call
      * {@link #setActivityInitialTouchMode(boolean)} from {@link #setUp()}.
-     * 
+     *
      * @param initialTouchMode true if the Activity should be placed into "touch mode" when started
      */
     public void setActivityInitialTouchMode(boolean initialTouchMode) {
         mInitialTouchMode = initialTouchMode;
     }
-    
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        
+
         mInitialTouchMode = false;
         mActivityIntent = null;
     }
@@ -165,8 +165,8 @@
             a.finish();
             setActivity(null);
         }
-        
-        // Scrub out members - protects against memory leaks in the case where someone 
+
+        // Scrub out members - protects against memory leaks in the case where someone
         // creates a non-static inner class (thus referencing the test case) and gives it to
         // someone else to hold onto
         scrubClass(ActivityInstrumentationTestCase2.class);
diff --git a/test-runner/src/android/test/ActivityTestCase.java b/test-runner/src/android/test/ActivityTestCase.java
index c7b1d70..51dd3ef 100644
--- a/test-runner/src/android/test/ActivityTestCase.java
+++ b/test-runner/src/android/test/ActivityTestCase.java
@@ -25,7 +25,11 @@
  * This is common code used to support Activity test cases.  For more useful classes, please see
  * {@link android.test.ActivityUnitTestCase} and
  * {@link android.test.ActivityInstrumentationTestCase}.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public abstract class ActivityTestCase extends InstrumentationTestCase {
 
     /**
diff --git a/test-runner/src/android/test/ActivityUnitTestCase.java b/test-runner/src/android/test/ActivityUnitTestCase.java
index 40cca90..a191445 100644
--- a/test-runner/src/android/test/ActivityUnitTestCase.java
+++ b/test-runner/src/android/test/ActivityUnitTestCase.java
@@ -32,14 +32,14 @@
 
 /**
  * This class provides isolated testing of a single activity.  The activity under test will
- * be created with minimal connection to the system infrastructure, and you can inject mocked or 
+ * be created with minimal connection to the system infrastructure, and you can inject mocked or
  * wrappered versions of many of Activity's dependencies.  Most of the work is handled
  * automatically here by {@link #setUp} and {@link #tearDown}.
- * 
+ *
  * <p>If you prefer a functional test, see {@link android.test.ActivityInstrumentationTestCase}.
- * 
+ *
  * <p>It must be noted that, as a true unit test, your Activity will not be running in the
- * normal system and will not participate in the normal interactions with other Activities.  
+ * normal system and will not participate in the normal interactions with other Activities.
  * The following methods should not be called in this configuration - most of them will throw
  * exceptions:
  * <ul>
@@ -54,17 +54,17 @@
  * <li>{@link android.app.Activity#isTaskRoot()}</li>
  * <li>{@link android.app.Activity#moveTaskToBack(boolean)}</li>
  * </ul>
- * 
- * <p>The following methods may be called but will not do anything.  For test purposes, you can use 
- * the methods {@link #getStartedActivityIntent()} and {@link #getStartedActivityRequest()} to 
+ *
+ * <p>The following methods may be called but will not do anything.  For test purposes, you can use
+ * the methods {@link #getStartedActivityIntent()} and {@link #getStartedActivityRequest()} to
  * inspect the parameters that they were called with.
  * <ul>
  * <li>{@link android.app.Activity#startActivity(Intent)}</li>
  * <li>{@link android.app.Activity#startActivityForResult(Intent, int)}</li>
  * </ul>
  *
- * <p>The following methods may be called but will not do anything.  For test purposes, you can use 
- * the methods {@link #isFinishCalled()} and {@link #getFinishedActivityRequest()} to inspect the 
+ * <p>The following methods may be called but will not do anything.  For test purposes, you can use
+ * the methods {@link #isFinishCalled()} and {@link #getFinishedActivityRequest()} to inspect the
  * parameters that they were called with.
  * <ul>
  * <li>{@link android.app.Activity#finish()}</li>
@@ -72,8 +72,12 @@
  * <li>{@link android.app.Activity#finishActivity(int requestCode)}</li>
  * </ul>
  *
+ * @deprecated Write
+ * <a href="{@docRoot}training/testing/unit-testing/local-unit-tests.html">Local Unit Tests</a>
+ * instead.
  */
-public abstract class ActivityUnitTestCase<T extends Activity> 
+@Deprecated
+public abstract class ActivityUnitTestCase<T extends Activity>
         extends ActivityTestCase {
 
     private static final String TAG = "ActivityUnitTestCase";
@@ -102,31 +106,31 @@
         // default value for target context, as a default
       mActivityContext = getInstrumentation().getTargetContext();
     }
-    
+
     /**
      * Start the activity under test, in the same way as if it was started by
-     * {@link android.content.Context#startActivity Context.startActivity()}, providing the 
+     * {@link android.content.Context#startActivity Context.startActivity()}, providing the
      * arguments it supplied.  When you use this method to start the activity, it will automatically
      * be stopped by {@link #tearDown}.
-     * 
-     * <p>This method will call onCreate(), but if you wish to further exercise Activity life 
+     *
+     * <p>This method will call onCreate(), but if you wish to further exercise Activity life
      * cycle methods, you must call them yourself from your test case.
-     * 
+     *
      * <p><i>Do not call from your setUp() method.  You must call this method from each of your
      * test methods.</i>
-     *  
+     *
      * @param intent The Intent as if supplied to {@link android.content.Context#startActivity}.
      * @param savedInstanceState The instance state, if you are simulating this part of the life
      * cycle.  Typically null.
-     * @param lastNonConfigurationInstance This Object will be available to the 
-     * Activity if it calls {@link android.app.Activity#getLastNonConfigurationInstance()}.  
+     * @param lastNonConfigurationInstance This Object will be available to the
+     * Activity if it calls {@link android.app.Activity#getLastNonConfigurationInstance()}.
      * Typically null.
      * @return Returns the Activity that was created
      */
     protected T startActivity(Intent intent, Bundle savedInstanceState,
             Object lastNonConfigurationInstance) {
         assertFalse("Activity already created", mCreated);
-        
+
         if (!mAttached) {
             assertNotNull(mActivityClass);
             setActivity(null);
@@ -154,7 +158,7 @@
 
             assertNotNull(newActivity);
             setActivity(newActivity);
-            
+
             mAttached = true;
         }
 
@@ -165,22 +169,22 @@
         }
         return result;
     }
-    
+
     @Override
     protected void tearDown() throws Exception {
-        
+
         setActivity(null);
-        
-        // Scrub out members - protects against memory leaks in the case where someone 
+
+        // Scrub out members - protects against memory leaks in the case where someone
         // creates a non-static inner class (thus referencing the test case) and gives it to
         // someone else to hold onto
         scrubClass(ActivityInstrumentationTestCase.class);
 
         super.tearDown();
     }
-    
+
     /**
-     * Set the application for use during the test.  You must call this function before calling 
+     * Set the application for use during the test.  You must call this function before calling
      * {@link #startActivity}.  If your test does not call this method,
      * @param application The Application object that will be injected into the Activity under test.
      */
@@ -198,7 +202,7 @@
     }
 
     /**
-     * This method will return the value if your Activity under test calls 
+     * This method will return the value if your Activity under test calls
      * {@link android.app.Activity#setRequestedOrientation}.
      */
     public int getRequestedOrientation() {
@@ -207,10 +211,10 @@
         }
         return 0;
     }
-    
+
     /**
-     * This method will return the launch intent if your Activity under test calls 
-     * {@link android.app.Activity#startActivity(Intent)} or 
+     * This method will return the launch intent if your Activity under test calls
+     * {@link android.app.Activity#startActivity(Intent)} or
      * {@link android.app.Activity#startActivityForResult(Intent, int)}.
      * @return The Intent provided in the start call, or null if no start call was made.
      */
@@ -220,9 +224,9 @@
         }
         return null;
     }
-    
+
     /**
-     * This method will return the launch request code if your Activity under test calls 
+     * This method will return the launch request code if your Activity under test calls
      * {@link android.app.Activity#startActivityForResult(Intent, int)}.
      * @return The request code provided in the start call, or -1 if no start call was made.
      */
@@ -234,9 +238,9 @@
     }
 
     /**
-     * This method will notify you if the Activity under test called 
-     * {@link android.app.Activity#finish()}, 
-     * {@link android.app.Activity#finishFromChild(Activity)}, or 
+     * This method will notify you if the Activity under test called
+     * {@link android.app.Activity#finish()},
+     * {@link android.app.Activity#finishFromChild(Activity)}, or
      * {@link android.app.Activity#finishActivity(int)}.
      * @return Returns true if one of the listed finish methods was called.
      */
@@ -246,9 +250,9 @@
         }
         return false;
     }
-    
+
     /**
-     * This method will return the request code if the Activity under test called 
+     * This method will return the request code if the Activity under test called
      * {@link android.app.Activity#finishActivity(int)}.
      * @return The request code provided in the start call, or -1 if no finish call was made.
      */
@@ -258,7 +262,7 @@
         }
         return 0;
     }
-    
+
     /**
      * This mock Activity represents the "parent" activity.  By injecting this, we allow the user
      * to call a few more Activity methods, including:
@@ -269,7 +273,7 @@
      * <li>{@link android.app.Activity#finishActivity(int requestCode)}</li>
      * <li>{@link android.app.Activity#finishFromChild(Activity child)}</li>
      * </ul>
-     * 
+     *
      * TODO: Make this overrideable, and the unit test can look for calls to other methods
      */
     private static class MockParent extends Activity {
@@ -303,7 +307,7 @@
         public Window getWindow() {
             return null;
         }
-        
+
         /**
          * By defining this in the parent, we allow the tested activity to call
          * <ul>
@@ -316,7 +320,7 @@
             mStartedActivityIntent = intent;
             mStartedActivityRequest = requestCode;
         }
-        
+
         /**
          * By defining this in the parent, we allow the tested activity to call
          * <ul>
diff --git a/test-runner/src/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java
index aa7c677..50eaafb 100644
--- a/test-runner/src/android/test/AndroidTestRunner.java
+++ b/test-runner/src/android/test/AndroidTestRunner.java
@@ -33,6 +33,13 @@
 import java.lang.reflect.InvocationTargetException;
 import java.util.List;
 
+/**
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
 public class AndroidTestRunner extends BaseTestRunner {
 
     private TestResult mTestResult;
diff --git a/test-runner/src/android/test/ApplicationTestCase.java b/test-runner/src/android/test/ApplicationTestCase.java
index f093181..4d73f53 100644
--- a/test-runner/src/android/test/ApplicationTestCase.java
+++ b/test-runner/src/android/test/ApplicationTestCase.java
@@ -32,7 +32,7 @@
  * In order to support the lifecycle of a Application, this test case will make the
  * following calls at the following times.
  *
- * <ul><li>The test case will not call onCreate() until your test calls 
+ * <ul><li>The test case will not call onCreate() until your test calls
  * {@link #createApplication()}.  This gives you a chance
  * to set up or adjust any additional framework or test logic before
  * onCreate().</li>
@@ -40,22 +40,28 @@
  * automatically called, and it will stop & destroy your application by calling its
  * onDestroy() method.</li>
  * </ul>
- * 
+ *
  * <p><b>Dependency Injection.</b>
  * Every Application has one inherent dependency, the {@link android.content.Context Context} in
  * which it runs.
- * This framework allows you to inject a modified, mock, or isolated replacement for this 
+ * This framework allows you to inject a modified, mock, or isolated replacement for this
  * dependencies, and thus perform a true unit test.
- * 
+ *
  * <p>If simply run your tests as-is, your Application will be injected with a fully-functional
  * Context.
- * You can create and inject alternative types of Contexts by calling 
+ * You can create and inject alternative types of Contexts by calling
  * {@link AndroidTestCase#setContext(Context) setContext()}.  You must do this <i>before</i> calling
  * {@link #createApplication()}.  The test framework provides a
- * number of alternatives for Context, including {@link android.test.mock.MockContext MockContext}, 
- * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, and 
+ * number of alternatives for Context, including {@link android.test.mock.MockContext MockContext},
+ * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, and
  * {@link android.content.ContextWrapper ContextWrapper}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public abstract class ApplicationTestCase<T extends Application> extends AndroidTestCase {
 
     Class<T> mApplicationClass;
@@ -78,17 +84,17 @@
     }
 
     /**
-     * This will do the work to instantiate the Application under test.  After this, your test 
+     * This will do the work to instantiate the Application under test.  After this, your test
      * code must also start and stop the Application.
      */
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        
+
         // get the real context, before the individual tests have a chance to muck with it
         mSystemContext = getContext();
     }
-    
+
     /**
      * Load and attach the application under test.
      */
@@ -101,26 +107,26 @@
         }
         mAttached = true;
     }
-    
+
     /**
-     * Start the Application under test, in the same way as if it was started by the system.  
+     * Start the Application under test, in the same way as if it was started by the system.
      * If you use this method to start the Application, it will automatically
      * be stopped by {@link #tearDown}.  If you wish to inject a specialized Context for your
-     * test, by calling {@link AndroidTestCase#setContext(Context) setContext()}, 
+     * test, by calling {@link AndroidTestCase#setContext(Context) setContext()},
      * you must do so  before calling this method.
      */
     final protected void createApplication() {
         assertFalse(mCreated);
-        
+
         if (!mAttached) {
             setupApplication();
         }
         assertNotNull(mApplication);
-        
+
         mApplication.onCreate();
         mCreated = true;
     }
-    
+
     /**
      * This will make the necessary calls to terminate the Application under test (it will
      * call onTerminate().  Ordinarily this will be called automatically (by {@link #tearDown}, but
@@ -131,13 +137,13 @@
             mApplication.onTerminate();
         }
     }
-    
+
     /**
-     * Shuts down the Application under test.  Also makes sure all resources are cleaned up and 
+     * Shuts down the Application under test.  Also makes sure all resources are cleaned up and
      * garbage collected before moving on to the next
      * test.  Subclasses that override this method should make sure they call super.tearDown()
      * at the end of the overriding method.
-     * 
+     *
      * @throws Exception
      */
     @Override
@@ -145,7 +151,7 @@
         terminateApplication();
         mApplication = null;
 
-        // Scrub out members - protects against memory leaks in the case where someone 
+        // Scrub out members - protects against memory leaks in the case where someone
         // creates a non-static inner class (thus referencing the test case) and gives it to
         // someone else to hold onto
         scrubClass(ApplicationTestCase.class);
@@ -156,7 +162,7 @@
     /**
      * Return a real (not mocked or instrumented) system Context that can be used when generating
      * Mock or other Context objects for your Application under test.
-     * 
+     *
      * @return Returns a reference to a normal Context.
      */
     public Context getSystemContext() {
@@ -165,7 +171,7 @@
 
     /**
      * This test simply confirms that the Application class can be instantiated properly.
-     * 
+     *
      * @throws Exception
      */
     final public void testApplicationTestCaseSetUpProperly() throws Exception {
diff --git a/test-runner/src/android/test/AssertionFailedError.java b/test-runner/src/android/test/AssertionFailedError.java
index b3ac6d1..fc3e98e 100644
--- a/test-runner/src/android/test/AssertionFailedError.java
+++ b/test-runner/src/android/test/AssertionFailedError.java
@@ -18,17 +18,18 @@
 
 /**
  * Thrown when an assertion failed.
- * 
+ *
  * @deprecated use junit.framework.AssertionFailedError
  */
+@Deprecated
 public class AssertionFailedError extends Error {
-    
+
     /**
      * It is more typical to call {@link #AssertionFailedError(String)}.
      */
     public AssertionFailedError() {
     }
-    
+
     public AssertionFailedError(String errorMessage) {
         super(errorMessage);
     }
diff --git a/test-runner/src/android/test/ClassPathPackageInfo.java b/test-runner/src/android/test/ClassPathPackageInfo.java
index 1f6e647..1ab7c7f 100644
--- a/test-runner/src/android/test/ClassPathPackageInfo.java
+++ b/test-runner/src/android/test/ClassPathPackageInfo.java
@@ -24,9 +24,10 @@
 /**
  * The Package object doesn't allow you to iterate over the contained
  * classes and subpackages of that package.  This is a version that does.
- * 
+ *
  * {@hide} Not needed for 1.0 SDK.
  */
+@Deprecated
 public class ClassPathPackageInfo {
 
     private final ClassPathPackageInfoSource source;
diff --git a/test-runner/src/android/test/ClassPathPackageInfoSource.java b/test-runner/src/android/test/ClassPathPackageInfoSource.java
index 0ffecdb..89bb494 100644
--- a/test-runner/src/android/test/ClassPathPackageInfoSource.java
+++ b/test-runner/src/android/test/ClassPathPackageInfoSource.java
@@ -33,9 +33,10 @@
 
 /**
  * Generate {@link ClassPathPackageInfo}s by scanning apk paths.
- * 
+ *
  * {@hide} Not needed for 1.0 SDK.
  */
+@Deprecated
 public class ClassPathPackageInfoSource {
 
     private static final String CLASS_EXTENSION = ".class";
@@ -82,7 +83,7 @@
                 // Don't try to load classes that are generated. They usually aren't in test apks.
                 continue;
             }
-            
+
             try {
                 // We get errors in the emulator if we don't use the caller's class loader.
                 topLevelClasses.add(Class.forName(className, false,
diff --git a/test-runner/src/android/test/DatabaseTestUtils.java b/test-runner/src/android/test/DatabaseTestUtils.java
index 23e0aba..42ef48b 100644
--- a/test-runner/src/android/test/DatabaseTestUtils.java
+++ b/test-runner/src/android/test/DatabaseTestUtils.java
@@ -27,6 +27,7 @@
  * A collection of utilities for writing unit tests for database code.
  * @hide pending API council approval
  */
+@Deprecated
 public class DatabaseTestUtils {
 
     /**
diff --git a/test-runner/src/android/test/InstrumentationCoreTestRunner.java b/test-runner/src/android/test/InstrumentationCoreTestRunner.java
index 655a65c..2b05e4a 100644
--- a/test-runner/src/android/test/InstrumentationCoreTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationCoreTestRunner.java
@@ -41,6 +41,7 @@
  *
  * @hide
  */
+@Deprecated
 public class InstrumentationCoreTestRunner extends InstrumentationTestRunner {
 
     /**
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index db80ef951..9bd4c96 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -155,6 +155,10 @@
  * -e coverageFile /sdcard/myFile.ec
  * <br/>
  * in addition to the other arguments.
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
 
 /* (not JavaDoc)
@@ -170,6 +174,7 @@
  *
  * This model is used by many existing app tests, but can probably be deprecated.
  */
+@Deprecated
 public class InstrumentationTestRunner extends Instrumentation implements TestSuiteProvider {
 
     /** @hide */
diff --git a/test-runner/src/android/test/InstrumentationUtils.java b/test-runner/src/android/test/InstrumentationUtils.java
index 1a7002a..cc50813 100644
--- a/test-runner/src/android/test/InstrumentationUtils.java
+++ b/test-runner/src/android/test/InstrumentationUtils.java
@@ -17,17 +17,17 @@
 package android.test;
 
 /**
- * 
  * The InstrumentationUtils class has all the utility functions needed for
  * instrumentation tests.
  *
  * {@hide} - Not currently used.
  */
+@Deprecated
 public class InstrumentationUtils {
     /**
      * An utility function that returns the menu identifier for a particular
      * menu item.
-     * 
+     *
      * @param cls Class object of the class that handles the menu ite,.
      * @param identifier Menu identifier.
      * @return The integer corresponding to the menu item.
@@ -35,7 +35,7 @@
     public static int getMenuIdentifier(Class cls, String identifier) {
         int id = -1;
         try {
-            Integer field = (Integer)cls.getDeclaredField(identifier).get(cls);   
+            Integer field = (Integer)cls.getDeclaredField(identifier).get(cls);
             id = field.intValue();
         } catch (NoSuchFieldException e) {
             e.printStackTrace();
diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java
index f971b5d..3abf38f 100644
--- a/test-runner/src/android/test/IsolatedContext.java
+++ b/test-runner/src/android/test/IsolatedContext.java
@@ -43,9 +43,13 @@
 
 
 /**
-     * A mock context which prevents its users from talking to the rest of the device while
+ * A mock context which prevents its users from talking to the rest of the device while
  * stubbing enough methods to satify code that tries to talk to other packages.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class IsolatedContext extends ContextWrapper {
 
     private ContentResolver mResolver;
diff --git a/test-runner/src/android/test/LaunchPerformanceBase.java b/test-runner/src/android/test/LaunchPerformanceBase.java
index d423e62..62c90d6 100644
--- a/test-runner/src/android/test/LaunchPerformanceBase.java
+++ b/test-runner/src/android/test/LaunchPerformanceBase.java
@@ -26,6 +26,7 @@
  *
  * @hide
  */
+@Deprecated
 public class LaunchPerformanceBase extends Instrumentation {
 
     public static final String LOG_TAG = "Launch Performance";
@@ -39,7 +40,7 @@
         mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         setAutomaticPerformanceSnapshots();
     }
-   
+
     /**
      * Launches intent, and waits for idle before returning.
      *
diff --git a/test-runner/src/android/test/MoreAsserts.java b/test-runner/src/android/test/MoreAsserts.java
index 3364895..d33911a 100644
--- a/test-runner/src/android/test/MoreAsserts.java
+++ b/test-runner/src/android/test/MoreAsserts.java
@@ -30,7 +30,10 @@
 
 /**
  * Contains additional assertion methods not found in JUnit.
+ * @deprecated Use
+ * <a href="https://github.com/hamcrest">Hamcrest matchers</a> instead.
  */
+@Deprecated
 public final class MoreAsserts {
 
     private MoreAsserts() { }
@@ -375,7 +378,7 @@
                 failWithMessage(message, "Extra object in actual: (" + actualObj.toString() + ")");
             }
         }
-        
+
         if (expectedMap.size() > 0) {
             failWithMessage(message, "Extra objects in expected.");
         }
diff --git a/test-runner/src/android/test/NoExecTestResult.java b/test-runner/src/android/test/NoExecTestResult.java
index 1ee62c1..a01b6aa 100644
--- a/test-runner/src/android/test/NoExecTestResult.java
+++ b/test-runner/src/android/test/NoExecTestResult.java
@@ -19,11 +19,12 @@
 import junit.framework.TestResult;
 
 /**
- * A benign test result that does no actually test execution, just runs 
+ * A benign test result that does no actually test execution, just runs
  * through the motions
- * 
+ *
  * {@hide} Not needed for SDK.
  */
+@Deprecated
 class NoExecTestResult extends TestResult {
 
     /**
diff --git a/test-runner/src/android/test/PackageInfoSources.java b/test-runner/src/android/test/PackageInfoSources.java
index ef37449..205f86b 100644
--- a/test-runner/src/android/test/PackageInfoSources.java
+++ b/test-runner/src/android/test/PackageInfoSources.java
@@ -19,6 +19,7 @@
 /**
  * {@hide} Not needed for SDK.
  */
+@Deprecated
 public class PackageInfoSources {
 
     private static ClassPathPackageInfoSource classPathSource;
diff --git a/test-runner/src/android/test/PerformanceCollectorTestCase.java b/test-runner/src/android/test/PerformanceCollectorTestCase.java
index 4309ff7..3a5dafc 100644
--- a/test-runner/src/android/test/PerformanceCollectorTestCase.java
+++ b/test-runner/src/android/test/PerformanceCollectorTestCase.java
@@ -30,6 +30,7 @@
  *
  * {@hide} Not needed for SDK.
  */
+@Deprecated
 public interface PerformanceCollectorTestCase {
     public PerformanceCollector mPerfCollector = new PerformanceCollector();
 
diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
index 3c4da9e..36786b0 100644
--- a/test-runner/src/android/test/RenamingDelegatingContext.java
+++ b/test-runner/src/android/test/RenamingDelegatingContext.java
@@ -36,7 +36,11 @@
  * This is a class which delegates to the given context, but performs database
  * and file operations with a renamed database/file name (prefixes default
  * names with a given prefix).
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class RenamingDelegatingContext extends ContextWrapper {
 
     private Context mFileContext;
@@ -168,7 +172,7 @@
             return false;
         }
     }
-    
+
     @Override
     public File getDatabasePath(String name) {
         return mFileContext.getDatabasePath(renamedFileName(name));
@@ -216,7 +220,7 @@
     public String[] fileList() {
         return mFileNames.toArray(new String[]{});
     }
-    
+
     /**
      * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real
      * one) and return it instead.  This code is basically getCacheDir(), except it uses the real
@@ -241,21 +245,4 @@
         }
         return mCacheDir;
     }
-
-
-//    /**
-//     * Given an array of files returns only those whose names indicate that they belong to this
-//     * context.
-//     * @param allFiles the original list of files
-//     * @return the pruned list of files
-//     */
-//    private String[] prunedFileList(String[] allFiles) {
-//        List<String> files = Lists.newArrayList();
-//        for (String file : allFiles) {
-//            if (file.startsWith(mFilePrefix)) {
-//                files.add(file);
-//            }
-//        }
-//        return files.toArray(new String[]{});
-//    }
 }
diff --git a/test-runner/src/android/test/ServiceTestCase.java b/test-runner/src/android/test/ServiceTestCase.java
index ba20c09..c8ff0f9 100644
--- a/test-runner/src/android/test/ServiceTestCase.java
+++ b/test-runner/src/android/test/ServiceTestCase.java
@@ -92,7 +92,13 @@
  *      {@link android.test.RenamingDelegatingContext RenamingDelegatingContext},
  *      {@link android.content.ContextWrapper ContextWrapper}, and
  *      {@link android.test.IsolatedContext}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ServiceTestRule.html">
+ * ServiceTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public abstract class ServiceTestCase<T extends Service> extends AndroidTestCase {
 
     Class<T> mServiceClass;
diff --git a/test-runner/src/android/test/SimpleCache.java b/test-runner/src/android/test/SimpleCache.java
index 44424ec..46143e4 100644
--- a/test-runner/src/android/test/SimpleCache.java
+++ b/test-runner/src/android/test/SimpleCache.java
@@ -19,6 +19,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
+@Deprecated
 abstract class SimpleCache<K, V> {
     private Map<K, V> map = new HashMap<K, V>();
 
diff --git a/test-runner/src/android/test/SingleLaunchActivityTestCase.java b/test-runner/src/android/test/SingleLaunchActivityTestCase.java
index 72c93ce..af1448e 100644
--- a/test-runner/src/android/test/SingleLaunchActivityTestCase.java
+++ b/test-runner/src/android/test/SingleLaunchActivityTestCase.java
@@ -22,13 +22,19 @@
  * If you would like to test a single activity with an
  * {@link android.test.InstrumentationTestCase}, this provides some of the boiler plate to
  * launch and finish the activity in {@link #setUp} and {@link #tearDown}.
- * 
- * This launches the activity only once for the entire class instead of doing it 
+ *
+ * This launches the activity only once for the entire class instead of doing it
  * in every setup / teardown call.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+ * ActivityTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public abstract class SingleLaunchActivityTestCase<T extends Activity>
         extends InstrumentationTestCase {
-    
+
     String mPackage;
     Class<T> mActivityClass;
     private static int sTestCaseCounter = 0;
@@ -44,10 +50,10 @@
      */
     public SingleLaunchActivityTestCase(String pkg, Class<T> activityClass) {
         mPackage = pkg;
-        mActivityClass = activityClass;        
-        sTestCaseCounter ++;                
+        mActivityClass = activityClass;
+        sTestCaseCounter ++;
     }
-    
+
     /**
      * The activity that will be set up for use in each test method.
      */
@@ -66,7 +72,7 @@
             getInstrumentation().setInTouchMode(false);
             sActivity = launchActivity(mPackage, mActivityClass, null);
             sActivityLaunchedFlag = true;
-        }                        
+        }
     }
 
     @Override
@@ -75,7 +81,7 @@
         sTestCaseCounter --;
         if (sTestCaseCounter == 0) {
             sActivity.finish();
-        }        
+        }
         super.tearDown();
     }
 
diff --git a/test-runner/src/android/test/SyncBaseInstrumentation.java b/test-runner/src/android/test/SyncBaseInstrumentation.java
index 7d418f0..de36b4f 100644
--- a/test-runner/src/android/test/SyncBaseInstrumentation.java
+++ b/test-runner/src/android/test/SyncBaseInstrumentation.java
@@ -27,7 +27,13 @@
  * If you would like to test sync a single provider with an
  * {@link InstrumentationTestCase}, this provides some of the boiler plate in {@link #setUp} and
  * {@link #tearDown}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class SyncBaseInstrumentation extends InstrumentationTestCase {
     private Context mTargetContext;
     ContentResolver mContentResolver;
diff --git a/test-runner/src/android/test/TestCase.java b/test-runner/src/android/test/TestCase.java
index 5432ce8..b234f44 100644
--- a/test-runner/src/android/test/TestCase.java
+++ b/test-runner/src/android/test/TestCase.java
@@ -23,14 +23,13 @@
  * More complex interface for test cases.
  *
  * <p>Just implementing Runnable is enough for many test cases.  If you
- * have additional setup or teardown, this interface might be for you, 
+ * have additional setup or teardown, this interface might be for you,
  * especially if you need to share it between different test cases, or your
  * teardown code must execute regardless of whether your test passed.
  *
  * <p>See the android.test package documentation (click the more... link)
  * for a full description
  */
-
 @Deprecated
 public interface TestCase extends Runnable
 {
diff --git a/test-runner/src/android/test/TestCaseUtil.java b/test-runner/src/android/test/TestCaseUtil.java
index 3ba9711..c46d403 100644
--- a/test-runner/src/android/test/TestCaseUtil.java
+++ b/test-runner/src/android/test/TestCaseUtil.java
@@ -35,6 +35,7 @@
  * @hide - This is part of a framework that is under development and should not be used for
  * active development.
  */
+@Deprecated
 public class TestCaseUtil {
 
     private TestCaseUtil() {
@@ -67,7 +68,7 @@
              */
             if (test instanceof TestCase &&
                     ((TestCase)test).getName() == null) {
-                workingTest = invokeSuiteMethodIfPossible(test.getClass(), 
+                workingTest = invokeSuiteMethodIfPossible(test.getClass(),
                         seen);
             }
             if (workingTest == null) {
@@ -155,7 +156,7 @@
     public static TestSuite createTestSuite(Class<? extends Test> testClass)
             throws InstantiationException, IllegalAccessException {
 
-        Test test = invokeSuiteMethodIfPossible(testClass, 
+        Test test = invokeSuiteMethodIfPossible(testClass,
                 new HashSet<Class<?>>());
         if (test == null) {
             return new TestSuite(testClass);
diff --git a/test-runner/src/android/test/TestPrinter.java b/test-runner/src/android/test/TestPrinter.java
index 37bd721..a23f06d 100644
--- a/test-runner/src/android/test/TestPrinter.java
+++ b/test-runner/src/android/test/TestPrinter.java
@@ -30,9 +30,10 @@
  * probably will not need to create or extend this class or call its methods manually.
  * See the full {@link android.test} package description for information about
  * getting test results.
- * 
+ *
  * {@hide} Not needed for 1.0 SDK.
  */
+@Deprecated
 public class TestPrinter implements TestRunner.Listener, TestListener {
 
     private String mTag;
@@ -89,7 +90,7 @@
         mFailedTests.add(test.toString());
         failed(test.toString(), t);
     }
-    
+
     public void addError(Test test, Throwable t) {
         failed(test, t);
     }
diff --git a/test-runner/src/android/test/TestRunner.java b/test-runner/src/android/test/TestRunner.java
index 012df35..beecc6f 100644
--- a/test-runner/src/android/test/TestRunner.java
+++ b/test-runner/src/android/test/TestRunner.java
@@ -42,6 +42,7 @@
  *
  * {@hide} Not needed for 1.0 SDK.
  */
+@Deprecated
 public class TestRunner implements PerformanceTestCase.Intermediates {
     public static final int REGRESSION = 0;
     public static final int PERFORMANCE = 1;
diff --git a/test-runner/src/android/test/TestSuiteProvider.java b/test-runner/src/android/test/TestSuiteProvider.java
index dc9ce6e..c74651c 100644
--- a/test-runner/src/android/test/TestSuiteProvider.java
+++ b/test-runner/src/android/test/TestSuiteProvider.java
@@ -21,6 +21,7 @@
 /**
  * Implementors will know how to get a test suite.
  */
+@Deprecated
 public interface TestSuiteProvider {
 
     TestSuite getTestSuite();
diff --git a/test-runner/src/android/test/TimedTest.java b/test-runner/src/android/test/TimedTest.java
index 95cc9bf..cb15ef9 100644
--- a/test-runner/src/android/test/TimedTest.java
+++ b/test-runner/src/android/test/TimedTest.java
@@ -30,6 +30,7 @@
  *
  * {@hide} Pending approval for public API.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 public @interface TimedTest {
     boolean includeDetailedStats() default false;
diff --git a/test-runner/src/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java
index 1b854b0..28dc7b2 100644
--- a/test-runner/src/android/test/TouchUtils.java
+++ b/test-runner/src/android/test/TouchUtils.java
@@ -31,9 +31,15 @@
  * Reusable methods for generating touch events. These methods can be used with
  * InstrumentationTestCase or ActivityInstrumentationTestCase2 to simulate user interaction with
  * the application through a touch screen.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}training/testing/ui-testing/espresso-testing.html">Espresso UI testing
+ * framework</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class TouchUtils {
-    
+
     /**
      * Simulate touching in the center of the screen and dragging one quarter of the way down
      * @param test The test case that is being run
@@ -46,7 +52,7 @@
     public static void dragQuarterScreenDown(ActivityInstrumentationTestCase test) {
         dragQuarterScreenDown(test, test.getActivity());
     }
-    
+
     /**
      * Simulate touching in the center of the screen and dragging one quarter of the way down
      * @param test The test case that is being run
@@ -56,14 +62,14 @@
         Display display = activity.getWindowManager().getDefaultDisplay();
         final Point size = new Point();
         display.getSize(size);
-        
+
         final float x = size.x / 2.0f;
         final float fromY = size.y * 0.5f;
         final float toY = size.y * 0.75f;
-      
+
         drag(test, x, x, fromY, toY, 4);
     }
-    
+
     /**
      * Simulate touching in the center of the screen and dragging one quarter of the way up
      * @param test The test case that is being run
@@ -76,7 +82,7 @@
     public static void dragQuarterScreenUp(ActivityInstrumentationTestCase test) {
         dragQuarterScreenUp(test, test.getActivity());
     }
-    
+
     /**
      * Simulate touching in the center of the screen and dragging one quarter of the way up
      * @param test The test case that is being run
@@ -86,18 +92,18 @@
         Display display = activity.getWindowManager().getDefaultDisplay();
         final Point size = new Point();
         display.getSize(size);
-        
+
         final float x = size.x / 2.0f;
         final float fromY = size.y * 0.5f;
         final float toY = size.y * 0.25f;
-      
+
         drag(test, x, x, fromY, toY, 4);
     }
-    
+
     /**
      * Scroll a ViewGroup to the bottom by repeatedly calling
      * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
-     * 
+     *
      * @param test The test case that is being run
      * @param v The ViewGroup that should be dragged
      *
@@ -109,11 +115,11 @@
     public static void scrollToBottom(ActivityInstrumentationTestCase test, ViewGroup v) {
         scrollToBottom(test, test.getActivity(), v);
     }
-    
+
     /**
      * Scroll a ViewGroup to the bottom by repeatedly calling
      * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
-     * 
+     *
      * @param test The test case that is being run
      * @param activity The activity that is in the foreground of the test case
      * @param v The ViewGroup that should be dragged
@@ -132,7 +138,7 @@
     /**
      * Scroll a ViewGroup to the top by repeatedly calling
      * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)}
-     * 
+     *
      * @param test The test case that is being run
      * @param v The ViewGroup that should be dragged
      *
@@ -144,11 +150,11 @@
     public static void scrollToTop(ActivityInstrumentationTestCase test, ViewGroup v) {
         scrollToTop(test, test.getActivity(), v);
     }
-    
+
     /**
      * Scroll a ViewGroup to the top by repeatedly calling
      * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)}
-     * 
+     *
      * @param test The test case that is being run
      * @param activity The activity that is in the foreground of the test case
      * @param v The ViewGroup that should be dragged
@@ -162,10 +168,10 @@
             next = new ViewStateSnapshot(v);
         } while (!prev.equals(next));
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the bottom of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      *
@@ -177,10 +183,10 @@
     public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v) {
         dragViewToBottom(test, test.getActivity(), v, 4);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the bottom of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param activity The activity that is in the foreground of the test case
      * @param v The view that should be dragged
@@ -188,10 +194,10 @@
     public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v) {
         dragViewToBottom(test, activity, v, 4);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the bottom of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param stepCount How many move steps to include in the drag
@@ -205,10 +211,10 @@
             int stepCount) {
         dragViewToBottom(test, test.getActivity(), v, stepCount);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the bottom of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param activity The activity that is in the foreground of the test case
      * @param v The view that should be dragged
@@ -220,38 +226,38 @@
 
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
-        
+
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         final float x = xy[0] + (viewWidth / 2.0f);
         float fromY = xy[1] + (viewHeight / 2.0f);
         float toY = screenHeight - 1;
-        
+
         drag(test, x, x, fromY, toY, stepCount);
     }
 
     /**
      * Simulate touching the center of a view and releasing quickly (before the tap timeout).
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be clicked
      */
     public static void tapView(InstrumentationTestCase test, View v) {
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
-        
+
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         final float x = xy[0] + (viewWidth / 2.0f);
         float y = xy[1] + (viewHeight / 2.0f);
-        
+
         Instrumentation inst = test.getInstrumentation();
 
         long downTime = SystemClock.uptimeMillis();
         long eventTime = SystemClock.uptimeMillis();
-        
+
         MotionEvent event = MotionEvent.obtain(downTime, eventTime,
                 MotionEvent.ACTION_DOWN, x, y, 0);
         inst.sendPointerSync(event);
@@ -308,30 +314,30 @@
 
     /**
      * Simulate touching the center of a view and releasing.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be clicked
      */
     public static void clickView(InstrumentationTestCase test, View v) {
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
-        
+
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         final float x = xy[0] + (viewWidth / 2.0f);
         float y = xy[1] + (viewHeight / 2.0f);
-        
+
         Instrumentation inst = test.getInstrumentation();
 
         long downTime = SystemClock.uptimeMillis();
         long eventTime = SystemClock.uptimeMillis();
-        
+
         MotionEvent event = MotionEvent.obtain(downTime, eventTime,
                 MotionEvent.ACTION_DOWN, x, y, 0);
         inst.sendPointerSync(event);
         inst.waitForIdleSync();
-        
+
 
         eventTime = SystemClock.uptimeMillis();
         final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
@@ -344,7 +350,7 @@
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
         inst.sendPointerSync(event);
         inst.waitForIdleSync();
-        
+
         try {
             Thread.sleep(1000);
         } catch (InterruptedException e) {
@@ -354,7 +360,7 @@
 
     /**
      * Simulate touching the center of a view, holding until it is a long press, and then releasing.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be clicked
      *
@@ -369,20 +375,20 @@
 
     /**
      * Simulate touching the center of a view, holding until it is a long press, and then releasing.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be clicked
      */
     public static void longClickView(InstrumentationTestCase test, View v) {
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
-        
+
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         final float x = xy[0] + (viewWidth / 2.0f);
         float y = xy[1] + (viewHeight / 2.0f);
-        
+
         Instrumentation inst = test.getInstrumentation();
 
         long downTime = SystemClock.uptimeMillis();
@@ -399,7 +405,7 @@
                 x + touchSlop / 2, y + touchSlop / 2, 0);
         inst.sendPointerSync(event);
         inst.waitForIdleSync();
-        
+
         try {
             Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f));
         } catch (InterruptedException e) {
@@ -414,7 +420,7 @@
 
     /**
      * Simulate touching the center of a view and dragging to the top of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      *
@@ -426,10 +432,10 @@
     public static void dragViewToTop(ActivityInstrumentationTestCase test, View v) {
         dragViewToTop((InstrumentationTestCase) test, v, 4);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the top of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param stepCount How many move steps to include in the drag
@@ -442,20 +448,20 @@
     public static void dragViewToTop(ActivityInstrumentationTestCase test, View v, int stepCount) {
         dragViewToTop((InstrumentationTestCase) test, v, stepCount);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the top of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      */
     public static void dragViewToTop(InstrumentationTestCase test, View v) {
         dragViewToTop(test, v, 4);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the top of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param stepCount How many move steps to include in the drag
@@ -463,21 +469,21 @@
     public static void dragViewToTop(InstrumentationTestCase test, View v, int stepCount) {
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
-        
+
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         final float x = xy[0] + (viewWidth / 2.0f);
         float fromY = xy[1] + (viewHeight / 2.0f);
         float toY = 0;
-        
+
         drag(test, x, x, fromY, toY, stepCount);
     }
-    
+
     /**
      * Get the location of a view. Use the gravity param to specify which part of the view to
      * return.
-     * 
+     *
      * @param v View to find
      * @param gravity A combination of (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL,
      *        RIGHT)
@@ -488,7 +494,7 @@
 
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
         case Gravity.TOP:
             break;
@@ -501,7 +507,7 @@
         default:
             // Same as top -- do nothing
         }
-        
+
         switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
         case Gravity.LEFT:
             break;
@@ -518,14 +524,14 @@
 
     /**
      * Simulate touching a view and dragging it by the specified amount.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param deltaX Amount to drag horizontally in pixels
      * @param deltaY Amount to drag vertically in pixels
-     * 
+     *
      * @return distance in pixels covered by the drag
      *
      * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -537,17 +543,17 @@
             int deltaX, int deltaY) {
         return dragViewBy((InstrumentationTestCase) test, v, gravity, deltaX, deltaY);
     }
-    
+
     /**
      * Simulate touching a view and dragging it by the specified amount.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param deltaX Amount to drag horizontally in pixels
      * @param deltaY Amount to drag vertically in pixels
-     * 
+     *
      * @return distance in pixels covered by the drag
      *
      * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -558,29 +564,29 @@
     public static int dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX,
             int deltaY) {
         int[] xy = new int[2];
-        
+
         getStartLocation(v, gravity, xy);
 
         final int fromX = xy[0];
         final int fromY = xy[1];
-        
+
         int distance = (int) Math.hypot(deltaX, deltaY);
 
         drag(test, fromX, fromX + deltaX, fromY, fromY + deltaY, distance);
 
         return distance;
     }
-    
+
     /**
      * Simulate touching a view and dragging it to a specified location.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toX Final location of the view after dragging
      * @param toY Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      *
      * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -595,14 +601,14 @@
 
     /**
      * Simulate touching a view and dragging it to a specified location.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toX Final location of the view after dragging
      * @param toY Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      */
     public static int dragViewTo(InstrumentationTestCase test, View v, int gravity, int toX,
@@ -610,28 +616,28 @@
         int[] xy = new int[2];
 
         getStartLocation(v, gravity, xy);
-        
+
         final int fromX = xy[0];
         final int fromY = xy[1];
-        
+
         int deltaX = fromX - toX;
         int deltaY = fromY - toY;
-        
+
         int distance = (int)Math.hypot(deltaX, deltaY);
         drag(test, fromX, toX, fromY, toY, distance);
-        
+
         return distance;
     }
 
     /**
      * Simulate touching a view and dragging it to a specified location. Only moves horizontally.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toX Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      *
      * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -646,39 +652,39 @@
 
     /**
      * Simulate touching a view and dragging it to a specified location. Only moves horizontally.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toX Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      */
     public static int dragViewToX(InstrumentationTestCase test, View v, int gravity, int toX) {
         int[] xy = new int[2];
 
         getStartLocation(v, gravity, xy);
-        
+
         final int fromX = xy[0];
         final int fromY = xy[1];
-        
+
         int deltaX = fromX - toX;
 
         drag(test, fromX, toX, fromY, fromY, deltaX);
-        
+
         return deltaX;
     }
-    
+
     /**
      * Simulate touching a view and dragging it to a specified location. Only moves vertically.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toY Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      *
      * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -690,37 +696,37 @@
             int toY) {
         return dragViewToY((InstrumentationTestCase) test, v, gravity, toY);
     }
-    
+
     /**
      * Simulate touching a view and dragging it to a specified location. Only moves vertically.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toY Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      */
     public static int dragViewToY(InstrumentationTestCase test, View v, int gravity, int toY) {
         int[] xy = new int[2];
 
         getStartLocation(v, gravity, xy);
-       
+
         final int fromX = xy[0];
         final int fromY = xy[1];
-        
+
         int deltaY = fromY - toY;
 
         drag(test, fromX, fromX, fromY, toY, deltaY);
-        
+
         return deltaY;
     }
-    
+
 
     /**
      * Simulate touching a specific location and dragging to a new location.
-     * 
+     *
      * @param test The test case that is being run
      * @param fromX X coordinate of the initial touch, in screen coordinates
      * @param toX Xcoordinate of the drag destination, in screen coordinates
@@ -737,10 +743,10 @@
             float fromY, float toY, int stepCount) {
         drag((InstrumentationTestCase) test, fromX, toX, fromY, toY, stepCount);
     }
-    
+
     /**
      * Simulate touching a specific location and dragging to a new location.
-     * 
+     *
      * @param test The test case that is being run
      * @param fromX X coordinate of the initial touch, in screen coordinates
      * @param toX Xcoordinate of the drag destination, in screen coordinates
@@ -757,7 +763,7 @@
 
         float y = fromY;
         float x = fromX;
-        
+
         float yStep = (toY - fromY) / stepCount;
         float xStep = (toX - fromX) / stepCount;
 
diff --git a/test-runner/src/android/test/ViewAsserts.java b/test-runner/src/android/test/ViewAsserts.java
index c575fc5..00ab443 100644
--- a/test-runner/src/android/test/ViewAsserts.java
+++ b/test-runner/src/android/test/ViewAsserts.java
@@ -23,7 +23,15 @@
 
 /**
  * Some useful assertions about views.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">Espresso
+ * View Matchers</a> instead. New test should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ * For more information about UI testing, take the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Espresso UI testing</a> training.
  */
+@Deprecated
 public class ViewAsserts {
 
     private ViewAsserts() {}
diff --git a/test-runner/src/android/test/mock/MockApplication.java b/test-runner/src/android/test/mock/MockApplication.java
index 572dfbf..3257ecf 100644
--- a/test-runner/src/android/test/mock/MockApplication.java
+++ b/test-runner/src/android/test/mock/MockApplication.java
@@ -20,12 +20,17 @@
 import android.content.res.Configuration;
 
 /**
- * A mock {@link android.app.Application} class.  All methods are non-functional and throw 
- * {@link java.lang.UnsupportedOperationException}.  Override it as necessary to provide the 
+ * A mock {@link android.app.Application} class.  All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}.  Override it as necessary to provide the
  * operations that you need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockApplication extends Application {
-    
+
     public MockApplication() {
     }
 
@@ -38,7 +43,7 @@
     public void onTerminate() {
         throw new UnsupportedOperationException();
     }
-    
+
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 5ef71df..3743fb0 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -41,7 +41,12 @@
  * Mock implementation of ContentProvider.  All methods are non-functional and throw
  * {@link java.lang.UnsupportedOperationException}.  Tests can extend this class to
  * implement behavior needed for tests.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockContentProvider extends ContentProvider {
     /*
      * Note: if you add methods to ContentProvider, you must add similar methods to
diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java
index aec6c77..75c8335 100644
--- a/test-runner/src/android/test/mock/MockContentResolver.java
+++ b/test-runner/src/android/test/mock/MockContentResolver.java
@@ -49,8 +49,12 @@
  * <p>For more information about application testing, read the
  * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p>
  * </div>
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
-
+@Deprecated
 public class MockContentResolver extends ContentResolver {
     Map<String, ContentProvider> mProviders;
 
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 64d2978..9b93bda 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -52,10 +52,15 @@
 import java.io.InputStream;
 
 /**
- * A mock {@link android.content.Context} class.  All methods are non-functional and throw 
+ * A mock {@link android.content.Context} class.  All methods are non-functional and throw
  * {@link java.lang.UnsupportedOperationException}.  You can use this to inject other dependencies,
  * mocks, or monitors into the classes you are testing.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockContext extends Context {
 
     @Override
@@ -82,12 +87,12 @@
     public Looper getMainLooper() {
         throw new UnsupportedOperationException();
     }
-    
+
     @Override
     public Context getApplicationContext() {
         throw new UnsupportedOperationException();
     }
-    
+
     @Override
     public void setTheme(int resid) {
         throw new UnsupportedOperationException();
@@ -124,7 +129,7 @@
     public ApplicationInfo getApplicationInfo() {
         throw new UnsupportedOperationException();
     }
-    
+
     @Override
     public String getPackageResourcePath() {
         throw new UnsupportedOperationException();
@@ -194,7 +199,7 @@
     public File getObbDir() {
         throw new UnsupportedOperationException();
     }
-    
+
     @Override
     public File getCacheDir() {
         throw new UnsupportedOperationException();
@@ -216,7 +221,7 @@
     }
 
     @Override
-    public SQLiteDatabase openOrCreateDatabase(String file, int mode, 
+    public SQLiteDatabase openOrCreateDatabase(String file, int mode,
             SQLiteDatabase.CursorFactory factory) {
         throw new UnsupportedOperationException();
     }
@@ -310,7 +315,7 @@
             Bundle options) throws IntentSender.SendIntentException {
         startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags);
     }
-    
+
     @Override
     public void sendBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockCursor.java b/test-runner/src/android/test/mock/MockCursor.java
index 28fa0f8..576f24a 100644
--- a/test-runner/src/android/test/mock/MockCursor.java
+++ b/test-runner/src/android/test/mock/MockCursor.java
@@ -25,15 +25,18 @@
 import android.os.Bundle;
 
 /**
- * <P>
  * A mock {@link android.database.Cursor} class that isolates the test code from real
  * Cursor implementation.
- * </P>
- * <P>
+ *
+ * <p>
  * All methods including ones related to querying the state of the cursor are
  * are non-functional and throw {@link java.lang.UnsupportedOperationException}.
- * </P>
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockCursor implements Cursor {
     @Override
     public int getColumnCount() {
diff --git a/test-runner/src/android/test/mock/MockDialogInterface.java b/test-runner/src/android/test/mock/MockDialogInterface.java
index e4dd0ba..d0a5a09 100644
--- a/test-runner/src/android/test/mock/MockDialogInterface.java
+++ b/test-runner/src/android/test/mock/MockDialogInterface.java
@@ -1,14 +1,33 @@
-// Copyright 2008 The Android Open Source Project
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package android.test.mock;
 
 import android.content.DialogInterface;
 
 /**
- * A mock {@link android.content.DialogInterface} class.  All methods are non-functional and throw 
- * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you 
+ * A mock {@link android.content.DialogInterface} class.  All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
  * need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockDialogInterface implements DialogInterface {
     public void cancel() {
         throw new UnsupportedOperationException("not implemented yet");
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 5296d4d..ffb73f6 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -60,7 +60,12 @@
  * A mock {@link android.content.pm.PackageManager} class.  All methods are non-functional and throw
  * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
  * need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockPackageManager extends PackageManager {
 
     @Override
diff --git a/test-runner/src/android/test/mock/MockResources.java b/test-runner/src/android/test/mock/MockResources.java
index 18752ce..880343e 100644
--- a/test-runner/src/android/test/mock/MockResources.java
+++ b/test-runner/src/android/test/mock/MockResources.java
@@ -32,10 +32,15 @@
 import java.io.InputStream;
 
 /**
- * A mock {@link android.content.res.Resources} class.  All methods are non-functional and throw 
- * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you 
+ * A mock {@link android.content.res.Resources} class. All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
  * need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockResources extends Resources {
 
     public MockResources() {
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml
new file mode 100644
index 0000000..e0e3f03
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:angle="90"
+          android:startColor="?android:attr/colorPrimary"
+          android:endColor="?android:attr/colorControlActivated"
+          android:centerColor="#00ff0000"
+          android:startX="0"
+          android:startY="0"
+          android:endX="100"
+          android:endY="100"
+          android:type="linear">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml
new file mode 100644
index 0000000..cfb1236
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:angle="90"
+          android:startColor="?android:attr/colorPrimary"
+          android:endColor="?android:attr/colorControlActivated"
+          android:centerColor="#f00"
+          android:startX="0"
+          android:startY="0"
+          android:endX="100"
+          android:endY="100"
+          android:type="linear">
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.4" android:color="#fff"/>
+    <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml
new file mode 100644
index 0000000..18274b9
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:angle="90"
+          android:startColor="?android:attr/colorPrimary"
+          android:endColor="?android:attr/colorControlActivated"
+          android:centerColor="#f00"
+          android:startX="0"
+          android:startY="0"
+          android:endX="100"
+          android:endY="100"
+          android:type="linear">
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.4" android:color="#f00"/>
+    <item android:offset="0.4" android:color="#fff"/>
+    <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml
new file mode 100644
index 0000000..ef6fd70
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerColor="#ff0000"
+          android:endColor="?android:attr/colorControlActivated"
+          android:centerX="300"
+          android:centerY="300"
+          android:gradientRadius="100"
+          android:startColor="?android:attr/colorPrimary"
+          android:type="radial">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
new file mode 100644
index 0000000..51b0e17
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+    <!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerColor="#ff0000"
+          android:endColor="#ff0000ff"
+          android:centerX="300"
+          android:centerY="300"
+          android:gradientRadius="100"
+          android:startColor="#ffffffff"
+          android:type="radial">
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.4" android:color="#fff"/>
+    <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
new file mode 100644
index 0000000..8caa1b4
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+    <!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerX="300"
+          android:centerY="300"
+          android:gradientRadius="100"
+          android:type="radial">
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml
new file mode 100644
index 0000000..e1fbd10
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerColor="#ff0000"
+          android:endColor="#ff0000ff"
+          android:centerX="500"
+          android:centerY="500"
+          android:gradientRadius="10"
+          android:startColor="#ffffffff"
+          android:type="sweep">
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml
new file mode 100644
index 0000000..332b938
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerColor="#ff0000"
+          android:endColor="#ff0000ff"
+          android:centerX="500"
+          android:centerY="500"
+          android:gradientRadius="10"
+          android:startColor="#ffffffff"
+          android:type="sweep">
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.4" android:color="#fff"/>
+    <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml
new file mode 100644
index 0000000..3931288
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerX="500"
+          android:centerY="500"
+          android:gradientRadius="10"
+          android:type="sweep">
+    <item android:offset="-0.3" android:color="#f00"/>
+    <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+    <item android:offset="0.4" android:color="#0f0"/>
+    <item android:offset="0.6" android:color="#00f"/>
+    <item android:offset="0.7" android:color="?android:attr/colorControlActivated"/>
+    <item android:offset="1.5" android:color="#00f"/>
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient.xml b/tests/VectorDrawableTest/res/color/stroke_gradient.xml
new file mode 100644
index 0000000..cb324c9
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:angle="90"
+          android:centerColor="#7f7f7f"
+          android:endColor="#ffffff"
+          android:startColor="#000000"
+          android:startX="0"
+          android:endX="100"
+          android:startY="0"
+          android:endY="0"
+          android:type="linear">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml
new file mode 100644
index 0000000..15d948c
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:angle="90"
+          android:centerColor="#7f7f7f"
+          android:endColor="#ffffff"
+          android:startColor="#000000"
+          android:startX="0"
+          android:endX="100"
+          android:startY="0"
+          android:endY="0"
+          android:type="linear">
+    <item android:offset="0.1" android:color="#f00"/>
+    <item android:offset="0.2" android:color="#f0f"/>
+    <item android:offset="0.9" android:color="#f00f"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml
new file mode 100644
index 0000000..fda2b88
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:startX="0"
+          android:endX="100"
+          android:startY="0"
+          android:endY="0"
+          android:type="linear">
+    <item android:offset="0.1" android:color="#f00"/>
+    <item android:offset="0.2" android:color="#2f0f"/>
+    <item android:offset="0.9" android:color="#f00f"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml
new file mode 100644
index 0000000..45d88b5
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?android:attr/colorPrimary" android:state_pressed="true" />
+    <item android:color="?android:attr/colorControlActivated" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml
new file mode 100644
index 0000000..16251c8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?android:attr/colorControlActivated" android:state_pressed="true" />
+    <item android:color="?android:attr/colorPrimary" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index 2be99be..89afde2 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -27,8 +27,8 @@
         <path
             android:name="box1"
             android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
-            android:fillColor="?android:attr/colorControlNormal"
-            android:strokeColor="?android:attr/colorControlNormal"
+            android:fillColor="?android:attr/colorPrimary"
+            android:strokeColor="?android:attr/colorPrimary"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
     </group>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml
new file mode 100644
index 0000000..d67aca7
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+       android:scaleX="0.5"
+       android:scaleY="0.5">
+    <path
+            android:name="background1"
+            android:fillColor="@color/fill_gradient_linear"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background2"
+            android:fillColor="@color/fill_gradient_radial"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background3"
+            android:fillColor="@color/fill_gradient_sweep"
+            android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
+    <path
+            android:name="twoLines"
+            android:pathData="@string/twoLinePathData"
+            android:strokeColor="@color/stroke_gradient"
+            android:strokeWidth="20" />
+
+    <group
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0">
+        <path
+                android:name="twoLines1"
+                android:pathData="@string/twoLinePathData"
+                android:strokeColor="@color/stroke_gradient"
+                android:strokeWidth="20" />
+
+        <group
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines3"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="@color/stroke_gradient"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+
+        <group
+                android:name="translateGroupHalf"
+                android:translateX="65.0"
+                android:translateY="80.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines2"
+                        android:pathData="@string/twoLinePathData"
+                        android:fillColor="@color/fill_gradient_linear"
+                        android:strokeColor="@color/stroke_gradient"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+    </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml
new file mode 100644
index 0000000..abf3c7a
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+       android:scaleX="0.5"
+       android:scaleY="0.5">
+    <path
+            android:name="background1"
+            android:fillColor="@color/fill_gradient_linear_item"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background2"
+            android:fillColor="@color/fill_gradient_radial_item"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background3"
+            android:fillColor="@color/fill_gradient_sweep_item"
+            android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
+    <path
+            android:name="twoLines"
+            android:pathData="@string/twoLinePathData"
+            android:strokeColor="@color/stroke_gradient_item"
+            android:strokeWidth="20" />
+
+    <group
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0">
+        <path
+                android:name="twoLines1"
+                android:pathData="@string/twoLinePathData"
+                android:strokeColor="@color/stroke_gradient_item"
+                android:strokeWidth="20" />
+
+        <group
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines3"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="@color/stroke_gradient_item"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+
+        <group
+                android:name="translateGroupHalf"
+                android:translateX="65.0"
+                android:translateY="80.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines2"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="@color/stroke_gradient_item"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+    </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml
new file mode 100644
index 0000000..5f9726f
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="400"
+        android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+       android:scaleX="0.5"
+       android:scaleY="0.5">
+    <path
+            android:name="background1"
+            android:fillColor="@color/fill_gradient_linear_item_overlap"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background2"
+            android:fillColor="@color/fill_gradient_radial_item_short"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+    <path
+            android:name="background3"
+            android:fillColor="@color/fill_gradient_sweep_item_long"
+            android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
+    <path
+            android:name="twoLines"
+            android:pathData="@string/twoLinePathData"
+            android:strokeColor="@color/stroke_gradient_item_alpha"
+            android:strokeWidth="20" />
+
+    <group
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0">
+        <path
+                android:name="twoLines1"
+                android:pathData="@string/twoLinePathData"
+                android:strokeColor="@color/stroke_gradient_item_alpha"
+                android:strokeWidth="20" />
+
+        <group
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines3"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="@color/stroke_gradient_item_alpha"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+
+        <group
+                android:name="translateGroupHalf"
+                android:translateX="65.0"
+                android:translateY="80.0">
+            <group android:name="scaleGroup" >
+                <path
+                        android:name="twoLines2"
+                        android:pathData="@string/twoLinePathData"
+                        android:strokeColor="@color/stroke_gradient_item_alpha"
+                        android:strokeWidth="20" />
+            </group>
+        </group>
+    </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml
new file mode 100644
index 0000000..b1ed850
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="24"
+        android:viewportWidth="24" >
+
+    <path
+        android:fillColor="@color/vector_icon_fill_state_list"
+        android:strokeColor="@color/vector_icon_stroke_state_list"
+        android:strokeWidth="3"
+        android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z"/>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index b4a93f6..a7da286 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -35,6 +35,10 @@
 public class VectorDrawablePerformance extends Activity {
     private static final String LOGCAT = "VectorDrawable1";
     protected int[] icon = {
+            R.drawable.vector_icon_gradient_1,
+            R.drawable.vector_icon_gradient_2,
+            R.drawable.vector_icon_gradient_3,
+            R.drawable.vector_icon_state_list,
             R.drawable.vector_drawable01,
             R.drawable.vector_drawable02,
             R.drawable.vector_drawable03,
@@ -102,7 +106,7 @@
         ScrollView scrollView = new ScrollView(this);
         GridLayout container = new GridLayout(this);
         scrollView.addView(container);
-        container.setColumnCount(5);
+        container.setColumnCount(4);
         Resources res = this.getResources();
         container.setBackgroundColor(0xFF888888);
         VectorDrawable []d = new VectorDrawable[icon.length];
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 274e985..4c22460 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -704,24 +704,6 @@
      */
     public int numUserTriggeredJoinAttempts;
 
-    /**
-     * @hide
-     * Connect choices
-     *
-     * remember the keys identifying the known WifiConfiguration over which this configuration
-     * was preferred by user or a "WiFi Network Management app", that is,
-     * a WifiManager.CONNECT_NETWORK or SELECT_NETWORK was received while this configuration
-     * was visible to the user:
-     * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
-     *
-     * The integer represents the configuration's RSSI at that time (useful?)
-     *
-     * The overall auto-join algorithm make use of past connect choice so as to sort configuration,
-     * the exact algorithm still fluctuating as of 5/7/2014
-     *
-     */
-    public HashMap<String, Integer> connectChoices;
-
     /** @hide
      * Boost given to RSSI on a home network for the purpose of calculating the score
      * This adds stickiness to home networks, as defined by:
@@ -831,6 +813,16 @@
          */
         public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L;
 
+        /**
+         *  This constant indicates the current configuration has connect choice set
+         */
+        private static final int CONNECT_CHOICE_EXISTS = 1;
+
+        /**
+         *  This constant indicates the current configuration does not have connect choice set
+         */
+        private static final int CONNECT_CHOICE_NOT_EXISTS = -1;
+
         // fields for QualityNetwork Selection
         /**
          * Network selection status, should be in one of three status: enable, temporaily disabled
@@ -854,7 +846,128 @@
         private int[] mNetworkSeclectionDisableCounter = new int[NETWORK_SELECTION_DISABLED_MAX];
 
         /**
-         * return current Quality network selection status in String (for debug purpose)
+         * Connect Choice over this configuration
+         *
+         * When current wifi configuration is visible to the user but user explicitly choose to
+         * connect to another network X, the another networks X's configure key will be stored here.
+         * We will consider user has a preference of X over this network. And in the future,
+         * network selection will always give X a higher preference over this configuration.
+         * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
+         */
+        private String mConnectChoice;
+
+        /**
+         * The system timestamp when we records the connectChoice. This value is obtained from
+         * System.currentTimeMillis
+         */
+        private long mConnectChoiceTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
+
+        /**
+         * Used to cache the temporary candidate during the network selection procedure. It will be
+         * kept updating once a new scan result has a higher score than current one
+         */
+        private ScanResult mCandidate;
+
+        /**
+         * Used to cache the score of the current temporary candidate during the network
+         * selection procedure.
+         */
+        private int mCandidateScore;
+
+        /**
+         * Indicate whether this network is visible in latest Qualified Network Selection. This
+         * means there is scan result found related to this Configuration and meet the minimum
+         * requirement. The saved network need not join latest Qualified Network Selection. For
+         * example, it is disabled. True means network is visible in latest Qualified Network
+         * Selection and false means network is invisible
+         */
+        private boolean mSeenInLastQualifiedNetworkSelection;
+
+        /**
+         * set whether this network is visible in latest Qualified Network Selection
+         * @param seen value set to candidate
+         */
+        public void setSeenInLastQualifiedNetworkSelection(boolean seen) {
+            mSeenInLastQualifiedNetworkSelection =  seen;
+        }
+
+        /**
+         * get whether this network is visible in latest Qualified Network Selection
+         * @return returns true -- network is visible in latest Qualified Network Selection
+         *         false -- network is invisible in latest Qualified Network Selection
+         */
+        public boolean getSeenInLastQualifiedNetworkSelection() {
+            return mSeenInLastQualifiedNetworkSelection;
+        }
+        /**
+         * set the temporary candidate of current network selection procedure
+         * @param scanCandidate {@link ScanResult} the candidate set to mCandidate
+         */
+        public void setCandidate(ScanResult scanCandidate) {
+            mCandidate = scanCandidate;
+        }
+
+        /**
+         * get the temporary candidate of current network selection procedure
+         * @return  returns {@link ScanResult} temporary candidate of current network selection
+         * procedure
+         */
+        public ScanResult getCandidate() {
+            return mCandidate;
+        }
+
+        /**
+         * set the score of the temporary candidate of current network selection procedure
+         * @param score value set to mCandidateScore
+         */
+        public void setCandidateScore(int score) {
+            mCandidateScore = score;
+        }
+
+        /**
+         * get the score of the temporary candidate of current network selection procedure
+         * @return returns score of the temporary candidate of current network selection procedure
+         */
+        public int getCandidateScore() {
+            return mCandidateScore;
+        }
+
+        /**
+         * get user preferred choice over this configuration
+         *@return returns configKey of user preferred choice over this configuration
+         */
+        public String getConnectChoice() {
+            return mConnectChoice;
+        }
+
+        /**
+         * set user preferred choice over this configuration
+         * @param newConnectChoice, the configKey of user preferred choice over this configuration
+         */
+        public void setConnectChoice(String newConnectChoice) {
+            mConnectChoice = newConnectChoice;
+        }
+
+        /**
+         * get the timeStamp when user select a choice over this configuration
+         * @return returns when current connectChoice is set (time from System.currentTimeMillis)
+         */
+        public long getConnectChoiceTimestamp() {
+            return mConnectChoiceTimestamp;
+        }
+
+        /**
+         * set the timeStamp when user select a choice over this configuration
+         * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should
+         *        be obtained from System.currentTimeMillis
+         */
+        public void setConnectChoiceTimestamp(long timeStamp) {
+            mConnectChoiceTimestamp = timeStamp;
+        }
+
+        /**
+         * get current Quality network selection status
+         * @return returns current Quality network selection status in String (for debug purpose)
          */
         public String getNetworkStatusString() {
             return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
@@ -874,6 +987,7 @@
             }
         }
         /**
+         * get current network disable reason
          * @return current network disable reason in String (for debug purpose)
          */
         public String getNetworkDisableReasonString() {
@@ -882,6 +996,7 @@
 
         /**
          * get current network network selection status
+         * @return return current network network selection status
          */
         public int getNetworkSelectionStatus() {
             return mStatus;
@@ -901,12 +1016,14 @@
         }
 
         /**
-         * return whether current network is permanently disabled
+         * @return returns whether current network is permanently disabled
          */
         public boolean isNetworkPermanentlyDisabled() {
             return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
         }
+
         /**
+         * set current networ work selection status
          * @param status network selection status to set
          */
         public void setNetworkSelectionStatus(int status) {
@@ -914,14 +1031,16 @@
                 mStatus = status;
             }
         }
+
         /**
-         * @return current network's disable reason
+         * @return returns current network's disable reason
          */
         public int getNetworkSelectionDisableReason() {
             return mNetworkSelectionDisableReason;
         }
 
         /**
+         * set Network disable reason
          * @param  reason Network disable reason
          */
         public void setNetworkSelectionDisableReason(int reason) {
@@ -931,12 +1050,17 @@
                 throw new IllegalArgumentException("Illegal reason value: " + reason);
             }
         }
+
         /**
-         * @param reason whether current network is disabled by this reason
+         * check whether network is disabled by this reason
+         * @param reason a specific disable reason
+         * @return true -- network is disabled for this reason
+         *         false -- network is not disabled for this reason
          */
         public boolean isDisabledByReason(int reason) {
             return mNetworkSelectionDisableReason == reason;
         }
+
         /**
          * @param timeStamp Set when current network is disabled in millisecond since January 1,
          * 1970 00:00:00.0 UTC
@@ -946,7 +1070,7 @@
         }
 
         /**
-         * @return Get when current network is disabled in millisecond since January 1,
+         * @return returns when current network is disabled in millisecond since January 1,
          * 1970 00:00:00.0 UTC
          */
         public long getDisableTime() {
@@ -954,6 +1078,7 @@
         }
 
         /**
+         * get the disable counter of a specific reason
          * @param  reason specific failure reason
          * @exception throw IllegalArgumentException for illegal input
          * @return counter number for specific error reason.
@@ -992,6 +1117,7 @@
                 throw new IllegalArgumentException("Illegal reason value: " + reason);
             }
         }
+
         /**
          * clear the counter of a specific failure reason
          * @hide
@@ -1005,6 +1131,7 @@
                 throw new IllegalArgumentException("Illegal reason value: " + reason);
             }
         }
+
         /**
          * clear all the failure reason counters
          */
@@ -1043,6 +1170,8 @@
             }
             mTemporarilyDisabledTimestamp = source.mTemporarilyDisabledTimestamp;
             mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
+            setConnectChoice(source.getConnectChoice());
+            setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
         }
 
         public void writeToParcel(Parcel dest) {
@@ -1054,6 +1183,13 @@
             }
             dest.writeLong(getDisableTime());
             dest.writeString(getNetworkSelectionBSSID());
+            if (getConnectChoice() != null) {
+                dest.writeInt(CONNECT_CHOICE_EXISTS);
+                dest.writeString(getConnectChoice());
+                dest.writeLong(getConnectChoiceTimestamp());
+            } else {
+                dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
+            }
         }
 
         public void readFromParcel(Parcel in) {
@@ -1065,6 +1201,13 @@
             }
             setDisableTime(in.readLong());
             setNetworkSelectionBSSID(in.readString());
+            if (in.readInt() == CONNECT_CHOICE_EXISTS) {
+                setConnectChoice(in.readString());
+                setConnectChoiceTimestamp(in.readLong());
+            } else {
+                setConnectChoice(null);
+                setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
+            }
         }
     }
 
@@ -1184,7 +1327,11 @@
                 }
             }
         }
-
+        if (mNetworkSelectionStatus.getConnectChoice() != null) {
+            sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
+            sbuf.append(" connect choice set time: ").append(mNetworkSelectionStatus
+                    .getConnectChoiceTimestamp());
+        }
 
         if (this.numAssociation > 0) {
             sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
@@ -1336,16 +1483,7 @@
                 sbuf.append('\n');
             }
         }
-        if (this.connectChoices != null) {
-            for(String key : this.connectChoices.keySet()) {
-                Integer choice = this.connectChoices.get(key);
-                if (choice != null) {
-                    sbuf.append(" choice: ").append(key);
-                    sbuf.append(" = ").append(choice);
-                    sbuf.append('\n');
-                }
-            }
-        }
+
         sbuf.append("triggeredLow: ").append(this.numUserTriggeredWifiDisableLowRSSI);
         sbuf.append(" triggeredBad: ").append(this.numUserTriggeredWifiDisableBadRSSI);
         sbuf.append(" triggeredNotHigh: ").append(this.numUserTriggeredWifiDisableNotHighRSSI);
@@ -1632,11 +1770,6 @@
 
             mIpConfiguration = new IpConfiguration(source.mIpConfiguration);
 
-            if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) {
-                connectChoices = new HashMap<String, Integer>();
-                connectChoices.putAll(source.connectChoices);
-            }
-
             if ((source.linkedConfigurations != null)
                     && (source.linkedConfigurations.size() > 0)) {
                 linkedConfigurations = new HashMap<String, Integer>();