Merge "Hiding the summary of notification groups with a single child now" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index eb7666a..8a83024 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7102,9 +7102,10 @@
     method public void onServicesDiscovered(android.bluetooth.BluetoothGatt, int);
   }
 
-  public class BluetoothGattCharacteristic {
+  public class BluetoothGattCharacteristic implements android.os.Parcelable {
     ctor public BluetoothGattCharacteristic(java.util.UUID, int, int);
     method public boolean addDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
     method public java.lang.Float getFloatValue(int, int);
@@ -7122,6 +7123,8 @@
     method public boolean setValue(int, int, int, int);
     method public boolean setValue(java.lang.String);
     method public void setWriteType(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR;
     field public static final int FORMAT_FLOAT = 52; // 0x34
     field public static final int FORMAT_SFLOAT = 50; // 0x32
     field public static final int FORMAT_SINT16 = 34; // 0x22
@@ -7152,13 +7155,16 @@
     field protected java.util.List<android.bluetooth.BluetoothGattDescriptor> mDescriptors;
   }
 
-  public class BluetoothGattDescriptor {
+  public class BluetoothGattDescriptor implements android.os.Parcelable {
     ctor public BluetoothGattDescriptor(java.util.UUID, int);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
     method public int getPermissions();
     method public java.util.UUID getUuid();
     method public byte[] getValue();
     method public boolean setValue(byte[]);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR;
     field public static final byte[] DISABLE_NOTIFICATION_VALUE;
     field public static final byte[] ENABLE_INDICATION_VALUE;
     field public static final byte[] ENABLE_NOTIFICATION_VALUE;
@@ -7201,16 +7207,19 @@
     method public void onServiceAdded(int, android.bluetooth.BluetoothGattService);
   }
 
-  public class BluetoothGattService {
+  public class BluetoothGattService implements android.os.Parcelable {
     ctor public BluetoothGattService(java.util.UUID, int);
     method public boolean addCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
     method public boolean addService(android.bluetooth.BluetoothGattService);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattCharacteristic> getCharacteristics();
     method public java.util.List<android.bluetooth.BluetoothGattService> getIncludedServices();
     method public int getInstanceId();
     method public int getType();
     method public java.util.UUID getUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattService> CREATOR;
     field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0
     field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1
     field protected java.util.List<android.bluetooth.BluetoothGattCharacteristic> mCharacteristics;
@@ -17751,9 +17760,6 @@
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
     method public android.icu.text.UnicodeSet addAll(T...);
     method public T addAllTo(T);
-    method public java.lang.String[] addAllTo(java.lang.String[]);
-    method public static U addAllTo(java.lang.Iterable<T>, U);
-    method public static T[] addAllTo(java.lang.Iterable<T>, T[]);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -17767,10 +17773,6 @@
     method public android.icu.text.UnicodeSet cloneAsThawed();
     method public android.icu.text.UnicodeSet closeOver(int);
     method public android.icu.text.UnicodeSet compact();
-    method public static int compare(java.lang.CharSequence, int);
-    method public static int compare(int, java.lang.CharSequence);
-    method public static int compare(java.lang.Iterable<T>, java.lang.Iterable<T>);
-    method public static int compare(java.util.Collection<T>, java.util.Collection<T>, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(android.icu.text.UnicodeSet);
     method public int compareTo(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(java.lang.Iterable<java.lang.String>);
@@ -17813,7 +17815,6 @@
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
-    method public static boolean resemblesPattern(java.lang.String, int);
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
@@ -17828,7 +17829,6 @@
     method public int spanBack(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
     method public int spanBack(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
     method public java.util.Collection<java.lang.String> strings();
-    method public static java.lang.String[] toArray(android.icu.text.UnicodeSet);
     method public java.lang.String toPattern(boolean);
     field public static final int ADD_CASE_MAPPINGS = 4; // 0x4
     field public static final android.icu.text.UnicodeSet ALL_CODE_POINTS;
@@ -17947,11 +17947,8 @@
     ctor protected CECalendar(int, int, int);
     ctor protected CECalendar(java.util.Date);
     ctor protected CECalendar(int, int, int, int, int, int);
-    method public static int ceToJD(long, int, int, int);
-    method protected abstract int getJDEpochOffset();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetLimit(int, int);
-    method public static void jdToCE(int, int, int[]);
   }
 
   public abstract class Calendar implements java.lang.Cloneable java.lang.Comparable java.io.Serializable {
@@ -18179,7 +18176,6 @@
     ctor public CopticCalendar(int, int, int);
     ctor public CopticCalendar(java.util.Date);
     ctor public CopticCalendar(int, int, int, int, int, int);
-    method protected deprecated int getJDEpochOffset();
     method protected deprecated int handleGetExtendedYear();
     field public static final int AMSHIR = 5; // 0x5
     field public static final int BABA = 1; // 0x1
@@ -18350,11 +18346,11 @@
     ctor public IslamicCalendar(java.util.Date);
     ctor public IslamicCalendar(int, int, int);
     ctor public IslamicCalendar(int, int, int, int, int, int);
+    method public android.icu.util.IslamicCalendar.CalculationType getCalculationType();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetExtendedYear();
     method protected int handleGetLimit(int, int);
-    method public boolean isCivil();
-    method public void setCivil(boolean);
+    method public void setCalculationType(android.icu.util.IslamicCalendar.CalculationType);
     field public static final int DHU_AL_HIJJAH = 11; // 0xb
     field public static final int DHU_AL_QIDAH = 10; // 0xa
     field public static final int JUMADA_1 = 4; // 0x4
@@ -18792,7 +18788,6 @@
     method public int getMicro();
     method public int getMilli();
     method public int getMinor();
-    method public static void main(java.lang.String[]);
     field public static final android.icu.util.VersionInfo ICU_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_BUILDER_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_RUNTIME_VERSION;
diff --git a/api/system-current.txt b/api/system-current.txt
index babd335..2cad670 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7377,9 +7377,10 @@
     method public void onServicesDiscovered(android.bluetooth.BluetoothGatt, int);
   }
 
-  public class BluetoothGattCharacteristic {
+  public class BluetoothGattCharacteristic implements android.os.Parcelable {
     ctor public BluetoothGattCharacteristic(java.util.UUID, int, int);
     method public boolean addDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
     method public java.lang.Float getFloatValue(int, int);
@@ -7397,6 +7398,8 @@
     method public boolean setValue(int, int, int, int);
     method public boolean setValue(java.lang.String);
     method public void setWriteType(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR;
     field public static final int FORMAT_FLOAT = 52; // 0x34
     field public static final int FORMAT_SFLOAT = 50; // 0x32
     field public static final int FORMAT_SINT16 = 34; // 0x22
@@ -7427,13 +7430,16 @@
     field protected java.util.List<android.bluetooth.BluetoothGattDescriptor> mDescriptors;
   }
 
-  public class BluetoothGattDescriptor {
+  public class BluetoothGattDescriptor implements android.os.Parcelable {
     ctor public BluetoothGattDescriptor(java.util.UUID, int);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
     method public int getPermissions();
     method public java.util.UUID getUuid();
     method public byte[] getValue();
     method public boolean setValue(byte[]);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR;
     field public static final byte[] DISABLE_NOTIFICATION_VALUE;
     field public static final byte[] ENABLE_INDICATION_VALUE;
     field public static final byte[] ENABLE_NOTIFICATION_VALUE;
@@ -7476,16 +7482,19 @@
     method public void onServiceAdded(int, android.bluetooth.BluetoothGattService);
   }
 
-  public class BluetoothGattService {
+  public class BluetoothGattService implements android.os.Parcelable {
     ctor public BluetoothGattService(java.util.UUID, int);
     method public boolean addCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
     method public boolean addService(android.bluetooth.BluetoothGattService);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattCharacteristic> getCharacteristics();
     method public java.util.List<android.bluetooth.BluetoothGattService> getIncludedServices();
     method public int getInstanceId();
     method public int getType();
     method public java.util.UUID getUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattService> CREATOR;
     field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0
     field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1
     field protected java.util.List<android.bluetooth.BluetoothGattCharacteristic> mCharacteristics;
@@ -18923,9 +18932,6 @@
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
     method public android.icu.text.UnicodeSet addAll(T...);
     method public T addAllTo(T);
-    method public java.lang.String[] addAllTo(java.lang.String[]);
-    method public static U addAllTo(java.lang.Iterable<T>, U);
-    method public static T[] addAllTo(java.lang.Iterable<T>, T[]);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -18939,10 +18945,6 @@
     method public android.icu.text.UnicodeSet cloneAsThawed();
     method public android.icu.text.UnicodeSet closeOver(int);
     method public android.icu.text.UnicodeSet compact();
-    method public static int compare(java.lang.CharSequence, int);
-    method public static int compare(int, java.lang.CharSequence);
-    method public static int compare(java.lang.Iterable<T>, java.lang.Iterable<T>);
-    method public static int compare(java.util.Collection<T>, java.util.Collection<T>, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(android.icu.text.UnicodeSet);
     method public int compareTo(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(java.lang.Iterable<java.lang.String>);
@@ -18985,7 +18987,6 @@
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
-    method public static boolean resemblesPattern(java.lang.String, int);
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
@@ -19000,7 +19001,6 @@
     method public int spanBack(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
     method public int spanBack(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
     method public java.util.Collection<java.lang.String> strings();
-    method public static java.lang.String[] toArray(android.icu.text.UnicodeSet);
     method public java.lang.String toPattern(boolean);
     field public static final int ADD_CASE_MAPPINGS = 4; // 0x4
     field public static final android.icu.text.UnicodeSet ALL_CODE_POINTS;
@@ -19119,11 +19119,8 @@
     ctor protected CECalendar(int, int, int);
     ctor protected CECalendar(java.util.Date);
     ctor protected CECalendar(int, int, int, int, int, int);
-    method public static int ceToJD(long, int, int, int);
-    method protected abstract int getJDEpochOffset();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetLimit(int, int);
-    method public static void jdToCE(int, int, int[]);
   }
 
   public abstract class Calendar implements java.lang.Cloneable java.lang.Comparable java.io.Serializable {
@@ -19351,7 +19348,6 @@
     ctor public CopticCalendar(int, int, int);
     ctor public CopticCalendar(java.util.Date);
     ctor public CopticCalendar(int, int, int, int, int, int);
-    method protected deprecated int getJDEpochOffset();
     method protected deprecated int handleGetExtendedYear();
     field public static final int AMSHIR = 5; // 0x5
     field public static final int BABA = 1; // 0x1
@@ -19522,11 +19518,11 @@
     ctor public IslamicCalendar(java.util.Date);
     ctor public IslamicCalendar(int, int, int);
     ctor public IslamicCalendar(int, int, int, int, int, int);
+    method public android.icu.util.IslamicCalendar.CalculationType getCalculationType();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetExtendedYear();
     method protected int handleGetLimit(int, int);
-    method public boolean isCivil();
-    method public void setCivil(boolean);
+    method public void setCalculationType(android.icu.util.IslamicCalendar.CalculationType);
     field public static final int DHU_AL_HIJJAH = 11; // 0xb
     field public static final int DHU_AL_QIDAH = 10; // 0xa
     field public static final int JUMADA_1 = 4; // 0x4
@@ -19964,7 +19960,6 @@
     method public int getMicro();
     method public int getMilli();
     method public int getMinor();
-    method public static void main(java.lang.String[]);
     field public static final android.icu.util.VersionInfo ICU_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_BUILDER_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_RUNTIME_VERSION;
@@ -31649,6 +31644,7 @@
     method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
     method public boolean hasUserRestriction(java.lang.String);
     method public boolean isManagedProfile();
+    method public boolean isManagedProfile(int);
     method public boolean isQuietModeEnabled(android.os.UserHandle);
     method public boolean isSystemUser();
     method public boolean isUserAGoat();
diff --git a/api/test-current.txt b/api/test-current.txt
index 5c471b3..d3a12ed 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -7106,9 +7106,10 @@
     method public void onServicesDiscovered(android.bluetooth.BluetoothGatt, int);
   }
 
-  public class BluetoothGattCharacteristic {
+  public class BluetoothGattCharacteristic implements android.os.Parcelable {
     ctor public BluetoothGattCharacteristic(java.util.UUID, int, int);
     method public boolean addDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
     method public java.lang.Float getFloatValue(int, int);
@@ -7126,6 +7127,8 @@
     method public boolean setValue(int, int, int, int);
     method public boolean setValue(java.lang.String);
     method public void setWriteType(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR;
     field public static final int FORMAT_FLOAT = 52; // 0x34
     field public static final int FORMAT_SFLOAT = 50; // 0x32
     field public static final int FORMAT_SINT16 = 34; // 0x22
@@ -7156,13 +7159,16 @@
     field protected java.util.List<android.bluetooth.BluetoothGattDescriptor> mDescriptors;
   }
 
-  public class BluetoothGattDescriptor {
+  public class BluetoothGattDescriptor implements android.os.Parcelable {
     ctor public BluetoothGattDescriptor(java.util.UUID, int);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
     method public int getPermissions();
     method public java.util.UUID getUuid();
     method public byte[] getValue();
     method public boolean setValue(byte[]);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR;
     field public static final byte[] DISABLE_NOTIFICATION_VALUE;
     field public static final byte[] ENABLE_INDICATION_VALUE;
     field public static final byte[] ENABLE_NOTIFICATION_VALUE;
@@ -7205,16 +7211,19 @@
     method public void onServiceAdded(int, android.bluetooth.BluetoothGattService);
   }
 
-  public class BluetoothGattService {
+  public class BluetoothGattService implements android.os.Parcelable {
     ctor public BluetoothGattService(java.util.UUID, int);
     method public boolean addCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
     method public boolean addService(android.bluetooth.BluetoothGattService);
+    method public int describeContents();
     method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattCharacteristic> getCharacteristics();
     method public java.util.List<android.bluetooth.BluetoothGattService> getIncludedServices();
     method public int getInstanceId();
     method public int getType();
     method public java.util.UUID getUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattService> CREATOR;
     field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0
     field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1
     field protected java.util.List<android.bluetooth.BluetoothGattCharacteristic> mCharacteristics;
@@ -17761,9 +17770,6 @@
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
     method public android.icu.text.UnicodeSet addAll(T...);
     method public T addAllTo(T);
-    method public java.lang.String[] addAllTo(java.lang.String[]);
-    method public static U addAllTo(java.lang.Iterable<T>, U);
-    method public static T[] addAllTo(java.lang.Iterable<T>, T[]);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -17777,10 +17783,6 @@
     method public android.icu.text.UnicodeSet cloneAsThawed();
     method public android.icu.text.UnicodeSet closeOver(int);
     method public android.icu.text.UnicodeSet compact();
-    method public static int compare(java.lang.CharSequence, int);
-    method public static int compare(int, java.lang.CharSequence);
-    method public static int compare(java.lang.Iterable<T>, java.lang.Iterable<T>);
-    method public static int compare(java.util.Collection<T>, java.util.Collection<T>, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(android.icu.text.UnicodeSet);
     method public int compareTo(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(java.lang.Iterable<java.lang.String>);
@@ -17823,7 +17825,6 @@
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
-    method public static boolean resemblesPattern(java.lang.String, int);
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
@@ -17838,7 +17839,6 @@
     method public int spanBack(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
     method public int spanBack(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
     method public java.util.Collection<java.lang.String> strings();
-    method public static java.lang.String[] toArray(android.icu.text.UnicodeSet);
     method public java.lang.String toPattern(boolean);
     field public static final int ADD_CASE_MAPPINGS = 4; // 0x4
     field public static final android.icu.text.UnicodeSet ALL_CODE_POINTS;
@@ -17957,11 +17957,8 @@
     ctor protected CECalendar(int, int, int);
     ctor protected CECalendar(java.util.Date);
     ctor protected CECalendar(int, int, int, int, int, int);
-    method public static int ceToJD(long, int, int, int);
-    method protected abstract int getJDEpochOffset();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetLimit(int, int);
-    method public static void jdToCE(int, int, int[]);
   }
 
   public abstract class Calendar implements java.lang.Cloneable java.lang.Comparable java.io.Serializable {
@@ -18189,7 +18186,6 @@
     ctor public CopticCalendar(int, int, int);
     ctor public CopticCalendar(java.util.Date);
     ctor public CopticCalendar(int, int, int, int, int, int);
-    method protected deprecated int getJDEpochOffset();
     method protected deprecated int handleGetExtendedYear();
     field public static final int AMSHIR = 5; // 0x5
     field public static final int BABA = 1; // 0x1
@@ -18360,11 +18356,11 @@
     ctor public IslamicCalendar(java.util.Date);
     ctor public IslamicCalendar(int, int, int);
     ctor public IslamicCalendar(int, int, int, int, int, int);
+    method public android.icu.util.IslamicCalendar.CalculationType getCalculationType();
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetExtendedYear();
     method protected int handleGetLimit(int, int);
-    method public boolean isCivil();
-    method public void setCivil(boolean);
+    method public void setCalculationType(android.icu.util.IslamicCalendar.CalculationType);
     field public static final int DHU_AL_HIJJAH = 11; // 0xb
     field public static final int DHU_AL_QIDAH = 10; // 0xa
     field public static final int JUMADA_1 = 4; // 0x4
@@ -18802,7 +18798,6 @@
     method public int getMicro();
     method public int getMilli();
     method public int getMinor();
-    method public static void main(java.lang.String[]);
     field public static final android.icu.util.VersionInfo ICU_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_BUILDER_VERSION;
     field public static final android.icu.util.VersionInfo UCOL_RUNTIME_VERSION;
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 5ef03d1..5b7dae6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1147,8 +1147,7 @@
     }
 
     private Drawable getManagedProfileIconForDensity(UserHandle user, int drawableId, int density) {
-        UserInfo userInfo = getUserInfo(user.getIdentifier());
-        if (userInfo != null && userInfo.isManagedProfile()) {
+        if (isManagedProfile(user.getIdentifier())) {
             return getDrawableForDensity(drawableId, density);
         }
         return null;
@@ -1156,8 +1155,7 @@
 
     @Override
     public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
-        UserInfo userInfo = getUserInfo(user.getIdentifier());
-        if (userInfo != null && userInfo.isManagedProfile()) {
+        if (isManagedProfile(user.getIdentifier())) {
             return Resources.getSystem().getString(
                     com.android.internal.R.string.managed_profile_label_badge, label);
         }
@@ -2259,17 +2257,16 @@
         return drawable;
     }
 
-    private int getBadgeResIdForUser(int userHandle) {
+    private int getBadgeResIdForUser(int userId) {
         // Return the framework-provided badge.
-        UserInfo userInfo = getUserInfo(userHandle);
-        if (userInfo != null && userInfo.isManagedProfile()) {
+        if (isManagedProfile(userId)) {
             return com.android.internal.R.drawable.ic_corp_icon_badge;
         }
         return 0;
     }
 
-    private UserInfo getUserInfo(int userHandle) {
-        return getUserManager().getUserInfo(userHandle);
+    private boolean isManagedProfile(int userId) {
+        return getUserManager().isManagedProfile(userId);
     }
 
     /** {@hide} */
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index fe5c45f..98d356b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -145,19 +145,23 @@
      * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, although specifying only
      * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported.
      *
-     * <p> The intent may also contain the following extras:
+     * <p>The intent may also contain the following extras:
      * <ul>
-     * <li> {@link #EXTRA_PROVISIONING_LOGO_URI}, optional </li>
-     * <li> {@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional </li>
+     * <li>{@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}, optional </li>
+     * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional, supported from
+     * {@link android.os.Build.VERSION_CODES#N}</li>
+     * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
      * </ul>
      *
-     * <p> When managed provisioning has completed, broadcasts are sent to the application specified
+     * <p>When managed provisioning has completed, broadcasts are sent to the application specified
      * in the provisioning intent. The
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} broadcast is sent in the
      * managed profile and the {@link #ACTION_MANAGED_PROFILE_PROVISIONED} broadcast is sent in
      * the primary profile.
      *
-     * <p> If provisioning fails, the managedProfile is removed so the device returns to its
+     * <p>If provisioning fails, the managedProfile is removed so the device returns to its
      * previous state.
      *
      * <p>If launched with {@link android.app.Activity#startActivityForResult(Intent, int)} a
@@ -171,7 +175,6 @@
         = "android.app.action.PROVISION_MANAGED_PROFILE";
 
     /**
-     * @hide
      * Activity action: Starts the provisioning flow which sets up a managed user.
      *
      * <p>This intent will typically be sent by a mobile device management application (MDM).
@@ -180,16 +183,24 @@
      * been completed. Use {@link #isProvisioningAllowed(String)} to check if provisioning is
      * allowed.
      *
-     * <p>This intent should contain the extra
-     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}.
+     * <p>The intent contains the following extras:
+     * <ul>
+     * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</li>
+     * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
+     * </ul>
      *
-     * <p> If provisioning fails, the device returns to its previous state.
+     * <p>If provisioning fails, the device returns to its previous state.
      *
      * <p>If launched with {@link android.app.Activity#startActivityForResult(Intent, int)} a
      * result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part of
      * the provisioning flow was successful, although this doesn't guarantee the full flow will
      * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} implies
      * that the user backed-out of provisioning, or some precondition for provisioning wasn't met.
+     *
+     * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PROVISION_MANAGED_USER
@@ -220,11 +231,11 @@
      * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
      * </ul>
      *
-     * <p> When device owner provisioning has completed, an intent of the type
+     * <p>When device owner provisioning has completed, an intent of the type
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcast to the
      * device owner.
      *
-     * <p> If provisioning fails, the device is factory reset.
+     * <p>If provisioning fails, the device is factory reset.
      *
      * <p>A result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part
      * of the provisioning flow was successful, although this doesn't guarantee the full flow will
@@ -288,14 +299,14 @@
      * The primary benefit is that multiple non-system users are supported when provisioning using
      * this form of device management.
      *
-     * <p> During device owner provisioning a device admin app is set as the owner of the device.
+     * <p>During device owner provisioning a device admin app is set as the owner of the device.
      * A device owner has full control over the device. The device owner can not be modified by the
      * user.
      *
-     * <p> A typical use case would be a device that is owned by a company, but used by either an
+     * <p>A typical use case would be a device that is owned by a company, but used by either an
      * employee or client.
      *
-     * <p> An intent with this action can be sent only on an unprovisioned device.
+     * <p>An intent with this action can be sent only on an unprovisioned device.
      * It is possible to check if provisioning is allowed or not by querying the method
      * {@link #isProvisioningAllowed(String)}.
      *
@@ -305,13 +316,15 @@
      * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
      * </ul>
      *
-     * <p> When device owner provisioning has completed, an intent of the type
+     * <p>When device owner provisioning has completed, an intent of the type
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcast to the
      * device owner.
      *
-     * <p> If provisioning fails, the device is factory reset.
+     * <p>If provisioning fails, the device is factory reset.
      *
      * <p>A result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part
      * of the provisioning flow was successful, although this doesn't guarantee the full flow will
@@ -439,7 +452,7 @@
      *
      * <p> When this extra is set, the application must have exactly one device admin receiver.
      * This receiver will be set as the profile or device owner and active admin.
-
+     *
      * @see DeviceAdminReceiver
      * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still
      * supported, but only if there is only one device admin receiver in the package that requires
@@ -461,7 +474,7 @@
      * <p>This component is set as device owner and active admin when device owner provisioning is
      * started by an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE} or by an NFC
      * message containing an NFC record with MIME type
-     * {@link #MIME_TYPE_PROVISIONING_NFC}. For the NFC record, the component name should be
+     * {@link #MIME_TYPE_PROVISIONING_NFC}. For the NFC record, the component name must be
      * flattened to a string, via {@link ComponentName#flattenToShortString()}.
      *
      * @see DeviceAdminReceiver
@@ -664,8 +677,8 @@
      * the file at download location specified in
      * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
      *
-     * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} should be
-     * present. The provided checksum should match the checksum of the file at the download
+     * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} must be
+     * present. The provided checksum must match the checksum of the file at the download
      * location. If the checksum doesn't match an error will be shown to the user and the user will
      * be asked to factory reset the device.
      *
@@ -689,8 +702,8 @@
      * {@link android.content.pm.PackageManager#getPackageArchiveInfo} with flag
      * {@link android.content.pm.PackageManager#GET_SIGNATURES}.
      *
-     * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM} should be
-     * present. The provided checksum should match the checksum of any signature of the file at
+     * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM} must be
+     * present. The provided checksum must match the checksum of any signature of the file at
      * the download location. If the checksum does not match an error will be shown to the user and
      * the user will be asked to factory reset the device.
      *
@@ -715,11 +728,14 @@
         = "android.app.action.MANAGED_PROFILE_PROVISIONED";
 
     /**
-     * A boolean extra indicating whether device encryption can be skipped as part of Device Owner
-     * provisioning.
+     * A boolean extra indicating whether device encryption can be skipped as part of device owner
+     * or managed profile provisioning.
      *
      * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} or an intent with action
      * {@link #ACTION_PROVISION_MANAGED_DEVICE} that starts device owner provisioning.
+     *
+     * <p>From {@link android.os.Build.VERSION_CODES#N} onwards, this is also supported for an
+     * intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE}.
      */
     public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION =
              "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
@@ -762,7 +778,7 @@
             "android.app.extra.PROVISIONING_SKIP_USER_SETUP";
 
     /**
-     * This MIME type is used for starting the Device Owner provisioning.
+     * This MIME type is used for starting the device owner provisioning.
      *
      * <p>During device owner provisioning a device admin app is set as the owner of the device.
      * A device owner has full control over the device. The device owner can not be modified by the
@@ -772,7 +788,7 @@
      * <p> A typical use case would be a device that is owned by a company, but used by either an
      * employee or client.
      *
-     * <p> The NFC message should be send to an unprovisioned device.
+     * <p> The NFC message must be sent to an unprovisioned device.
      *
      * <p>The NFC record must contain a serialized {@link java.util.Properties} object which
      * contains the following properties:
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index ea2dca0..68442ea 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -197,109 +197,43 @@
             }
 
             /**
-             * A new GATT service has been discovered.
-             * The service is added to the internal list and the search
-             * continues.
-             * @hide
-             */
-            public void onGetService(String address, int srvcType,
-                                     int srvcInstId, ParcelUuid srvcUuid) {
-                if (VDBG) Log.d(TAG, "onGetService() - Device=" + address + " UUID=" + srvcUuid);
-                if (!address.equals(mDevice.getAddress())) {
-                    return;
-                }
-                mServices.add(new BluetoothGattService(mDevice, srvcUuid.getUuid(),
-                                                       srvcInstId, srvcType));
-            }
-
-            /**
-             * An included service has been found durig GATT discovery.
-             * The included service is added to the respective parent.
-             * @hide
-             */
-            public void onGetIncludedService(String address, int srvcType,
-                                             int srvcInstId, ParcelUuid srvcUuid,
-                                             int inclSrvcType, int inclSrvcInstId,
-                                             ParcelUuid inclSrvcUuid) {
-                if (VDBG) Log.d(TAG, "onGetIncludedService() - Device=" + address
-                    + " UUID=" + srvcUuid + " Included=" + inclSrvcUuid);
-
-                if (!address.equals(mDevice.getAddress())) {
-                    return;
-                }
-                BluetoothGattService service = getService(mDevice,
-                        srvcUuid.getUuid(), srvcInstId, srvcType);
-                BluetoothGattService includedService = getService(mDevice,
-                        inclSrvcUuid.getUuid(), inclSrvcInstId, inclSrvcType);
-
-                if (service != null && includedService != null) {
-                    service.addIncludedService(includedService);
-                }
-            }
-
-            /**
-             * A new GATT characteristic has been discovered.
-             * Add the new characteristic to the relevant service and continue
-             * the remote device inspection.
-             * @hide
-             */
-            public void onGetCharacteristic(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             int charProps) {
-                if (VDBG) Log.d(TAG, "onGetCharacteristic() - Device=" + address + " UUID=" +
-                               charUuid);
-
-                if (!address.equals(mDevice.getAddress())) {
-                    return;
-                }
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service != null) {
-                    service.addCharacteristic(new BluetoothGattCharacteristic(
-                           service, charUuid.getUuid(), charInstId, charProps, 0));
-                }
-            }
-
-            /**
-             * A new GATT descriptor has been discovered.
-             * Finally, add the descriptor to the related characteristic.
-             * This should conclude the remote device update.
-             * @hide
-             */
-            public void onGetDescriptor(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             int descrInstId, ParcelUuid descUuid) {
-                if (VDBG) Log.d(TAG, "onGetDescriptor() - Device=" + address + " UUID=" + descUuid);
-
-                if (!address.equals(mDevice.getAddress())) {
-                    return;
-                }
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
-
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                    charUuid.getUuid(), charInstId);
-                if (characteristic == null) return;
-
-                characteristic.addDescriptor(new BluetoothGattDescriptor(
-                    characteristic, descUuid.getUuid(), descrInstId, 0));
-            }
-
-            /**
              * Remote search has been completed.
              * The internal object structure should now reflect the state
              * of the remote device database. Let the application know that
              * we are done at this point.
              * @hide
              */
-            public void onSearchComplete(String address, int status) {
+            public void onSearchComplete(String address, List<BluetoothGattService> services,
+                                         int status) {
                 if (DBG) Log.d(TAG, "onSearchComplete() = Device=" + address + " Status=" + status);
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                for (BluetoothGattService s : services) {
+                    //services we receive don't have device set properly.
+                    s.setDevice(mDevice);
+                }
+
+                mServices.addAll(services);
+
+                // Fix references to included services, as they doesn't point to right objects.
+                for (BluetoothGattService fixedService : mServices) {
+                    ArrayList<BluetoothGattService> includedServices =
+                        new ArrayList(fixedService.getIncludedServices());
+                    fixedService.getIncludedServices().clear();
+
+                    for(BluetoothGattService brokenRef : includedServices) {
+                        BluetoothGattService includedService = getService(mDevice,
+                            brokenRef.getUuid(), brokenRef.getInstanceId(), brokenRef.getType());
+                        if (includedService != null) {
+                            fixedService.addIncludedService(includedService);
+                        } else {
+                            Log.e(TAG, "Broken GATT database: can't find included service.");
+                        }
+                    }
+                }
+
                 try {
                     mCallback.onServicesDiscovered(BluetoothGatt.this, status);
                 } catch (Exception ex) {
@@ -312,11 +246,12 @@
              * Updates the internal value.
              * @hide
              */
-            public void onCharacteristicRead(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid, byte[] value) {
+            public void onCharacteristicRead(String address, int status, int handle, byte[] value) {
                 if (VDBG) Log.d(TAG, "onCharacteristicRead() - Device=" + address
-                            + " UUID=" + charUuid + " Status=" + status);
+                            + " handle=" + handle + " Status=" + status);
+
+                 Log.w(TAG, "onCharacteristicRead() - Device=" + address
+                            + " handle=" + handle + " Status=" + status);
 
                 if (!address.equals(mDevice.getAddress())) {
                     return;
@@ -331,9 +266,7 @@
                   && mAuthRetry == false) {
                     try {
                         mAuthRetry = true;
-                        mService.readCharacteristic(mClientIf, address,
-                            srvcType, srvcInstId, srvcUuid,
-                            charInstId, charUuid, AUTHENTICATION_MITM);
+                        mService.readCharacteristic(mClientIf, address, handle, AUTHENTICATION_MITM);
                         return;
                     } catch (RemoteException e) {
                         Log.e(TAG,"",e);
@@ -342,13 +275,11 @@
 
                 mAuthRetry = false;
 
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
-
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                        charUuid.getUuid(), charInstId);
-                if (characteristic == null) return;
+                BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
+                if (characteristic == null) {
+                    Log.w(TAG, "onCharacteristicRead() failed to find characteristic!");
+                    return;
+                }
 
                 if (status == 0) characteristic.setValue(value);
 
@@ -364,11 +295,9 @@
              * Let the app know how we did...
              * @hide
              */
-            public void onCharacteristicWrite(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid) {
+            public void onCharacteristicWrite(String address, int status, int handle) {
                 if (VDBG) Log.d(TAG, "onCharacteristicWrite() - Device=" + address
-                            + " UUID=" + charUuid + " Status=" + status);
+                            + " handle=" + handle + " Status=" + status);
 
                 if (!address.equals(mDevice.getAddress())) {
                     return;
@@ -378,12 +307,7 @@
                     mDeviceBusy = false;
                 }
 
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
-
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                        charUuid.getUuid(), charInstId);
+                BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
                 if (characteristic == null) return;
 
                 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
@@ -391,8 +315,7 @@
                   && mAuthRetry == false) {
                     try {
                         mAuthRetry = true;
-                        mService.writeCharacteristic(mClientIf, address,
-                            srvcType, srvcInstId, srvcUuid, charInstId, charUuid,
+                        mService.writeCharacteristic(mClientIf, address, handle,
                             characteristic.getWriteType(), AUTHENTICATION_MITM,
                             characteristic.getValue());
                         return;
@@ -415,21 +338,14 @@
              * Updates the internal value.
              * @hide
              */
-            public void onNotify(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             byte[] value) {
-                if (VDBG) Log.d(TAG, "onNotify() - Device=" + address + " UUID=" + charUuid);
+            public void onNotify(String address, int handle, byte[] value) {
+                if (VDBG) Log.d(TAG, "onNotify() - Device=" + address + " handle=" + handle);
 
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
 
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                        charUuid.getUuid(), charInstId);
+                BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle);
                 if (characteristic == null) return;
 
                 characteristic.setValue(value);
@@ -445,12 +361,8 @@
              * Descriptor has been read.
              * @hide
              */
-            public void onDescriptorRead(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             int descrInstId, ParcelUuid descrUuid,
-                             byte[] value) {
-                if (VDBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " UUID=" + charUuid);
+            public void onDescriptorRead(String address, int status, int handle, byte[] value) {
+                if (VDBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " handle=" + handle);
 
                 if (!address.equals(mDevice.getAddress())) {
                     return;
@@ -460,16 +372,7 @@
                     mDeviceBusy = false;
                 }
 
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
-
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                        charUuid.getUuid(), charInstId);
-                if (characteristic == null) return;
-
-                BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
-                        descrUuid.getUuid(), descrInstId);
+                BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
                 if (descriptor == null) return;
 
                 if (status == 0) descriptor.setValue(value);
@@ -479,9 +382,7 @@
                   && mAuthRetry == false) {
                     try {
                         mAuthRetry = true;
-                        mService.readDescriptor(mClientIf, address,
-                            srvcType, srvcInstId, srvcUuid, charInstId, charUuid,
-                            descrInstId, descrUuid, AUTHENTICATION_MITM);
+                        mService.readDescriptor(mClientIf, address, handle, AUTHENTICATION_MITM);
                         return;
                     } catch (RemoteException e) {
                         Log.e(TAG,"",e);
@@ -501,11 +402,8 @@
              * Descriptor write operation complete.
              * @hide
              */
-            public void onDescriptorWrite(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             int descrInstId, ParcelUuid descrUuid) {
-                if (VDBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " UUID=" + charUuid);
+            public void onDescriptorWrite(String address, int status, int handle) {
+                if (VDBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " handle=" + handle);
 
                 if (!address.equals(mDevice.getAddress())) {
                     return;
@@ -515,16 +413,7 @@
                     mDeviceBusy = false;
                 }
 
-                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
-                                                          srvcInstId, srvcType);
-                if (service == null) return;
-
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                        charUuid.getUuid(), charInstId);
-                if (characteristic == null) return;
-
-                BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
-                        descrUuid.getUuid(), descrInstId);
+                BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
                 if (descriptor == null) return;
 
                 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
@@ -532,9 +421,8 @@
                   && mAuthRetry == false) {
                     try {
                         mAuthRetry = true;
-                        mService.writeDescriptor(mClientIf, address,
-                            srvcType, srvcInstId, srvcUuid, charInstId, charUuid,
-                            descrInstId, descrUuid, characteristic.getWriteType(),
+                        mService.writeDescriptor(mClientIf, address, handle,
+                            descriptor.getCharacteristic().getWriteType(),
                             AUTHENTICATION_MITM, descriptor.getValue());
                         return;
                     } catch (RemoteException e) {
@@ -651,6 +539,37 @@
 
 
     /**
+     * Returns a characteristic with id equal to instanceId.
+     * @hide
+     */
+    /*package*/ BluetoothGattCharacteristic getCharacteristicById(BluetoothDevice device, int instanceId) {
+        for(BluetoothGattService svc : mServices) {
+            for(BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
+                Log.w(TAG, "getCharacteristicById() comparing " + charac.getInstanceId() + " and " + instanceId);
+                if (charac.getInstanceId() == instanceId)
+                    return charac;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a descriptor with id equal to instanceId.
+     * @hide
+     */
+    /*package*/ BluetoothGattDescriptor getDescriptorById(BluetoothDevice device, int instanceId) {
+        for(BluetoothGattService svc : mServices) {
+            for(BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
+                for(BluetoothGattDescriptor desc : charac.getDescriptors()) {
+                    if (desc.getInstanceId() == instanceId)
+                        return desc;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
      * Register an application callback to start using GATT.
      *
      * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
@@ -898,9 +817,7 @@
 
         try {
             mService.readCharacteristic(mClientIf, device.getAddress(),
-                service.getType(), service.getInstanceId(),
-                new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
-                new ParcelUuid(characteristic.getUuid()), AUTHENTICATION_NONE);
+                characteristic.getInstanceId(), AUTHENTICATION_NONE);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             mDeviceBusy = false;
@@ -943,11 +860,8 @@
 
         try {
             mService.writeCharacteristic(mClientIf, device.getAddress(),
-                service.getType(), service.getInstanceId(),
-                new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
-                new ParcelUuid(characteristic.getUuid()),
-                characteristic.getWriteType(), AUTHENTICATION_NONE,
-                characteristic.getValue());
+                characteristic.getInstanceId(), characteristic.getWriteType(),
+                AUTHENTICATION_NONE, characteristic.getValue());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             mDeviceBusy = false;
@@ -988,11 +902,8 @@
         }
 
         try {
-            mService.readDescriptor(mClientIf, device.getAddress(), service.getType(),
-                service.getInstanceId(), new ParcelUuid(service.getUuid()),
-                characteristic.getInstanceId(), new ParcelUuid(characteristic.getUuid()),
-                descriptor.getInstanceId(), new ParcelUuid(descriptor.getUuid()),
-                AUTHENTICATION_NONE);
+            mService.readDescriptor(mClientIf, device.getAddress(),
+                descriptor.getInstanceId(), AUTHENTICATION_NONE);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             mDeviceBusy = false;
@@ -1032,12 +943,8 @@
         }
 
         try {
-            mService.writeDescriptor(mClientIf, device.getAddress(), service.getType(),
-                service.getInstanceId(), new ParcelUuid(service.getUuid()),
-                characteristic.getInstanceId(), new ParcelUuid(characteristic.getUuid()),
-                descriptor.getInstanceId(), new ParcelUuid(descriptor.getUuid()),
-                characteristic.getWriteType(), AUTHENTICATION_NONE,
-                descriptor.getValue());
+            mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(),
+                characteristic.getWriteType(), AUTHENTICATION_NONE, descriptor.getValue());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             mDeviceBusy = false;
@@ -1168,10 +1075,7 @@
 
         try {
             mService.registerForNotification(mClientIf, device.getAddress(),
-                service.getType(), service.getInstanceId(),
-                new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
-                new ParcelUuid(characteristic.getUuid()),
-                enable);
+                characteristic.getInstanceId(), enable);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
diff --git a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
index 01778b3..17e533a 100644
--- a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
+++ b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.le.AdvertiseSettings;
 import android.bluetooth.le.ScanResult;
+import android.bluetooth.BluetoothGattService;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
 
@@ -48,41 +49,17 @@
     }
 
     @Override
-    public void onGetService(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid)
+    public void onSearchComplete(String address, List<BluetoothGattService> services,
+            int status) throws RemoteException {
+    }
+
+    @Override
+    public void onCharacteristicRead(String address, int status, int handle, byte[] value)
             throws RemoteException {
     }
 
     @Override
-    public void onGetIncludedService(String address, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int inclSrvcType, int inclSrvcInstId, ParcelUuid inclSrvcUuid)
-            throws RemoteException {
-    }
-
-    @Override
-    public void onGetCharacteristic(String address, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, int charProps)
-            throws RemoteException {
-    }
-
-    @Override
-    public void onGetDescriptor(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid,
-            int charInstId, ParcelUuid charUuid, int descrInstId, ParcelUuid descrUuid)
-            throws RemoteException {
-    }
-
-    @Override
-    public void onSearchComplete(String address, int status) throws RemoteException {
-    }
-
-    @Override
-    public void onCharacteristicRead(String address, int status, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, byte[] value)
-            throws RemoteException {
-    }
-
-    @Override
-    public void onCharacteristicWrite(String address, int status, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid) throws RemoteException {
+    public void onCharacteristicWrite(String address, int status, int handle) throws RemoteException {
     }
 
     @Override
@@ -90,20 +67,15 @@
     }
 
     @Override
-    public void onDescriptorRead(String address, int status, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, int descrInstId,
-            ParcelUuid descrUuid, byte[] value) throws RemoteException {
+    public void onDescriptorRead(String address, int status, int handle, byte[] value) throws RemoteException {
     }
 
     @Override
-    public void onDescriptorWrite(String address, int status, int srvcType, int srvcInstId,
-            ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, int descrInstId,
-            ParcelUuid descrUuid) throws RemoteException {
+    public void onDescriptorWrite(String address, int status, int handle) throws RemoteException {
     }
 
     @Override
-    public void onNotify(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid,
-            int charInstId, ParcelUuid charUuid, byte[] value) throws RemoteException {
+    public void onNotify(String address, int handle, byte[] value) throws RemoteException {
     }
 
     @Override
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.aidl b/core/java/android/bluetooth/BluetoothGattCharacteristic.aidl
new file mode 100644
index 0000000..bbb8623
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattCharacteristic;
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 7cdcc2c..7d698b3 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -15,6 +15,9 @@
  */
 package android.bluetooth;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
@@ -26,7 +29,7 @@
  * {@link BluetoothGattService}. The characteristic contains a value as well as
  * additional information and optional GATT descriptors, {@link BluetoothGattDescriptor}.
  */
-public class BluetoothGattCharacteristic {
+public class BluetoothGattCharacteristic implements Parcelable {
 
     /**
      * Characteristic proprty: Characteristic is broadcastable.
@@ -242,6 +245,15 @@
         initCharacteristic(service, uuid, instanceId, properties, permissions);
     }
 
+    /**
+     * Create a new BluetoothGattCharacteristic
+     * @hide
+     */
+    public BluetoothGattCharacteristic(UUID uuid, int instanceId,
+                                       int properties, int permissions) {
+        initCharacteristic(null, uuid, instanceId, properties, permissions);
+    }
+
     private void initCharacteristic(BluetoothGattService service,
                                     UUID uuid, int instanceId,
                                     int properties, int permissions) {
@@ -261,6 +273,50 @@
     }
 
     /**
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(new ParcelUuid(mUuid), 0);
+        out.writeInt(mInstance);
+        out.writeInt(mProperties);
+        out.writeInt(mPermissions);
+        out.writeTypedList(mDescriptors);
+    }
+
+    public static final Parcelable.Creator<BluetoothGattCharacteristic> CREATOR
+            = new Parcelable.Creator<BluetoothGattCharacteristic>() {
+        public BluetoothGattCharacteristic createFromParcel(Parcel in) {
+            return new BluetoothGattCharacteristic(in);
+        }
+
+        public BluetoothGattCharacteristic[] newArray(int size) {
+            return new BluetoothGattCharacteristic[size];
+        }
+    };
+
+    private BluetoothGattCharacteristic(Parcel in) {
+        mUuid = ((ParcelUuid)in.readParcelable(null)).getUuid();
+        mInstance = in.readInt();
+        mProperties = in.readInt();
+        mPermissions = in.readInt();
+
+        mDescriptors = new ArrayList<BluetoothGattDescriptor>();
+
+        ArrayList<BluetoothGattDescriptor> descs =
+                in.createTypedArrayList(BluetoothGattDescriptor.CREATOR);
+        if (descs != null) {
+            for (BluetoothGattDescriptor desc: descs) {
+                desc.setCharacteristic(this);
+                mDescriptors.add(desc);
+            }
+        }
+    }
+
+    /**
      * Returns the deisred key size.
      * @hide
      */
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.aidl b/core/java/android/bluetooth/BluetoothGattDescriptor.aidl
new file mode 100644
index 0000000..4393273
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattDescriptor;
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
index 5f525dc..28317c4 100644
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java
@@ -16,6 +16,9 @@
 
 package android.bluetooth;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
 import java.util.UUID;
 
 /**
@@ -25,7 +28,7 @@
  * characteristic, {@link BluetoothGattCharacteristic}. They can be used to describe
  * the characteristic's features or to control certain behaviours of the characteristic.
  */
-public class BluetoothGattDescriptor {
+public class BluetoothGattDescriptor implements Parcelable {
 
     /**
      * Value used to enable notification for a client configuration descriptor
@@ -138,6 +141,13 @@
         initDescriptor(characteristic, uuid, instance, permissions);
     }
 
+    /**
+     * @hide
+     */
+    public BluetoothGattDescriptor(UUID uuid, int instance, int permissions) {
+        initDescriptor(null, uuid, instance, permissions);
+    }
+
     private void initDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
                                 int instance, int permissions) {
         mCharacteristic = characteristic;
@@ -147,6 +157,36 @@
     }
 
     /**
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(new ParcelUuid(mUuid), 0);
+        out.writeInt(mInstance);
+        out.writeInt(mPermissions);
+    }
+
+    public static final Parcelable.Creator<BluetoothGattDescriptor> CREATOR
+            = new Parcelable.Creator<BluetoothGattDescriptor>() {
+        public BluetoothGattDescriptor createFromParcel(Parcel in) {
+            return new BluetoothGattDescriptor(in);
+        }
+
+        public BluetoothGattDescriptor[] newArray(int size) {
+            return new BluetoothGattDescriptor[size];
+        }
+    };
+
+    private BluetoothGattDescriptor(Parcel in) {
+        mUuid = ((ParcelUuid)in.readParcelable(null)).getUuid();
+        mInstance = in.readInt();
+        mPermissions = in.readInt();
+    }
+
+    /**
      * Returns the characteristic this descriptor belongs to.
      * @return The characteristic.
      */
diff --git a/core/java/android/bluetooth/BluetoothGattIncludedService.aidl b/core/java/android/bluetooth/BluetoothGattIncludedService.aidl
new file mode 100644
index 0000000..1ef427e
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattIncludedService.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattIncludedService;
diff --git a/core/java/android/bluetooth/BluetoothGattIncludedService.java b/core/java/android/bluetooth/BluetoothGattIncludedService.java
new file mode 100644
index 0000000..155dc57
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattIncludedService.java
@@ -0,0 +1,110 @@
+/*
+ * 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Represents a Bluetooth GATT Included Service
+ * @hide
+ */
+public class BluetoothGattIncludedService implements Parcelable {
+
+    /**
+     * The UUID of this service.
+     */
+    protected UUID mUuid;
+
+    /**
+     * Instance ID for this service.
+     */
+    protected int mInstanceId;
+
+    /**
+     * Service type (Primary/Secondary).
+     */
+    protected int mServiceType;
+
+    /**
+     * Create a new BluetoothGattIncludedService
+     */
+    public BluetoothGattIncludedService(UUID uuid, int instanceId, int serviceType) {
+        mUuid = uuid;
+        mInstanceId = instanceId;
+        mServiceType = serviceType;
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(new ParcelUuid(mUuid), 0);
+        out.writeInt(mInstanceId);
+        out.writeInt(mServiceType);
+     }
+
+    public static final Parcelable.Creator<BluetoothGattIncludedService> CREATOR
+            = new Parcelable.Creator<BluetoothGattIncludedService>() {
+        public BluetoothGattIncludedService createFromParcel(Parcel in) {
+            return new BluetoothGattIncludedService(in);
+        }
+
+        public BluetoothGattIncludedService[] newArray(int size) {
+            return new BluetoothGattIncludedService[size];
+        }
+    };
+
+    private BluetoothGattIncludedService(Parcel in) {
+        mUuid = ((ParcelUuid)in.readParcelable(null)).getUuid();
+        mInstanceId = in.readInt();
+        mServiceType = in.readInt();
+    }
+
+    /**
+     * Returns the UUID of this service
+     *
+     * @return UUID of this service
+     */
+    public UUID getUuid() {
+        return mUuid;
+    }
+
+    /**
+     * Returns the instance ID for this service
+     *
+     * <p>If a remote device offers multiple services with the same UUID
+     * (ex. multiple battery services for different batteries), the instance
+     * ID is used to distuinguish services.
+     *
+     * @return Instance ID of this service
+     */
+    public int getInstanceId() {
+        return mInstanceId;
+    }
+
+    /**
+     * Get the type of this service (primary/secondary)
+     */
+    public int getType() {
+        return mServiceType;
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothGattService.aidl b/core/java/android/bluetooth/BluetoothGattService.aidl
new file mode 100644
index 0000000..84314d2
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattService.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattService;
diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java
index 52bc0f7..a4e1dc0 100644
--- a/core/java/android/bluetooth/BluetoothGattService.java
+++ b/core/java/android/bluetooth/BluetoothGattService.java
@@ -15,6 +15,9 @@
  */
 package android.bluetooth;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
@@ -25,7 +28,7 @@
  * <p> Gatt Service contains a collection of {@link BluetoothGattCharacteristic},
  * as well as referenced services.
  */
-public class BluetoothGattService {
+public class BluetoothGattService implements Parcelable {
 
     /**
      * Primary service
@@ -117,6 +120,81 @@
     }
 
     /**
+     * Create a new BluetoothGattService
+     * @hide
+     */
+    public BluetoothGattService(UUID uuid, int instanceId, int serviceType) {
+        mDevice = null;
+        mUuid = uuid;
+        mInstanceId = instanceId;
+        mServiceType = serviceType;
+        mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
+        mIncludedServices = new ArrayList<BluetoothGattService>();
+    }
+
+    /**
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(new ParcelUuid(mUuid), 0);
+        out.writeInt(mInstanceId);
+        out.writeInt(mServiceType);
+        out.writeTypedList(mCharacteristics);
+
+        ArrayList<BluetoothGattIncludedService> includedServices =
+                new ArrayList<BluetoothGattIncludedService>(mIncludedServices.size());
+        for(BluetoothGattService s : mIncludedServices) {
+            includedServices.add(new BluetoothGattIncludedService(s.getUuid(),
+                                                                  s.getInstanceId(), s.getType()));
+        }
+        out.writeTypedList(includedServices);
+     }
+
+    public static final Parcelable.Creator<BluetoothGattService> CREATOR
+            = new Parcelable.Creator<BluetoothGattService>() {
+        public BluetoothGattService createFromParcel(Parcel in) {
+            return new BluetoothGattService(in);
+        }
+
+        public BluetoothGattService[] newArray(int size) {
+            return new BluetoothGattService[size];
+        }
+    };
+
+    private BluetoothGattService(Parcel in) {
+        mUuid = ((ParcelUuid)in.readParcelable(null)).getUuid();
+        mInstanceId = in.readInt();
+        mServiceType = in.readInt();
+
+        mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
+
+        ArrayList<BluetoothGattCharacteristic> chrcs =
+                in.createTypedArrayList(BluetoothGattCharacteristic.CREATOR);
+        if (chrcs != null) {
+            for (BluetoothGattCharacteristic chrc : chrcs) {
+                chrc.setService(this);
+                mCharacteristics.add(chrc);
+            }
+        }
+
+        mIncludedServices = new ArrayList<BluetoothGattService>();
+
+        ArrayList<BluetoothGattIncludedService> inclSvcs =
+                in.createTypedArrayList(BluetoothGattIncludedService.CREATOR);
+        if (chrcs != null) {
+            for (BluetoothGattIncludedService isvc : inclSvcs) {
+                mIncludedServices.add(new BluetoothGattService(null, isvc.getUuid(),
+                                                            isvc.getInstanceId(), isvc.getType()));
+            }
+        }
+    }
+
+    /**
      * Returns the device associated with this service.
      * @hide
      */
@@ -125,6 +203,14 @@
     }
 
     /**
+     * Returns the device associated with this service.
+     * @hide
+     */
+    /*package*/ void setDevice(BluetoothDevice device) {
+        this.mDevice = device;
+    }
+
+    /**
      * Add an included service to this service.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
@@ -192,7 +278,7 @@
      * Add an included service to the internal map.
      * @hide
      */
-    /*package*/ void addIncludedService(BluetoothGattService includedService) {
+    public void addIncludedService(BluetoothGattService includedService) {
         mIncludedServices.add(includedService);
     }
 
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 6b5f77f..adb07df 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -51,28 +51,13 @@
     void clientDisconnect(in int clientIf, in String address);
     void refreshDevice(in int clientIf, in String address);
     void discoverServices(in int clientIf, in String address);
-    void readCharacteristic(in int clientIf, in String address, in int srvcType,
-                            in int srvcInstanceId, in ParcelUuid srvcId,
-                            in int charInstanceId, in ParcelUuid charId,
-                            in int authReq);
-    void writeCharacteristic(in int clientIf, in String address, in int srvcType,
-                            in int srvcInstanceId, in ParcelUuid srvcId,
-                            in int charInstanceId, in ParcelUuid charId,
+    void readCharacteristic(in int clientIf, in String address, in int handle, in int authReq);
+    void writeCharacteristic(in int clientIf, in String address, in int handle,
                             in int writeType, in int authReq, in byte[] value);
-    void readDescriptor(in int clientIf, in String address, in int srvcType,
-                            in int srvcInstanceId, in ParcelUuid srvcId,
-                            in int charInstanceId, in ParcelUuid charId,
-                            in int descrInstanceId, in ParcelUuid descrUuid,
-                            in int authReq);
-    void writeDescriptor(in int clientIf, in String address, in int srvcType,
-                            in int srvcInstanceId, in ParcelUuid srvcId,
-                            in int charInstanceId, in ParcelUuid charId,
-                            in int descrInstanceId, in ParcelUuid descrId,
+    void readDescriptor(in int clientIf, in String address, in int handle, in int authReq);
+    void writeDescriptor(in int clientIf, in String address, in int handle,
                             in int writeType, in int authReq, in byte[] value);
-    void registerForNotification(in int clientIf, in String address, in int srvcType,
-                            in int srvcInstanceId, in ParcelUuid srvcId,
-                            in int charInstanceId, in ParcelUuid charId,
-                            in boolean enable);
+    void registerForNotification(in int clientIf, in String address, in int handle, in boolean enable);
     void beginReliableWrite(in int clientIf, in String address);
     void endReliableWrite(in int clientIf, in String address, in boolean execute);
     void readRemoteRssi(in int clientIf, in String address);
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index cbba9f0..7163c37 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -16,6 +16,7 @@
 package android.bluetooth;
 
 import android.os.ParcelUuid;
+import android.bluetooth.BluetoothGattService;
 import android.bluetooth.le.AdvertiseSettings;
 import android.bluetooth.le.ScanResult;
 
@@ -29,41 +30,13 @@
                                  in boolean connected, in String address);
     void onScanResult(in ScanResult scanResult);
     void onBatchScanResults(in List<ScanResult> batchResults);
-    void onGetService(in String address, in int srvcType, in int srvcInstId,
-                      in ParcelUuid srvcUuid);
-    void onGetIncludedService(in String address, in int srvcType, in int srvcInstId,
-                              in ParcelUuid srvcUuid, in int inclSrvcType,
-                              in int inclSrvcInstId, in ParcelUuid inclSrvcUuid);
-    void onGetCharacteristic(in String address, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in int charProps);
-    void onGetDescriptor(in String address, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in int descrInstId, in ParcelUuid descrUuid);
-    void onSearchComplete(in String address, in int status);
-    void onCharacteristicRead(in String address, in int status, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in byte[] value);
-    void onCharacteristicWrite(in String address, in int status, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid);
+    void onSearchComplete(in String address, in List<BluetoothGattService> services, in int status);
+    void onCharacteristicRead(in String address, in int status, in int handle, in byte[] value);
+    void onCharacteristicWrite(in String address, in int status, in int handle);
     void onExecuteWrite(in String address, in int status);
-    void onDescriptorRead(in String address, in int status, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in int descrInstId, in ParcelUuid descrUuid,
-                             in byte[] value);
-    void onDescriptorWrite(in String address, in int status, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in int descrInstId, in ParcelUuid descrUuid);
-    void onNotify(in String address, in int srvcType,
-                             in int srvcInstId, in ParcelUuid srvcUuid,
-                             in int charInstId, in ParcelUuid charUuid,
-                             in byte[] value);
+    void onDescriptorRead(in String address, in int status, in int handle, in byte[] value);
+    void onDescriptorWrite(in String address, in int status, in int handle);
+    void onNotify(in String address, in int handle, in byte[] value);
     void onReadRemoteRssi(in String address, in int rssi, in int status);
     void onMultiAdvertiseCallback(in int status, boolean isStart,
                                   in AdvertiseSettings advertiseSettings);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 5f1043b..f0673ff 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2744,7 +2744,9 @@
         if (networkCallback == null) {
             throw new IllegalArgumentException("null NetworkCallback");
         }
-        if (need == null) throw new IllegalArgumentException("null NetworkCapabilities");
+        if (need == null && action != REQUEST) {
+            throw new IllegalArgumentException("null NetworkCapabilities");
+        }
         try {
             incCallbackHandlerRefCount();
             synchronized(sNetworkCallback) {
@@ -2767,7 +2769,7 @@
     }
 
     /**
-     * Helper function to requests a network with a particular legacy type.
+     * Helper function to request a network with a particular legacy type.
      *
      * This is temporarily public @hide so it can be called by system code that uses the
      * NetworkRequest API to request networks but relies on CONNECTIVITY_ACTION broadcasts for
@@ -3011,6 +3013,28 @@
     }
 
     /**
+     * Registers to receive notifications about whichever network currently satisfies the
+     * system default {@link NetworkRequest}.  The callbacks will continue to be called until
+     * either the application exits or {@link #unregisterNetworkCallback} is called
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * @param networkCallback The {@link NetworkCallback} that the system will call as the
+     *                        system default network changes.
+     * @hide
+     */
+    public void registerDefaultNetworkCallback(NetworkCallback networkCallback) {
+        // This works because if the NetworkCapabilities are null,
+        // ConnectivityService takes them from the default request.
+        //
+        // Since the capabilities are exactly the same as the default request's
+        // capabilities, this request is guaranteed, at all times, to be
+        // satisfied by the same network, if any, that satisfies the default
+        // request, i.e., the system default network.
+        sendRequestForNetwork(null, networkCallback, 0, REQUEST, TYPE_NONE);
+    }
+
+    /**
      * Requests bandwidth update for a given {@link Network} and returns whether the update request
      * is accepted by ConnectivityService. Once accepted, ConnectivityService will poll underlying
      * network connection for updated bandwidth information. The caller will be notified via
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 555032d..141af3d 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -39,23 +39,6 @@
 
     private static final String TAG = "NetworkUtils";
 
-    /** Setting bit 0 indicates reseting of IPv4 addresses required */
-    public static final int RESET_IPV4_ADDRESSES = 0x01;
-
-    /** Setting bit 1 indicates reseting of IPv4 addresses required */
-    public static final int RESET_IPV6_ADDRESSES = 0x02;
-
-    /** Reset all addresses */
-    public static final int RESET_ALL_ADDRESSES = RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES;
-
-    /**
-     * Reset IPv6 or IPv4 sockets that are connected via the named interface.
-     *
-     * @param interfaceName is the interface to reset
-     * @param mask {@see #RESET_IPV4_ADDRESSES} and {@see #RESET_IPV6_ADDRESSES}
-     */
-    public native static int resetConnections(String interfaceName, int mask);
-
     /**
      * Attaches a socket filter that accepts DHCP packets to the given socket.
      */
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index f382241..55b107a 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -19,8 +19,11 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.TypedProperties;
 
+import android.app.AppGlobals;
+import android.content.Context;
 import android.util.Log;
 
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -100,14 +103,6 @@
      */
     private static final String DEFAULT_TRACE_BODY = "dmtrace";
     private static final String DEFAULT_TRACE_EXTENSION = ".trace";
-    private static class NoPreloadHolder {
-        private static final String DEFAULT_TRACE_PATH_PREFIX =
-                Environment.getLegacyExternalStorageDirectory().getPath() + "/";
-        private static final String DEFAULT_TRACE_FILE_PATH =
-                DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY
-                + DEFAULT_TRACE_EXTENSION;
-    }
-
 
     /**
      * This class is used to retrieved various statistics about the memory mappings for this
@@ -938,109 +933,171 @@
     }
 
     /**
-     * Start method tracing with default log name and buffer size. See <a
-href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
-     * information about reading these files. Call stopMethodTracing() to stop
-     * tracing.
+     * Start method tracing with default log name and buffer size.
+     * <p>
+     * By default, the trace file is called "dmtrace.trace" and it's placed
+     * under your package-specific directory on primary shared/external storage,
+     * as returned by {@link Context#getExternalFilesDir(String)}.
+     * <p>
+     * See <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview:
+     * A Graphical Log Viewer</a> for information about reading trace files.
+     * <p class="note">
+     * When method tracing is enabled, the VM will run more slowly than usual,
+     * so the timings from the trace files should only be considered in relative
+     * terms (e.g. was run #1 faster than run #2). The times for native methods
+     * will not change, so don't try to use this to compare the performance of
+     * interpreted and native implementations of the same method. As an
+     * alternative, consider using sampling-based method tracing via
+     * {@link #startMethodTracingSampling(String, int, int)} or "native" tracing
+     * in the emulator via {@link #startNativeTracing()}.
+     * </p>
      */
     public static void startMethodTracing() {
-        VMDebug.startMethodTracing(fixTraceName(null), 0, 0, false, 0);
+        VMDebug.startMethodTracing(fixTracePath(null), 0, 0, false, 0);
     }
 
     /**
-     * Start method tracing, specifying the trace log file name.  The trace
-     * file will be put under "/sdcard" unless an absolute path is given.
-     * See <a
-       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
-     * information about reading trace files.
-     *
-     * @param traceName Name for the trace log file to create.
-     * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace".
-     * If the files already exist, they will be truncated.
-     * If the trace file given does not end in ".trace", it will be appended for you.
-     */
-    public static void startMethodTracing(String traceName) {
-        startMethodTracing(traceName, 0, 0);
-    }
-
-    /**
-     * Start method tracing, specifying the trace log file name and the
-     * buffer size. The trace files will be put under "/sdcard" unless an
-     * absolute path is given. See <a
-       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
-     * information about reading trace files.
-     * @param traceName    Name for the trace log file to create.
-     * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace".
-     * If the files already exist, they will be truncated.
-     * If the trace file given does not end in ".trace", it will be appended for you.
-     *
-     * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
-     */
-    public static void startMethodTracing(String traceName, int bufferSize) {
-        startMethodTracing(traceName, bufferSize, 0);
-    }
-
-    /**
-     * Start method tracing, specifying the trace log file name and the
-     * buffer size. The trace files will be put under "/sdcard" unless an
-     * absolute path is given. See <a
-       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
-     * information about reading trace files.
-     *
+     * Start method tracing, specifying the trace log file path.
      * <p>
-     * When method tracing is enabled, the VM will run more slowly than
-     * usual, so the timings from the trace files should only be considered
-     * in relative terms (e.g. was run #1 faster than run #2).  The times
-     * for native methods will not change, so don't try to use this to
-     * compare the performance of interpreted and native implementations of the
-     * same method.  As an alternative, consider using sampling-based method
-     * tracing via {@link #startMethodTracingSampling(String, int, int)} or
-     * "native" tracing in the emulator via {@link #startNativeTracing()}.
+     * When a relative file path is given, the trace file will be placed under
+     * your package-specific directory on primary shared/external storage, as
+     * returned by {@link Context#getExternalFilesDir(String)}.
+     * <p>
+     * See <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview:
+     * A Graphical Log Viewer</a> for information about reading trace files.
+     * <p class="note">
+     * When method tracing is enabled, the VM will run more slowly than usual,
+     * so the timings from the trace files should only be considered in relative
+     * terms (e.g. was run #1 faster than run #2). The times for native methods
+     * will not change, so don't try to use this to compare the performance of
+     * interpreted and native implementations of the same method. As an
+     * alternative, consider using sampling-based method tracing via
+     * {@link #startMethodTracingSampling(String, int, int)} or "native" tracing
+     * in the emulator via {@link #startNativeTracing()}.
      * </p>
      *
-     * @param traceName    Name for the trace log file to create.
-     * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace".
-     * If the files already exist, they will be truncated.
-     * If the trace file given does not end in ".trace", it will be appended for you.
-     * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
-     * @param flags    Flags to control method tracing. The only one that is currently defined is {@link #TRACE_COUNT_ALLOCS}.
+     * @param tracePath Path to the trace log file to create. If {@code null},
+     *            this will default to "dmtrace.trace". If the file already
+     *            exists, it will be truncated. If the path given does not end
+     *            in ".trace", it will be appended for you.
      */
-    public static void startMethodTracing(String traceName, int bufferSize,
-        int flags) {
-        VMDebug.startMethodTracing(fixTraceName(traceName), bufferSize, flags, false, 0);
+    public static void startMethodTracing(String tracePath) {
+        startMethodTracing(tracePath, 0, 0);
+    }
+
+    /**
+     * Start method tracing, specifying the trace log file name and the buffer
+     * size.
+     * <p>
+     * When a relative file path is given, the trace file will be placed under
+     * your package-specific directory on primary shared/external storage, as
+     * returned by {@link Context#getExternalFilesDir(String)}.
+     * <p>
+     * See <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview:
+     * A Graphical Log Viewer</a> for information about reading trace files.
+     * <p class="note">
+     * When method tracing is enabled, the VM will run more slowly than usual,
+     * so the timings from the trace files should only be considered in relative
+     * terms (e.g. was run #1 faster than run #2). The times for native methods
+     * will not change, so don't try to use this to compare the performance of
+     * interpreted and native implementations of the same method. As an
+     * alternative, consider using sampling-based method tracing via
+     * {@link #startMethodTracingSampling(String, int, int)} or "native" tracing
+     * in the emulator via {@link #startNativeTracing()}.
+     * </p>
+     *
+     * @param tracePath Path to the trace log file to create. If {@code null},
+     *            this will default to "dmtrace.trace". If the file already
+     *            exists, it will be truncated. If the path given does not end
+     *            in ".trace", it will be appended for you.
+     * @param bufferSize The maximum amount of trace data we gather. If not
+     *            given, it defaults to 8MB.
+     */
+    public static void startMethodTracing(String tracePath, int bufferSize) {
+        startMethodTracing(tracePath, bufferSize, 0);
+    }
+
+    /**
+     * Start method tracing, specifying the trace log file name, the buffer
+     * size, and flags.
+     * <p>
+     * When a relative file path is given, the trace file will be placed under
+     * your package-specific directory on primary shared/external storage, as
+     * returned by {@link Context#getExternalFilesDir(String)}.
+     * <p>
+     * See <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview:
+     * A Graphical Log Viewer</a> for information about reading trace files.
+     * <p class="note">
+     * When method tracing is enabled, the VM will run more slowly than usual,
+     * so the timings from the trace files should only be considered in relative
+     * terms (e.g. was run #1 faster than run #2). The times for native methods
+     * will not change, so don't try to use this to compare the performance of
+     * interpreted and native implementations of the same method. As an
+     * alternative, consider using sampling-based method tracing via
+     * {@link #startMethodTracingSampling(String, int, int)} or "native" tracing
+     * in the emulator via {@link #startNativeTracing()}.
+     * </p>
+     *
+     * @param tracePath Path to the trace log file to create. If {@code null},
+     *            this will default to "dmtrace.trace". If the file already
+     *            exists, it will be truncated. If the path given does not end
+     *            in ".trace", it will be appended for you.
+     * @param bufferSize The maximum amount of trace data we gather. If not
+     *            given, it defaults to 8MB.
+     * @param flags Flags to control method tracing. The only one that is
+     *            currently defined is {@link #TRACE_COUNT_ALLOCS}.
+     */
+    public static void startMethodTracing(String tracePath, int bufferSize, int flags) {
+        VMDebug.startMethodTracing(fixTracePath(tracePath), bufferSize, flags, false, 0);
     }
 
     /**
      * Start sampling-based method tracing, specifying the trace log file name,
-     * the buffer size, and the sampling interval. The trace files will be put
-     * under "/sdcard" unless an absolute path is given. See <a
-       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a>
-     * for information about reading trace files.
+     * the buffer size, and the sampling interval.
+     * <p>
+     * When a relative file path is given, the trace file will be placed under
+     * your package-specific directory on primary shared/external storage, as
+     * returned by {@link Context#getExternalFilesDir(String)}.
+     * <p>
+     * See <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview:
+     * A Graphical Log Viewer</a> for information about reading trace files.
      *
-     * @param traceName    Name for the trace log file to create.
-     * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace".
-     * If the files already exist, they will be truncated.
-     * If the trace file given does not end in ".trace", it will be appended for you.
-     * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
-     * @param intervalUs    The amount of time between each sample in microseconds.
+     * @param tracePath Path to the trace log file to create. If {@code null},
+     *            this will default to "dmtrace.trace". If the file already
+     *            exists, it will be truncated. If the path given does not end
+     *            in ".trace", it will be appended for you.
+     * @param bufferSize The maximum amount of trace data we gather. If not
+     *            given, it defaults to 8MB.
+     * @param intervalUs The amount of time between each sample in microseconds.
      */
-    public static void startMethodTracingSampling(String traceName,
-        int bufferSize, int intervalUs) {
-        VMDebug.startMethodTracing(fixTraceName(traceName), bufferSize, 0, true, intervalUs);
+    public static void startMethodTracingSampling(String tracePath, int bufferSize,
+            int intervalUs) {
+        VMDebug.startMethodTracing(fixTracePath(tracePath), bufferSize, 0, true, intervalUs);
     }
-
+    
     /**
      * Formats name of trace log file for method tracing.
      */
-    private static String fixTraceName(String traceName) {
-        if (traceName == null)
-            traceName = NoPreloadHolder.DEFAULT_TRACE_FILE_PATH;
-        if (traceName.charAt(0) != '/')
-            traceName = NoPreloadHolder.DEFAULT_TRACE_PATH_PREFIX + traceName;
-        if (!traceName.endsWith(DEFAULT_TRACE_EXTENSION))
-            traceName = traceName + DEFAULT_TRACE_EXTENSION;
+    private static String fixTracePath(String tracePath) {
+        if (tracePath == null || tracePath.charAt(0) != '/') {
+            final Context context = AppGlobals.getInitialApplication();
+            final File dir;
+            if (context != null) {
+                dir = context.getExternalFilesDir(null);
+            } else {
+                dir = Environment.getExternalStorageDirectory();
+            }
 
-        return traceName;
+            if (tracePath == null) {
+                tracePath = new File(dir, DEFAULT_TRACE_BODY).getAbsolutePath();
+            } else {
+                tracePath = new File(dir, tracePath).getAbsolutePath();
+            }
+        }
+        if (!tracePath.endsWith(DEFAULT_TRACE_EXTENSION)) {
+            tracePath += DEFAULT_TRACE_EXTENSION;
+        }
+        return tracePath;
     }
 
     /**
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index cd84c8f..100f6a1 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -97,12 +97,6 @@
     void setInterfaceIpv6NdOffload(String iface, boolean enable);
 
     /**
-     * Retrieves the network routes currently configured on the specified
-     * interface
-     */
-    RouteInfo[] getRoutes(String iface);
-
-    /**
      * Add the specified route to the interface.
      */
     void addRoute(int netId, in RouteInfo route);
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index bc2566b..c38bf3c 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -76,4 +76,5 @@
     PersistableBundle getSeedAccountOptions();
     void clearSeedAccountData();
     boolean someUserHasSeedAccount(in String accountName, in String accountType);
+    boolean isManagedProfile(int userId);
 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 0ff0154..707d5f5 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -822,8 +822,28 @@
      */
     @SystemApi
     public boolean isManagedProfile() {
-        UserInfo user = getUserInfo(UserHandle.myUserId());
-        return user != null ? user.isManagedProfile() : false;
+        try {
+            return mService.isManagedProfile(UserHandle.myUserId());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Checks if the specified user is a managed profile.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission, otherwise the caller
+     * must be in the same profile group of specified user.
+     *
+     * @return whether the specified user is a managed profile.
+     * @hide
+     */
+    @SystemApi
+    public boolean isManagedProfile(@UserIdInt int userId) {
+        try {
+            return mService.isManagedProfile(userId);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -964,8 +984,7 @@
 
     /**
      * Returns the UserInfo object describing a specific user.
-     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission or the caller is
-     * in the same profile group of target user.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param userHandle the user handle of the user whose information is being requested.
      * @return the UserInfo object for a specific user.
      * @hide
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index ea0597d..4b70649 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -438,6 +438,10 @@
         final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
         intent.setData(uri);
+
+        // note that docsui treats this as *force* show advanced. So sending
+        // false permits advanced to be shown based on user preferences.
+        intent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, isPrimary());
         intent.putExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, true);
         return intent;
     }
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 4ad7969..4412459 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -93,6 +93,9 @@
     public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
 
     /** {@hide} */
+    public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";
+
+    /** {@hide} */
     public static final String EXTRA_SHOW_FILESIZE = "android.content.extra.SHOW_FILESIZE";
 
     /** {@hide} */
@@ -556,13 +559,22 @@
         public static final int FLAG_EMPTY = 1 << 16;
 
         /**
+         * Flag indicating that this root should only be visible to advanced
+         * users.
+         *
+         * @see #COLUMN_FLAGS
+         * @hide
+         */
+        public static final int FLAG_ADVANCED = 1 << 17;
+
+        /**
          * Flag indicating that this root has settings.
          *
          * @see #COLUMN_FLAGS
          * @see DocumentsContract#ACTION_DOCUMENT_ROOT_SETTINGS
          * @hide
          */
-        public static final int FLAG_HAS_SETTINGS = 1 << 17;
+        public static final int FLAG_HAS_SETTINGS = 1 << 18;
 
         /**
          * Flag indicating that this root is on removable SD card storage.
@@ -570,7 +582,7 @@
          * @see #COLUMN_FLAGS
          * @hide
          */
-        public static final int FLAG_REMOVABLE_SD = 1 << 18;
+        public static final int FLAG_REMOVABLE_SD = 1 << 19;
 
         /**
          * Flag indicating that this root is on removable USB storage.
@@ -578,7 +590,7 @@
          * @see #COLUMN_FLAGS
          * @hide
          */
-        public static final int FLAG_REMOVABLE_USB = 1 << 19;
+        public static final int FLAG_REMOVABLE_USB = 1 << 20;
     }
 
     /**
diff --git a/core/java/android/provider/UserDictionary.java b/core/java/android/provider/UserDictionary.java
index a9b106a..c6e58cb 100644
--- a/core/java/android/provider/UserDictionary.java
+++ b/core/java/android/provider/UserDictionary.java
@@ -28,6 +28,9 @@
  * A provider of user defined words for input methods to use for predictive text input.
  * Applications and input methods may add words into the dictionary. Words can have associated
  * frequency information and locale information.
+ *
+ * <p><strong>NOTE: </strong>Starting on API 23, the user dictionary is only accessible through
+ * IME and spellchecker.
  */
 public class UserDictionary {
 
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 880a79c..2364787 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -41,7 +41,6 @@
 extern "C" {
 int ifc_enable(const char *ifname);
 int ifc_disable(const char *ifname);
-int ifc_reset_connections(const char *ifname, int reset_mask);
 }
 
 #define NETUTILS_PKG_NAME "android/net/NetworkUtils"
@@ -50,21 +49,6 @@
 
 static const uint16_t kDhcpClientPort = 68;
 
-static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
-      jstring ifname, jint mask)
-{
-    int result;
-
-    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
-
-    ALOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n",
-          env, clazz, nameStr, mask);
-
-    result = ::ifc_reset_connections(nameStr, mask);
-    env->ReleaseStringUTFChars(ifname, nameStr);
-    return (jint)result;
-}
-
 static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
     uint32_t ip_offset = sizeof(ether_header);
@@ -181,7 +165,6 @@
  */
 static const JNINativeMethod gNetworkUtilMethods[] = {
     /* name, signature, funcPtr */
-    { "resetConnections", "(Ljava/lang/String;I)I",  (void *)android_net_utils_resetConnections },
     { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
     { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
     { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 30607dd..60f05448 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -417,6 +417,7 @@
     <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
     <protected-broadcast android:name="android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.storage.action.VOLUME_STATE_CHANGED" />
+    <protected-broadcast android:name="android.os.storage.action.DISK_SCANNED" />
     <protected-broadcast android:name="com.android.server.action.UPDATE_TWILIGHT_STATE" />
     <protected-broadcast android:name="com.android.server.device_idle.STEP_IDLE_STATE" />
     <protected-broadcast android:name="com.android.server.device_idle.STEP_LIGHT_IDLE_STATE" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ba9bcaa..74ce753 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3368,8 +3368,8 @@
          tapping/clicking the whole thing is going to do. -->
     <string name="action_bar_home_subtitle_description_format">%1$s, %2$s, %3$s</string>
 
-    <!-- Storage description for internal storage. [CHAR LIMIT=NONE] -->
-    <string name="storage_internal">Internal storage</string>
+    <!-- Storage description for internal shared storage. [CHAR LIMIT=NONE] -->
+    <string name="storage_internal">Internal shared storage</string>
 
     <!-- Storage description for a generic SD card. [CHAR LIMIT=NONE] -->
     <string name="storage_sd_card">SD card</string>
diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd
index 46db371..0d3bb4d 100644
--- a/docs/html/guide/topics/data/data-storage.jd
+++ b/docs/html/guide/topics/data/data-storage.jd
@@ -178,6 +178,19 @@
 android.content.Context#MODE_WORLD_READABLE}, and {@link
 android.content.Context#MODE_WORLD_WRITEABLE}.</p>
 
+<p class="note"><strong>Note:</strong> The constants {@link
+android.content.Context#MODE_WORLD_READABLE} and {@link
+android.content.Context#MODE_WORLD_WRITEABLE} have been deprecated since API level 17. Since
+API level 24 their use will result in a {@link java.lang.SecurityException} to be thrown.
+This means that apps targeting API level 24 and higher
+cannot share private files by name, and attempts to share a "file://" URI will result in a
+{@link android.os.FileUriExposedException} to be thrown. If your app needs to share private
+files with other apps, it may use a {@link android.support.v4.content.FileProvider} with
+the {@link android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION}.
+See also <a
+href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a>.
+</p>
+
 <p>To read a file from internal storage:</p>
 
 <ol>
diff --git a/docs/html/training/basics/data-storage/files.jd b/docs/html/training/basics/data-storage/files.jd
index 49a9169..983d59a 100644
--- a/docs/html/training/basics/data-storage/files.jd
+++ b/docs/html/training/basics/data-storage/files.jd
@@ -59,7 +59,7 @@
 <p><b>Internal storage:</b></p>
 <ul>
 <li>It's always available.</li>
-<li>Files saved here are accessible by only your app by default.</li>
+<li>Files saved here are accessible by only your app.</li>
 <li>When the user uninstalls your app, the system removes all your app's files from
 internal storage.</li>
 </ul>
@@ -83,6 +83,12 @@
 with other apps or allow the user to access with a computer.</p>
 </div>
 
+<p class="note">
+<strong>Note:</strong> Before API level 24, internal files could be made accessible to other
+apps by means of relaxing file system permissions. This is no longer the case. If you wish
+to make the content of a private file accessible to other apps, your app may use the
+{@link android.support.v4.content.FileProvider}. See <a
+href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a>.</p>
 
 <p class="note" style="clear:both">
 <strong>Tip:</strong> Although apps are installed onto the internal storage by
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index ed358d3..dbedf34 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -830,7 +830,9 @@
         } catch (IOException e) {
             // Ignore exceptions in order to keep the compatibility with the old versions of
             // ExifInterface.
-            Log.w(TAG, "Invalid JPEG", e);
+            Log.w(TAG, "Invalid JPEG: ExifInterface got an unsupported image format file"
+                    + "(ExifInterface supports JPEG and some RAW image formats only) "
+                    + "or a corrupted JPEG file to ExifInterface.", e);
         }
 
         if (DEBUG) {
@@ -1189,6 +1191,10 @@
         ++bytesRead;
         while (true) {
             marker = dataInputStream.readByte();
+            if (marker == -1) {
+                Log.w(TAG, "Reading JPEG has ended unexpectedly");
+                break;
+            }
             if (marker != MARKER) {
                 throw new IOException("Invalid marker:" + Integer.toHexString(marker & 0xff));
             }
@@ -1207,7 +1213,8 @@
             int length = dataInputStream.readUnsignedShort() - 2;
             bytesRead += 2;
             if (DEBUG) {
-                Log.d(TAG, "JPEG segment: " + marker + " (length: " + (length + 2) + ")");
+                Log.d(TAG, "JPEG segment: " + Integer.toHexString(marker & 0xff) + " (length: "
+                        + (length + 2) + ")");
             }
             if (length < 0) {
                 throw new IOException("Invalid length");
@@ -1270,7 +1277,9 @@
                 case MARKER_SOF13:
                 case MARKER_SOF14:
                 case MARKER_SOF15: {
-                    dataInputStream.skipBytes(1);
+                    if (dataInputStream.skipBytes(1) != 1) {
+                        throw new IOException("Invalid SOFx");
+                    }
                     setAttribute("ImageLength",
                             String.valueOf(dataInputStream.readUnsignedShort()));
                     setAttribute("ImageWidth", String.valueOf(dataInputStream.readUnsignedShort()));
@@ -1285,7 +1294,9 @@
             if (length < 0) {
                 throw new IOException("Invalid length");
             }
-            dataInputStream.skipBytes(length);
+            if (dataInputStream.skipBytes(length) != length) {
+                throw new IOException("Invalid JPEG segment");
+            }
             bytesRead += length;
         }
     }
@@ -1317,10 +1328,15 @@
         byte[] bytes = new byte[4096];
 
         while (true) {
-            if (dataInputStream.readByte() != MARKER) {
+            byte marker = dataInputStream.readByte();
+            if (marker == -1) {
+                Log.w(TAG, "Reading JPEG has ended unexpectedly");
+                break;
+            }
+            if (marker != MARKER) {
                 throw new IOException("Invalid marker");
             }
-            byte marker = dataInputStream.readByte();
+            marker = dataInputStream.readByte();
             switch (marker) {
                 case MARKER_APP1: {
                     int length = dataInputStream.readUnsignedShort() - 2;
@@ -1644,7 +1660,7 @@
             String tagName = (String) sExifTagMapsForReading[hint].get(tagNumber);
 
             if (DEBUG) {
-                Log.d(TAG, String.format("hint: %d, tagNumber: %d, tagName: %s, dataFormat: %d," +
+                Log.d(TAG, String.format("hint: %d, tagNumber: %d, tagName: %s, dataFormat: %d, " +
                         "numberOfComponents: %d", hint, tagNumber, tagName, dataFormat,
                         numberOfComponents));
             }
@@ -2025,6 +2041,12 @@
         int bytesWritten = 0;
         int dataFormat = getDataFormatOfExifEntryValue(entryValue);
 
+        if (dataFormat == IFD_FORMAT_STRING) {
+            byte[] asciiArray = (entryValue + '\0').getBytes(Charset.forName("US-ASCII"));
+            dataOutputStream.write(asciiArray);
+            return asciiArray.length;
+        }
+
         // Values can be composed of several components. Each component is separated by char ','.
         String[] components = entryValue.split(",");
         for (String component : components) {
@@ -2037,11 +2059,6 @@
                     dataOutputStream.writeDouble(Double.parseDouble(component));
                     bytesWritten += 8;
                     break;
-                case IFD_FORMAT_STRING:
-                    byte[] asciiArray = (component + '\0').getBytes(Charset.forName("US-ASCII"));
-                    dataOutputStream.write(asciiArray);
-                    bytesWritten += asciiArray.length;
-                    break;
                 case IFD_FORMAT_SRATIONAL:
                     String[] rationalNumber = component.split("/");
                     dataOutputStream.writeInt(Integer.parseInt(rationalNumber[0]));
@@ -2060,11 +2077,31 @@
         // See TIFF 6.0 spec Types. page 15.
         // Take the first component if there are more than one component.
         if (entryValue.contains(",")) {
-            entryValue = entryValue.split(",")[0];
+            String[] entryValues = entryValue.split(",");
+            int dataFormat = getDataFormatOfExifEntryValue(entryValues[0]);
+            if (dataFormat == IFD_FORMAT_STRING) {
+                return IFD_FORMAT_STRING;
+            }
+            for (int i = 1; i < entryValues.length; ++i) {
+                if (getDataFormatOfExifEntryValue(entryValues[i]) != dataFormat) {
+                    return IFD_FORMAT_STRING;
+                }
+            }
+            return dataFormat;
         }
 
         if (entryValue.contains("/")) {
-            return IFD_FORMAT_SRATIONAL;
+            String[] rationalNumber = entryValue.split("/");
+            if (rationalNumber.length == 2) {
+                try {
+                    Integer.parseInt(rationalNumber[0]);
+                    Integer.parseInt(rationalNumber[1]);
+                    return IFD_FORMAT_SRATIONAL;
+                } catch (NumberFormatException e)  {
+                    // Ignored
+                }
+            }
+            return IFD_FORMAT_STRING;
         }
         try {
             Integer.parseInt(entryValue);
@@ -2084,6 +2121,9 @@
     // Determines the size of EXIF entry value.
     private static int getSizeOfExifEntryValue(int dataFormat, String entryValue) {
         // See TIFF 6.0 spec Types page 15.
+        if (dataFormat == IFD_FORMAT_STRING) {
+            return (entryValue + '\0').getBytes(Charset.forName("US-ASCII")).length;
+        }
         int bytesEstimated = 0;
         String[] components = entryValue.split(",");
         for (String component : components) {
@@ -2094,10 +2134,6 @@
                 case IFD_FORMAT_DOUBLE:
                     bytesEstimated += 8;
                     break;
-                case IFD_FORMAT_STRING:
-                    bytesEstimated
-                            += (component + '\0').getBytes(Charset.forName("US-ASCII")).length;
-                    break;
                 case IFD_FORMAT_SRATIONAL:
                     bytesEstimated += 8;
                     break;
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index d5e48b5..3197abd 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -31,9 +31,13 @@
   --extra-packages android.support.v7.recyclerview
 
 LOCAL_JACK_FLAGS := \
-  -D jack.assert.policy=enable \
   -D jack.optimization.inner-class.accessors=true
 
+# Only enable asserts on userdebug/eng builds
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+LOCAL_JACK_FLAGS += -D jack.assert.policy=enable
+endif
+
 LOCAL_PACKAGE_NAME := DocumentsUI
 LOCAL_CERTIFICATE := platform
 
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_launcher_download.png b/packages/DocumentsUI/res/drawable-hdpi/ic_launcher_download.png
new file mode 100644
index 0000000..f958bbd
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_launcher_download.png b/packages/DocumentsUI/res/drawable-mdpi/ic_launcher_download.png
new file mode 100644
index 0000000..f2e9376
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_launcher_download.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_launcher_download.png
new file mode 100644
index 0000000..4dc5336
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_launcher_download.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_launcher_download.png
new file mode 100644
index 0000000..8716290
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_launcher_download.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_launcher_download.png
new file mode 100644
index 0000000..f5be219
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/ic_files_app.xml b/packages/DocumentsUI/res/drawable/ic_files_app.xml
index ff7189e..76e3ba6 100644
--- a/packages/DocumentsUI/res/drawable/ic_files_app.xml
+++ b/packages/DocumentsUI/res/drawable/ic_files_app.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/icon256"
+    android:src="@drawable/ic_launcher_download"
     android:tint="?android:attr/colorControlNormal"
     android:autoMirrored="true" />
diff --git a/packages/DocumentsUI/res/drawable/icon256.png b/packages/DocumentsUI/res/drawable/icon256.png
deleted file mode 100644
index 631c951..0000000
--- a/packages/DocumentsUI/res/drawable/icon256.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index ebb3969..408603e 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -24,5 +24,6 @@
     <!-- Indicates if the home directory should be hidden in the roots list, that is presented
          in the drawer/left side panel ) -->
     <bool name="home_root_hidden">true</bool>
-
+    <!-- Indicates if the advanced roots like internal storage should be hidden in the roots list) -->
+    <bool name="advanced_roots_hidden">true</bool>
 </resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index a548d89..b16554c 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -36,6 +36,8 @@
         <item name="android:windowActionBar">false</item>
         <item name="android:windowActionModeOverlay">true</item>
         <item name="android:windowNoTitle">true</item>
+        <item name="android:windowTranslucentStatus">true</item>
+        <item name="android:fitsSystemWindows">false</item>
 
         <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
     </style>
@@ -43,7 +45,7 @@
     <style name="TrimmedHorizontalProgressBar" parent="android:Widget.Material.ProgressBar.Horizontal">
         <item name="android:indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material_trimmed</item>
         <item name="android:minHeight">3dp</item>
-        <item name="android:maxHeight">3dp</item>    
+        <item name="android:maxHeight">3dp</item>
     </style>
 
 </resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index fe61094..3b300d0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -127,6 +127,7 @@
         mSearchManager = new SearchViewManager(this, icicle);
 
         DocumentsToolbar toolbar = (DocumentsToolbar) findViewById(R.id.toolbar);
+        Display.adjustToolbar(toolbar, this);
         setActionBar(toolbar);
         mNavigator = new NavigationView(
                 mDrawer,
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Display.java b/packages/DocumentsUI/src/com/android/documentsui/Display.java
index bae2d58..d46a3ea 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Display.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Display.java
@@ -20,13 +20,15 @@
 import android.content.Context;
 import android.graphics.Point;
 import android.util.TypedValue;
+import android.view.WindowManager;
+import android.widget.Toolbar;
 
 /*
  * Convenience class for getting display related attributes
  */
 public final class Display {
     /*
-     * Returns the screen width in pixels.
+     * Returns the screen width in raw pixels.
      */
     public static float screenWidth(Activity activity) {
         Point size = new Point();
@@ -42,15 +44,44 @@
     }
 
     /*
-     * Returns action bar height in pixels.
+     * Returns action bar height in raw pixels.
      */
     public static float actionBarHeight(Context context) {
-        int actionBarHeight = 0;
+        int height = 0;
         TypedValue tv = new TypedValue();
         if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
-            actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,
+            height = TypedValue.complexToDimensionPixelSize(tv.data,
                     context.getResources().getDisplayMetrics());
         }
-        return actionBarHeight;
+        return height;
+    }
+
+    /*
+     * Returns status bar height in raw pixels.
+     */
+    private static int statusBarHeight(Context context) {
+        int height = 0;
+        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen",
+                "android");
+        if (resourceId > 0) {
+            height = context.getResources().getDimensionPixelSize(resourceId);
+        }
+        return height;
+    }
+
+    /*
+     * Adjusts toolbar for the layout with translucent status bar. Increases the
+     * height of the toolbar and adds padding at the top to accommodate status bar visible above
+     * toolbar.
+     */
+    public static void adjustToolbar(Toolbar toolbar, Activity activity) {
+        if ((activity.getWindow().getAttributes().flags
+                & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
+            int statusBarHeight = Display.statusBarHeight(activity);
+            toolbar.getLayoutParams().height = (int) (Display.actionBarHeight(activity)
+                    + statusBarHeight);
+            toolbar.setPadding(toolbar.getPaddingLeft(), statusBarHeight, toolbar.getPaddingRight(),
+                    toolbar.getPaddingBottom());
+        }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index da75103..770e35d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -95,7 +95,7 @@
         }
 
         if (mState.restored) {
-            if (DEBUG) Log.d(TAG, "Stack already resolved");
+            refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
         } else {
             // We set the activity title in AsyncTask.onPostExecute().
             // To prevent talkback from reading aloud the default title, we clear it here.
@@ -108,7 +108,9 @@
             // we restore the stack as last used from that app.
             if (mState.action == ACTION_PICK_COPY_DESTINATION) {
                 if (DEBUG) Log.d(TAG, "Launching directly into Home directory.");
-                loadRoot(DocumentsContract.buildHomeUri());
+                Uri homeUri = DocumentsContract.buildHomeUri();
+                new LoadRootTask(this, homeUri).executeOnExecutor(
+                        ProviderExecutor.forAuthority(homeUri.getAuthority()));
             } else {
                 if (DEBUG) Log.d(TAG, "Attempting to load last used stack for calling package.");
                 new LoadLastUsedStackTask(this).execute();
@@ -154,6 +156,30 @@
         }
     }
 
+    private void onStackRestored(boolean restored, boolean external) {
+        // Show drawer when no stack restored, but only when requesting
+        // non-visual content. However, if we last used an external app,
+        // drawer is always shown.
+
+        boolean showDrawer = false;
+        if (!restored) {
+            showDrawer = true;
+        }
+        if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
+            showDrawer = false;
+        }
+        if (external && mState.action == ACTION_GET_CONTENT) {
+            showDrawer = true;
+        }
+        if (mState.action == ACTION_PICK_COPY_DESTINATION) {
+            showDrawer = true;
+        }
+
+        if (showDrawer) {
+            mNavigator.revealRootsDrawer(true);
+        }
+    }
+
     public void onAppPicked(ResolveInfo info) {
         final Intent intent = new Intent(getIntent());
         intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
@@ -491,8 +517,8 @@
         @Override
         protected void finish(Void result) {
             mState.restored = true;
-            mState.external = mExternal;
             mOwner.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
+            mOwner.onStackRestored(mRestoredStack, mExternal);
         }
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
index 020f2c0..2dbb730 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
@@ -55,7 +55,7 @@
 
         View drawer = activity.findViewById(R.id.drawer_roots);
         Toolbar toolbar = (Toolbar) activity.findViewById(R.id.roots_toolbar);
-
+        Display.adjustToolbar(toolbar, activity);
         drawer.getLayoutParams().width = calculateDrawerWidth(activity);
 
         ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 54e6287..1864431 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -320,6 +320,8 @@
 
                 if (root.isHome() && isHomeRootHidden(context)) {
                     continue;
+                } else if (root.isAdvanced() && areAdvancedRootsHidden(context)) {
+                    continue;
                 } else if (root.isLibrary()) {
                     if (DEBUG) Log.d(TAG, "Adding " + root + " as library.");
                     libraries.add(item);
@@ -377,6 +379,13 @@
             return context.getResources().getBoolean(R.bool.home_root_hidden);
         }
 
+        /*
+         * Indicates if the advanced roots should be hidden.
+         */
+        private boolean areAdvancedRootsHidden(Context context) {
+            return context.getResources().getBoolean(R.bool.advanced_roots_hidden);
+        }
+
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             final Item item = getItem(position);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index 16b7660..43468e3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -85,10 +85,6 @@
     public boolean showSize;
     public boolean localOnly;
     public boolean restored;
-    /*
-     * Indicates handler was an external app, like photos.
-     */
-    public boolean external;
 
     // Indicates that a copy operation (or move) includes a directory.
     // Why? Directory creation isn't supported by some roots (like Downloads).
@@ -186,7 +182,6 @@
         out.writeInt(showSize ? 1 : 0);
         out.writeInt(localOnly ? 1 : 0);
         out.writeInt(restored ? 1 : 0);
-        out.writeInt(external ? 1 : 0);
         DurableUtils.writeToParcel(out, stack);
         out.writeMap(dirState);
         out.writeParcelable(selectedDocuments, 0);
@@ -215,7 +210,6 @@
             state.showSize = in.readInt() != 0;
             state.localOnly = in.readInt() != 0;
             state.restored = in.readInt() != 0;
-            state.external = in.readInt() != 0;
             DurableUtils.readFromParcel(in, state.stack);
             in.readMap(state.dirState, loader);
             state.selectedDocuments = in.readParcelable(loader);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 60e4b9a..0810d194 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -506,8 +506,10 @@
             getActivity().getWindow().setStatusBarColor(color.data);
 
             if (mActionMode != null) {
-                mActionMode.setTitle(Shared.getQuantityString(getActivity(),
-                        R.plurals.elements_selected, mSelected.size()));
+                final String title = Shared.getQuantityString(getActivity(),
+                        R.plurals.elements_selected, mSelected.size());
+                mActionMode.setTitle(title);
+                mRecView.announceForAccessibility(title);
             }
         }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index ea1deb4..06cb9aa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -157,27 +157,8 @@
 
         @Override
         void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
-            boolean showDrawer = false;
-
-            if (mState.restored) {
-                showDrawer = true;
-            }
-            if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
-                showDrawer = false;
-            }
-            if (mState.external && mState.action == ACTION_GET_CONTENT) {
-                showDrawer = true;
-            }
-            if (mState.action == ACTION_PICK_COPY_DESTINATION) {
-                showDrawer = true;
-            }
-
             // When launched into empty root, open drawer.
-            if (model.isEmpty()) {
-                showDrawer = true;
-            }
-
-            if (showDrawer && !mState.hasInitialLocationChanged() && !isSearch) {
+            if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch) {
                 // This noops on layouts without drawer, so no need to guard.
                 ((BaseActivity) mContext).setRootsDrawerOpen(true);
             }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 3960475..0709652 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -298,6 +298,10 @@
         return (flags & Root.FLAG_SUPPORTS_SEARCH) != 0;
     }
 
+    public boolean isAdvanced() {
+        return (flags & Root.FLAG_ADVANCED) != 0;
+    }
+
     public boolean isLocalOnly() {
         return (flags & Root.FLAG_LOCAL_ONLY) != 0;
     }
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 9a51b05..62f33bf 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -196,6 +196,7 @@
             if (volume.isPrimary()) {
                 // save off the primary volume for subsequent "Home" dir initialization.
                 primaryVolume = volume;
+                root.flags |= Root.FLAG_ADVANCED;
             }
             // Dunno when this would NOT be the case, but never hurts to be correct.
             if (volume.isMountedWritable()) {
diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk
index b31b0b1..0f945ee 100644
--- a/packages/MtpDocumentsProvider/Android.mk
+++ b/packages/MtpDocumentsProvider/Android.mk
@@ -9,5 +9,10 @@
 LOCAL_JNI_SHARED_LIBRARIES := libappfuse_jni
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
+# Only enable asserts on userdebug/eng builds
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+LOCAL_JACK_FLAGS += -D jack.assert.policy=enable
+endif
+
 include $(BUILD_PACKAGE)
 include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index 0705214..68f426f 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -69,7 +69,8 @@
      */
     synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
             throws IOException {
-        Preconditions.checkArgument(parent.mDeviceId == mDevice.deviceId);
+        assert parent.mDeviceId == mDevice.deviceId;
+
         LoaderTask task = mTaskList.findTask(parent);
         if (task == null) {
             if (parent.mDocumentId == null) {
@@ -81,11 +82,9 @@
             // 3. startAddingChildDocuemnts.
             // 4. stopAddingChildDocuments - It removes the new document added at the step 2,
             //     because it is not updated between start/stopAddingChildDocuments.
-            task = LoaderTask.create(mDatabase, mMtpManager, mDevice.operationsSupported, parent);
-            task.fillDocuments(loadDocuments(
-                    mMtpManager,
-                    parent.mDeviceId,
-                    task.getUnloadedObjectHandles(NUM_INITIAL_ENTRIES)));
+            task = new LoaderTask(mMtpManager, mDatabase, mDevice.operationsSupported, parent);
+            task.loadObjectHandles();
+            task.loadObjectInfoList(NUM_INITIAL_ENTRIES);
         } else {
             // Once remove the existing task in order to add it to the head of the list.
             mTaskList.remove(task);
@@ -130,15 +129,11 @@
                 Preconditions.checkState(existingTask.getState() != LoaderTask.STATE_LOADING);
                 mTaskList.remove(existingTask);
             }
-            try {
-                final LoaderTask newTask = LoaderTask.create(
-                        mDatabase, mMtpManager, mDevice.operationsSupported, identifier);
-                mTaskList.addFirst(newTask);
-                return newTask;
-            } catch (IOException exception) {
-                Log.e(MtpDocumentsProvider.TAG, "Failed to create a task for mapping", exception);
-                // Continue to release the background thread.
-            }
+            final LoaderTask newTask = new LoaderTask(
+                    mMtpManager, mDatabase, mDevice.operationsSupported, identifier);
+            newTask.loadObjectHandles();
+            mTaskList.addFirst(newTask);
+            return newTask;
         }
 
         mBackgroundThread = null;
@@ -170,24 +165,6 @@
     }
 
     /**
-     * Helper method to loads multiple object info.
-     */
-    private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
-            throws IOException {
-        final ArrayList<MtpObjectInfo> objects = new ArrayList<>();
-        for (int i = 0; i < handles.length; i++) {
-            final MtpObjectInfo info = manager.getObjectInfo(deviceId, handles[i]);
-            if (info == null) {
-                Log.e(MtpDocumentsProvider.TAG,
-                        "Failed to obtain object info handle=" + handles[i]);
-                continue;
-            }
-            objects.add(info);
-        }
-        return objects.toArray(new MtpObjectInfo[objects.size()]);
-    }
-
-    /**
      * Background thread to fetch object info.
      */
     private class BackgroundLoaderThread extends Thread {
@@ -203,21 +180,13 @@
                 if (task == null) {
                     return;
                 }
-                try {
-                    final MtpObjectInfo[] objectInfos = loadDocuments(
-                            mMtpManager,
-                            task.mIdentifier.mDeviceId,
-                            task.getUnloadedObjectHandles(NUM_LOADING_ENTRIES));
-                    task.fillDocuments(objectInfos);
-                    final boolean shouldNotify =
-                            task.mLastNotified.getTime() <
-                            new Date().getTime() - NOTIFY_PERIOD_MS ||
-                            task.getState() != LoaderTask.STATE_LOADING;
-                    if (shouldNotify) {
-                        task.notify(mResolver);
-                    }
-                } catch (IOException exception) {
-                    task.setError(exception);
+                task.loadObjectInfoList(NUM_LOADING_ENTRIES);
+                final boolean shouldNotify =
+                        task.mLastNotified.getTime() <
+                        new Date().getTime() - NOTIFY_PERIOD_MS ||
+                        task.getState() != LoaderTask.STATE_LOADING;
+                if (shouldNotify) {
+                    task.notify(mResolver);
                 }
             }
         }
@@ -271,43 +240,67 @@
      * Each task is responsible for fetching child documents for the given parent document.
      */
     private static class LoaderTask {
-        static final int STATE_LOADING = 0;
-        static final int STATE_COMPLETED = 1;
-        static final int STATE_ERROR = 2;
+        static final int STATE_START = 0;
+        static final int STATE_LOADING = 1;
+        static final int STATE_COMPLETED = 2;
+        static final int STATE_ERROR = 3;
 
+        final MtpManager mManager;
         final MtpDatabase mDatabase;
         final int[] mOperationsSupported;
         final Identifier mIdentifier;
-        final int[] mObjectHandles;
+        int[] mObjectHandles;
+        int mState;
         Date mLastNotified;
-        int mNumLoaded;
-        Exception mError;
+        int mPosition;
+        IOException mError;
 
-        LoaderTask(MtpDatabase database, int[] operationsSupported, Identifier identifier,
-                int[] objectHandles) {
-            Preconditions.checkNotNull(operationsSupported);
-            Preconditions.checkNotNull(objectHandles);
+        LoaderTask(MtpManager manager, MtpDatabase database, int[] operationsSupported,
+                Identifier identifier) {
+            assert operationsSupported != null;
+            assert identifier.mDocumentType != MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE;
+            mManager = manager;
             mDatabase = database;
             mOperationsSupported = operationsSupported;
             mIdentifier = identifier;
-            mObjectHandles = objectHandles;
-            mNumLoaded = 0;
+            mObjectHandles = null;
+            mState = STATE_START;
+            mPosition = 0;
             mLastNotified = new Date();
         }
 
+        synchronized void loadObjectHandles() {
+            assert mState == STATE_START;
+            int parentHandle = mIdentifier.mObjectHandle;
+            // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
+            // getObjectHandles if we would like to obtain children under the root.
+            if (mIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE) {
+                parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
+            }
+            try {
+                mObjectHandles = mManager.getObjectHandles(
+                        mIdentifier.mDeviceId, mIdentifier.mStorageId, parentHandle);
+                mState = STATE_LOADING;
+            } catch (IOException error) {
+                mError = error;
+                mState = STATE_ERROR;
+            }
+        }
+
         /**
          * Returns a cursor that traverses the child document of the parent document handled by the
          * task.
          * The returned task may have a EXTRA_LOADING flag.
          */
-        Cursor createCursor(ContentResolver resolver, String[] columnNames) throws IOException {
+        synchronized Cursor createCursor(ContentResolver resolver, String[] columnNames)
+                throws IOException {
             final Bundle extras = new Bundle();
             switch (getState()) {
                 case STATE_LOADING:
                     extras.putBoolean(DocumentsContract.EXTRA_LOADING, true);
                     break;
                 case STATE_ERROR:
-                    throw new IOException(mError);
+                    throw mError;
             }
 
             final Cursor cursor =
@@ -319,26 +312,67 @@
         }
 
         /**
-         * Returns a state of the task.
+         * Stores object information into database.
          */
-        int getState() {
-            if (mError != null) {
-                return STATE_ERROR;
-            } else if (mNumLoaded == mObjectHandles.length) {
-                return STATE_COMPLETED;
-            } else {
-                return STATE_LOADING;
+        void loadObjectInfoList(int count) {
+            synchronized (this) {
+                if (mState != STATE_LOADING) {
+                    return;
+                }
+                if (mPosition == 0) {
+                    try{
+                        mDatabase.getMapper().startAddingDocuments(mIdentifier.mDocumentId);
+                    } catch (FileNotFoundException error) {
+                        mError = error;
+                        mState = STATE_ERROR;
+                        return;
+                    }
+                }
+            }
+            final ArrayList<MtpObjectInfo> infoList = new ArrayList<>();
+            for (int chunkEnd = mPosition + count;
+                    mPosition < mObjectHandles.length && mPosition < chunkEnd;
+                    mPosition++) {
+                try {
+                    infoList.add(mManager.getObjectInfo(
+                            mIdentifier.mDeviceId, mObjectHandles[mPosition]));
+                } catch (IOException error) {
+                    Log.e(MtpDocumentsProvider.TAG, "Failed to load object info", error);
+                }
+            }
+            synchronized (this) {
+                try {
+                    mDatabase.getMapper().putChildDocuments(
+                            mIdentifier.mDeviceId,
+                            mIdentifier.mDocumentId,
+                            mOperationsSupported,
+                            infoList.toArray(new MtpObjectInfo[infoList.size()]));
+                } catch (FileNotFoundException error) {
+                    // Looks like the parent document information is removed.
+                    // Adding documents has already cancelled in Mapper so we don't need to invoke
+                    // stopAddingDocuments.
+                    mError = error;
+                    mState = STATE_ERROR;
+                    return;
+                }
+                if (mPosition >= mObjectHandles.length) {
+                    try{
+                        mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
+                        mState = STATE_COMPLETED;
+                    } catch (FileNotFoundException error) {
+                        mError = error;
+                        mState = STATE_ERROR;
+                        return;
+                    }
+                }
             }
         }
 
         /**
-         * Obtains object handles that have not been loaded yet.
+         * Returns a state of the task.
          */
-        int[] getUnloadedObjectHandles(int count) {
-            return Arrays.copyOfRange(
-                    mObjectHandles,
-                    mNumLoaded,
-                    Math.min(mNumLoaded + count, mObjectHandles.length));
+        int getState() {
+            return mState;
         }
 
         /**
@@ -349,69 +383,9 @@
             mLastNotified = new Date();
         }
 
-        /**
-         * Stores object information into database.
-         */
-        void fillDocuments(MtpObjectInfo[] objectInfoList) {
-            if (objectInfoList.length == 0 || getState() != STATE_LOADING) {
-                return;
-            }
-            try{
-                if (mNumLoaded == 0) {
-                    mDatabase.getMapper().startAddingDocuments(mIdentifier.mDocumentId);
-                }
-                mDatabase.getMapper().putChildDocuments(
-                        mIdentifier.mDeviceId, mIdentifier.mDocumentId, mOperationsSupported,
-                        objectInfoList);
-                mNumLoaded += objectInfoList.length;
-                if (getState() != STATE_LOADING) {
-                    mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
-                }
-            } catch (FileNotFoundException exception) {
-                setErrorInternal(exception);
-            }
-        }
-
-        /**
-         * Marks the loading task as error.
-         */
-        void setError(Exception error) {
-            final int lastState = getState();
-            setErrorInternal(error);
-            if (lastState == STATE_LOADING) {
-                try {
-                    mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
-                } catch (FileNotFoundException exception) {
-                    setErrorInternal(exception);
-                }
-            }
-        }
-
-        private void setErrorInternal(Exception error) {
-            Log.e(MtpDocumentsProvider.TAG, "Error in DocumentLoader thread", error);
-            mError = error;
-            mNumLoaded = 0;
-        }
-
         private Uri createUri() {
             return DocumentsContract.buildChildDocumentsUri(
                     MtpDocumentsProvider.AUTHORITY, mIdentifier.mDocumentId);
         }
-
-        /**
-         * Creates a LoaderTask that loads children of the given document.
-         */
-        static LoaderTask create(MtpDatabase database, MtpManager manager,
-                int[] operationsSupported, Identifier parent)
-                throws IOException {
-            int parentHandle = parent.mObjectHandle;
-            // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
-            // getObjectHandles if we would like to obtain children under the root.
-            if (parent.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE) {
-                parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
-            }
-            return new LoaderTask(database, operationsSupported, parent, manager.getObjectHandles(
-                    parent.mDeviceId, parent.mStorageId, parentHandle));
-        }
     }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 8c73211..4564018 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -617,6 +617,7 @@
         final String whereClosure =
                 "parent." + COLUMN_DEVICE_ID + " = ? AND " +
                 "parent." + COLUMN_ROW_STATE + " IN (?, ?) AND " +
+                "parent." + COLUMN_DOCUMENT_TYPE + " != ? AND " +
                 "child." + COLUMN_ROW_STATE + " = ?";
         try (final Cursor cursor = mDatabase.query(
                 fromClosure,
@@ -626,7 +627,7 @@
                         "parent." + Document.COLUMN_DOCUMENT_ID,
                         "parent." + COLUMN_DOCUMENT_TYPE),
                 whereClosure,
-                strings(deviceId, ROW_STATE_VALID, ROW_STATE_INVALIDATED,
+                strings(deviceId, ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_DEVICE,
                         ROW_STATE_DISCONNECTED),
                 null,
                 null,
@@ -750,7 +751,12 @@
         values.putNull(Document.COLUMN_SUMMARY);
         values.putNull(Document.COLUMN_LAST_MODIFIED);
         values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp);
-        values.put(Document.COLUMN_FLAGS, 0);
+        values.put(Document.COLUMN_FLAGS, getDocumentFlags(
+                device.operationsSupported,
+                Document.MIME_TYPE_DIR,
+                0,
+                MtpConstants.PROTECTION_STATUS_NONE,
+                DOCUMENT_TYPE_DEVICE));
         values.putNull(Document.COLUMN_SIZE);
 
         extraValues.clear();
@@ -765,7 +771,7 @@
      * @param values {@link ContentValues} that receives values.
      * @param extraValues {@link ContentValues} that receives extra values for roots.
      * @param parentDocumentId Parent document ID.
-     * @param supportedOperations Array of Operation code supported by the device.
+     * @param operationsSupported Array of Operation code supported by the device.
      * @param root Root to be converted {@link ContentValues}.
      */
     static void getStorageDocumentValues(
@@ -786,7 +792,12 @@
         values.putNull(Document.COLUMN_SUMMARY);
         values.putNull(Document.COLUMN_LAST_MODIFIED);
         values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp);
-        values.put(Document.COLUMN_FLAGS, 0);
+        values.put(Document.COLUMN_FLAGS, getDocumentFlags(
+                operationsSupported,
+                Document.MIME_TYPE_DIR,
+                0,
+                MtpConstants.PROTECTION_STATUS_NONE,
+                DOCUMENT_TYPE_STORAGE));
         values.put(Document.COLUMN_SIZE, root.mMaxCapacity - root.mFreeSpace);
 
         extraValues.put(Root.COLUMN_FLAGS, getRootFlags(operationsSupported));
@@ -803,8 +814,8 @@
      * @param info MTP object info.
      */
     static void getObjectDocumentValues(
-            ContentValues values, int deviceId, String parentId, int[] operationsSupported,
-            MtpObjectInfo info) {
+            ContentValues values, int deviceId, String parentId,
+            int[] operationsSupported, MtpObjectInfo info) {
         values.clear();
         final String mimeType = getMimeType(info);
         values.put(COLUMN_DEVICE_ID, deviceId);
@@ -822,7 +833,7 @@
         values.putNull(Document.COLUMN_ICON);
         values.put(Document.COLUMN_FLAGS, getDocumentFlags(
                 operationsSupported, mimeType, info.getThumbCompressedSizeLong(),
-                info.getProtectionStatus()));
+                info.getProtectionStatus(), DOCUMENT_TYPE_OBJECT));
         values.put(Document.COLUMN_SIZE, info.getCompressedSizeLong());
     }
 
@@ -861,16 +872,19 @@
     }
 
     private static int getDocumentFlags(
-            int[] operationsSupported, String mimeType, long thumbnailSize, int protectionState) {
+            @Nullable int[] operationsSupported, String mimeType, long thumbnailSize,
+            int protectionState, @DocumentType int documentType) {
         int flag = 0;
-        if (MtpDeviceRecord.isWritingSupported(operationsSupported) &&
+        if (!mimeType.equals(Document.MIME_TYPE_DIR) &&
+                MtpDeviceRecord.isWritingSupported(operationsSupported) &&
                 protectionState == MtpConstants.PROTECTION_STATUS_NONE) {
             flag |= Document.FLAG_SUPPORTS_WRITE;
         }
         if (MtpDeviceRecord.isSupported(
                 operationsSupported, MtpConstants.OPERATION_DELETE_OBJECT) &&
                 (protectionState == MtpConstants.PROTECTION_STATUS_NONE ||
-                 protectionState == MtpConstants.PROTECTION_STATUS_NON_TRANSFERABLE_DATA)) {
+                 protectionState == MtpConstants.PROTECTION_STATUS_NON_TRANSFERABLE_DATA) &&
+                documentType == DOCUMENT_TYPE_OBJECT) {
             flag |= Document.FLAG_SUPPORTS_DELETE;
         }
         if (mimeType.equals(Document.MIME_TYPE_DIR) &&
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 6fb2a78..0599b70 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -130,11 +130,14 @@
         return devices.toArray(new MtpDeviceRecord[devices.size()]);
     }
 
-    MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
-            throws IOException {
+    MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
         final MtpDevice device = getDevice(deviceId);
         synchronized (device) {
-            return device.getObjectInfo(objectHandle);
+            final MtpObjectInfo info = device.getObjectInfo(objectHandle);
+            if (info == null) {
+                throw new IOException("Failed to get object info: " + objectHandle);
+            }
+            return info;
         }
     }
 
@@ -291,7 +294,7 @@
             if (usbInterface.getInterfaceClass() == UsbConstants.USB_SUBCLASS_VENDOR_SPEC &&
                     usbInterface.getInterfaceSubclass() == SUBCLASS_MTP &&
                     usbInterface.getInterfaceProtocol() == PROTOCOL_MTP &&
-                    usbInterface.getName().equals("MTP")) {
+                    "MTP".equals(usbInterface.getName())) {
                 return true;
             }
         }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index db25421..45f89e4 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -55,13 +55,6 @@
 
         mManager = new BlockableTestMtpManager(getContext());
         mResolver = new TestContentResolver();
-        mLoader = new DocumentLoader(
-                new MtpDeviceRecord(
-                        0, "Device", "Key", true, new MtpRoot[0],
-                        TestUtil.OPERATIONS_SUPPORTED, new int[0]),
-                mManager,
-                mResolver,
-                mDatabase);
     }
 
     @Override
@@ -71,6 +64,8 @@
     }
 
     public void testBasic() throws Exception {
+        setUpLoader();
+
         final Uri uri = DocumentsContract.buildChildDocumentsUri(
                 MtpDocumentsProvider.AUTHORITY, mParentIdentifier.mDocumentId);
         setUpDocument(mManager, 40);
@@ -107,6 +102,55 @@
         assertEquals(2, mResolver.getChangeCount(uri));
     }
 
+    public void testError_GetObjectHandles() throws Exception {
+        mManager = new BlockableTestMtpManager(getContext()) {
+            @Override
+            int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
+                    throws IOException {
+                throw new IOException();
+            }
+        };
+        setUpLoader();
+        mManager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, null);
+        try {
+            try (final Cursor cursor = mLoader.queryChildDocuments(
+                    MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {}
+            fail();
+        } catch (IOException exception) {
+            // Expect exception.
+        }
+    }
+
+    public void testError_GetObjectInfo() throws Exception {
+        mManager = new BlockableTestMtpManager(getContext()) {
+            @Override
+            MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
+                if (objectHandle == DocumentLoader.NUM_INITIAL_ENTRIES) {
+                    throw new IOException();
+                } else {
+                    return super.getObjectInfo(deviceId, objectHandle);
+                }
+            }
+        };
+        setUpLoader();
+        setUpDocument(mManager, DocumentLoader.NUM_INITIAL_ENTRIES);
+        try (final Cursor cursor = mLoader.queryChildDocuments(
+                MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {
+            // Even if MtpManager returns an error for a document, loading must complete.
+            assertFalse(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING));
+        }
+    }
+
+    private void setUpLoader() {
+        mLoader = new DocumentLoader(
+                new MtpDeviceRecord(
+                        0, "Device", "Key", true, new MtpRoot[0],
+                        TestUtil.OPERATIONS_SUPPORTED, new int[0]),
+                mManager,
+                mResolver,
+                mDatabase);
+    }
+
     private void setUpDocument(TestMtpManager manager, int count) {
         int[] childDocuments = new int[count];
         for (int i = 0; i < childDocuments.length; i++) {
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index b74069a..284223b 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -103,7 +103,7 @@
             assertTrue(isNull(cursor, COLUMN_SUMMARY));
             assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
             assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON));
-            assertEquals(0, getInt(cursor, COLUMN_FLAGS));
+            assertEquals(Document.FLAG_DIR_SUPPORTS_CREATE, getInt(cursor, COLUMN_FLAGS));
             assertEquals(1000, getInt(cursor, COLUMN_SIZE));
             assertEquals(
                     MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE,
@@ -165,7 +165,7 @@
             assertTrue(isNull(cursor, COLUMN_SUMMARY));
             assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
             assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON));
-            assertEquals(0, getInt(cursor, COLUMN_FLAGS));
+            assertEquals(Document.FLAG_DIR_SUPPORTS_CREATE, getInt(cursor, COLUMN_FLAGS));
             assertEquals(1000, getInt(cursor, COLUMN_SIZE));
             assertEquals(
                     MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE));
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 9c1880a..da6af37 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -351,7 +351,6 @@
         assertEquals(1422716400000L, cursor.getLong(3));
         assertEquals(
                 DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
-                DocumentsContract.Document.FLAG_SUPPORTS_WRITE |
                 DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE,
                 cursor.getInt(4));
         assertEquals(0, cursor.getInt(5));
@@ -419,20 +418,16 @@
         try {
             mProvider.queryChildDocuments("1", null, null);
             fail();
-        } catch (Throwable error) {
-            assertTrue(error instanceof FileNotFoundException);
-        }
+        } catch (FileNotFoundException error) {}
     }
 
     public void testQueryChildDocuments_documentError() throws Exception {
         setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
         setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
         mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
-        try {
-            mProvider.queryChildDocuments("1", null, null);
-            fail();
-        } catch (Throwable error) {
-            assertTrue(error instanceof FileNotFoundException);
+        try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {
+            assertEquals(0, cursor.getCount());
+            assertFalse(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING));
         }
     }
 
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 1aee490..a2a3fd3 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -793,4 +793,23 @@
     <!-- Label for length of time until battery is charged [CHAR LIMIT=20] -->
     <string name="remaining_length_format"><xliff:g name="time" example="3 hours">%1$s</xliff:g> left</string>
 
+    <!-- Hint text for the IP address -->
+    <string name="wifi_ip_address_hint" translatable="false">192.168.1.128</string>
+    <!-- Hint text for DNS -->
+    <string name="wifi_dns1_hint" translatable="false">8.8.8.8</string>
+    <!-- Hint text for DNS -->
+    <string name="wifi_dns2_hint" translatable="false">8.8.4.4</string>
+    <!-- Hint text for the gateway -->
+    <string name="wifi_gateway_hint" translatable="false">192.168.1.1</string>
+    <!-- Hint text for network prefix length -->
+    <string name="wifi_network_prefix_length_hint" translatable="false">24</string>
+    <!-- HTTP proxy settings. The hint text field for port. -->
+    <string name="proxy_port_hint" translatable="false">8080</string>
+    <!-- HTTP proxy settings. Hint for Proxy-Auto Config URL. -->
+    <string name="proxy_url_hint" translatable="false">https://www.example.com/proxy.pac</string>
+    <!-- HTTP proxy settings. The hint text for proxy exclusion list. -->
+    <string name="proxy_exclusionlist_hint" translatable="false">example.com,mycomp.test.com,localhost</string>
+    <!-- HTTP proxy settings. The hint text field for the hostname. -->
+    <string name="proxy_hostname_hint" translatable="false">proxy.example.com</string>
+
 </resources>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 7fae0ee..c9582ea 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -149,6 +149,10 @@
     // Passed to Message.obtain() when msg.arg2 is not used.
     private static final int UNUSED_ARG2 = -2;
 
+    // Maximum progress displayed (like 99.00%).
+    private static final int CAPPED_PROGRESS = 9900;
+    private static final int CAPPED_MAX = 10000;
+
     /**
      * Delay before a screenshot is taken.
      * <p>
@@ -427,7 +431,7 @@
         final NumberFormat nf = NumberFormat.getPercentInstance();
         nf.setMinimumFractionDigits(2);
         nf.setMaximumFractionDigits(2);
-        final String percentText = nf.format((double) info.progress / info.max);
+        final String percentageText = nf.format((double) info.progress / info.max);
         final Action cancelAction = new Action.Builder(null, mContext.getString(
                 com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
         final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
@@ -458,7 +462,7 @@
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(name)
-                .setContentInfo(percentText)
+                .setContentInfo(percentageText)
                 .setProgress(info.max, info.progress, false)
                 .setOngoing(true)
                 .setContentIntent(infoPendingIntent)
@@ -472,7 +476,7 @@
         }
         if (DEBUG) {
             Log.d(TAG, "Sending 'Progress' notification for id " + info.id + "(pid " + info.pid
-                    + "): " + percentText);
+                    + "): " + percentageText);
         }
         NotificationManager.from(mContext).notify(TAG, info.id, notification);
     }
@@ -545,25 +549,47 @@
             }
             activeProcesses++;
             final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX;
-            final int progress = SystemProperties.getInt(progressKey, 0);
-            if (progress == 0) {
+            info.realProgress = SystemProperties.getInt(progressKey, 0);
+            if (info.realProgress == 0) {
                 Log.v(TAG, "System property " + progressKey + " is not set yet");
             }
-            final int max = SystemProperties.getInt(DUMPSTATE_PREFIX + pid + MAX_SUFFIX, 0);
-            final boolean maxChanged = max > 0 && max != info.max;
-            final boolean progressChanged = progress > 0 && progress != info.progress;
+            final String maxKey = DUMPSTATE_PREFIX + pid + MAX_SUFFIX;
+            info.realMax = SystemProperties.getInt(maxKey, info.max);
+            if (info.realMax <= 0 ) {
+                Log.w(TAG, "Property " + maxKey + " is not positive: " + info.max);
+                continue;
+            }
+            /*
+             * Checks whether the progress changed in a way that should be displayed to the user:
+             * - info.progress / info.max represents the displayed progress
+             * - info.realProgress / info.realMax represents the real progress
+             * - since the real progress can decrease, the displayed progress is only updated if it
+             *   increases
+             * - the displayed progress is capped at a maximum (like 99%)
+             */
+            final int oldPercentage = (CAPPED_MAX * info.progress) / info.max;
+            int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax;
+            int max = info.realMax;
+            int progress = info.realProgress;
 
-            if (progressChanged || maxChanged) {
-                if (progressChanged) {
-                    if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id
-                            + ") from " + info.progress + " to " + progress);
-                    info.progress = progress;
+            if (newPercentage > CAPPED_PROGRESS) {
+                progress = newPercentage = CAPPED_PROGRESS;
+                max = CAPPED_MAX;
+            }
+
+            if (newPercentage > oldPercentage) {
+                if (DEBUG) {
+                    if (progress != info.progress) {
+                        Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id + ") from "
+                                + info.progress + " to " + progress);
+                    }
+                    if (max != info.max) {
+                        Log.v(TAG, "Updating max progress for PID " + pid + "(id: " + id + ") from "
+                                + info.max + " to " + max);
+                    }
                 }
-                if (maxChanged) {
-                    Log.i(TAG, "Updating max progress for PID " + pid + "(id: " + id
-                            + ") from " + info.max + " to " + max);
-                    info.max = max;
-                }
+                info.progress = progress;
+                info.max = max;
                 info.lastUpdate = System.currentTimeMillis();
                 updateProgress(info);
             } else {
@@ -1450,16 +1476,26 @@
         String description;
 
         /**
-         * Maximum progress of the bugreport generation.
+         * Maximum progress of the bugreport generation as displayed by the UI.
          */
         int max;
 
         /**
-         * Current progress of the bugreport generation.
+         * Current progress of the bugreport generation as displayed by the UI.
          */
         int progress;
 
         /**
+         * Maximum progress of the bugreport generation as reported by dumpstate.
+         */
+        int realMax;
+
+        /**
+         * Current progress of the bugreport generation as reported by dumpstate.
+         */
+        int realProgress;
+
+        /**
          * Time of the last progress update.
          */
         long lastUpdate = System.currentTimeMillis();
@@ -1568,10 +1604,12 @@
         @Override
         public String toString() {
             final float percent = ((float) progress * 100 / max);
+            final float realPercent = ((float) realProgress * 100 / realMax);
             return "id: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
                     + "\n\ttitle: " + title + "\n\tdescription: " + description
                     + "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
                     + "\n\tprogress: " + progress + "/" + max + " (" + percent + ")"
+                    + "\n\treal progress: " + realProgress + "/" + realMax + " (" + realPercent + ")"
                     + "\n\tlast_update: " + getFormattedLastUpdate()
                     + "\naddingDetailsToZip: " + addingDetailsToZip
                     + " addedDetailsToZip: " + addedDetailsToZip;
@@ -1587,6 +1625,8 @@
             description = in.readString();
             max = in.readInt();
             progress = in.readInt();
+            realMax = in.readInt();
+            realProgress = in.readInt();
             lastUpdate = in.readLong();
             formattedLastUpdate = in.readString();
             bugreportFile = readFile(in);
@@ -1609,6 +1649,8 @@
             dest.writeString(description);
             dest.writeInt(max);
             dest.writeInt(progress);
+            dest.writeInt(realMax);
+            dest.writeInt(realProgress);
             dest.writeLong(lastUpdate);
             dest.writeString(getFormattedLastUpdate());
             writeFile(dest, bugreportFile);
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 49759c5..814aa8c 100644
--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -56,7 +56,7 @@
         final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
         final RowBuilder row = result.newRow();
         row.add(Root.COLUMN_ROOT_ID, DOC_ID_ROOT);
-        row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY);
+        row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED);
         row.add(Root.COLUMN_ICON, android.R.mipmap.sym_def_app_icon);
         row.add(Root.COLUMN_TITLE, getContext().getString(R.string.bugreport_storage_title));
         row.add(Root.COLUMN_DOCUMENT_ID, DOC_ID_ROOT);
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 17f6f6b..e1e0c3b 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -26,6 +26,7 @@
 import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_STARTED;
+import static com.android.shell.BugreportProgressService.POLLING_FREQUENCY;
 import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS;
 
 import java.io.BufferedOutputStream;
@@ -92,7 +93,7 @@
     private static final String TAG = "BugreportReceiverTest";
 
     // Timeout for UI operations, in milliseconds.
-    private static final int TIMEOUT = (int) BugreportProgressService.POLLING_FREQUENCY * 4;
+    private static final int TIMEOUT = (int) POLLING_FREQUENCY * 4;
 
     // Timeout for when waiting for a screenshot to finish.
     private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10;
@@ -190,8 +191,30 @@
         SystemProperties.set(PROGRESS_PROPERTY, "500");
         assertProgressNotification(NAME, nf.format(0.50));
 
+        SystemProperties.set(PROGRESS_PROPERTY, "950");
+        assertProgressNotification(NAME, nf.format(0.95));
+
+        // Make sure progress never goes back...
         SystemProperties.set(MAX_PROPERTY, "2000");
-        assertProgressNotification(NAME, nf.format(0.25));
+        Thread.sleep(POLLING_FREQUENCY + DateUtils.SECOND_IN_MILLIS);
+        assertProgressNotification(NAME, nf.format(0.95));
+
+        SystemProperties.set(PROGRESS_PROPERTY, "1000");
+        assertProgressNotification(NAME, nf.format(0.95));
+
+        // ...only forward...
+        SystemProperties.set(PROGRESS_PROPERTY, "1902");
+        assertProgressNotification(NAME, nf.format(0.9510));
+
+        SystemProperties.set(PROGRESS_PROPERTY, "1960");
+        assertProgressNotification(NAME, nf.format(0.98));
+
+        // ...but never more than the capped value.
+        SystemProperties.set(PROGRESS_PROPERTY, "2000");
+        assertProgressNotification(NAME, nf.format(0.99));
+
+        SystemProperties.set(PROGRESS_PROPERTY, "3000");
+        assertProgressNotification(NAME, nf.format(0.99));
 
         Bundle extras =
                 sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, mScreenshotPath);
diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java
index 384c3da..5bfe1a0 100644
--- a/packages/Shell/tests/src/com/android/shell/UiBot.java
+++ b/packages/Shell/tests/src/com/android/shell/UiBot.java
@@ -32,7 +32,7 @@
 final class UiBot {
 
     private static final String TAG = "UiBot";
-    private static final String SYSTEMUI_PACKAGED = "com.android.systemui";
+    private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
 
     private final UiDevice mDevice;
     private final int mTimeout;
@@ -51,8 +51,8 @@
     public UiObject getNotification(String text) {
         boolean opened = mDevice.openNotification();
         Log.v(TAG, "openNotification(): " + opened);
-        boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGED)), mTimeout);
-        assertTrue("could not get system ui (" + SYSTEMUI_PACKAGED + ")", gotIt);
+        boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGE)), mTimeout);
+        assertTrue("could not get system ui (" + SYSTEMUI_PACKAGE + ")", gotIt);
 
         return getObject(text);
     }
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
index 567e009..9764074 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -38,16 +38,15 @@
         android:id="@+id/pip_shade"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:visibility="invisible"
+        android:visibility="gone"
         android:background="#76000000"/>
 
     <!-- Placeholder view to handle key events for PIP when it's focused.
-         Size and positions will be adjusted to comply with
-         config_pictureInPictureBoundsInRecents -->
+         Size and positions will be adjusted to comply with the PIP bounds -->
     <View
         android:id="@+id/pip"
         android:layout_width="0dp"
         android:layout_height="0dp"
-        android:visibility="invisible"
+        android:visibility="gone"
         android:focusable="true" />
 </com.android.systemui.recents.tv.views.RecentsTvView>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 0e1fe8f..2957914 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -19,13 +19,13 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Picture-in-Picture (PIP) menu -->
     <eat-comment />
-    <!-- Button to close picture-in-picture (PIP) in PIP menu [CHAR LIMIT=16] -->
+    <!-- Button to close picture-in-picture (PIP) in PIP menu [CHAR LIMIT=30] -->
     <string name="pip_close">Close PIP</string>
-    <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=16] -->
+    <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=30] -->
     <string name="pip_fullscreen">Full screen</string>
-    <!-- Button to play the current media on picture-in-picture (PIP) [CHAR LIMIT=16] -->
+    <!-- Button to play the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
     <string name="pip_play">Play</string>
-    <!-- Button to pause the current media on picture-in-picture (PIP) [CHAR LIMIT=16] -->
+    <!-- Button to pause the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
     <string name="pip_pause">Pause</string>
     <!-- Overlay text on picture-in-picture (PIP) to indicate that longpress HOME key to control PIP [CHAR LIMIT=52] -->
     <string name="pip_hold_home">Hold <b>HOME</b> to control PIP</string>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index dae522f..960bd8c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -85,9 +85,13 @@
     private PipManager mPipManager;
     private PipManager.Listener mPipListener = new PipManager.Listener() {
         @Override
+        public void onPipEntered() {
+            updatePipUI();
+        }
+
+        @Override
         public void onPipActivityClosed() {
-            mPipView.setVisibility(View.GONE);
-            mPipShadeView.setVisibility(View.GONE);
+            updatePipUI();
         }
 
         @Override
@@ -102,6 +106,7 @@
         @Override
         public void onMediaControllerChanged() { }
     };
+    private boolean mHasPip;
 
     /**
      * A common Runnable to finish Recents by launching Home with an animation depending on the
@@ -266,6 +271,10 @@
         homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
         mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
+
+        mHasPip = false;
+        updatePipUI();
+        mPipManager.addListener(mPipListener);
     }
 
     @Override
@@ -296,34 +305,6 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
 
-        if (mPipManager.isPipShown()) {
-            // Place mPipView at the PIP bounds for fine tuned focus handling.
-            Rect pipBounds = mPipManager.getPipBounds();
-            LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
-            lp.width = pipBounds.width();
-            lp.height = pipBounds.height();
-            lp.leftMargin = pipBounds.left;
-            lp.topMargin = pipBounds.top;
-            mPipView.setLayoutParams(lp);
-
-            mPipView.setVisibility(View.VISIBLE);
-            mPipView.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    mPipManager.resizePinnedStack(PipManager.STATE_PIP_MENU);
-                }
-            });
-            mPipView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-                @Override
-                public void onFocusChange(View v, boolean hasFocus) {
-                    mPipManager.onPipViewFocusChangedInRecents(hasFocus);
-                    mPipShadeView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
-                }
-            });
-            mPipManager.addListener(mPipListener);
-        } else {
-            mPipView.setVisibility(View.GONE);
-        }
         mPipManager.onRecentsStarted();
         // Give focus to the recents row whenever its visible to an user.
         mRecentsView.requestFocus();
@@ -340,7 +321,6 @@
         super.onStop();
 
         mPipManager.onRecentsStopped();
-        mPipManager.removeListener(mPipListener);
         mIgnoreAltTabRelease = false;
         // Notify that recents is now hidden
         EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
@@ -357,6 +337,7 @@
     protected void onDestroy() {
         super.onDestroy();
 
+        mPipManager.removeListener(mPipListener);
         // In the case that the activity finished on startup, just skip the unregistration below
         if (mFinishedOnStartup) {
             return;
@@ -480,4 +461,40 @@
         });
         return true;
     }
+
+    private void updatePipUI() {
+        if (mHasPip == mPipManager.isPipShown()) {
+            return;
+        }
+        mHasPip = mPipManager.isPipShown();
+        if (mHasPip) {
+            // Place mPipView at the PIP bounds for fine tuned focus handling.
+            Rect pipBounds = mPipManager.getPipBounds();
+            LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
+            lp.width = pipBounds.width();
+            lp.height = pipBounds.height();
+            lp.leftMargin = pipBounds.left;
+            lp.topMargin = pipBounds.top;
+            mPipView.setLayoutParams(lp);
+
+            mPipView.setVisibility(View.VISIBLE);
+            mPipView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mPipManager.resizePinnedStack(PipManager.STATE_PIP_MENU);
+                }
+            });
+            mPipView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+                @Override
+                public void onFocusChange(View v, boolean hasFocus) {
+                    mPipManager.onPipViewFocusChangedInRecents(hasFocus);
+                    mPipShadeView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+                }
+            });
+            mPipShadeView.setVisibility(View.GONE);
+        } else {
+            mPipView.setVisibility(View.GONE);
+            mPipShadeView.setVisibility(View.GONE);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 451203d..95cee4c 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -120,6 +120,14 @@
             mMediaSessionManager.addOnActiveSessionsChangedListener(
                     mActiveMediaSessionListener, null);
             updateMediaController(mMediaSessionManager.getActiveSessions(null));
+            if (mIsRecentsShown) {
+                // If an activity becomes PIPed again after the fullscreen, the Recents is shown
+                // behind so we need to resize the pinned stack and show the correct overlay.
+                resizePinnedStack(STATE_PIP_OVERLAY);
+            }
+            for (int i = mListeners.size() - 1; i >= 0; i--) {
+                mListeners.get(i).onPipEntered();
+            }
         }
     };
     private final Runnable mOnTaskStackChanged = new Runnable() {
@@ -384,7 +392,7 @@
         try {
             mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds, true, true, true, -1);
         } catch (RemoteException e) {
-            Log.e(TAG, "showPipMenu failed", e);
+            Log.e(TAG, "resizeStack failed", e);
         }
     }
 
@@ -482,17 +490,7 @@
      * Returns {@code true} if PIP is shown.
      */
     public boolean isPipShown() {
-        return hasPipTasks();
-    }
-
-    private boolean hasPipTasks() {
-        try {
-            StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
-            return stackInfo != null;
-        } catch (RemoteException e) {
-            Log.e(TAG, "getStackInfo failed", e);
-            return false;
-        }
+        return mState != STATE_NO_PIP;
     }
 
     private void handleMediaResourceGranted(String[] packageNames) {
@@ -600,6 +598,13 @@
      * A listener interface to receive notification on changes in PIP.
      */
     public interface Listener {
+        /**
+         * Invoked when an activity is pinned and PIP manager is set corresponding information.
+         * Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned}
+         * because there's no guarantee for the PIP manager be return relavent information
+         * correctly. (e.g. {@link isPipShown}, {@link getPipBounds})
+         */
+        void onPipEntered();
         /** Invoked when a PIPed activity is closed. */
         void onPipActivityClosed();
         /** Invoked when the PIP menu gets shown. */
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index 285dfd1..b8b837a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -198,6 +198,9 @@
     }
 
     @Override
+    public void onPipEntered() { }
+
+    @Override
     public void onPipActivityClosed() {
         finish();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index ad45625b..79daf3d 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -67,6 +67,9 @@
     }
 
     @Override
+    public void onPipEntered() { }
+
+    @Override
     public void onPipActivityClosed() {
         finish();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index 4bd3f49..1de321d 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -109,6 +109,9 @@
     }
 
     @Override
+    public void onPipEntered() { }
+
+    @Override
     public void onPipActivityClosed() {
         finish();
     }
@@ -131,8 +134,7 @@
     }
 
     @Override
-    public void onMediaControllerChanged() {
-    }
+    public void onMediaControllerChanged() { }
 
     @Override
     public void finish() {
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 425569c..9beaba3 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -1387,6 +1387,27 @@
     }
 
     /**
+     * Name of the file that holds the object cache.
+     */
+    private static String mCachePath;
+
+    /**
+     * Gets the path to the code cache.
+     */
+    static synchronized String getCachePath() {
+        if (mCachePath == null) {
+            final String CACHE_PATH = "com.android.renderscript.cache";
+            if (RenderScriptCacheDir.mCacheDir == null) {
+                throw new RSRuntimeException("RenderScript code cache directory uninitialized.");
+            }
+            File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
+            mCachePath = f.getAbsolutePath();
+            f.mkdirs();
+        }
+        return mCachePath;
+    }
+
+    /**
      * Create a RenderScript context.
      *
      * @param ctx The context.
@@ -1415,11 +1436,7 @@
         }
 
         // set up cache directory for entire context
-        final String CACHE_PATH = "com.android.renderscript.cache";
-        File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
-        String mCachePath = f.getAbsolutePath();
-        f.mkdirs();
-        rs.nContextSetCacheDir(mCachePath);
+        rs.nContextSetCacheDir(RenderScript.getCachePath());
 
         rs.mMessageThread = new MessageThread(rs);
         rs.mMessageThread.start();
diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java
index bf706c1..00ebe57 100644
--- a/rs/java/android/renderscript/ScriptC.java
+++ b/rs/java/android/renderscript/ScriptC.java
@@ -84,13 +84,6 @@
         setID(id);
     }
 
-    /**
-     * Name of the file that holds the object cache.
-     */
-    private static final String CACHE_PATH = "com.android.renderscript.cache";
-
-    static String mCachePath;
-
     private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) {
         byte[] pgm;
         int pgmLength;
@@ -122,26 +115,12 @@
 
         String resName = resources.getResourceEntryName(resourceID);
 
-        // Create the RS cache path if we haven't done so already.
-        if (mCachePath == null) {
-            File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
-            mCachePath = f.getAbsolutePath();
-            f.mkdirs();
-        }
         //        Log.v(TAG, "Create script for resource = " + resName);
-        return rs.nScriptCCreate(resName, mCachePath, pgm, pgmLength);
+        return rs.nScriptCCreate(resName, RenderScript.getCachePath(), pgm, pgmLength);
     }
 
     private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) {
-        // Create the RS cache path if we haven't done so already.
-        if (mCachePath == null) {
-            File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
-            mCachePath = f.getAbsolutePath();
-            f.mkdirs();
-        }
         //        Log.v(TAG, "Create script for resource = " + resName);
-        return rs.nScriptCCreate(resName, mCachePath, bitcode, bitcode.length);
+        return rs.nScriptCCreate(resName, RenderScript.getCachePath(), bitcode, bitcode.length);
     }
-
-
 }
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index 9bbacbc..9357c3bb 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -396,7 +396,7 @@
         for (int i = 0; i < closureIDs.length; i++) {
             closureIDs[i] = closures.get(i).getID(rs);
         }
-        long id = rs.nScriptGroup2Create(name, ScriptC.mCachePath, closureIDs);
+        long id = rs.nScriptGroup2Create(name, RenderScript.getCachePath(), closureIDs);
         setID(id);
     }
 
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index a94c8b8..e7db2a8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -447,12 +447,8 @@
             int[] ops) {
         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
                 Binder.getCallingPid(), Binder.getCallingUid(), null);
-        String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return Collections.emptyList();
-        }
         synchronized (this) {
-            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false);
+            Ops pkgOps = getOpsLocked(uid, packageName, false);
             if (pkgOps == null) {
                 return null;
             }
@@ -470,7 +466,7 @@
 
     private void pruneOp(Op op, int uid, String packageName) {
         if (op.time == 0 && op.rejectTime == 0) {
-            Ops ops = getOpsRawLocked(uid, packageName, false);
+            Ops ops = getOpsLocked(uid, packageName, false);
             if (ops != null) {
                 ops.remove(op.op);
                 if (ops.size() <= 0) {
@@ -884,12 +880,8 @@
     public int checkOperation(int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return AppOpsManager.MODE_IGNORED;
-        }
         synchronized (this) {
-            if (isOpRestricted(uid, code, resolvedPackageName)) {
+            if (isOpRestricted(uid, code, packageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             code = AppOpsManager.opToSwitch(code);
@@ -900,7 +892,7 @@
                     return uidMode;
                 }
             }
-            Op op = getOpLocked(code, uid, resolvedPackageName, false);
+            Op op = getOpLocked(code, uid, packageName, false);
             if (op == null) {
                 return AppOpsManager.opToDefaultMode(code);
             }
@@ -976,7 +968,6 @@
 
     @Override
     public int checkPackage(int uid, String packageName) {
-        Preconditions.checkNotNull(packageName);
         synchronized (this) {
             if (getOpsRawLocked(uid, packageName, true) != null) {
                 return AppOpsManager.MODE_ALLOWED;
@@ -990,39 +981,26 @@
     public int noteProxyOperation(int code, String proxyPackageName,
             int proxiedUid, String proxiedPackageName) {
         verifyIncomingOp(code);
-        final int proxyUid = Binder.getCallingUid();
-        String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
-        if (resolveProxyPackageName == null) {
-            return AppOpsManager.MODE_IGNORED;
-        }
-        final int proxyMode = noteOperationUnchecked(code, proxyUid,
-                resolveProxyPackageName, -1, null);
+        final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(),
+                proxyPackageName, -1, null);
         if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
             return proxyMode;
         }
-        String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
-        if (resolveProxiedPackageName == null) {
-            return AppOpsManager.MODE_IGNORED;
-        }
-        return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
-                proxyMode, resolveProxyPackageName);
+        return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
+                Binder.getCallingUid(), proxyPackageName);
     }
 
     @Override
     public int noteOperation(int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return AppOpsManager.MODE_IGNORED;
-        }
-        return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
+        return noteOperationUnchecked(code, uid, packageName, 0, null);
     }
 
     private int noteOperationUnchecked(int code, int uid, String packageName,
             int proxyUid, String proxyPackageName) {
         synchronized (this) {
-            Ops ops = getOpsRawLocked(uid, packageName, true);
+            Ops ops = getOpsLocked(uid, packageName, true);
             if (ops == null) {
                 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
                         + " package " + packageName);
@@ -1070,20 +1048,16 @@
     public int startOperation(IBinder token, int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return  AppOpsManager.MODE_IGNORED;
-        }
         ClientState client = (ClientState)token;
         synchronized (this) {
-            Ops ops = getOpsRawLocked(uid, resolvedPackageName, true);
+            Ops ops = getOpsLocked(uid, packageName, true);
             if (ops == null) {
                 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
-                        + " package " + resolvedPackageName);
+                        + " package " + packageName);
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
-            if (isOpRestricted(uid, code, resolvedPackageName)) {
+            if (isOpRestricted(uid, code, packageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             final int switchCode = AppOpsManager.opToSwitch(code);
@@ -1093,7 +1067,7 @@
                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
                     if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
-                            + resolvedPackageName);
+                            + packageName);
                     op.rejectTime = System.currentTimeMillis();
                     return uidMode;
                 }
@@ -1101,13 +1075,12 @@
             final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
             if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
                 if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
-                        + switchCode + " (" + code + ") uid " + uid + " package "
-                        + resolvedPackageName);
+                        + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
                 op.rejectTime = System.currentTimeMillis();
                 return switchOp.mode;
             }
             if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
-                    + " package " + resolvedPackageName);
+                    + " package " + packageName);
             if (op.nesting == 0) {
                 op.time = System.currentTimeMillis();
                 op.rejectTime = 0;
@@ -1125,16 +1098,9 @@
     public void finishOperation(IBinder token, int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return;
-        }
-        if (!(token instanceof ClientState)) {
-            return;
-        }
-        ClientState client = (ClientState) token;
+        ClientState client = (ClientState)token;
         synchronized (this) {
-            Op op = getOpLocked(code, uid, resolvedPackageName, true);
+            Op op = getOpLocked(code, uid, packageName, true);
             if (op == null) {
                 return;
             }
@@ -1150,9 +1116,6 @@
 
     @Override
     public int permissionToOpCode(String permission) {
-        if (permission == null) {
-            return AppOpsManager.OP_NONE;
-        }
         return AppOpsManager.permissionToOpCode(permission);
     }
 
@@ -1202,6 +1165,15 @@
         return uidState;
     }
 
+    private Ops getOpsLocked(int uid, String packageName, boolean edit) {
+        if (uid == 0) {
+            packageName = "root";
+        } else if (uid == Process.SHELL_UID) {
+            packageName = "com.android.shell";
+        }
+        return getOpsRawLocked(uid, packageName, edit);
+    }
+
     private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
         UidState uidState = getUidStateLocked(uid, edit);
         if (uidState == null) {
@@ -1287,7 +1259,7 @@
     }
 
     private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
-        Ops ops = getOpsRawLocked(uid, packageName, edit);
+        Ops ops = getOpsLocked(uid, packageName, edit);
         if (ops == null) {
             return null;
         }
@@ -1345,7 +1317,7 @@
                 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
                     // If we are the system, bypass user restrictions for certain codes
                     synchronized (this) {
-                        Ops ops = getOpsRawLocked(uid, packageName, true);
+                        Ops ops = getOpsLocked(uid, packageName, true);
                         if ((ops != null) && ops.isPrivileged) {
                             return false;
                         }
@@ -1610,7 +1582,7 @@
                         out.startTag(null, "uid");
                         out.attribute(null, "n", Integer.toString(pkg.getUid()));
                         synchronized (this) {
-                            Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
+                            Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false);
                             // Should always be present as the list of PackageOps is generated
                             // from Ops.
                             if (ops != null) {
@@ -2131,7 +2103,6 @@
     @Override
     public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
         checkSystemUid("setUserRestrictions");
-        Preconditions.checkNotNull(restrictions);
         Preconditions.checkNotNull(token);
         final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
         for (int i = 0; i < opRestrictions.length; ++i) {
@@ -2346,15 +2317,6 @@
         }
     }
 
-    private static String resolvePackageName(int uid, String packageName)  {
-        if (uid == 0) {
-            return "root";
-        } else if (uid == Process.SHELL_UID) {
-            return "com.android.shell";
-        }
-        return packageName;
-    }
-
     private static String[] getPackagesForUid(int uid) {
         String[] packageNames = null;
         try {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b7fca1a..5b01062 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3845,8 +3845,16 @@
     @Override
     public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
             Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
-        networkCapabilities = new NetworkCapabilities(networkCapabilities);
-        enforceNetworkRequestPermissions(networkCapabilities);
+        // If the requested networkCapabilities is null, take them instead from
+        // the default network request. This allows callers to keep track of
+        // the system default network.
+        if (networkCapabilities == null) {
+            networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities);
+            enforceAccessPermission();
+        } else {
+            networkCapabilities = new NetworkCapabilities(networkCapabilities);
+            enforceNetworkRequestPermissions(networkCapabilities);
+        }
         enforceMeteredApnPolicy(networkCapabilities);
         ensureRequestableCapabilities(networkCapabilities);
 
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 07c10b0..548b662 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1149,81 +1149,6 @@
     }
 
     @Override
-    public RouteInfo[] getRoutes(String interfaceName) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
-
-        // v4 routes listed as:
-        // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
-        for (String s : readRouteList("/proc/net/route")) {
-            String[] fields = s.split("\t");
-
-            if (fields.length > 7) {
-                String iface = fields[0];
-
-                if (interfaceName.equals(iface)) {
-                    String dest = fields[1];
-                    String gate = fields[2];
-                    String flags = fields[3]; // future use?
-                    String mask = fields[7];
-                    try {
-                        // address stored as a hex string, ex: 0014A8C0
-                        InetAddress destAddr =
-                                NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
-                        int prefixLength =
-                                NetworkUtils.netmaskIntToPrefixLength(
-                                (int)Long.parseLong(mask, 16));
-                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
-
-                        // address stored as a hex string, ex 0014A8C0
-                        InetAddress gatewayAddr =
-                                NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
-
-                        RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
-                        routes.add(route);
-                    } catch (Exception e) {
-                        Log.e(TAG, "Error parsing route " + s + " : " + e);
-                        continue;
-                    }
-                }
-            }
-        }
-
-        // v6 routes listed as:
-        // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
-        for (String s : readRouteList("/proc/net/ipv6_route")) {
-            String[]fields = s.split("\\s+");
-            if (fields.length > 9) {
-                String iface = fields[9].trim();
-                if (interfaceName.equals(iface)) {
-                    String dest = fields[0];
-                    String prefix = fields[1];
-                    String gate = fields[4];
-
-                    try {
-                        // prefix length stored as a hex string, ex 40
-                        int prefixLength = Integer.parseInt(prefix, 16);
-
-                        // address stored as a 32 char hex string
-                        // ex fe800000000000000000000000000000
-                        InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
-                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
-
-                        InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
-
-                        RouteInfo route = new RouteInfo(linkAddress, gateAddr);
-                        routes.add(route);
-                    } catch (Exception e) {
-                        Log.e(TAG, "Error parsing route " + s + " : " + e);
-                        continue;
-                    }
-                }
-            }
-        }
-        return routes.toArray(new RouteInfo[routes.size()]);
-    }
-
-    @Override
     public void setMtu(String iface, int mtu) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
diff --git a/services/core/java/com/android/server/connectivity/ApfFilter.java b/services/core/java/com/android/server/connectivity/ApfFilter.java
index d62a0b3..0014665 100644
--- a/services/core/java/com/android/server/connectivity/ApfFilter.java
+++ b/services/core/java/com/android/server/connectivity/ApfFilter.java
@@ -90,6 +90,7 @@
     }
 
     private static final String TAG = "ApfFilter";
+    private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
     private final ConnectivityService mConnectivityService;
@@ -205,6 +206,10 @@
         // For debugging only. How many times this RA was seen.
         int seenCount = 0;
 
+        // For debugging only. Returns the hex representation of the last matching packet.
+        String getLastMatchingPacket() {
+            return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(), false /* lowercase */);
+        }
 
         private String IPv6AddresstoString(int pos) {
             try {
@@ -454,7 +459,7 @@
     private long mLastInstalledProgramMinLifetime;
 
     // For debugging only. The length in bytes of the last program.
-    private long mLastInstalledProgramLength;
+    private byte[] mLastInstalledProgram;
 
     private void installNewProgram() {
         if (mRas.size() == 0) return;
@@ -495,7 +500,7 @@
         }
         mLastTimeInstalledProgram = curTime();
         mLastInstalledProgramMinLifetime = programMinLifetime;
-        mLastInstalledProgramLength = program.length;
+        mLastInstalledProgram = program;
         if (VDBG) {
             hexDump("Installing filter: ", program, program.length);
         } else {
@@ -515,7 +520,7 @@
     }
 
     private void hexDump(String msg, byte[] packet, int length) {
-        log(msg + HexDump.toHexString(packet, 0, length));
+        log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
     }
 
     private void processRa(byte[] packet, int length) {
@@ -608,7 +613,7 @@
 
         pw.println(String.format(
                 "Last program length %d, installed %ds ago, lifetime %d",
-                mLastInstalledProgramLength, curTime() - mLastTimeInstalledProgram,
+                mLastInstalledProgram.length, curTime() - mLastTimeInstalledProgram,
                 mLastInstalledProgramMinLifetime));
 
         pw.println("RA filters:");
@@ -618,8 +623,22 @@
             pw.increaseIndent();
             pw.println(String.format(
                     "Seen: %d, last %ds ago", ra.seenCount, curTime() - ra.mLastSeen));
+            if (DBG) {
+                pw.println("Last match:");
+                pw.increaseIndent();
+                pw.println(ra.getLastMatchingPacket());
+                pw.decreaseIndent();
+            }
             pw.decreaseIndent();
         }
+
+        if (DBG) {
+            pw.println("Last program:");
+            pw.increaseIndent();
+            pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
+            pw.decreaseIndent();
+        }
+
         pw.decreaseIndent();
     }
 }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a3622b5..715f1e5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (C) 2011 The Android Open Source Project
  *
@@ -650,18 +651,27 @@
 
     @Override
     public UserInfo getUserInfo(int userId) {
+        checkManageUsersPermission("query user");
+        synchronized (mUsersLock) {
+            return getUserInfoLU(userId);
+        }
+    }
+
+    @Override
+    public boolean isManagedProfile(int userId) {
         int callingUserId = UserHandle.getCallingUserId();
         if (callingUserId != userId && !hasManageUsersPermission()) {
             synchronized (mPackagesLock) {
                 if (!isSameProfileGroupLP(callingUserId, userId)) {
                     throw new SecurityException(
-                            "You need MANAGE_USERS permission to: query users outside profile" +
-                                    " group");
+                            "You need MANAGE_USERS permission to: check if specified user a " +
+                            "managed profile outside your profile group");
                 }
             }
         }
         synchronized (mUsersLock) {
-            return getUserInfoLU(userId);
+            UserInfo userInfo =  getUserInfoLU(userId);
+            return userInfo != null && userInfo.isManagedProfile();
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 34f2e2e..8e11511 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -1008,29 +1008,41 @@
     private class TestNetworkCallback extends NetworkCallback {
         private final ConditionVariable mConditionVariable = new ConditionVariable();
         private CallbackState mLastCallback = CallbackState.NONE;
+        private Network mLastNetwork;
 
         public void onAvailable(Network network) {
             assertEquals(CallbackState.NONE, mLastCallback);
             mLastCallback = CallbackState.AVAILABLE;
+            mLastNetwork = network;
             mConditionVariable.open();
         }
 
         public void onLosing(Network network, int maxMsToLive) {
             assertEquals(CallbackState.NONE, mLastCallback);
             mLastCallback = CallbackState.LOSING;
+            mLastNetwork = network;
             mConditionVariable.open();
         }
 
         public void onLost(Network network) {
             assertEquals(CallbackState.NONE, mLastCallback);
             mLastCallback = CallbackState.LOST;
+            mLastNetwork = network;
             mConditionVariable.open();
         }
 
         void expectCallback(CallbackState state) {
+            expectCallback(state, null);
+        }
+
+        void expectCallback(CallbackState state, MockNetworkAgent mockAgent) {
             waitFor(mConditionVariable);
             assertEquals(state, mLastCallback);
+            if (mockAgent != null) {
+                assertEquals(mockAgent.getNetwork(), mLastNetwork);
+            }
             mLastCallback = CallbackState.NONE;
+            mLastNetwork = null;
             mConditionVariable.close();
         }
 
@@ -1389,6 +1401,55 @@
                 execptionCalled);
     }
 
+    @LargeTest
+    public void testRegisterDefaultNetworkCallback() throws Exception {
+        final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
+        defaultNetworkCallback.assertNoCallback();
+
+        // Create a TRANSPORT_CELLULAR request to keep the mobile interface up
+        // whenever Wi-Fi is up. Without this, the mobile network agent is
+        // reaped before any other activity can take place.
+        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+        final NetworkRequest cellRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build();
+        mCm.requestNetwork(cellRequest, cellNetworkCallback);
+        cellNetworkCallback.assertNoCallback();
+
+        // Bring up cell and expect CALLBACK_AVAILABLE.
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+
+        // Bring up wifi and expect CALLBACK_AVAILABLE.
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+        cellNetworkCallback.assertNoCallback();
+        defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+
+        // Bring down cell. Expect no default network callback, since it wasn't the default.
+        mCellNetworkAgent.disconnect();
+        cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+        defaultNetworkCallback.assertNoCallback();
+
+        // Bring up cell. Expect no default network callback, since it won't be the default.
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultNetworkCallback.assertNoCallback();
+
+        // Bring down wifi. Expect the default network callback to notified of LOST wifi
+        // followed by AVAILABLE cell.
+        mWiFiNetworkAgent.disconnect();
+        cellNetworkCallback.assertNoCallback();
+        defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+        defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        mCellNetworkAgent.disconnect();
+        cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+        defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+    }
+
     private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
 
         public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
index 1ca94dc..ff3f19f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -48,7 +48,7 @@
 
     // ---- delegate data ----
 
-    private final int mSrcColor;
+    private final java.awt.Color mSrcColor;
     private final Mode mMode;
 
 
@@ -66,9 +66,9 @@
 
     @Override
     public void applyFilter(Graphics2D g, int width, int height) {
-        BufferedImage image = createFilterImage(width, height);
         g.setComposite(getComposite(mMode, 0xFF));
-        g.drawImage(image, 0, 0, null);
+        g.setColor(mSrcColor);
+        g.fillRect(0, 0, width, height);
     }
 
     // ---- native methods ----
@@ -84,22 +84,10 @@
     // ---- Private delegate/helper methods ----
 
     private PorterDuffColorFilter_Delegate(int srcColor, int mode) {
-        mSrcColor = srcColor;
+        mSrcColor = new java.awt.Color(srcColor, true /* hasAlpha */);
         mMode = getCompatibleMode(getPorterDuffMode(mode));
     }
 
-    private BufferedImage createFilterImage(int width, int height) {
-        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        Graphics2D graphics = image.createGraphics();
-        try {
-            graphics.setColor(new java.awt.Color(mSrcColor, true /* hasAlpha */));
-            graphics.fillRect(0, 0, width, height);
-        } finally {
-            graphics.dispose();
-        }
-        return image;
-    }
-
     // For filtering the colors, the src image should contain the "color" only for pixel values
     // which are not transparent in the target image. But, we are using a simple rectangular image
     // completely filled with color. Hence some Composite rules do not apply as intended. However,