Merge "Change internal intents from android.* to com.android.internal.*"
diff --git a/Android.mk b/Android.mk
index b204da7..109f610 100644
--- a/Android.mk
+++ b/Android.mk
@@ -931,6 +931,7 @@
     -since $(SRC_API_DIR)/23.txt 23 \
     -since $(SRC_API_DIR)/24.txt 24 \
     -since $(SRC_API_DIR)/25.txt 25 \
+    -since ./frameworks/base/api/current.txt O \
 		-werror -hide 111 -hide 113 \
 		-overview $(LOCAL_PATH)/core/java/overview.html
 
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml
index a8d3de0..4a4b3b4 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml
@@ -35,7 +35,7 @@
           android:layout_width="400dp"
           android:layout_height="600dp"
           android:text="@string/long_text"
-          android:autoSizeText="uniform"
+          android:autoSizeTextType="uniform"
           android:autoSizeMinTextSize="10px"
           android:textSize="20px"
           android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml
index d991862..0b326e8 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml
@@ -19,7 +19,7 @@
           android:layout_width="400dp"
           android:layout_height="600dp"
           android:text="@string/long_text"
-          android:autoSizeText="uniform"
+          android:autoSizeTextType="uniform"
           android:autoSizeMinTextSize="10px"
           android:textSize="110px"
           android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml
index 3b55b6c..2f4239d 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml
@@ -19,7 +19,7 @@
           android:layout_width="400dp"
           android:layout_height="600dp"
           android:text="@string/long_text"
-          android:autoSizeText="uniform"
+          android:autoSizeTextType="uniform"
           android:autoSizeMinTextSize="10px"
           android:textSize="1010px"
           android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml
index 64a25c2..b6be10a 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml
@@ -19,7 +19,7 @@
           android:layout_width="400dp"
           android:layout_height="600dp"
           android:text="@string/long_text"
-          android:autoSizeText="uniform"
+          android:autoSizeTextType="uniform"
           android:autoSizeMinTextSize="10px"
           android:textSize="10010px"
           android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml
index 1f60783..aed339c 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml
@@ -19,7 +19,7 @@
           android:layout_width="400dp"
           android:layout_height="600dp"
           android:text="@string/long_text"
-          android:autoSizeText="uniform"
+          android:autoSizeTextType="uniform"
           android:autoSizeMinTextSize="10px"
           android:textSize="100010px"
           android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml
index 54c7e71..62522ba 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml
@@ -19,7 +19,7 @@
           android:layout_width="400dp"
           android:layout_height="600dp"
           android:text="@string/long_text"
-          android:autoSizeText="uniform"
+          android:autoSizeTextType="uniform"
           android:autoSizeMinTextSize="10px"
           android:textSize="310px"
           android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml
index 525b2c8..f383fa4 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml
@@ -35,7 +35,7 @@
           android:layout_width="400dp"
           android:layout_height="600dp"
           android:text="@string/long_text"
-          android:autoSizeText="uniform"
+          android:autoSizeTextType="uniform"
           android:autoSizeMinTextSize="10px"
           android:textSize="15px"
           android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml
index 470c4da..04dd6c2 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml
@@ -19,7 +19,7 @@
           android:layout_width="400dp"
           android:layout_height="600dp"
           android:text="@string/long_text"
-          android:autoSizeText="uniform"
+          android:autoSizeTextType="uniform"
           android:autoSizeMinTextSize="10px"
           android:textSize="60px"
           android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml
index b8a6e0a..a8e2b38 100644
--- a/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml
@@ -19,7 +19,7 @@
           android:layout_width="400dp"
           android:layout_height="600dp"
           android:text="@string/long_text"
-          android:autoSizeText="uniform"
+          android:autoSizeTextType="uniform"
           android:autoSizeMinTextSize="10px"
           android:textSize="510px"
           android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
index 6ee6f70..c310166 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
@@ -89,7 +89,7 @@
 
             while (state.keepRunning()) {
                 TextView textView = new TextView(activity);
-                // TextView#onMeasure() gets called, which triggers TextView#autoSizeText()
+                // TextView#onLayout() gets called, which triggers TextView#autoSizeText()
                 // which is the method we want to benchmark.
                 textView.requestLayout();
             }
diff --git a/api/current.txt b/api/current.txt
index 62365cc..df31f2c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -305,7 +305,7 @@
     field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
     field public static final int autoSizePresetSizes = 16844087; // 0x1010537
     field public static final int autoSizeStepGranularity = 16844086; // 0x1010536
-    field public static final int autoSizeText = 16844085; // 0x1010535
+    field public static final int autoSizeTextType = 16844085; // 0x1010535
     field public static final int autoStart = 16843445; // 0x10102b5
     field public static final deprecated int autoText = 16843114; // 0x101016a
     field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -410,6 +410,7 @@
     field public static final int colorControlHighlight = 16843820; // 0x101042c
     field public static final int colorControlNormal = 16843817; // 0x1010429
     field public static final int colorEdgeEffect = 16843982; // 0x10104ce
+    field public static final int colorError = 16844100; // 0x1010544
     field public static final int colorFocusedHighlight = 16843663; // 0x101038f
     field public static final int colorForeground = 16842800; // 0x1010030
     field public static final int colorForegroundInverse = 16843270; // 0x1010206
@@ -1316,7 +1317,6 @@
     field public static final int textCheckMarkInverse = 16842823; // 0x1010047
     field public static final int textColor = 16842904; // 0x1010098
     field public static final int textColorAlertDialogListItem = 16843526; // 0x1010306
-    field public static final int textColorError = 16844100; // 0x1010544
     field public static final int textColorHighlight = 16842905; // 0x1010099
     field public static final int textColorHighlightInverse = 16843599; // 0x101034f
     field public static final int textColorHint = 16842906; // 0x101009a
@@ -9041,6 +9041,7 @@
     field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
     field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
     field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+    field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
@@ -10102,10 +10103,12 @@
     ctor public LauncherApps.ShortcutQuery();
     method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
     method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+    method public android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent);
     method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
     method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
     method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
     field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+    field public static final int FLAG_MATCH_CHOOSER = 16; // 0x10
     field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
     field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
     field public static final int FLAG_MATCH_PINNED = 2; // 0x2
@@ -10644,6 +10647,9 @@
     method public int describeContents();
     method public android.content.ComponentName getActivity();
     method public java.util.Set<java.lang.String> getCategories();
+    method public android.content.ComponentName[] getChooserComponentNames();
+    method public android.os.PersistableBundle getChooserExtras();
+    method public android.content.IntentFilter[] getChooserIntentFilters();
     method public java.lang.CharSequence getDisabledMessage();
     method public android.os.PersistableBundle getExtras();
     method public java.lang.String getId();
@@ -10656,6 +10662,7 @@
     method public java.lang.CharSequence getShortLabel();
     method public android.os.UserHandle getUserHandle();
     method public boolean hasKeyFieldsOnly();
+    method public boolean isChooser();
     method public boolean isDeclaredInManifest();
     method public boolean isDynamic();
     method public boolean isEnabled();
@@ -10668,9 +10675,11 @@
 
   public static class ShortcutInfo.Builder {
     ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName);
     method public android.content.pm.ShortcutInfo build();
     method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
     method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
+    method public android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle);
     method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
     method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
@@ -12575,6 +12584,7 @@
     method public static android.graphics.ColorSpace.Adaptation valueOf(java.lang.String);
     method public static final android.graphics.ColorSpace.Adaptation[] values();
     enum_constant public static final android.graphics.ColorSpace.Adaptation BRADFORD;
+    enum_constant public static final android.graphics.ColorSpace.Adaptation CIECAT02;
     enum_constant public static final android.graphics.ColorSpace.Adaptation VON_KRIES;
   }
 
@@ -14011,6 +14021,8 @@
 
   public class ArcShape extends android.graphics.drawable.shapes.RectShape {
     ctor public ArcShape(float, float);
+    method public final float getStartAngle();
+    method public final float getSweepAngle();
   }
 
   public class OvalShape extends android.graphics.drawable.shapes.RectShape {
@@ -20997,13 +21009,14 @@
     field public long nanoTime;
   }
 
-  public class AudioTrack implements android.media.AudioRouting {
+  public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
     ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
     method public int attachAuxEffect(int);
+    method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
     method public void flush();
     method public int getAudioFormat();
     method public int getAudioSessionId();
@@ -22161,6 +22174,7 @@
     field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
     field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
     field public static final java.lang.String KEY_LANGUAGE = "language";
+    field public static final java.lang.String KEY_LATENCY = "latency";
     field public static final java.lang.String KEY_LEVEL = "level";
     field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
     field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
@@ -22344,7 +22358,7 @@
     field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
   }
 
-  public class MediaPlayer {
+  public class MediaPlayer implements android.media.VolumeAutomation {
     ctor public MediaPlayer();
     method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -22356,6 +22370,7 @@
     method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
     method public static android.media.MediaPlayer create(android.content.Context, int);
     method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
+    method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
     method public void deselectTrack(int) throws java.lang.IllegalStateException;
     method public int getAudioSessionId();
     method public android.media.BufferingParams getBufferingParams();
@@ -23183,6 +23198,10 @@
     ctor public UnsupportedSchemeException(java.lang.String);
   }
 
+  public abstract interface VolumeAutomation {
+    method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
+  }
+
   public abstract class VolumeProvider {
     ctor public VolumeProvider(int, int, int);
     method public final int getCurrentVolume();
@@ -23196,6 +23215,53 @@
     field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
   }
 
+  public final class VolumeShaper implements java.lang.AutoCloseable {
+    method public void apply(android.media.VolumeShaper.Operation);
+    method public void close();
+    method public float getVolume();
+    method public void replace(android.media.VolumeShaper.Configuration, android.media.VolumeShaper.Operation, boolean);
+  }
+
+  public static final class VolumeShaper.Configuration implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getDurationMs();
+    method public int getInterpolatorType();
+    method public static int getMaximumCurvePoints();
+    method public float[] getTimes();
+    method public float[] getVolumes();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Configuration> CREATOR;
+    field public static final android.media.VolumeShaper.Configuration CUBIC_RAMP;
+    field public static final int INTERPOLATOR_TYPE_CUBIC = 2; // 0x2
+    field public static final int INTERPOLATOR_TYPE_CUBIC_MONOTONIC = 3; // 0x3
+    field public static final int INTERPOLATOR_TYPE_LINEAR = 1; // 0x1
+    field public static final int INTERPOLATOR_TYPE_STEP = 0; // 0x0
+    field public static final android.media.VolumeShaper.Configuration LINEAR_RAMP;
+    field public static final android.media.VolumeShaper.Configuration SCURVE_RAMP;
+    field public static final android.media.VolumeShaper.Configuration SINE_RAMP;
+  }
+
+  public static final class VolumeShaper.Configuration.Builder {
+    ctor public VolumeShaper.Configuration.Builder();
+    ctor public VolumeShaper.Configuration.Builder(android.media.VolumeShaper.Configuration);
+    method public android.media.VolumeShaper.Configuration build();
+    method public android.media.VolumeShaper.Configuration.Builder invertVolumes();
+    method public android.media.VolumeShaper.Configuration.Builder reflectTimes();
+    method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
+    method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
+    method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
+    method public android.media.VolumeShaper.Configuration.Builder setDurationMs(double);
+    method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
+  }
+
+  public static final class VolumeShaper.Operation implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Operation> CREATOR;
+    field public static final android.media.VolumeShaper.Operation PLAY;
+    field public static final android.media.VolumeShaper.Operation REVERSE;
+  }
+
 }
 
 package android.media.audiofx {
@@ -26075,8 +26141,6 @@
   public class DiscoverySession {
     method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
     method public void destroy();
-    method public static int getMaxSendRetryCount();
-    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
     method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
   }
 
@@ -36321,10 +36385,10 @@
   public static final class FillResponse.Builder {
     ctor public FillResponse.Builder();
     method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
-    method public android.service.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
     method public android.service.autofill.FillResponse build();
     method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
     method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
   }
 
   public final class SaveCallback {
@@ -36332,6 +36396,23 @@
     method public void onSuccess();
   }
 
+  public final class SaveInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
+    field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
+    field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+    field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
+    field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+  }
+
+  public static final class SaveInfo.Builder {
+    ctor public SaveInfo.Builder(int);
+    method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...);
+    method public android.service.autofill.SaveInfo build();
+    method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
+  }
+
 }
 
 package android.service.carrier {
@@ -42447,30 +42528,51 @@
     method public abstract void setValue(T, float);
   }
 
-  public final class Half {
+  public final class Half extends java.lang.Number implements java.lang.Comparable {
+    ctor public Half(short);
+    ctor public Half(float);
+    ctor public Half(double);
+    ctor public Half(java.lang.String) throws java.lang.NumberFormatException;
     method public static short abs(short);
     method public static short ceil(short);
+    method public static int compare(short, short);
+    method public int compareTo(android.util.Half);
     method public static short copySign(short, short);
+    method public double doubleValue();
     method public static boolean equals(short, short);
+    method public float floatValue();
     method public static short floor(short);
     method public static int getExponent(short);
     method public static int getSign(short);
     method public static int getSignificand(short);
     method public static boolean greater(short, short);
     method public static boolean greaterEquals(short, short);
+    method public static int halfToIntBits(short);
+    method public static int halfToRawIntBits(short);
+    method public static short halfToShortBits(short);
+    method public short halfValue();
+    method public static int hashCode(short);
+    method public static short intBitsToHalf(int);
+    method public int intValue();
     method public static boolean isInfinite(short);
+    method public boolean isNaN();
     method public static boolean isNaN(short);
     method public static boolean isNormalized(short);
     method public static boolean less(short, short);
     method public static boolean lessEquals(short, short);
+    method public long longValue();
     method public static short max(short, short);
     method public static short min(short, short);
+    method public static short parseHalf(java.lang.String) throws java.lang.NumberFormatException;
     method public static short round(short);
     method public static float toFloat(short);
+    method public static short toHalf(float);
     method public static java.lang.String toHexString(short);
     method public static java.lang.String toString(short);
     method public static short trunc(short);
-    method public static short valueOf(float);
+    method public static android.util.Half valueOf(short);
+    method public static android.util.Half valueOf(float);
+    method public static android.util.Half valueOf(java.lang.String);
     field public static final short EPSILON = 5120; // 0x1400
     field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
     field public static final int MAX_EXPONENT = 15; // 0xf
@@ -44574,8 +44676,8 @@
     method public void drawableHotspotChanged(float, float);
     method protected void drawableStateChanged();
     method public android.view.View findFocus();
-    method public final android.view.View findViewById(int);
-    method public final android.view.View findViewWithTag(java.lang.Object);
+    method public final <T extends android.view.View> T findViewById(int);
+    method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
diff --git a/api/removed.txt b/api/removed.txt
index e467811..c5dbf8d 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -20,25 +20,14 @@
 package android.content {
 
   public abstract class Context {
-    method public deprecated android.content.Context createCredentialEncryptedStorageContext();
-    method public deprecated android.content.Context createDeviceEncryptedStorageContext();
     method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
     method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
-    method public deprecated boolean isCredentialEncryptedStorage();
-    method public deprecated boolean isDeviceEncryptedStorage();
-    method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public deprecated boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
   }
 
 }
 
 package android.content.pm {
 
-  public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
-    field public deprecated java.lang.String credentialEncryptedDataDir;
-    field public deprecated java.lang.String deviceEncryptedDataDir;
-  }
-
   public class ComponentInfo extends android.content.pm.PackageItemInfo {
     field public deprecated boolean encryptionAware;
   }
@@ -47,12 +36,6 @@
     field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
   }
 
-  public abstract class PackageManager {
-    field public static final deprecated int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
-    field public static final deprecated int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final deprecated int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
-  }
-
 }
 
 package android.database {
@@ -169,10 +152,6 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndLocked();
-    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndUnlocked();
-    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
   }
 
 }
@@ -190,15 +169,6 @@
 
 }
 
-package android.preference {
-
-  public class PreferenceManager {
-    method public deprecated void setStorageCredentialEncrypted();
-    method public deprecated void setStorageDeviceEncrypted();
-  }
-
-}
-
 package android.provider {
 
   public class Browser {
diff --git a/api/system-current.txt b/api/system-current.txt
index 8626f1b..dcf62cd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -418,7 +418,7 @@
     field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
     field public static final int autoSizePresetSizes = 16844087; // 0x1010537
     field public static final int autoSizeStepGranularity = 16844086; // 0x1010536
-    field public static final int autoSizeText = 16844085; // 0x1010535
+    field public static final int autoSizeTextType = 16844085; // 0x1010535
     field public static final int autoStart = 16843445; // 0x10102b5
     field public static final deprecated int autoText = 16843114; // 0x101016a
     field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -523,6 +523,7 @@
     field public static final int colorControlHighlight = 16843820; // 0x101042c
     field public static final int colorControlNormal = 16843817; // 0x1010429
     field public static final int colorEdgeEffect = 16843982; // 0x10104ce
+    field public static final int colorError = 16844100; // 0x1010544
     field public static final int colorFocusedHighlight = 16843663; // 0x101038f
     field public static final int colorForeground = 16842800; // 0x1010030
     field public static final int colorForegroundInverse = 16843270; // 0x1010206
@@ -1433,7 +1434,6 @@
     field public static final int textCheckMarkInverse = 16842823; // 0x1010047
     field public static final int textColor = 16842904; // 0x1010098
     field public static final int textColorAlertDialogListItem = 16843526; // 0x1010306
-    field public static final int textColorError = 16844100; // 0x1010544
     field public static final int textColorHighlight = 16842905; // 0x1010099
     field public static final int textColorHighlightInverse = 16843599; // 0x101034f
     field public static final int textColorHint = 16842906; // 0x101009a
@@ -9515,6 +9515,7 @@
     field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
     field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
     field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+    field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
@@ -10639,10 +10640,12 @@
     ctor public LauncherApps.ShortcutQuery();
     method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
     method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+    method public android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent);
     method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
     method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
     method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
     field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+    field public static final int FLAG_MATCH_CHOOSER = 16; // 0x10
     field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
     field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
     field public static final int FLAG_MATCH_PINNED = 2; // 0x2
@@ -11266,6 +11269,9 @@
     method public int describeContents();
     method public android.content.ComponentName getActivity();
     method public java.util.Set<java.lang.String> getCategories();
+    method public android.content.ComponentName[] getChooserComponentNames();
+    method public android.os.PersistableBundle getChooserExtras();
+    method public android.content.IntentFilter[] getChooserIntentFilters();
     method public java.lang.CharSequence getDisabledMessage();
     method public android.os.PersistableBundle getExtras();
     method public java.lang.String getId();
@@ -11278,6 +11284,7 @@
     method public java.lang.CharSequence getShortLabel();
     method public android.os.UserHandle getUserHandle();
     method public boolean hasKeyFieldsOnly();
+    method public boolean isChooser();
     method public boolean isDeclaredInManifest();
     method public boolean isDynamic();
     method public boolean isEnabled();
@@ -11290,9 +11297,11 @@
 
   public static class ShortcutInfo.Builder {
     ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName);
     method public android.content.pm.ShortcutInfo build();
     method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
     method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
+    method public android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle);
     method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
     method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
@@ -13211,6 +13220,7 @@
     method public static android.graphics.ColorSpace.Adaptation valueOf(java.lang.String);
     method public static final android.graphics.ColorSpace.Adaptation[] values();
     enum_constant public static final android.graphics.ColorSpace.Adaptation BRADFORD;
+    enum_constant public static final android.graphics.ColorSpace.Adaptation CIECAT02;
     enum_constant public static final android.graphics.ColorSpace.Adaptation VON_KRIES;
   }
 
@@ -14647,6 +14657,8 @@
 
   public class ArcShape extends android.graphics.drawable.shapes.RectShape {
     ctor public ArcShape(float, float);
+    method public final float getStartAngle();
+    method public final float getSweepAngle();
   }
 
   public class OvalShape extends android.graphics.drawable.shapes.RectShape {
@@ -22685,13 +22697,14 @@
     field public long nanoTime;
   }
 
-  public class AudioTrack implements android.media.AudioRouting {
+  public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
     ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
     method public int attachAuxEffect(int);
+    method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
     method public void flush();
     method public int getAudioFormat();
     method public int getAudioSessionId();
@@ -23849,6 +23862,7 @@
     field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
     field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
     field public static final java.lang.String KEY_LANGUAGE = "language";
+    field public static final java.lang.String KEY_LATENCY = "latency";
     field public static final java.lang.String KEY_LEVEL = "level";
     field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
     field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
@@ -24032,7 +24046,7 @@
     field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
   }
 
-  public class MediaPlayer {
+  public class MediaPlayer implements android.media.VolumeAutomation {
     ctor public MediaPlayer();
     method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -24044,6 +24058,7 @@
     method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
     method public static android.media.MediaPlayer create(android.content.Context, int);
     method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
+    method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
     method public void deselectTrack(int) throws java.lang.IllegalStateException;
     method public int getAudioSessionId();
     method public android.media.BufferingParams getBufferingParams();
@@ -24882,6 +24897,10 @@
     ctor public UnsupportedSchemeException(java.lang.String);
   }
 
+  public abstract interface VolumeAutomation {
+    method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
+  }
+
   public abstract class VolumeProvider {
     ctor public VolumeProvider(int, int, int);
     method public final int getCurrentVolume();
@@ -24895,6 +24914,53 @@
     field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
   }
 
+  public final class VolumeShaper implements java.lang.AutoCloseable {
+    method public void apply(android.media.VolumeShaper.Operation);
+    method public void close();
+    method public float getVolume();
+    method public void replace(android.media.VolumeShaper.Configuration, android.media.VolumeShaper.Operation, boolean);
+  }
+
+  public static final class VolumeShaper.Configuration implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getDurationMs();
+    method public int getInterpolatorType();
+    method public static int getMaximumCurvePoints();
+    method public float[] getTimes();
+    method public float[] getVolumes();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Configuration> CREATOR;
+    field public static final android.media.VolumeShaper.Configuration CUBIC_RAMP;
+    field public static final int INTERPOLATOR_TYPE_CUBIC = 2; // 0x2
+    field public static final int INTERPOLATOR_TYPE_CUBIC_MONOTONIC = 3; // 0x3
+    field public static final int INTERPOLATOR_TYPE_LINEAR = 1; // 0x1
+    field public static final int INTERPOLATOR_TYPE_STEP = 0; // 0x0
+    field public static final android.media.VolumeShaper.Configuration LINEAR_RAMP;
+    field public static final android.media.VolumeShaper.Configuration SCURVE_RAMP;
+    field public static final android.media.VolumeShaper.Configuration SINE_RAMP;
+  }
+
+  public static final class VolumeShaper.Configuration.Builder {
+    ctor public VolumeShaper.Configuration.Builder();
+    ctor public VolumeShaper.Configuration.Builder(android.media.VolumeShaper.Configuration);
+    method public android.media.VolumeShaper.Configuration build();
+    method public android.media.VolumeShaper.Configuration.Builder invertVolumes();
+    method public android.media.VolumeShaper.Configuration.Builder reflectTimes();
+    method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
+    method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
+    method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
+    method public android.media.VolumeShaper.Configuration.Builder setDurationMs(double);
+    method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
+  }
+
+  public static final class VolumeShaper.Operation implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Operation> CREATOR;
+    field public static final android.media.VolumeShaper.Operation PLAY;
+    field public static final android.media.VolumeShaper.Operation REVERSE;
+  }
+
 }
 
 package android.media.audiofx {
@@ -25876,6 +25942,12 @@
     method public static final boolean isChannelUriForTunerInput(android.net.Uri);
     method public static final boolean isProgramUri(android.net.Uri);
     field public static final java.lang.String AUTHORITY = "android.media.tv";
+    field public static final java.lang.String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
+    field public static final java.lang.String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
+    field public static final java.lang.String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
+    field public static final java.lang.String EXTRA_EXISTING_COLUMN_NAMES = "android.media.tv.extra.EXISTING_COLUMN_NAMES";
+    field public static final java.lang.String METHOD_ADD_COLUMN = "add_column";
+    field public static final java.lang.String METHOD_GET_COLUMNS = "get_columns";
   }
 
   public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
@@ -27124,7 +27196,8 @@
   }
 
   public abstract class NetworkRecommendationProvider {
-    ctor public NetworkRecommendationProvider(android.os.Handler);
+    ctor public deprecated NetworkRecommendationProvider(android.os.Handler);
+    ctor public NetworkRecommendationProvider(android.content.Context, java.util.concurrent.Executor);
     method public final android.os.IBinder getBinder();
     method public abstract void onRequestRecommendation(android.net.RecommendationRequest, android.net.NetworkRecommendationProvider.ResultCallback);
     method public abstract void onRequestScores(android.net.NetworkKey[]);
@@ -28653,8 +28726,6 @@
   public class DiscoverySession {
     method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
     method public void destroy();
-    method public static int getMaxSendRetryCount();
-    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
     method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
   }
 
@@ -39234,10 +39305,10 @@
   public static final class FillResponse.Builder {
     ctor public FillResponse.Builder();
     method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
-    method public android.service.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
     method public android.service.autofill.FillResponse build();
     method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
     method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
   }
 
   public final class SaveCallback {
@@ -39245,6 +39316,23 @@
     method public void onSuccess();
   }
 
+  public final class SaveInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
+    field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
+    field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+    field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
+    field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+  }
+
+  public static final class SaveInfo.Builder {
+    ctor public SaveInfo.Builder(int);
+    method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...);
+    method public android.service.autofill.SaveInfo build();
+    method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
+  }
+
 }
 
 package android.service.carrier {
@@ -45785,30 +45873,51 @@
     method public abstract void setValue(T, float);
   }
 
-  public final class Half {
+  public final class Half extends java.lang.Number implements java.lang.Comparable {
+    ctor public Half(short);
+    ctor public Half(float);
+    ctor public Half(double);
+    ctor public Half(java.lang.String) throws java.lang.NumberFormatException;
     method public static short abs(short);
     method public static short ceil(short);
+    method public static int compare(short, short);
+    method public int compareTo(android.util.Half);
     method public static short copySign(short, short);
+    method public double doubleValue();
     method public static boolean equals(short, short);
+    method public float floatValue();
     method public static short floor(short);
     method public static int getExponent(short);
     method public static int getSign(short);
     method public static int getSignificand(short);
     method public static boolean greater(short, short);
     method public static boolean greaterEquals(short, short);
+    method public static int halfToIntBits(short);
+    method public static int halfToRawIntBits(short);
+    method public static short halfToShortBits(short);
+    method public short halfValue();
+    method public static int hashCode(short);
+    method public static short intBitsToHalf(int);
+    method public int intValue();
     method public static boolean isInfinite(short);
+    method public boolean isNaN();
     method public static boolean isNaN(short);
     method public static boolean isNormalized(short);
     method public static boolean less(short, short);
     method public static boolean lessEquals(short, short);
+    method public long longValue();
     method public static short max(short, short);
     method public static short min(short, short);
+    method public static short parseHalf(java.lang.String) throws java.lang.NumberFormatException;
     method public static short round(short);
     method public static float toFloat(short);
+    method public static short toHalf(float);
     method public static java.lang.String toHexString(short);
     method public static java.lang.String toString(short);
     method public static short trunc(short);
-    method public static short valueOf(float);
+    method public static android.util.Half valueOf(short);
+    method public static android.util.Half valueOf(float);
+    method public static android.util.Half valueOf(java.lang.String);
     field public static final short EPSILON = 5120; // 0x1400
     field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
     field public static final int MAX_EXPONENT = 15; // 0xf
@@ -47912,8 +48021,8 @@
     method public void drawableHotspotChanged(float, float);
     method protected void drawableStateChanged();
     method public android.view.View findFocus();
-    method public final android.view.View findViewById(int);
-    method public final android.view.View findViewWithTag(java.lang.Object);
+    method public final <T extends android.view.View> T findViewById(int);
+    method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 6773112..a3093e2 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -18,25 +18,14 @@
 package android.content {
 
   public abstract class Context {
-    method public deprecated android.content.Context createCredentialEncryptedStorageContext();
-    method public deprecated android.content.Context createDeviceEncryptedStorageContext();
     method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
     method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
-    method public deprecated boolean isCredentialEncryptedStorage();
-    method public deprecated boolean isDeviceEncryptedStorage();
-    method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public deprecated boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
   }
 
 }
 
 package android.content.pm {
 
-  public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
-    field public deprecated java.lang.String credentialEncryptedDataDir;
-    field public deprecated java.lang.String deviceEncryptedDataDir;
-  }
-
   public class ComponentInfo extends android.content.pm.PackageItemInfo {
     field public deprecated boolean encryptionAware;
   }
@@ -45,12 +34,6 @@
     field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
   }
 
-  public abstract class PackageManager {
-    field public static final deprecated int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
-    field public static final deprecated int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final deprecated int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
-  }
-
 }
 
 package android.database {
@@ -163,10 +146,6 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndLocked();
-    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndUnlocked();
-    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
   }
 
 }
@@ -184,15 +163,6 @@
 
 }
 
-package android.preference {
-
-  public class PreferenceManager {
-    method public deprecated void setStorageCredentialEncrypted();
-    method public deprecated void setStorageDeviceEncrypted();
-  }
-
-}
-
 package android.provider {
 
   public class Browser {
diff --git a/api/test-current.txt b/api/test-current.txt
index 44386be..d90b5f0 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -305,7 +305,7 @@
     field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
     field public static final int autoSizePresetSizes = 16844087; // 0x1010537
     field public static final int autoSizeStepGranularity = 16844086; // 0x1010536
-    field public static final int autoSizeText = 16844085; // 0x1010535
+    field public static final int autoSizeTextType = 16844085; // 0x1010535
     field public static final int autoStart = 16843445; // 0x10102b5
     field public static final deprecated int autoText = 16843114; // 0x101016a
     field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -410,6 +410,7 @@
     field public static final int colorControlHighlight = 16843820; // 0x101042c
     field public static final int colorControlNormal = 16843817; // 0x1010429
     field public static final int colorEdgeEffect = 16843982; // 0x10104ce
+    field public static final int colorError = 16844100; // 0x1010544
     field public static final int colorFocusedHighlight = 16843663; // 0x101038f
     field public static final int colorForeground = 16842800; // 0x1010030
     field public static final int colorForegroundInverse = 16843270; // 0x1010206
@@ -1316,7 +1317,6 @@
     field public static final int textCheckMarkInverse = 16842823; // 0x1010047
     field public static final int textColor = 16842904; // 0x1010098
     field public static final int textColorAlertDialogListItem = 16843526; // 0x1010306
-    field public static final int textColorError = 16844100; // 0x1010544
     field public static final int textColorHighlight = 16842905; // 0x1010099
     field public static final int textColorHighlightInverse = 16843599; // 0x101034f
     field public static final int textColorHint = 16842906; // 0x101009a
@@ -9070,6 +9070,7 @@
     field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
     field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
     field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+    field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
@@ -10134,10 +10135,12 @@
     ctor public LauncherApps.ShortcutQuery();
     method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
     method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+    method public android.content.pm.LauncherApps.ShortcutQuery setIntent(android.content.Intent);
     method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
     method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
     method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
     field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+    field public static final int FLAG_MATCH_CHOOSER = 16; // 0x10
     field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
     field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
     field public static final int FLAG_MATCH_PINNED = 2; // 0x2
@@ -10680,6 +10683,9 @@
     method public int describeContents();
     method public android.content.ComponentName getActivity();
     method public java.util.Set<java.lang.String> getCategories();
+    method public android.content.ComponentName[] getChooserComponentNames();
+    method public android.os.PersistableBundle getChooserExtras();
+    method public android.content.IntentFilter[] getChooserIntentFilters();
     method public java.lang.CharSequence getDisabledMessage();
     method public android.os.PersistableBundle getExtras();
     method public java.lang.String getId();
@@ -10692,6 +10698,7 @@
     method public java.lang.CharSequence getShortLabel();
     method public android.os.UserHandle getUserHandle();
     method public boolean hasKeyFieldsOnly();
+    method public boolean isChooser();
     method public boolean isDeclaredInManifest();
     method public boolean isDynamic();
     method public boolean isEnabled();
@@ -10704,9 +10711,11 @@
 
   public static class ShortcutInfo.Builder {
     ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder addChooserIntentFilter(android.content.IntentFilter, android.content.ComponentName);
     method public android.content.pm.ShortcutInfo build();
     method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
     method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
+    method public android.content.pm.ShortcutInfo.Builder setChooserExtras(android.os.PersistableBundle);
     method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
     method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
@@ -12612,6 +12621,7 @@
     method public static android.graphics.ColorSpace.Adaptation valueOf(java.lang.String);
     method public static final android.graphics.ColorSpace.Adaptation[] values();
     enum_constant public static final android.graphics.ColorSpace.Adaptation BRADFORD;
+    enum_constant public static final android.graphics.ColorSpace.Adaptation CIECAT02;
     enum_constant public static final android.graphics.ColorSpace.Adaptation VON_KRIES;
   }
 
@@ -14049,6 +14059,8 @@
 
   public class ArcShape extends android.graphics.drawable.shapes.RectShape {
     ctor public ArcShape(float, float);
+    method public final float getStartAngle();
+    method public final float getSweepAngle();
   }
 
   public class OvalShape extends android.graphics.drawable.shapes.RectShape {
@@ -21093,13 +21105,14 @@
     field public long nanoTime;
   }
 
-  public class AudioTrack implements android.media.AudioRouting {
+  public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
     ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
     method public int attachAuxEffect(int);
+    method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
     method public void flush();
     method public int getAudioFormat();
     method public int getAudioSessionId();
@@ -22257,6 +22270,7 @@
     field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
     field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
     field public static final java.lang.String KEY_LANGUAGE = "language";
+    field public static final java.lang.String KEY_LATENCY = "latency";
     field public static final java.lang.String KEY_LEVEL = "level";
     field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
     field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
@@ -22440,7 +22454,7 @@
     field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
   }
 
-  public class MediaPlayer {
+  public class MediaPlayer implements android.media.VolumeAutomation {
     ctor public MediaPlayer();
     method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -22452,6 +22466,7 @@
     method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
     method public static android.media.MediaPlayer create(android.content.Context, int);
     method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
+    method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
     method public void deselectTrack(int) throws java.lang.IllegalStateException;
     method public int getAudioSessionId();
     method public android.media.BufferingParams getBufferingParams();
@@ -23279,6 +23294,10 @@
     ctor public UnsupportedSchemeException(java.lang.String);
   }
 
+  public abstract interface VolumeAutomation {
+    method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
+  }
+
   public abstract class VolumeProvider {
     ctor public VolumeProvider(int, int, int);
     method public final int getCurrentVolume();
@@ -23292,6 +23311,53 @@
     field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
   }
 
+  public final class VolumeShaper implements java.lang.AutoCloseable {
+    method public void apply(android.media.VolumeShaper.Operation);
+    method public void close();
+    method public float getVolume();
+    method public void replace(android.media.VolumeShaper.Configuration, android.media.VolumeShaper.Operation, boolean);
+  }
+
+  public static final class VolumeShaper.Configuration implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getDurationMs();
+    method public int getInterpolatorType();
+    method public static int getMaximumCurvePoints();
+    method public float[] getTimes();
+    method public float[] getVolumes();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Configuration> CREATOR;
+    field public static final android.media.VolumeShaper.Configuration CUBIC_RAMP;
+    field public static final int INTERPOLATOR_TYPE_CUBIC = 2; // 0x2
+    field public static final int INTERPOLATOR_TYPE_CUBIC_MONOTONIC = 3; // 0x3
+    field public static final int INTERPOLATOR_TYPE_LINEAR = 1; // 0x1
+    field public static final int INTERPOLATOR_TYPE_STEP = 0; // 0x0
+    field public static final android.media.VolumeShaper.Configuration LINEAR_RAMP;
+    field public static final android.media.VolumeShaper.Configuration SCURVE_RAMP;
+    field public static final android.media.VolumeShaper.Configuration SINE_RAMP;
+  }
+
+  public static final class VolumeShaper.Configuration.Builder {
+    ctor public VolumeShaper.Configuration.Builder();
+    ctor public VolumeShaper.Configuration.Builder(android.media.VolumeShaper.Configuration);
+    method public android.media.VolumeShaper.Configuration build();
+    method public android.media.VolumeShaper.Configuration.Builder invertVolumes();
+    method public android.media.VolumeShaper.Configuration.Builder reflectTimes();
+    method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
+    method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
+    method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
+    method public android.media.VolumeShaper.Configuration.Builder setDurationMs(double);
+    method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
+  }
+
+  public static final class VolumeShaper.Operation implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Operation> CREATOR;
+    field public static final android.media.VolumeShaper.Operation PLAY;
+    field public static final android.media.VolumeShaper.Operation REVERSE;
+  }
+
 }
 
 package android.media.audiofx {
@@ -26171,8 +26237,6 @@
   public class DiscoverySession {
     method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
     method public void destroy();
-    method public static int getMaxSendRetryCount();
-    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
     method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
   }
 
@@ -36460,10 +36524,10 @@
   public static final class FillResponse.Builder {
     ctor public FillResponse.Builder();
     method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
-    method public android.service.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
     method public android.service.autofill.FillResponse build();
     method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
     method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
   }
 
   public final class SaveCallback {
@@ -36471,6 +36535,23 @@
     method public void onSuccess();
   }
 
+  public final class SaveInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.SaveInfo> CREATOR;
+    field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
+    field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3
+    field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
+    field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+  }
+
+  public static final class SaveInfo.Builder {
+    ctor public SaveInfo.Builder(int);
+    method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...);
+    method public android.service.autofill.SaveInfo build();
+    method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
+  }
+
 }
 
 package android.service.carrier {
@@ -42636,30 +42717,51 @@
     method public abstract void setValue(T, float);
   }
 
-  public final class Half {
+  public final class Half extends java.lang.Number implements java.lang.Comparable {
+    ctor public Half(short);
+    ctor public Half(float);
+    ctor public Half(double);
+    ctor public Half(java.lang.String) throws java.lang.NumberFormatException;
     method public static short abs(short);
     method public static short ceil(short);
+    method public static int compare(short, short);
+    method public int compareTo(android.util.Half);
     method public static short copySign(short, short);
+    method public double doubleValue();
     method public static boolean equals(short, short);
+    method public float floatValue();
     method public static short floor(short);
     method public static int getExponent(short);
     method public static int getSign(short);
     method public static int getSignificand(short);
     method public static boolean greater(short, short);
     method public static boolean greaterEquals(short, short);
+    method public static int halfToIntBits(short);
+    method public static int halfToRawIntBits(short);
+    method public static short halfToShortBits(short);
+    method public short halfValue();
+    method public static int hashCode(short);
+    method public static short intBitsToHalf(int);
+    method public int intValue();
     method public static boolean isInfinite(short);
+    method public boolean isNaN();
     method public static boolean isNaN(short);
     method public static boolean isNormalized(short);
     method public static boolean less(short, short);
     method public static boolean lessEquals(short, short);
+    method public long longValue();
     method public static short max(short, short);
     method public static short min(short, short);
+    method public static short parseHalf(java.lang.String) throws java.lang.NumberFormatException;
     method public static short round(short);
     method public static float toFloat(short);
+    method public static short toHalf(float);
     method public static java.lang.String toHexString(short);
     method public static java.lang.String toString(short);
     method public static short trunc(short);
-    method public static short valueOf(float);
+    method public static android.util.Half valueOf(short);
+    method public static android.util.Half valueOf(float);
+    method public static android.util.Half valueOf(java.lang.String);
     field public static final short EPSILON = 5120; // 0x1400
     field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
     field public static final int MAX_EXPONENT = 15; // 0xf
@@ -44929,8 +45031,8 @@
     method public void drawableHotspotChanged(float, float);
     method protected void drawableStateChanged();
     method public android.view.View findFocus();
-    method public final android.view.View findViewById(int);
-    method public final android.view.View findViewWithTag(java.lang.Object);
+    method public final <T extends android.view.View> T findViewById(int);
+    method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index e467811..c5dbf8d 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -20,25 +20,14 @@
 package android.content {
 
   public abstract class Context {
-    method public deprecated android.content.Context createCredentialEncryptedStorageContext();
-    method public deprecated android.content.Context createDeviceEncryptedStorageContext();
     method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
     method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
-    method public deprecated boolean isCredentialEncryptedStorage();
-    method public deprecated boolean isDeviceEncryptedStorage();
-    method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
-    method public deprecated boolean migrateSharedPreferencesFrom(android.content.Context, java.lang.String);
   }
 
 }
 
 package android.content.pm {
 
-  public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
-    field public deprecated java.lang.String credentialEncryptedDataDir;
-    field public deprecated java.lang.String deviceEncryptedDataDir;
-  }
-
   public class ComponentInfo extends android.content.pm.PackageItemInfo {
     field public deprecated boolean encryptionAware;
   }
@@ -47,12 +36,6 @@
     field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
   }
 
-  public abstract class PackageManager {
-    field public static final deprecated int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
-    field public static final deprecated int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final deprecated int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
-  }
-
 }
 
 package android.database {
@@ -169,10 +152,6 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndLocked();
-    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndUnlocked();
-    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
   }
 
 }
@@ -190,15 +169,6 @@
 
 }
 
-package android.preference {
-
-  public class PreferenceManager {
-    method public deprecated void setStorageCredentialEncrypted();
-    method public deprecated void setStorageDeviceEncrypted();
-  }
-
-}
-
 package android.provider {
 
   public class Browser {
diff --git a/core/java/android/annotation/HalfFloat.java b/core/java/android/annotation/HalfFloat.java
index d3e9f08..256008c 100644
--- a/core/java/android/annotation/HalfFloat.java
+++ b/core/java/android/annotation/HalfFloat.java
@@ -37,7 +37,7 @@
  * }</pre>
  *
  * @see android.util.Half
- * @see android.util.Half#valueOf(float)
+ * @see android.util.Half#toHalf(float)
  * @see android.util.Half#toFloat(short)
  *
  * @hide
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 1652299..0608acb 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1024,12 +1024,18 @@
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public List<ProviderInfo> queryContentProviders(String processName,
             int uid, int flags) {
+        return queryContentProviders(processName, uid, flags, null);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<ProviderInfo> queryContentProviders(String processName,
+            int uid, int flags, String metaDataKey) {
         try {
             ParceledListSlice<ProviderInfo> slice =
-                    mPM.queryContentProviders(processName, uid, flags);
+                    mPM.queryContentProviders(processName, uid, flags, metaDataKey);
             return slice != null ? slice.getList() : Collections.<ProviderInfo>emptyList();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 3e9b987..7ee93d0 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -38,6 +38,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.AssetManager;
+import android.content.res.CompatResources;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -49,6 +50,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Environment;
@@ -1925,8 +1927,8 @@
             final int displayId = mDisplay != null
                     ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
 
-            c.mResources = createResources(mActivityToken, pi, displayId, null,
-                    getDisplayAdjustments(displayId).getCompatibilityInfo());
+            c.setResources(createResources(mActivityToken, pi, displayId, null,
+                    getDisplayAdjustments(displayId).getCompatibilityInfo()));
             if (c.mResources != null) {
                 return c;
             }
@@ -1962,8 +1964,8 @@
             final int displayId = mDisplay != null
                     ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
 
-            c.mResources = createResources(mActivityToken, pi, displayId, null,
-                    getDisplayAdjustments(displayId).getCompatibilityInfo());
+            c.setResources(createResources(mActivityToken, pi, displayId, null,
+                    getDisplayAdjustments(displayId).getCompatibilityInfo()));
             if (c.mResources != null) {
                 return c;
             }
@@ -1990,7 +1992,7 @@
         final int displayId = mDisplay != null
                 ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
 
-        context.mResources = ResourcesManager.getInstance().getResources(
+        context.setResources(ResourcesManager.getInstance().getResources(
                 mActivityToken,
                 mPackageInfo.getResDir(),
                 paths,
@@ -1999,7 +2001,7 @@
                 displayId,
                 null,
                 mPackageInfo.getCompatibilityInfo(),
-                classLoader);
+                classLoader));
         return context;
     }
 
@@ -2013,8 +2015,8 @@
                 mUser, mFlags, mClassLoader);
 
         final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
-        context.mResources = createResources(mActivityToken, mPackageInfo, displayId,
-                overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo());
+        context.setResources(createResources(mActivityToken, mPackageInfo, displayId,
+                overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo()));
         return context;
     }
 
@@ -2028,8 +2030,8 @@
                 mUser, mFlags, mClassLoader);
 
         final int displayId = display.getDisplayId();
-        context.mResources = createResources(mActivityToken, mPackageInfo, displayId, null,
-                getDisplayAdjustments(displayId).getCompatibilityInfo());
+        context.setResources(createResources(mActivityToken, mPackageInfo, displayId, null,
+                getDisplayAdjustments(displayId).getCompatibilityInfo()));
         context.mDisplay = display;
         return context;
     }
@@ -2136,7 +2138,7 @@
         LoadedApk packageInfo = new LoadedApk(mainThread);
         ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0,
                 null);
-        context.mResources = packageInfo.getResources();
+        context.setResources(packageInfo.getResources());
         context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
                 context.mResourcesManager.getDisplayMetrics());
         return context;
@@ -2146,7 +2148,7 @@
         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
         ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0,
                 null);
-        context.mResources = packageInfo.getResources();
+        context.setResources(packageInfo.getResources());
         return context;
     }
 
@@ -2185,7 +2187,7 @@
 
         // Create the base resources for which all configuration contexts for this Activity
         // will be rebased upon.
-        context.mResources = resourcesManager.createBaseActivityResources(activityToken,
+        context.setResources(resourcesManager.createBaseActivityResources(activityToken,
                 packageInfo.getResDir(),
                 splitDirs,
                 packageInfo.getOverlayDirs(),
@@ -2193,7 +2195,7 @@
                 displayId,
                 overrideConfiguration,
                 compatInfo,
-                classLoader);
+                classLoader));
         context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
                 context.getResources());
         return context;
@@ -2232,7 +2234,7 @@
         if (container != null) {
             mBasePackageName = container.mBasePackageName;
             mOpPackageName = container.mOpPackageName;
-            mResources = container.mResources;
+            setResources(container.mResources);
             mDisplay = container.mDisplay;
         } else {
             mBasePackageName = packageInfo.mPackageName;
@@ -2251,6 +2253,14 @@
         mContentResolver = new ApplicationContentResolver(this, mainThread, user);
     }
 
+    void setResources(Resources r) {
+        if (mPackageInfo.getTargetSdkVersion() < VERSION_CODES.O) {
+            mResources = new CompatResources(r, this);
+        } else {
+            mResources = r;
+        }
+    }
+
     void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
         mPackageInfo.installSystemApplicationInfo(info, classLoader);
     }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 812daf8..64fc44b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2702,11 +2702,11 @@
         }
 
         /**
-         * Specifies the time at which this notification should be canceled, if it is not already
-         * canceled.
+         * Specifies a duration in milliseconds after which this notification should be canceled,
+         * if it is not already canceled.
          */
-        public Builder setTimeout(long when) {
-            mN.mTimeout = when;
+        public Builder setTimeout(long durationMs) {
+            mN.mTimeout = durationMs;
             return this;
         }
 
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9cb3dd6..6585793 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3346,6 +3346,17 @@
     public static final int KEYGUARD_DISABLE_FEATURES_ALL = 0x7fffffff;
 
     /**
+     * Keyguard features that when set on a managed profile that doesn't have its own challenge will
+     * affect the profile's parent user. These can also be set on the managed profile's parent
+     * {@link DevicePolicyManager} instance.
+     *
+     * @hide
+     */
+    public static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
+            DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
+            | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+
+    /**
      * Called by an application that is administering the device to request that the storage system
      * be encrypted.
      * <p>
@@ -7697,7 +7708,34 @@
     /**
      * Called by a device owner to control the network logging feature.
      *
-     * <p> Network logs contain DNS lookup and connect() library call events.
+     * <p> Network logs contain DNS lookup and connect() library call events. The following library
+     *     functions are recorded while network logging is active:
+     *     <ul>
+     *       <li>{@code getaddrinfo()}</li>
+     *       <li>{@code gethostbyname()}</li>
+     *       <li>{@code connect()}</li>
+     *     </ul>
+     *
+     * <p> Network logging is a low-overhead tool for forensics but it is not guaranteed to use
+     *     full system call logging; event reporting is enabled by default for all processes but not
+     *     strongly enforced.
+     *     Events from applications using alternative implementations of libc, making direct kernel
+     *     calls, or deliberately obfuscating traffic may not be recorded.
+     *
+     * <p> Some common network events may not be reported. For example:
+     *     <ul>
+     *       <li>Applications may hardcode IP addresses to reduce the number of DNS lookups, or use
+     *           an alternative system for name resolution, and so avoid calling
+     *           {@code getaddrinfo()} or {@code gethostbyname}.</li>
+     *       <li>Applications may use datagram sockets for performance reasons, for example
+     *           for a game client. Calling {@code connect()} is unnecessary for this kind of
+     *           socket, so it will not trigger a network event.</li>
+     *     </ul>
+     *
+     * <p> It is possible to directly intercept layer 3 traffic leaving the device using an
+     *     always-on VPN service.
+     *     See {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)}
+     *     and {@link android.net.VpnService} for details.
      *
      * <p><strong>Note:</strong> The device owner won't be able to retrieve network logs if there
      * are unaffiliated secondary users or profiles on the device, regardless of whether the
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 4480b41..687d590 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -500,6 +500,7 @@
     public ContentResolver(Context context) {
         mContext = context != null ? context : ActivityThread.currentApplication();
         mPackageName = mContext.getOpPackageName();
+        mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
     }
 
     /** @hide */
@@ -1868,13 +1869,18 @@
     /**
      * Register an observer class that gets callbacks when data identified by a
      * given content URI changes.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+     * notifications must be backed by a valid {@link ContentProvider}.
      *
-     * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
-     * for a whole class of content.
-     * @param notifyForDescendants When false, the observer will be notified whenever a
-     * change occurs to the exact URI specified by <code>uri</code> or to one of the
-     * URI's ancestors in the path hierarchy.  When true, the observer will also be notified
-     * whenever a change occurs to the URI's descendants in the path hierarchy.
+     * @param uri The URI to watch for changes. This can be a specific row URI,
+     *            or a base URI for a whole class of content.
+     * @param notifyForDescendants When false, the observer will be notified
+     *            whenever a change occurs to the exact URI specified by
+     *            <code>uri</code> or to one of the URI's ancestors in the path
+     *            hierarchy. When true, the observer will also be notified
+     *            whenever a change occurs to the URI's descendants in the path
+     *            hierarchy.
      * @param observer The object that receives callbacks when changes occur.
      * @see #unregisterContentObserver
      */
@@ -1894,7 +1900,7 @@
             ContentObserver observer, @UserIdInt int userHandle) {
         try {
             getContentService().registerContentObserver(uri, notifyForDescendents,
-                    observer.getContentObserver(), userHandle);
+                    observer.getContentObserver(), userHandle, mTargetSdkVersion);
         } catch (RemoteException e) {
         }
     }
@@ -1918,16 +1924,22 @@
     }
 
     /**
-     * Notify registered observers that a row was updated and attempt to sync changes
-     * to the network.
-     * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
-     * By default, CursorAdapter objects will get this notification.
+     * Notify registered observers that a row was updated and attempt to sync
+     * changes to the network.
+     * <p>
+     * To observe events sent through this call, use
+     * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+     * notifications must be backed by a valid {@link ContentProvider}.
      *
      * @param uri The uri of the content that was changed.
-     * @param observer The observer that originated the change, may be <code>null</null>.
-     * The observer that originated the change will only receive the notification if it
-     * has requested to receive self-change notifications by implementing
-     * {@link ContentObserver#deliverSelfNotifications()} to return true.
+     * @param observer The observer that originated the change, may be
+     *            <code>null</null>. The observer that originated the change
+     *            will only receive the notification if it has requested to
+     *            receive self-change notifications by implementing
+     *            {@link ContentObserver#deliverSelfNotifications()} to return
+     *            true.
      */
     public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
         notifyChange(uri, observer, true /* sync to network */);
@@ -1935,17 +1947,25 @@
 
     /**
      * Notify registered observers that a row was updated.
-     * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
-     * By default, CursorAdapter objects will get this notification.
-     * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
-     * adapter that's registered for the authority of the provided uri. No account will be
-     * passed to the sync adapter, so all matching accounts will be synchronized.
+     * <p>
+     * To observe events sent through this call, use
+     * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+     * <p>
+     * If syncToNetwork is true, this will attempt to schedule a local sync
+     * using the sync adapter that's registered for the authority of the
+     * provided uri. No account will be passed to the sync adapter, so all
+     * matching accounts will be synchronized.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+     * notifications must be backed by a valid {@link ContentProvider}.
      *
      * @param uri The uri of the content that was changed.
-     * @param observer The observer that originated the change, may be <code>null</null>.
-     * The observer that originated the change will only receive the notification if it
-     * has requested to receive self-change notifications by implementing
-     * {@link ContentObserver#deliverSelfNotifications()} to return true.
+     * @param observer The observer that originated the change, may be
+     *            <code>null</null>. The observer that originated the change
+     *            will only receive the notification if it has requested to
+     *            receive self-change notifications by implementing
+     *            {@link ContentObserver#deliverSelfNotifications()} to return
+     *            true.
      * @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}.
      * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
      */
@@ -1961,17 +1981,25 @@
 
     /**
      * Notify registered observers that a row was updated.
-     * To register, call {@link #registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver) registerContentObserver()}.
-     * By default, CursorAdapter objects will get this notification.
-     * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
-     * adapter that's registered for the authority of the provided uri. No account will be
-     * passed to the sync adapter, so all matching accounts will be synchronized.
+     * <p>
+     * To observe events sent through this call, use
+     * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+     * <p>
+     * If syncToNetwork is true, this will attempt to schedule a local sync
+     * using the sync adapter that's registered for the authority of the
+     * provided uri. No account will be passed to the sync adapter, so all
+     * matching accounts will be synchronized.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+     * notifications must be backed by a valid {@link ContentProvider}.
      *
      * @param uri The uri of the content that was changed.
-     * @param observer The observer that originated the change, may be <code>null</null>.
-     * The observer that originated the change will only receive the notification if it
-     * has requested to receive self-change notifications by implementing
-     * {@link ContentObserver#deliverSelfNotifications()} to return true.
+     * @param observer The observer that originated the change, may be
+     *            <code>null</null>. The observer that originated the change
+     *            will only receive the notification if it has requested to
+     *            receive self-change notifications by implementing
+     *            {@link ContentObserver#deliverSelfNotifications()} to return
+     *            true.
      * @param flags Additional flags: {@link #NOTIFY_SYNC_TO_NETWORK}.
      * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
      */
@@ -1997,7 +2025,7 @@
                     uri, observer == null ? null : observer.getContentObserver(),
                     observer != null && observer.deliverSelfNotifications(),
                     syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
-                    userHandle);
+                    userHandle, mTargetSdkVersion);
         } catch (RemoteException e) {
         }
     }
@@ -2013,7 +2041,7 @@
             getContentService().notifyChange(
                     uri, observer == null ? null : observer.getContentObserver(),
                     observer != null && observer.deliverSelfNotifications(), flags,
-                    userHandle);
+                    userHandle, mTargetSdkVersion);
         } catch (RemoteException e) {
         }
     }
@@ -2932,6 +2960,7 @@
     private final Context mContext;
 
     final String mPackageName;
+    final int mTargetSdkVersion;
 
     private static final String TAG = "ContentResolver";
 
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 44f6c43..aff00c3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -730,12 +730,6 @@
      */
     public abstract boolean moveSharedPreferencesFrom(Context sourceContext, String name);
 
-    /** @removed */
-    @Deprecated
-    public boolean migrateSharedPreferencesFrom(Context sourceContext, String name) {
-        return moveSharedPreferencesFrom(sourceContext, name);
-    }
-
     /**
      * Delete an existing shared preferences file.
      *
@@ -1451,12 +1445,6 @@
      */
     public abstract boolean moveDatabaseFrom(Context sourceContext, String name);
 
-    /** @removed */
-    @Deprecated
-    public boolean migrateDatabaseFrom(Context sourceContext, String name) {
-        return moveDatabaseFrom(sourceContext, name);
-    }
-
     /**
      * Delete an existing private SQLiteDatabase associated with this Context's
      * application package.
@@ -4382,12 +4370,6 @@
      */
     public abstract Context createDeviceProtectedStorageContext();
 
-    /** @removed */
-    @Deprecated
-    public Context createDeviceEncryptedStorageContext() {
-        return createDeviceProtectedStorageContext();
-    }
-
     /**
      * Return a new Context object for the current Context but whose storage
      * APIs are backed by credential-protected storage. This is the default
@@ -4416,12 +4398,6 @@
     @SystemApi
     public abstract Context createCredentialProtectedStorageContext();
 
-    /** @removed */
-    @Deprecated
-    public Context createCredentialEncryptedStorageContext() {
-        return createCredentialProtectedStorageContext();
-    }
-
     /**
      * Gets the display adjustments holder for this context.  This information
      * is provided on a per-application or activity basis and is used to simulate lower density
@@ -4462,12 +4438,6 @@
      */
     public abstract boolean isDeviceProtectedStorage();
 
-    /** @removed */
-    @Deprecated
-    public boolean isDeviceEncryptedStorage() {
-        return isDeviceProtectedStorage();
-    }
-
     /**
      * Indicates if the storage APIs of this Context are backed by
      * credential-protected storage.
@@ -4478,12 +4448,6 @@
     @SystemApi
     public abstract boolean isCredentialProtectedStorage();
 
-    /** @removed */
-    @Deprecated
-    public boolean isCredentialEncryptedStorage() {
-        return isCredentialProtectedStorage();
-    }
-
     /**
      * @hide
      */
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 3446e03..c500116 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -42,7 +42,7 @@
      *     USER_CURRENT are properly handled.
      */
     void registerContentObserver(in Uri uri, boolean notifyForDescendants,
-            IContentObserver observer, int userHandle);
+            IContentObserver observer, int userHandle, int targetSdkVersion);
 
     /**
      * Notify observers of a particular user's view of the provider.
@@ -53,7 +53,7 @@
      */
     void notifyChange(in Uri uri, IContentObserver observer,
             boolean observerWantsSelfNotifications, int flags,
-            int userHandle);
+            int userHandle, int targetSdkVersion);
 
     void requestSync(in Account account, String authority, in Bundle extras);
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 28068c5..870db217 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1115,6 +1115,15 @@
     public static final String ACTION_SIM_ACTIVATION_REQUEST =
             "android.intent.action.SIM_ACTIVATION_REQUEST";
     /**
+     * Activity Action: Main entry point for carrier setup apps.
+     * <p>Carrier apps that provide an implementation for this action may be invoked to configure
+     * carrier service and typically require
+     * {@link android.telephony.TelephonyManager#hasCarrierPrivileges() carrier privileges} to
+     * fulfill their duties.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
+    /**
      * Activity Action: Send a message to someone specified by the data.
      * <p>Input: {@link #getData} is URI describing the target.
      * <p>Output: nothing.
@@ -9260,6 +9269,13 @@
             mClipData.prepareToLeaveProcess(leavingPackage, getFlags());
         }
 
+        if (mExtras != null && !mExtras.isParcelled()) {
+            final Object intent = mExtras.get(Intent.EXTRA_INTENT);
+            if (intent instanceof Intent) {
+                ((Intent) intent).prepareToLeaveProcess(leavingPackage);
+            }
+        }
+
         if (mAction != null && mData != null && StrictMode.vmFileUriExposureEnabled()
                 && leavingPackage) {
             switch (mAction) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9737b11..b4d77a0 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -720,10 +720,6 @@
      */
     public String deviceProtectedDataDir;
 
-    /** @removed */
-    @Deprecated
-    public String deviceEncryptedDataDir;
-
     /**
      * Full path to the credential-protected directory assigned to the package
      * for its persistent data.
@@ -733,10 +729,6 @@
     @SystemApi
     public String credentialProtectedDataDir;
 
-    /** @removed */
-    @Deprecated
-    public String credentialEncryptedDataDir;
-
     /**
      * Full path to the directory where native JNI libraries are stored.
      */
@@ -1140,8 +1132,8 @@
         seInfoUser = orig.seInfoUser;
         sharedLibraryFiles = orig.sharedLibraryFiles;
         dataDir = orig.dataDir;
-        deviceEncryptedDataDir = deviceProtectedDataDir = orig.deviceProtectedDataDir;
-        credentialEncryptedDataDir = credentialProtectedDataDir = orig.credentialProtectedDataDir;
+        deviceProtectedDataDir = orig.deviceProtectedDataDir;
+        credentialProtectedDataDir = orig.credentialProtectedDataDir;
         uid = orig.uid;
         minSdkVersion = orig.minSdkVersion;
         targetSdkVersion = orig.targetSdkVersion;
@@ -1264,8 +1256,8 @@
         seInfoUser = source.readString();
         sharedLibraryFiles = source.readStringArray();
         dataDir = source.readString();
-        deviceEncryptedDataDir = deviceProtectedDataDir = source.readString();
-        credentialEncryptedDataDir = credentialProtectedDataDir = source.readString();
+        deviceProtectedDataDir = source.readString();
+        credentialProtectedDataDir = source.readString();
         uid = source.readInt();
         minSdkVersion = source.readInt();
         targetSdkVersion = source.readInt();
@@ -1336,10 +1328,10 @@
             return;
         }
 
-        deviceEncryptedDataDir = deviceProtectedDataDir = Environment
+        deviceProtectedDataDir = Environment
                 .getDataUserDePackageDirectory(volumeUuid, userId, packageName)
                 .getAbsolutePath();
-        credentialEncryptedDataDir = credentialProtectedDataDir = Environment
+        credentialProtectedDataDir = Environment
                 .getDataUserCePackageDirectory(volumeUuid, userId, packageName)
                 .getAbsolutePath();
 
diff --git a/core/java/android/content/pm/ContainerEncryptionParams.aidl b/core/java/android/content/pm/ContainerEncryptionParams.aidl
deleted file mode 100644
index c13d946..0000000
--- a/core/java/android/content/pm/ContainerEncryptionParams.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-parcelable ContainerEncryptionParams;
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index c08bd1d..41311eb 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -55,7 +55,8 @@
             String callingPackage, String packageName, int flags, in UserHandle user);
 
     ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName,
-            in List shortcutIds, in ComponentName componentName, int flags, in UserHandle user);
+            in List shortcutIds, in ComponentName componentName, in Intent intent, int flags,
+            in UserHandle user);
     void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
             in UserHandle user);
     boolean startShortcut(String callingPackage, String packageName, String id,
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index ffb777d..147b3e1 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -22,7 +22,6 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.ChangedPackages;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.FeatureInfo;
@@ -38,7 +37,6 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.KeySet;
 import android.content.pm.PackageInfo;
-import android.content.pm.ManifestDigest;
 import android.content.pm.PackageCleanItem;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ProviderInfo;
@@ -213,7 +211,7 @@
             inout List<ProviderInfo> outInfo);
 
     ParceledListSlice queryContentProviders(
-            String processName, int uid, int flags);
+            String processName, int uid, int flags, String metaDataKey);
 
     InstrumentationInfo getInstrumentationInfo(
             in ComponentName className, int flags);
diff --git a/core/java/android/content/pm/IPinItemRequest.aidl b/core/java/android/content/pm/IPinItemRequest.aidl
index efe2835..eddce58 100644
--- a/core/java/android/content/pm/IPinItemRequest.aidl
+++ b/core/java/android/content/pm/IPinItemRequest.aidl
@@ -16,6 +16,8 @@
 package android.content.pm;
 
 import android.os.Bundle;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.pm.ShortcutInfo;
 
 /**
  * {@hide}
@@ -23,4 +25,6 @@
 interface IPinItemRequest {
     boolean isValid();
     boolean accept(in Bundle options);
+    ShortcutInfo getShortcutInfo();
+    AppWidgetProviderInfo getAppWidgetProviderInfo();
 }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 0866af2..776492a 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -275,7 +275,18 @@
         @Deprecated
         public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
 
-        /** @hide */
+        /**
+         * Include chooser shortcuts in the result.
+         * STOPSHIP TODO: Unless explicitly requesting chooser fields, we should strip out chooser
+         *           relevant fields from the Shortcut. This should also be adequately documented.
+         */
+        public static final int FLAG_MATCH_CHOOSER = 1 << 4;
+
+        /**
+         * Does not retrieve CHOOSER only shortcuts.
+         * TODO: Add another flag for MATCH_ALL_PINNED
+         * @hide
+         */
         public static final int FLAG_MATCH_ALL_KINDS =
                 FLAG_GET_DYNAMIC | FLAG_GET_PINNED | FLAG_GET_MANIFEST;
 
@@ -308,6 +319,7 @@
                         FLAG_MATCH_DYNAMIC,
                         FLAG_MATCH_PINNED,
                         FLAG_MATCH_MANIFEST,
+                        FLAG_MATCH_CHOOSER,
                         FLAG_GET_KEY_FIELDS_ONLY,
                 })
         @Retention(RetentionPolicy.SOURCE)
@@ -324,6 +336,9 @@
         @Nullable
         ComponentName mActivity;
 
+        @Nullable
+        Intent mIntent;
+
         @QueryFlags
         int mQueryFlags;
 
@@ -368,6 +383,14 @@
         }
 
         /**
+         * If non-null, returns only shortcuts with intent filters that match this intent.
+         */
+        public ShortcutQuery setIntent(@Nullable Intent intent) {
+            mIntent = intent;
+            return this;
+        }
+
+        /**
          * Set query options.  At least one of the {@code MATCH} flags should be set.  Otherwise,
          * no shortcuts will be returned.
          *
@@ -681,7 +704,7 @@
         try {
             return mService.getShortcuts(mContext.getPackageName(),
                     query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
-                    query.mQueryFlags, user)
+                    query.mIntent, query.mQueryFlags, user)
                     .getList();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -1291,28 +1314,14 @@
         public @interface RequestType {}
 
         private final int mRequestType;
-        private final ShortcutInfo mShortcutInfo;
-        private final AppWidgetProviderInfo mAppWidgetInfo;
         private final IPinItemRequest mInner;
 
         /**
          * @hide
          */
-        public PinItemRequest(ShortcutInfo shortcutInfo, IPinItemRequest inner) {
-            mRequestType = REQUEST_TYPE_SHORTCUT;
-            mShortcutInfo = shortcutInfo;
-            mAppWidgetInfo = null;
+        public PinItemRequest(IPinItemRequest inner, int type) {
             mInner = inner;
-        }
-
-        /**
-         * @hide
-         */
-        public PinItemRequest(AppWidgetProviderInfo appWidgetInfo, IPinItemRequest inner) {
-            mRequestType = REQUEST_TYPE_APPWIDGET;
-            mShortcutInfo = null;
-            mAppWidgetInfo = appWidgetInfo;
-            mInner = inner;
+            mRequestType = type;
         }
 
         /**
@@ -1330,7 +1339,11 @@
          */
         @Nullable
         public ShortcutInfo getShortcutInfo() {
-            return mShortcutInfo;
+            try {
+                return mInner.getShortcutInfo();
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
         }
 
         /**
@@ -1339,12 +1352,16 @@
          */
         @Nullable
         public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
-            if (mAppWidgetInfo != null) {
-                AppWidgetProviderInfo info = mAppWidgetInfo.clone();
+            try {
+                final AppWidgetProviderInfo info = mInner.getAppWidgetProviderInfo();
+                if (info == null) {
+                    return null;
+                }
                 info.updateDimensions(context.getResources().getDisplayMetrics());
                 return info;
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
             }
-            return null;
         }
 
         /**
@@ -1381,22 +1398,12 @@
             final ClassLoader cl = getClass().getClassLoader();
 
             mRequestType = source.readInt();
-            mShortcutInfo = mRequestType == REQUEST_TYPE_SHORTCUT ?
-                (ShortcutInfo) source.readParcelable(cl) : null;
-            mAppWidgetInfo = mRequestType == REQUEST_TYPE_APPWIDGET ?
-                (AppWidgetProviderInfo) source.readParcelable(cl) : null;
             mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mRequestType);
-            if (mRequestType == REQUEST_TYPE_SHORTCUT) {
-                dest.writeParcelable(mShortcutInfo, flags);
-            }
-            if (mRequestType == REQUEST_TYPE_APPWIDGET) {
-                dest.writeParcelable(mAppWidgetInfo, flags);
-            }
             dest.writeStrongBinder(mInner.asBinder());
         }
 
diff --git a/core/java/android/content/pm/ManifestDigest.aidl b/core/java/android/content/pm/ManifestDigest.aidl
deleted file mode 100644
index ebabab0..0000000
--- a/core/java/android/content/pm/ManifestDigest.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2011, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-parcelable ManifestDigest;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5733982..0482f51 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -411,17 +411,6 @@
      */
     public static final int MATCH_DIRECT_BOOT_AWARE = 0x00080000;
 
-    /** @removed */
-    @Deprecated
-    public static final int MATCH_ENCRYPTION_UNAWARE = 0x00040000;
-    /** @removed */
-    @Deprecated
-    public static final int MATCH_ENCRYPTION_AWARE = 0x00080000;
-    /** @removed */
-    @Deprecated
-    public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE
-            | MATCH_ENCRYPTION_UNAWARE;
-
     /**
      * Querying flag: include only components from applications that are marked
      * with {@link ApplicationInfo#FLAG_SYSTEM}.
@@ -624,8 +613,10 @@
      * should be installed as forward locked, i.e. only the app itself should
      * have access to its code and non-resource assets.
      *
+     * @deprecated new installs into ASEC containers are no longer supported.
      * @hide
      */
+    @Deprecated
     public static final int INSTALL_FORWARD_LOCK = 0x00000001;
 
     /**
@@ -648,8 +639,11 @@
      * Flag parameter for {@link #installPackage} to indicate that this package
      * must be installed to an ASEC on a {@link VolumeInfo#TYPE_PUBLIC}.
      *
+     * @deprecated new installs into ASEC containers are no longer supported;
+     *             use adoptable storage instead.
      * @hide
      */
+    @Deprecated
     public static final int INSTALL_EXTERNAL = 0x00000008;
 
     /**
@@ -4468,6 +4462,27 @@
             String processName, int uid, @ComponentInfoFlags int flags);
 
     /**
+     * Same as {@link #queryContentProviders}, except when {@code metaDataKey} is not null,
+     * it only returns providers which have metadata with the {@code metaDataKey} key.
+     *
+     * <p>DO NOT USE the {@code metaDataKey} parameter, unless you're the contacts provider.
+     * You really shouldn't need it.  Other apps should use {@link #queryIntentContentProviders}
+     * instead.
+     *
+     * <p>The {@code metaDataKey} parameter was added to allow the contacts provider to quickly
+     * scan the GAL providers on the device.  Unfortunately the discovery protocol used metadata
+     * to mark GAL providers, rather than intent filters, so we can't use
+     * {@link #queryIntentContentProviders} for that.
+     *
+     * @hide
+     */
+    public List<ProviderInfo> queryContentProviders(
+            String processName, int uid, @ComponentInfoFlags int flags, String metaDataKey) {
+        // Provide the default implementation for mocks.
+        return queryContentProviders(processName, uid, flags);
+    }
+
+    /**
      * Retrieve all of the information we know about a particular
      * instrumentation class.
      *
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 94fe572..6272822 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -306,4 +306,10 @@
      */
     public abstract boolean setEnabledOverlayPackages(int userId, String targetPackageName,
             List<String> overlayPackageNames);
+
+    /**
+     * Resolves an intent, allowing instant apps to be resolved.
+     */
+    public abstract ResolveInfo resolveIntent(Intent intent, String resolvedType,
+            int flags, int userId);
 }
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index f1f2683..d3d3c66 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -21,8 +21,10 @@
 import android.annotation.UserIdInt;
 import android.app.TaskStackBuilder;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
@@ -38,10 +40,12 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.MemInfoReader;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -95,6 +99,14 @@
     public static final int FLAG_MASKABLE_BITMAP = 1 << 9;
 
     /** @hide */
+    public static final int FLAG_CHOOSER = 1 << 10;
+
+    /**
+     * TODO: Add FLAG_CHOOSER_INFO_OMITTED to reflect that chooser info was omitted in the Shortcut
+     *       due to the context in which it was retrieved.
+     * TODO: Add a FLAG_LAUNCHABLE to reflect whether or not the Shortcut has a launchable intent
+     * @hide
+     */
     @IntDef(flag = true,
             value = {
             FLAG_DYNAMIC,
@@ -107,6 +119,7 @@
             FLAG_STRINGS_RESOLVED,
             FLAG_IMMUTABLE,
             FLAG_MASKABLE_BITMAP,
+            FLAG_CHOOSER,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ShortcutFlags {}
@@ -201,6 +214,24 @@
     @Nullable
     private PersistableBundle[] mIntentPersistableExtrases;
 
+    /**
+     * If used in a chooser, extras that should be added into the intent passed through.
+     */
+    @Nullable
+    private PersistableBundle mChooserExtras;
+
+    /**
+     * Intent filters to be used if the shortcut is to be used in a chooser context.
+     */
+    @Nullable
+    private IntentFilter[] mChooserIntentFilters;
+
+    /**
+     * Component names corresponding to the above intent filters.
+     */
+    @Nullable
+    private ComponentName[] mChooserComponentNames;
+
     private int mRank;
 
     /**
@@ -250,6 +281,13 @@
         mDisabledMessageResId = b.mDisabledMessageResId;
         mCategories = cloneCategories(b.mCategories);
         mIntents = cloneIntents(b.mIntents);
+        if (b.mChooserIntentFilters != null) {
+            mChooserIntentFilters = b.mChooserIntentFilters.toArray(new IntentFilter[0]);
+        }
+        if (b.mChooserComponentNames != null) {
+            mChooserComponentNames = b.mChooserComponentNames.toArray(new ComponentName[0]);
+        }
+        mChooserExtras = b.mChooserExtras;
         fixUpIntentExtras();
         mRank = b.mRank;
         mExtras = b.mExtras;
@@ -330,8 +368,28 @@
         if (mTitle == null && mTitleResId == 0) {
             throw new IllegalArgumentException("Short label must be provided");
         }
-        Preconditions.checkNotNull(mIntents, "Shortcut Intent must be provided");
-        Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided");
+
+        // For a shortcut to be valid, there should either be an Intent, or a non-empty set of
+        // intent filters.
+        if (mIntents == null || mIntents.length == 0) {
+            Preconditions.checkNotNull(mChooserIntentFilters,
+                    "Intent must be provided if not a chooser target");
+            Preconditions.checkNotNull(mChooserComponentNames,
+                    "Intent must be provided if not a chooser target");
+        }
+
+        // If ChooserIntentFilter are provided, they should match the length of the provided
+        // component names.
+        if (mChooserIntentFilters != null) {
+            if (mChooserComponentNames == null
+                    || mChooserIntentFilters.length != mChooserComponentNames.length) {
+                throw new IllegalArgumentException("Inconsistent intent filters and "
+                        + "component names given");
+            }
+            if (mChooserIntentFilters.length == 0 || mChooserComponentNames.length == 0) {
+                throw new IllegalArgumentException("Empty intent filter and component names given");
+            }
+        }
     }
 
     /**
@@ -376,6 +434,10 @@
                 mDisabledMessageResName = source.mDisabledMessageResName;
                 mIconResName = source.mIconResName;
             }
+            // TODO: Omit these by default and add a new clone flag.
+            mChooserIntentFilters = source.mChooserIntentFilters;
+            mChooserComponentNames = source.mChooserComponentNames;
+            mChooserExtras = source.mChooserExtras;
         } else {
             // Set this bit.
             mFlags |= FLAG_KEY_FIELDS_ONLY;
@@ -503,6 +565,25 @@
     }
 
     /**
+     * Whether the shortcut has any intentFilter matching the passed in one.
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean hasMatchingFilter(ContentResolver resolver, Intent intent) {
+        if (mChooserIntentFilters == null) {
+            return false;
+        }
+        for (IntentFilter filter : mChooserIntentFilters) {
+            int match = filter.match(resolver, intent, false, TAG);
+            if (match > 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
      * Extract the entry name from a fully-donated resource name.
      * e.g. "com.android.app1:drawable/icon1" -> "icon1"
      * @hide
@@ -685,6 +766,15 @@
         if (source.mExtras != null) {
             mExtras = source.mExtras;
         }
+        if (source.mChooserExtras != null) {
+            mChooserExtras = source.mChooserExtras;
+        }
+        if (source.mChooserIntentFilters != null) {
+            mChooserIntentFilters = source.mChooserIntentFilters;
+        }
+        if (source.mChooserComponentNames != null) {
+            mChooserComponentNames = source.mChooserComponentNames;
+        }
     }
 
     /**
@@ -746,6 +836,12 @@
 
         private PersistableBundle mExtras;
 
+        private PersistableBundle mChooserExtras;
+
+        private List<IntentFilter> mChooserIntentFilters;
+
+        private List<ComponentName> mChooserComponentNames;
+
         /**
          * Old style constructor.
          * @hide
@@ -1032,6 +1128,40 @@
         }
 
         /**
+         * Extras that can be added which will be added to the Intent used to launch the app if
+         * launched from a chooser context.
+         */
+        @NonNull
+        public Builder setChooserExtras(@NonNull PersistableBundle extras) {
+            mChooserExtras = extras;
+            return this;
+        }
+
+        /**
+         * IntentFilters and the components that should resolve a match for a given chooser target.
+         * If multiple matches are found, the component corresponding to the closest match will be
+         * used.
+         *
+         * @param filter IntendFilter that if matched will have the intent forwarded to the given
+         *               component
+         * @param name The component that an intent that passes this filter will resolve to.
+         */
+        public Builder addChooserIntentFilter(@NonNull IntentFilter filter,
+                @NonNull ComponentName name) {
+            Preconditions.checkNotNull(filter, "intent filter cannot be null");
+            Preconditions.checkNotNull(name, "component name cannot be null");
+
+            if (mChooserIntentFilters == null || mChooserComponentNames == null) {
+                mChooserIntentFilters = new ArrayList<>();
+                mChooserComponentNames = new ArrayList<>();
+            }
+
+            mChooserIntentFilters.add(filter);
+            mChooserComponentNames.add(name);
+            return this;
+        }
+
+        /**
          * Creates a {@link ShortcutInfo} instance.
          */
         @NonNull
@@ -1232,6 +1362,30 @@
     }
 
     /**
+     * Retrieve the extras that will be added in to any intent launched through the chooser.
+     */
+    @NonNull
+    public PersistableBundle getChooserExtras() {
+        return mChooserExtras;
+    }
+
+    /**
+     * Retrieve the list of intent filters for chooser targets.
+     */
+    @NonNull
+    public IntentFilter[] getChooserIntentFilters() {
+        return mChooserIntentFilters;
+    }
+
+    /**
+     * Retrieve the list of component names corresponding to the above intent filters.
+     */
+    @NonNull
+    public ComponentName[] getChooserComponentNames() {
+        return mChooserComponentNames;
+    }
+
+    /**
      * "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
      * {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
      *
@@ -1352,6 +1506,11 @@
         return hasFlags(FLAG_PINNED);
     }
 
+    /** Return whether a shortcut can be shown in the chooser. */
+    public boolean isChooser() {
+        return hasFlags(FLAG_CHOOSER);
+    }
+
     /**
      * Return whether a shortcut is static; that is, whether a shortcut is
      * published from AndroidManifest.xml.  If {@code true}, the shortcut is
@@ -1380,6 +1539,14 @@
         return isPinned() && !(isDynamic() || isManifestShortcut());
     }
 
+    /**
+     * @return true if pinned but neither static nor dynamic.
+     * @hide
+     */
+    public boolean isDynamicOrChooser() {
+        return hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_CHOOSER);
+    }
+
     /** @hide */
     public boolean isOriginallyFromManifest() {
         return hasFlags(FLAG_IMMUTABLE);
@@ -1661,6 +1828,19 @@
                 mCategories.add(source.readString().intern());
             }
         }
+
+        // We put a placeholder empty array in to keep the parcelable order, but can do away with
+        // them at this point if they're empty.
+        mChooserComponentNames = source.readParcelableArray(cl, ComponentName.class);
+        if (mChooserComponentNames.length == 0) {
+            mChooserComponentNames = null;
+        }
+
+        mChooserIntentFilters = source.readParcelableArray(cl, IntentFilter.class);
+        if (mChooserIntentFilters.length == 0) {
+            mChooserIntentFilters = null;
+        }
+        mChooserExtras = source.readPersistableBundle(cl);
     }
 
     @Override
@@ -1707,6 +1887,17 @@
         } else {
             dest.writeInt(0);
         }
+        if (mChooserComponentNames != null) {
+            dest.writeParcelableArray(mChooserComponentNames, flags);
+        } else {
+            dest.writeParcelableArray(new ComponentName[0], flags);
+        }
+        if (mChooserIntentFilters != null) {
+            dest.writeParcelableArray(mChooserIntentFilters, flags);
+        } else {
+            dest.writeParcelableArray(new IntentFilter[0], flags);
+        }
+        dest.writePersistableBundle(mChooserExtras);
     }
 
     public static final Creator<ShortcutInfo> CREATOR =
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 87a6d4a..696fe81 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -44,8 +44,8 @@
             getShortcuts(int launcherUserId,
             @NonNull String callingPackage, long changedSince,
             @Nullable String packageName, @Nullable List<String> shortcutIds,
-            @Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags,
-            int userId);
+            @Nullable ComponentName componentName, @Nullable Intent intent,
+            @ShortcutQuery.QueryFlags int flags, int userId);
 
     public abstract boolean
             isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
diff --git a/core/java/android/content/res/CompatResources.java b/core/java/android/content/res/CompatResources.java
new file mode 100644
index 0000000..15575fd
--- /dev/null
+++ b/core/java/android/content/res/CompatResources.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package android.content.res;
+
+import android.annotation.ColorRes;
+import android.annotation.DrawableRes;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Version of resources generated for apps targeting <26.
+ * @hide
+ */
+public class CompatResources extends Resources {
+
+    private final WeakReference<Context> mContext;
+
+    public CompatResources(Resources base, Context context) {
+        super(base.getClassLoader());
+        setImpl(base.getImpl());
+        mContext = new WeakReference<>(context);
+    }
+
+    @Override
+    public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
+        return getDrawable(id, getTheme());
+    }
+
+    @Override
+    public Drawable getDrawableForDensity(@DrawableRes int id, int density)
+            throws NotFoundException {
+        return getDrawableForDensity(id, density, getTheme());
+    }
+
+    @Override
+    public int getColor(@ColorRes int id) throws NotFoundException {
+        return getColor(id, getTheme());
+    }
+
+    @Override
+    public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException {
+        return getColorStateList(id, getTheme());
+    }
+
+    private Theme getTheme() {
+        Context c = mContext.get();
+        return c != null ? c.getTheme() : null;
+    }
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index e6f3021..1259de6 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2952,15 +2952,6 @@
      * @hide
      */
     public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
-            int timeoutMs, int legacyType) {
-        requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
-    }
-
-    /**
-     * Helper function to request a network with a particular legacy type.
-     * @hide
-     */
-    private void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
             int timeoutMs, int legacyType, Handler handler) {
         CallbackHandler cbHandler = new CallbackHandler(handler);
         NetworkCapabilities nc = request.networkCapabilities;
@@ -3062,7 +3053,7 @@
     public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
             int timeoutMs) {
         int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
-        requestNetwork(request, networkCallback, timeoutMs, legacyType);
+        requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
     }
 
 
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index f249daf..362ea9d 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -18,7 +18,7 @@
 
 import android.net.INetworkScoreCache;
 import android.net.NetworkKey;
-import android.net.NetworkScorerAppManager;
+import android.net.NetworkScorerAppData;
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
@@ -135,11 +135,11 @@
     /**
      * Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
      */
-    NetworkScorerAppManager.NetworkScorerAppData getActiveScorer();
+    NetworkScorerAppData getActiveScorer();
 
     /**
      * Returns the list of available scorer apps. The list will be empty if there are
      * no valid scorers.
      */
-    List<NetworkScorerAppManager.NetworkScorerAppData> getAllValidScorers();
+    List<NetworkScorerAppData> getAllValidScorers();
 }
diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java
index 8395864..271b0a7 100644
--- a/core/java/android/net/NetworkRecommendationProvider.java
+++ b/core/java/android/net/NetworkRecommendationProvider.java
@@ -1,6 +1,8 @@
 package android.net;
 
+import android.Manifest.permission;
 import android.annotation.SystemApi;
+import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -10,8 +12,10 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
 import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -32,6 +36,7 @@
     /**
      * Constructs a new instance.
      * @param handler indicates which thread to use when handling requests. Cannot be {@code null}.
+     * @deprecated use {@link #NetworkRecommendationProvider(Context, Executor)}
      */
     public NetworkRecommendationProvider(Handler handler) {
         if (handler == null) {
@@ -41,6 +46,17 @@
     }
 
     /**
+     * Constructs a new instance.
+     * @param context the current context instance. Cannot be {@code null}.
+     * @param executor used to execute the incoming requests. Cannot be {@code null}.
+     */
+    public NetworkRecommendationProvider(Context context, Executor executor) {
+        Preconditions.checkNotNull(context);
+        Preconditions.checkNotNull(executor);
+        mService = new ServiceWrapper(context, executor);
+    }
+
+    /**
      * Invoked when a recommendation has been requested.
      *
      * @param request a {@link RecommendationRequest} instance containing additional
@@ -130,17 +146,28 @@
      * A wrapper around INetworkRecommendationProvider that dispatches to the provided Handler.
      */
     private final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
+        private final Context mContext;
+        private final Executor mExecutor;
         private final Handler mHandler;
 
         ServiceWrapper(Handler handler) {
             mHandler = handler;
+            mExecutor = null;
+            mContext = null;
+        }
+
+        ServiceWrapper(Context context, Executor executor) {
+            mContext = context;
+            mExecutor = executor;
+            mHandler = null;
         }
 
         @Override
         public void requestRecommendation(final RecommendationRequest request,
                 final IRemoteCallback callback, final int sequence) throws RemoteException {
+            enforceCallingPermission();
             if (VERBOSE) Log.v(TAG, "requestRecommendation(seq=" + sequence + ")");
-            mHandler.post(new Runnable() {
+            execute(new Runnable() {
                 @Override
                 public void run() {
                     if (VERBOSE) {
@@ -154,8 +181,9 @@
 
         @Override
         public void requestScores(final NetworkKey[] networks) throws RemoteException {
+            enforceCallingPermission();
             if (networks != null && networks.length > 0) {
-                mHandler.post(new Runnable() {
+                execute(new Runnable() {
                     @Override
                     public void run() {
                         onRequestScores(networks);
@@ -163,5 +191,20 @@
                 });
             }
         }
+
+        private void execute(Runnable command) {
+            if (mExecutor != null) {
+                mExecutor.execute(command);
+            } else {
+                mHandler.post(command);
+            }
+        }
+
+        private void enforceCallingPermission() {
+            if (mContext != null) {
+                mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES,
+                        "Permission denied.");
+            }
+        }
     }
 }
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index edfaee4..815d480 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -18,7 +18,6 @@
 
 import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
 
-import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -26,7 +25,6 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteCallback;
diff --git a/core/java/android/net/NetworkScorerAppManager.aidl b/core/java/android/net/NetworkScorerAppData.aidl
similarity index 91%
rename from core/java/android/net/NetworkScorerAppManager.aidl
rename to core/java/android/net/NetworkScorerAppData.aidl
index d968343..ee7f1d1 100644
--- a/core/java/android/net/NetworkScorerAppManager.aidl
+++ b/core/java/android/net/NetworkScorerAppData.aidl
@@ -16,4 +16,4 @@
 
 package android.net;
 
-parcelable NetworkScorerAppManager.NetworkScorerAppData;
+parcelable NetworkScorerAppData;
diff --git a/core/java/android/net/NetworkScorerAppData.java b/core/java/android/net/NetworkScorerAppData.java
new file mode 100644
index 0000000..fca0a2e
--- /dev/null
+++ b/core/java/android/net/NetworkScorerAppData.java
@@ -0,0 +1,99 @@
+package android.net;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Holds metadata about a discovered network scorer/recommendation application.
+ *
+ * @hide
+ */
+public final class NetworkScorerAppData implements Parcelable {
+    /** UID of the scorer app. */
+    public final int packageUid;
+    private final ComponentName mRecommendationService;
+    /**
+     * The {@link ComponentName} of the Activity to start before enabling the "connect to open
+     * wifi networks automatically" feature.
+     */
+    private final ComponentName mEnableUseOpenWifiActivity;
+
+    public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp,
+            ComponentName enableUseOpenWifiActivity) {
+        this.packageUid = packageUid;
+        this.mRecommendationService = recommendationServiceComp;
+        this.mEnableUseOpenWifiActivity = enableUseOpenWifiActivity;
+    }
+
+    protected NetworkScorerAppData(Parcel in) {
+        packageUid = in.readInt();
+        mRecommendationService = ComponentName.readFromParcel(in);
+        mEnableUseOpenWifiActivity = ComponentName.readFromParcel(in);
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(packageUid);
+        ComponentName.writeToParcel(mRecommendationService, dest);
+        ComponentName.writeToParcel(mEnableUseOpenWifiActivity, dest);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<NetworkScorerAppData> CREATOR =
+            new Creator<NetworkScorerAppData>() {
+                @Override
+                public NetworkScorerAppData createFromParcel(Parcel in) {
+                    return new NetworkScorerAppData(in);
+                }
+
+                @Override
+                public NetworkScorerAppData[] newArray(int size) {
+                    return new NetworkScorerAppData[size];
+                }
+            };
+
+    public String getRecommendationServicePackageName() {
+        return mRecommendationService.getPackageName();
+    }
+
+    public ComponentName getRecommendationServiceComponent() {
+        return mRecommendationService;
+    }
+
+    @Nullable
+    public ComponentName getEnableUseOpenWifiActivity() {
+        return mEnableUseOpenWifiActivity;
+    }
+
+    @Override
+    public String toString() {
+        return "NetworkScorerAppData{" +
+                "packageUid=" + packageUid +
+                ", mRecommendationService=" + mRecommendationService +
+                ", mEnableUseOpenWifiActivity=" + mEnableUseOpenWifiActivity +
+                '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        NetworkScorerAppData that = (NetworkScorerAppData) o;
+        return packageUid == that.packageUid &&
+                Objects.equals(mRecommendationService, that.mRecommendationService) &&
+                Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(packageUid, mRecommendationService, mEnableUseOpenWifiActivity);
+    }
+}
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
deleted file mode 100644
index bbc1c79..0000000
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net;
-
-import android.Manifest.permission;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.content.pm.ServiceInfo;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Internal class for discovering and managing the network scorer/recommendation application.
- *
- * @hide
- */
-public class NetworkScorerAppManager {
-    private static final String TAG = "NetworkScorerAppManager";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
-    private final Context mContext;
-
-    public NetworkScorerAppManager(Context context) {
-      mContext = context;
-    }
-
-    /**
-     * Holds metadata about a discovered network scorer/recommendation application.
-     */
-    public static final class NetworkScorerAppData implements Parcelable {
-        /** UID of the scorer app. */
-        public final int packageUid;
-        private final ComponentName mRecommendationService;
-        /**
-         * The {@link ComponentName} of the Activity to start before enabling the "connect to open
-         * wifi networks automatically" feature.
-         */
-        private final ComponentName mEnableUseOpenWifiActivity;
-
-        public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp,
-                ComponentName enableUseOpenWifiActivity) {
-            this.packageUid = packageUid;
-            this.mRecommendationService = recommendationServiceComp;
-            this.mEnableUseOpenWifiActivity = enableUseOpenWifiActivity;
-        }
-
-        protected NetworkScorerAppData(Parcel in) {
-            packageUid = in.readInt();
-            mRecommendationService = ComponentName.readFromParcel(in);
-            mEnableUseOpenWifiActivity = ComponentName.readFromParcel(in);
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(packageUid);
-            ComponentName.writeToParcel(mRecommendationService, dest);
-            ComponentName.writeToParcel(mEnableUseOpenWifiActivity, dest);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        public static final Creator<NetworkScorerAppData> CREATOR =
-                new Creator<NetworkScorerAppData>() {
-                    @Override
-                    public NetworkScorerAppData createFromParcel(Parcel in) {
-                        return new NetworkScorerAppData(in);
-                    }
-
-                    @Override
-                    public NetworkScorerAppData[] newArray(int size) {
-                        return new NetworkScorerAppData[size];
-                    }
-                };
-
-        public String getRecommendationServicePackageName() {
-            return mRecommendationService.getPackageName();
-        }
-
-        public ComponentName getRecommendationServiceComponent() {
-            return mRecommendationService;
-        }
-
-        @Nullable public ComponentName getEnableUseOpenWifiActivity() {
-            return mEnableUseOpenWifiActivity;
-        }
-
-        @Override
-        public String toString() {
-            return "NetworkScorerAppData{" +
-                    "packageUid=" + packageUid +
-                    ", mRecommendationService=" + mRecommendationService +
-                    ", mEnableUseOpenWifiActivity=" + mEnableUseOpenWifiActivity +
-                    '}';
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-            NetworkScorerAppData that = (NetworkScorerAppData) o;
-            return packageUid == that.packageUid &&
-                    Objects.equals(mRecommendationService, that.mRecommendationService) &&
-                    Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(packageUid, mRecommendationService, mEnableUseOpenWifiActivity);
-        }
-    }
-
-    /**
-     * Returns the list of available scorer apps. The list will be empty if there are
-     * no valid scorers.
-     */
-    public List<NetworkScorerAppData> getAllValidScorers() {
-        return Collections.emptyList();
-    }
-
-    /**
-     * @return A {@link NetworkScorerAppData} instance containing information about the
-     *         best configured network recommendation provider installed or {@code null}
-     *         if none of the configured packages can recommend networks.
-     *
-     * <p>A network recommendation provider is any application which:
-     * <ul>
-     * <li>Is listed in the <code>config_networkRecommendationPackageNames</code> config.
-     * <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
-     * <li>Includes a Service for {@link NetworkScoreManager#ACTION_RECOMMEND_NETWORKS}.
-     * </ul>
-     */
-    public NetworkScorerAppData getNetworkRecommendationProviderData() {
-        // Network recommendation apps can only run as the primary user right now.
-        // http://b/23422763
-        if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
-            return null;
-        }
-
-        final List<String> potentialPkgs = getPotentialRecommendationProviderPackages();
-        if (potentialPkgs.isEmpty()) {
-            if (DEBUG) {
-                Log.d(TAG, "No Network Recommendation Providers specified.");
-            }
-            return null;
-        }
-
-        for (int i = 0; i < potentialPkgs.size(); i++) {
-            final String potentialPkg = potentialPkgs.get(i);
-
-            // Look for the recommendation service class and required receiver.
-            final ServiceInfo serviceInfo = findRecommendationService(potentialPkg);
-            if (serviceInfo != null) {
-                final ComponentName serviceComponentName =
-                    new ComponentName(potentialPkg, serviceInfo.name);
-                final ComponentName useOpenWifiNetworksActivity =
-                        findUseOpenWifiNetworksActivity(serviceInfo);
-                return new NetworkScorerAppData(serviceInfo.applicationInfo.uid,
-                    serviceComponentName, useOpenWifiNetworksActivity);
-            } else {
-                if (DEBUG) {
-                    Log.d(TAG, potentialPkg + " does not have the required components, skipping.");
-                }
-            }
-        }
-
-        // None of the configured packages are valid.
-        return null;
-    }
-
-    @Nullable private ComponentName findUseOpenWifiNetworksActivity(ServiceInfo serviceInfo) {
-        if (serviceInfo.metaData == null) {
-            if (DEBUG) {
-                Log.d(TAG, "No metadata found on recommendation service.");
-            }
-            return null;
-        }
-        final String useOpenWifiPackage = serviceInfo.metaData
-                .getString(NetworkScoreManager.USE_OPEN_WIFI_PACKAGE_META_DATA);
-        if (TextUtils.isEmpty(useOpenWifiPackage)) {
-            if (DEBUG) {
-                Log.d(TAG, "No use_open_wifi_package metadata found.");
-            }
-            return null;
-        }
-        final Intent enableUseOpenWifiIntent = new Intent(NetworkScoreManager.ACTION_CUSTOM_ENABLE)
-                .setPackage(useOpenWifiPackage);
-        final ResolveInfo resolveActivityInfo = mContext.getPackageManager()
-                .resolveActivity(enableUseOpenWifiIntent, 0 /* flags */);
-        if (VERBOSE) {
-            Log.d(TAG, "Resolved " + enableUseOpenWifiIntent + " to " + serviceInfo);
-        }
-
-        if (resolveActivityInfo != null && resolveActivityInfo.activityInfo != null) {
-            return resolveActivityInfo.activityInfo.getComponentName();
-        }
-
-        return null;
-    }
-
-    /**
-     * @return A priority order list of package names that have been granted the
-     *         permission needed for them to act as a network recommendation provider.
-     *         The packages in the returned list may not contain the other required
-     *         network recommendation provider components so additional checks are required
-     *         before making a package the network recommendation provider.
-     */
-    public List<String> getPotentialRecommendationProviderPackages() {
-        final String[] packageArray = mContext.getResources().getStringArray(
-                R.array.config_networkRecommendationPackageNames);
-        if (packageArray == null || packageArray.length == 0) {
-            if (DEBUG) {
-                Log.d(TAG, "No Network Recommendation Providers specified.");
-            }
-            return Collections.emptyList();
-        }
-
-        if (VERBOSE) {
-            Log.d(TAG, "Configured packages: " + TextUtils.join(", ", packageArray));
-        }
-
-        List<String> packages = new ArrayList<>();
-        final PackageManager pm = mContext.getPackageManager();
-        for (String potentialPkg : packageArray) {
-            if (pm.checkPermission(permission.SCORE_NETWORKS, potentialPkg)
-                    == PackageManager.PERMISSION_GRANTED) {
-                packages.add(potentialPkg);
-            } else {
-                if (DEBUG) {
-                    Log.d(TAG, potentialPkg + " has not been granted " + permission.SCORE_NETWORKS
-                            + ", skipping.");
-                }
-            }
-        }
-
-        return packages;
-    }
-
-    @Nullable private ServiceInfo findRecommendationService(String packageName) {
-        final PackageManager pm = mContext.getPackageManager();
-        final int resolveFlags = PackageManager.GET_META_DATA;
-        final Intent serviceIntent = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
-        serviceIntent.setPackage(packageName);
-        final ResolveInfo resolveServiceInfo =
-                pm.resolveService(serviceIntent, resolveFlags);
-
-        if (VERBOSE) {
-            Log.d(TAG, "Resolved " + serviceIntent + " to " + resolveServiceInfo);
-        }
-
-        if (resolveServiceInfo != null && resolveServiceInfo.serviceInfo != null) {
-            return resolveServiceInfo.serviceInfo;
-        }
-
-        if (VERBOSE) {
-            Log.v(TAG, packageName + " does not have a service for " + serviceIntent);
-        }
-        return null;
-    }
-
-    /**
-     * Get the application to use for scoring networks.
-     *
-     * @return the scorer app info or null if scoring is disabled (including if no scorer was ever
-     *     selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
-     *     it was disabled or uninstalled).
-     */
-    @Nullable
-    public NetworkScorerAppData getActiveScorer() {
-        if (isNetworkRecommendationsDisabled()) {
-            // If recommendations are disabled then there can't be an active scorer.
-            return null;
-        }
-
-        // Otherwise return the recommendation provider (which may be null).
-        return getNetworkRecommendationProviderData();
-    }
-
-    /**
-     * Set the specified package as the default scorer application.
-     *
-     * <p>The caller must have permission to write to {@link android.provider.Settings.Global}.
-     *
-     * @param packageName the packageName of the new scorer to use. If null, scoring will be
-     *     disabled. Otherwise, the scorer will only be set if it is a valid scorer application.
-     * @return true if the scorer was changed, or false if the package is not a valid scorer or
-     *         a valid network recommendation provider exists.
-     * @deprecated Scorers are now selected from a configured list.
-     */
-    @Deprecated
-    public boolean setActiveScorer(String packageName) {
-        return false;
-    }
-
-    private boolean isNetworkRecommendationsDisabled() {
-        final ContentResolver cr = mContext.getContentResolver();
-        // A value of 1 indicates enabled.
-        return Settings.Global.getInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) != 1;
-    }
-}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index d299672..63d3e7a 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -18,8 +18,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.LooperProto;
 import android.util.Log;
 import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
 
 /**
   * Class used to run a message loop for a thread.  Threads by default do
@@ -289,6 +291,16 @@
         mQueue.dump(pw, prefix + "  ");
     }
 
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long looperToken = proto.start(fieldId);
+        proto.write(LooperProto.THREAD_NAME, mThread.getName());
+        proto.write(LooperProto.THREAD_ID, mThread.getId());
+        proto.write(LooperProto.IDENTITY_HASH_CODE, System.identityHashCode(this));
+        mQueue.writeToProto(proto, LooperProto.QUEUE);
+        proto.end(looperToken);
+    }
+
     @Override
     public String toString() {
         return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 8c75847..d066db1 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -16,13 +16,15 @@
 
 package android.os;
 
+import android.os.MessageProto;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 /**
- * 
+ *
  * Defines a message containing a description and arbitrary data object that can be
  * sent to a {@link Handler}.  This object contains two extra int fields and an
- * extra object field that allow you to not do allocations in many cases.  
+ * extra object field that allow you to not do allocations in many cases.
  *
  * <p class="note">While the constructor of Message is public, the best way to get
  * one of these is to call {@link #obtain Message.obtain()} or one of the
@@ -31,7 +33,7 @@
  */
 public final class Message implements Parcelable {
     /**
-     * User-defined message code so that the recipient can identify 
+     * User-defined message code so that the recipient can identify
      * what this message is about. Each {@link Handler} has its own name-space
      * for message codes, so you do not need to worry about yours conflicting
      * with other handlers.
@@ -43,7 +45,7 @@
      * {@link #setData(Bundle) setData()} if you only need to store a
      * few integer values.
      */
-    public int arg1; 
+    public int arg1;
 
     /**
      * arg1 and arg2 are lower-cost alternatives to using
@@ -58,7 +60,7 @@
      * be non-null if it contains a Parcelable of a framework class (not one
      * implemented by the application).   For other data transfer use
      * {@link #setData}.
-     * 
+     *
      * <p>Note that Parcelable objects here are not supported prior to
      * the {@link android.os.Build.VERSION_CODES#FROYO} release.
      */
@@ -97,13 +99,13 @@
     /*package*/ int flags;
 
     /*package*/ long when;
-    
+
     /*package*/ Bundle data;
-    
+
     /*package*/ Handler target;
-    
+
     /*package*/ Runnable callback;
-    
+
     // sometimes we store linked lists of these things
     /*package*/ Message next;
 
@@ -216,9 +218,9 @@
     }
 
     /**
-     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, 
+     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
      * <em>arg1</em>, and <em>arg2</em> members.
-     * 
+     *
      * @param h  The <em>target</em> value to set.
      * @param what  The <em>what</em> value to set.
      * @param arg1  The <em>arg1</em> value to set.
@@ -236,9 +238,9 @@
     }
 
     /**
-     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, 
+     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
      * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
-     * 
+     *
      * @param h  The <em>target</em> value to set.
      * @param what  The <em>what</em> value to set.
      * @param arg1  The <em>arg1</em> value to set.
@@ -246,7 +248,7 @@
      * @param obj  The <em>obj</em> value to set.
      * @return  A Message object from the global pool.
      */
-    public static Message obtain(Handler h, int what, 
+    public static Message obtain(Handler h, int what,
             int arg1, int arg2, Object obj) {
         Message m = obtain();
         m.target = h;
@@ -339,7 +341,7 @@
     public long getWhen() {
         return when;
     }
-    
+
     public void setTarget(Handler target) {
         this.target = target;
     }
@@ -367,8 +369,8 @@
     public Runnable getCallback() {
         return callback;
     }
-    
-    /** 
+
+    /**
      * Obtains a Bundle of arbitrary data associated with this
      * event, lazily creating it if necessary. Set this value by calling
      * {@link #setData(Bundle)}.  Note that when transferring data across
@@ -383,11 +385,11 @@
         if (data == null) {
             data = new Bundle();
         }
-        
+
         return data;
     }
 
-    /** 
+    /**
      * Like getData(), but does not lazily create the Bundle.  A null
      * is returned if the Bundle does not already exist.  See
      * {@link #getData} for further information on this.
@@ -401,7 +403,7 @@
     /**
      * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members
      * as a lower cost way to send a few simple integer values, if you can.
-     * @see #getData() 
+     * @see #getData()
      * @see #peekData()
      */
     public void setData(Bundle data) {
@@ -520,6 +522,37 @@
         return b.toString();
     }
 
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long messageToken = proto.start(fieldId);
+        proto.write(MessageProto.WHEN, when);
+
+        if (target != null) {
+            if (callback != null) {
+                proto.write(MessageProto.CALLBACK, callback.getClass().getName());
+            } else {
+                proto.write(MessageProto.WHAT, what);
+            }
+
+            if (arg1 != 0) {
+                proto.write(MessageProto.ARG1, arg1);
+            }
+
+            if (arg2 != 0) {
+                proto.write(MessageProto.ARG2, arg2);
+            }
+
+            if (obj != null) {
+                proto.write(MessageProto.OBJ, obj.toString());
+            }
+
+            proto.write(MessageProto.TARGET, target.getClass().getName());
+        } else {
+            proto.write(MessageProto.BARRIER, arg1);
+        }
+
+        proto.end(messageToken);
+    }
+
     public static final Parcelable.Creator<Message> CREATOR
             = new Parcelable.Creator<Message>() {
         public Message createFromParcel(Parcel source) {
@@ -527,12 +560,12 @@
             msg.readFromParcel(source);
             return msg;
         }
-        
+
         public Message[] newArray(int size) {
             return new Message[size];
         }
     };
-        
+
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 4f2e968..2a8c52e 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -18,9 +18,11 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.os.MessageQueueProto;
 import android.util.Log;
 import android.util.Printer;
 import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
@@ -31,7 +33,7 @@
  * Low-level class holding the list of messages to be dispatched by a
  * {@link Looper}.  Messages are not added directly to a MessageQueue,
  * but rather through {@link Handler} objects associated with the Looper.
- * 
+ *
  * <p>You can retrieve the MessageQueue for the current thread with
  * {@link Looper#myQueue() Looper.myQueue()}.
  */
@@ -770,6 +772,18 @@
         }
     }
 
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long messageQueueToken = proto.start(fieldId);
+        synchronized (this) {
+            for (Message msg = mMessages; msg != null; msg = msg.next) {
+                msg.writeToProto(proto, MessageQueueProto.MESSAGES);
+            }
+            proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
+            proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
+        }
+        proto.end(messageQueueToken);
+    }
+
     /**
      * Callback interface for discovering when a thread is going to block
      * waiting for more messages.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 21c70f9..13a495e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1097,40 +1097,6 @@
         }
     }
 
-    /** @removed */
-    @Deprecated
-    public boolean isUserRunningAndLocked() {
-        return isUserRunningAndLocked(Process.myUserHandle());
-    }
-
-    /** @removed */
-    @Deprecated
-    public boolean isUserRunningAndLocked(UserHandle user) {
-        try {
-            return ActivityManager.getService().isUserRunning(
-                    user.getIdentifier(), ActivityManager.FLAG_AND_LOCKED);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /** @removed */
-    @Deprecated
-    public boolean isUserRunningAndUnlocked() {
-        return isUserRunningAndUnlocked(Process.myUserHandle());
-    }
-
-    /** @removed */
-    @Deprecated
-    public boolean isUserRunningAndUnlocked(UserHandle user) {
-        try {
-            return ActivityManager.getService().isUserRunning(
-                    user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
     /**
      * Return whether the calling user is running in an "unlocked" state.
      * <p>
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index f8da87a..ecec448 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -1,6 +1,8 @@
 package android.os;
 
+import android.os.WorkSourceProto;
 import android.util.Log;
+import android.util.proto.ProtoOutputStream;
 
 import java.util.Arrays;
 
@@ -296,7 +298,7 @@
                 break;
             }
             if (mUids[i] == uid) {
-                int diff = mNames[i].compareTo(name); 
+                int diff = mNames[i].compareTo(name);
                 if (diff > 0) {
                     break;
                 }
@@ -692,6 +694,20 @@
         return result.toString();
     }
 
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long workSourceToken = proto.start(fieldId);
+        for (int i = 0; i < mNum; i++) {
+            final long contentProto = proto.start(WorkSourceProto.WORK_SOURCE_CONTENTS);
+            proto.write(WorkSourceProto.WorkSourceContentProto.UID, mUids[i]);
+            if (mNames != null) {
+                proto.write(WorkSourceProto.WorkSourceContentProto.NAME, mNames[i]);
+            }
+            proto.end(contentProto);
+        }
+        proto.end(workSourceToken);
+    }
+
     public static final Parcelable.Creator<WorkSource> CREATOR
             = new Parcelable.Creator<WorkSource>() {
         public WorkSource createFromParcel(Parcel in) {
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index a2f4db6..756c3f4 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -420,12 +420,6 @@
         mSharedPreferences = null;
     }
 
-    /** @removed */
-    @Deprecated
-    public void setStorageDeviceEncrypted() {
-        setStorageDeviceProtected();
-    }
-
     /**
      * Explicitly set the storage location used internally by this class to be
      * credential-protected storage. This is the default storage area for apps
@@ -445,12 +439,6 @@
         mSharedPreferences = null;
     }
 
-    /** @removed */
-    @Deprecated
-    public void setStorageCredentialEncrypted() {
-        setStorageCredentialProtected();
-    }
-
     /**
      * Indicates if the storage location used internally by this class is the
      * default provided by the hosting {@link Context}.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 40de928..b55a349 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6905,6 +6905,12 @@
         public static final String PACKAGE_VERIFIER_STATE = "package_verifier_state";
 
         /**
+         * Specifies additional package name for broadcasting the CMAS messages.
+         * @hide
+         */
+        public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 91c668e..ba75c8b 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -23,7 +23,6 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.ArraySet;
 import android.view.autofill.AutoFillId;
 import android.view.autofill.AutoFillManager;
 import android.widget.RemoteViews;
@@ -69,18 +68,19 @@
  *
  * <p>If the user does not have any data associated with this {@link android.app.Activity} but
  * the service wants to offer the user the option to save the data that was entered, then the
- * service could populate the response with {@code savableIds} instead of {@link Dataset}s:
+ * service could populate the response with a {@link SaveInfo} instead of {@link Dataset}s:
  *
  * <pre class="prettyprint">
  *  new FillResponse.Builder()
- *      .addSavableFields(id1, id2)
+ *      .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_INFO_TYPE_CREDENTIALS)
+ *                   .addSavableFields(id1, id2))
  *      .build();
  * </pre>
  *
  * <p>Similarly, there might be cases where the user data on the service is enough to populate some
  * fields but not all, and the service would still be interested on saving the other fields. In this
- * scenario, the service could populate the response with both {@link Dataset}s and {@code
- * savableIds}:
+ * scenario, the service could populate the response with both {@link Dataset}s and
+ * {@link SaveInfo}:
  *
  * <pre class="prettyprint">
  *   new FillResponse.Builder()
@@ -90,7 +90,8 @@
  *          .setTextFieldValue(id3, "742 Evergreen Terrace")  // street
  *          .setTextFieldValue(id4, "Springfield")            // city
  *          .build())
- *       .addSavableFields(id5, id6) // state and zipcode
+ *       .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_INFO_TYPE_ADDRESS)
+ *                   .addSavableFields(id5, id6)) // state and zipcode
  *       .build();
  *
  * </pre>
@@ -140,9 +141,11 @@
  * </pre>
  *
  * <p>The service could require user authentication at the {@link FillResponse} or the
- * {@link Dataset} level, prior to auto-filling an activity - see {@link FillResponse.Builder
- * #setAuthentication(IntentSender)} and {@link Dataset.Builder#setAuthentication(IntentSender)}.
- * It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
+ * {@link Dataset} level, prior to auto-filling an activity - see
+ * {@link FillResponse.Builder#setAuthentication(IntentSender, RemoteViews)} and
+ * {@link Dataset.Builder#setAuthentication(IntentSender)}.
+ *
+ * <p>It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
  * which would allow you to provide a dataset presentation views with labels and if the user
  * chooses one of them challenge the user to authenticate. For example, if the user has a
  * home and a work address the Home and Work labels could be stored unencrypted as they don't
@@ -158,14 +161,45 @@
 public final class FillResponse implements Parcelable {
 
     private final ArrayList<Dataset> mDatasets;
-    private final ArraySet<AutoFillId> mSavableIds;
+    private final SaveInfo mSaveInfo;
     private final Bundle mExtras;
     private final RemoteViews mPresentation;
     private final IntentSender mAuthentication;
 
     private FillResponse(@NonNull Builder builder) {
         mDatasets = builder.mDatasets;
-        mSavableIds = builder.mSavableIds;
+
+        if (false) {
+            // TODO(b/33197203, 35727295): this is how mSaveInfo will be set once we don't support
+            // FillResponse.setSavableIds()
+            mSaveInfo = builder.mSaveInfo;
+            if (mSaveInfo != null) {
+                mSaveInfo.addSavableIds(mDatasets);
+                if (mSaveInfo.getSavableIds() == null) {
+                    throw new IllegalArgumentException(
+                            "need to provide at least one savable id on SaveInfo");
+                }
+            }
+        } else {
+            // Temporary workaround to support FillResponse.setSavableIds()
+            SaveInfo saveInfo = builder.mSaveInfoBuilder != null ? builder.mSaveInfoBuilder.build()
+                    : builder.mSaveInfo;
+
+            // Handle the the case where service didn't call setSavableIds() because it would
+            // contain just the ids from the datasets.
+            if (saveInfo == null && mDatasets != null) {
+                saveInfo = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC).build();
+            }
+            if (saveInfo != null) {
+                saveInfo.addSavableIds(mDatasets);
+                if (saveInfo.getSavableIds() == null) {
+                    throw new IllegalArgumentException(
+                            "need to provide at least one savable id on SaveInfo");
+                }
+            }
+            mSaveInfo = saveInfo;
+        }
+
         mExtras = builder.mExtras;
         mPresentation = builder.mPresentation;
         mAuthentication = builder.mAuthentication;
@@ -182,8 +216,8 @@
     }
 
     /** @hide */
-    public @Nullable ArraySet<AutoFillId> getSavableIds() {
-        return mSavableIds;
+    public @Nullable SaveInfo getSaveInfo() {
+        return mSaveInfo;
     }
 
     /** @hide */
@@ -202,7 +236,10 @@
      */
     public static final class Builder {
         private ArrayList<Dataset> mDatasets;
-        private ArraySet<AutoFillId> mSavableIds;
+        // TODO(b/33197203, 35727295): temporary builder use by deprecated addSavableIds() method,
+        // should be removed once that method is gone
+        private SaveInfo.Builder mSaveInfoBuilder;
+        private SaveInfo mSaveInfo;
         private Bundle mExtras;
         private RemoteViews mPresentation;
         private IntentSender mAuthentication;
@@ -276,41 +313,37 @@
             if (!mDatasets.add(dataset)) {
                 return this;
             }
-            if (dataset.getFieldIds() != null) {
-                final int fieldCount = dataset.getFieldIds().size();
-                for (int i = 0; i < fieldCount; i++) {
-                    final AutoFillId id = dataset.getFieldIds().get(i);
-                    if (mSavableIds == null) {
-                        mSavableIds = new ArraySet<>();
-                    }
-                    mSavableIds.add(id);
-                }
+            return this;
+        }
+
+        /** @hide */
+        // TODO(b/33197203, 35727295): remove when not used by clients
+        public @NonNull Builder addSavableFields(@Nullable AutoFillId... ids) {
+            throwIfDestroyed();
+            if (mSaveInfo != null) {
+                throw new IllegalStateException("setSaveInfo() already called");
             }
+            if (mSaveInfoBuilder == null) {
+                mSaveInfoBuilder = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC);
+            }
+            mSaveInfoBuilder.addSavableIds(ids);
+
             return this;
         }
 
         /**
-         * Adds ids of additional fields that the service would be interested to save (through
-         * {@link AutoFillService#onSaveRequest(
-         * android.app.assist.AssistStructure, Bundle, SaveCallback)})
-         * but were not indirectly set through {@link #addDataset(Dataset)}.
+         * Sets the {@link SaveInfo} associated with this response.
          *
-         * @param ids The savable ids.
+         * <p>See {@link FillResponse} for more info.
+         *
          * @return This builder.
-         *
-         * @see FillResponse
          */
-        public @NonNull Builder addSavableFields(@Nullable AutoFillId... ids) {
+        public @NonNull Builder setSaveInfo(@NonNull SaveInfo saveInfo) {
             throwIfDestroyed();
-            if (ids == null) {
-                return this;
+            if (mSaveInfoBuilder != null) {
+                throw new IllegalStateException("addSavableFields() already called");
             }
-            for (AutoFillId id : ids) {
-                if (mSavableIds == null) {
-                    mSavableIds = new ArraySet<>();
-                }
-                mSavableIds.add(id);
-            }
+            mSaveInfo = saveInfo;
             return this;
         }
 
@@ -340,9 +373,11 @@
          */
         public FillResponse build() {
             throwIfDestroyed();
-            if (mAuthentication == null && mDatasets == null && mSavableIds == null) {
-                throw new IllegalArgumentException("need to provide at least one"
-                        + " data set or savable ids or an authentication with a presentation");
+
+            if (mAuthentication == null && mDatasets == null && mSaveInfoBuilder == null
+                    && mSaveInfo == null) {
+                throw new IllegalArgumentException("need to provide at least one DataSet or a "
+                        + "SaveInfo or an authentication with a presentation");
             }
             mDestroyed = true;
             return new FillResponse(this);
@@ -361,9 +396,10 @@
     @Override
     public String toString() {
         if (!DEBUG) return super.toString();
+
         return new StringBuilder(
                 "FillResponse: [datasets=").append(mDatasets)
-                .append(", savableIds=").append(mSavableIds)
+                .append(", saveInfo=").append(mSaveInfo)
                 .append(", hasExtras=").append(mExtras != null)
                 .append(", hasPresentation=").append(mPresentation != null)
                 .append(", hasAuthentication=").append(mAuthentication != null)
@@ -382,7 +418,7 @@
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeTypedArrayList(mDatasets, flags);
-        parcel.writeTypedArraySet(mSavableIds, flags);
+        parcel.writeParcelable(mSaveInfo, flags);
         parcel.writeParcelable(mExtras, flags);
         parcel.writeParcelable(mAuthentication, flags);
         parcel.writeParcelable(mPresentation, flags);
@@ -401,11 +437,7 @@
             for (int i = 0; i < datasetCount; i++) {
                 builder.addDataset(datasets.get(i));
             }
-            final ArraySet<AutoFillId> fillIds = parcel.readTypedArraySet(null);
-            final int fillIdCount = (fillIds != null) ? fillIds.size() : 0;
-            for (int i = 0; i < fillIdCount; i++) {
-                builder.addSavableFields(fillIds.valueAt(i));
-            }
+            builder.setSaveInfo(parcel.readParcelable(null));
             builder.setExtras(parcel.readParcelable(null));
             builder.setAuthentication(parcel.readParcelable(null),
                     parcel.readParcelable(null));
diff --git a/core/java/android/net/NetworkScorerAppManager.aidl b/core/java/android/service/autofill/SaveInfo.aidl
similarity index 88%
copy from core/java/android/net/NetworkScorerAppManager.aidl
copy to core/java/android/service/autofill/SaveInfo.aidl
index d968343..8cda608 100644
--- a/core/java/android/net/NetworkScorerAppManager.aidl
+++ b/core/java/android/service/autofill/SaveInfo.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net;
+package android.service.autofill;
 
-parcelable NetworkScorerAppManager.NetworkScorerAppData;
+parcelable SaveInfo;
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
new file mode 100644
index 0000000..096f28b
--- /dev/null
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2017 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.service.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+import android.view.autofill.AutoFillId;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+
+/**
+ * Information used to indicate that a service is interested on saving the user-inputed data for
+ * future use.
+ *
+ * <p>A {@link SaveInfo} is always associated with a {@link FillResponse}.
+ *
+ * <p>A {@link SaveInfo} must define the type it represents, and contain at least one
+ * {@code savableId}. A {@code savableId} is the {@link AutoFillId} of a view the service is
+ * interested to save in a {@code onSaveRequest()}; the ids of all {@link Dataset} present in the
+ * {@link FillResponse} associated with this {@link SaveInfo} are already marked as savable,
+ * but additional ids can be added through {@link Builder#addSavableIds(AutoFillId...)}.
+ *
+ * <p>See {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+ * SaveCallback)} and {@link FillResponse} for more info.
+ */
+public final class SaveInfo implements Parcelable {
+
+    /**
+     * Type used on when the service can save the contents of an activity, but cannot describe what
+     * the content is for.
+     */
+    public static final int SAVE_DATA_TYPE_GENERIC = 0;
+
+    /**
+     * Type used when the {@link FillResponse} represents user credentials that have a password.
+     */
+    public static final int SAVE_DATA_TYPE_PASSWORD = 1;
+
+
+    /**
+     * Type used on when the {@link FillResponse} represents a physical address (such as street,
+     * city, state, etc).
+     */
+    public static final int SAVE_DATA_TYPE_ADDRESS = 2;
+
+    /**
+     * Type used when the {@link FillResponse} represents a credit card.
+     */
+    public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3;
+
+    private final @SaveDataType int mType;
+    private ArraySet<AutoFillId> mSavableIds;
+    private final CharSequence mDescription;
+
+    /** @hide */
+    @IntDef({
+        SAVE_DATA_TYPE_GENERIC,
+        SAVE_DATA_TYPE_PASSWORD,
+        SAVE_DATA_TYPE_ADDRESS,
+        SAVE_DATA_TYPE_CREDIT_CARD
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SaveDataType {
+    }
+
+    private SaveInfo(Builder builder) {
+        mType = builder.mType;
+        mSavableIds = builder.mSavableIds;
+        mDescription = builder.mDescription;
+    }
+
+    /** @hide */
+    public @Nullable ArraySet<AutoFillId> getSavableIds() {
+        return mSavableIds;
+    }
+
+    /** @hide */
+    public int getType() {
+        return mType;
+    }
+
+    /** @hide */
+    public CharSequence getDescription() {
+        return mDescription;
+    }
+
+    /** @hide */
+    public void addSavableIds(@Nullable ArrayList<Dataset> datasets) {
+        if (datasets != null) {
+            for (Dataset dataset : datasets) {
+                final ArrayList<AutoFillId> ids = dataset.getFieldIds();
+                if (ids != null) {
+                    final int fieldCount = ids.size();
+                    for (int i = 0; i < fieldCount; i++) {
+                        final AutoFillId id = ids.get(i);
+                        if (mSavableIds == null) {
+                            mSavableIds = new ArraySet<>();
+                        }
+                        mSavableIds.add(id);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * A builder for {@link SaveInfo} objects.
+     */
+    public static final class Builder {
+
+        private final @SaveDataType int mType;
+        private ArraySet<AutoFillId> mSavableIds;
+        private CharSequence mDescription;
+        private boolean mDestroyed;
+
+        /**
+         * Creates a new builder.
+         *
+         * @param type the type of information the associated {@link FillResponse} represents. Must
+         * be {@link SaveInfo#SAVE_DATA_TYPE_GENERIC}, {@link SaveInfo#SAVE_DATA_TYPE_PASSWORD},
+         * {@link SaveInfo#SAVE_DATA_TYPE_ADDRESS}, or {@link SaveInfo#SAVE_DATA_TYPE_CREDIT_CARD};
+         * otherwise it will assume {@link SaveInfo#SAVE_DATA_TYPE_GENERIC}.
+         */
+        public Builder(@SaveDataType int type) {
+            switch (type) {
+                case SAVE_DATA_TYPE_PASSWORD:
+                case SAVE_DATA_TYPE_ADDRESS:
+                case SAVE_DATA_TYPE_CREDIT_CARD:
+                    mType = type;
+                    break;
+                default:
+                    mType = SAVE_DATA_TYPE_GENERIC;
+            }
+        }
+
+        /**
+         * Adds ids of additional views the service would be interested to save, but were not
+         * indirectly set through {@link FillResponse.Builder#addDataset(Dataset)}.
+         *
+         * @param ids The savable ids.
+         * @return This builder.
+         *
+         * @see FillResponse
+         */
+        public @NonNull Builder addSavableIds(@Nullable AutoFillId... ids) {
+            throwIfDestroyed();
+
+            if (ids == null) {
+                return this;
+            }
+            for (AutoFillId id : ids) {
+                if (mSavableIds == null) {
+                    mSavableIds = new ArraySet<>();
+                }
+                mSavableIds.add(id);
+            }
+            return this;
+        }
+
+        /**
+         * Sets an optional description to be shown in the UI when the user is asked to save.
+         *
+         * <p>Typically, it describes how the data will be stored by the service, so it can help
+         * users to decide whether they can trust the service to save their data.
+         *
+         * @param description a succint description.
+         * @return This Builder.
+         */
+        public @NonNull Builder setDescription(@Nullable CharSequence description) {
+            mDescription = description;
+            return this;
+        }
+
+        /**
+         * Builds a new {@link SaveInfo} instance.
+         */
+        public SaveInfo build() {
+            throwIfDestroyed();
+            mDestroyed = true;
+            return new SaveInfo(this);
+        }
+
+        private void throwIfDestroyed() {
+            if (mDestroyed) {
+                throw new IllegalStateException("Already called #build()");
+            }
+        }
+
+    }
+
+    /////////////////////////////////////
+    // Object "contract" methods. //
+    /////////////////////////////////////
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        return new StringBuilder("SaveInfo: [type=").append(mType)
+                .append(", savableIds=").append(mSavableIds)
+                .append("]").toString();
+    }
+
+    /////////////////////////////////////
+    // Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(mType);
+        parcel.writeTypedArraySet(mSavableIds, flags);
+        parcel.writeCharSequence(mDescription);
+    }
+
+    public static final Parcelable.Creator<SaveInfo> CREATOR = new Parcelable.Creator<SaveInfo>() {
+        @Override
+        public SaveInfo createFromParcel(Parcel parcel) {
+            // Always go through the builder to ensure the data ingested by
+            // the system obeys the contract of the builder to avoid attacks
+            // using specially crafted parcels.
+            final Builder builder = new Builder(parcel.readInt());
+            final ArraySet<AutoFillId> savableIds = parcel.readTypedArraySet(null);
+            final int savableIdsCount = (savableIds != null) ? savableIds.size() : 0;
+            for (int i = 0; i < savableIdsCount; i++) {
+                builder.addSavableIds(savableIds.valueAt(i));
+            }
+            builder.setDescription(parcel.readCharSequence());
+            return builder.build();
+        }
+
+        @Override
+        public SaveInfo[] newArray(int size) {
+            return new SaveInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 5f7ff67..8a83b7a 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -547,20 +547,20 @@
      * Inform the notification manager about snoozing a specific notification.
      * <p>
      * Use this if your listener has a user interface that allows the user to snooze a notification
-     * until a given time. It should be called after the user snoozes a single notification using
+     * for a time. It should be called after the user snoozes a single notification using
      * your UI; upon being informed, the notification manager will actually remove the notification
      * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. When the
      * snoozing period expires, you will get a
      * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
      * notification.
      * @param key The key of the notification to snooze
-     * @param snoozeUntil A time in the future, in milliseconds.
+     * @param durationMs A duration to snooze the notification for, in milliseconds.
      */
-    public final void snoozeNotification(String key, long snoozeUntil) {
+    public final void snoozeNotification(String key, long durationMs) {
         if (!isBound()) return;
         try {
             getNotificationInterface().snoozeNotificationUntilFromListener(
-                    mWrapper, key, snoozeUntil);
+                    mWrapper, key, durationMs);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
         }
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 356804e..80ec03e 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -189,7 +189,9 @@
         // TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
         String[] availableLanguages = {
             "as",
+            "bg",
             "bn",
+            "cu",
             "cy",
             "da",
             "de-1901", "de-1996", "de-CH-1901",
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java
index e4f8dd1..84c2e83 100644
--- a/core/java/android/util/Half.java
+++ b/core/java/android/util/Half.java
@@ -17,9 +17,13 @@
 package android.util;
 
 import android.annotation.HalfFloat;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import sun.misc.FloatingDecimal;
 
 /**
- * <p>Half is a utility class to manipulate half-precision 16-bit
+ * <p>The {@code Half} class is a wrapper and a utility class to manipulate half-precision 16-bit
  * <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a>
  * floating point data types (also called fp16 or binary16). A half-precision float can be
  * created from or converted to single-precision floats, and is stored in a short data type.
@@ -88,7 +92,7 @@
  * <p>This table shows that numbers higher than 1024 lose all fractional precision.</p>
  */
 @SuppressWarnings("SimplifiableIfStatement")
-public final class Half {
+public final class Half extends Number implements Comparable<Half> {
     /**
      * The number of bits used to represent a half-precision float value.
      */
@@ -164,7 +168,332 @@
     private static final int FP32_DENORMAL_MAGIC = 126 << 23;
     private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
 
-    private Half() {
+    private final @HalfFloat short mValue;
+
+    /**
+     * Constructs a newly allocated {@code Half} object that represents the
+     * half-precision float type argument.
+     *
+     * @param value The value to be represented by the {@code Half}
+     */
+    public Half(@HalfFloat short value) {
+        mValue = value;
+    }
+
+    /**
+     * Constructs a newly allocated {@code Half} object that represents the
+     * argument converted to a half-precision float.
+     *
+     * @param value The value to be represented by the {@code Half}
+     *
+     * @see #toHalf(float)
+     */
+    public Half(float value) {
+        mValue = toHalf(value);
+    }
+
+    /**
+     * Constructs a newly allocated {@code Half} object that
+     * represents the argument converted to a half-precision float.
+     *
+     * @param value The value to be represented by the {@code Half}
+     *
+     * @see #toHalf(float)
+     */
+    public Half(double value) {
+        mValue = toHalf((float) value);
+    }
+
+    /**
+     * <p>Constructs a newly allocated {@code Half} object that represents the
+     * half-precision float value represented by the string.
+     * The string is converted to a half-precision float value as if by the
+     * {@link #valueOf(String)} method.</p>
+     *
+     * <p>Calling this constructor is equivalent to calling:</p>
+     * <pre>
+     *     new Half(Float.parseFloat(value))
+     * </pre>
+     *
+     * @param value A string to be converted to a {@code Half}
+     * @throws NumberFormatException if the string does not contain a parsable number
+     *
+     * @see Float#valueOf(java.lang.String)
+     * @see #toHalf(float)
+     */
+    public Half(@NonNull String value) throws NumberFormatException {
+        mValue = toHalf(Float.parseFloat(value));
+    }
+
+    /**
+     * Returns the half-precision value of this {@code Half} as a {@code short}
+     * containing the bit representation described in {@link Half}.
+     *
+     * @return The half-precision float value represented by this object
+     */
+    public @HalfFloat short halfValue() {
+        return mValue;
+    }
+
+    /**
+     * Returns the value of this {@code Half} as a {@code byte} after
+     * a narrowing primitive conversion.
+     *
+     * @return The half-precision float value represented by this object
+     *         converted to type {@code byte}
+     */
+    @Override
+    public byte byteValue() {
+        return (byte) toFloat(mValue);
+    }
+
+    /**
+     * Returns the value of this {@code Half} as a {@code short} after
+     * a narrowing primitive conversion.
+     *
+     * @return The half-precision float value represented by this object
+     *         converted to type {@code short}
+     */
+    @Override
+    public short shortValue() {
+        return (short) toFloat(mValue);
+    }
+
+    /**
+     * Returns the value of this {@code Half} as a {@code int} after
+     * a narrowing primitive conversion.
+     *
+     * @return The half-precision float value represented by this object
+     *         converted to type {@code int}
+     */
+    @Override
+    public int intValue() {
+        return (int) toFloat(mValue);
+    }
+
+    /**
+     * Returns the value of this {@code Half} as a {@code long} after
+     * a narrowing primitive conversion.
+     *
+     * @return The half-precision float value represented by this object
+     *         converted to type {@code long}
+     */
+    @Override
+    public long longValue() {
+        return (long) toFloat(mValue);
+    }
+
+    /**
+     * Returns the value of this {@code Half} as a {@code float} after
+     * a widening primitive conversion.
+     *
+     * @return The half-precision float value represented by this object
+     *         converted to type {@code float}
+     */
+    @Override
+    public float floatValue() {
+        return toFloat(mValue);
+    }
+
+    /**
+     * Returns the value of this {@code Half} as a {@code double} after
+     * a widening primitive conversion.
+     *
+     * @return The half-precision float value represented by this object
+     *         converted to type {@code double}
+     */
+    @Override
+    public double doubleValue() {
+        return toFloat(mValue);
+    }
+
+    /**
+     * Returns true if this {@code Half} value represents a Not-a-Number,
+     * false otherwise.
+     *
+     * @return True if the value is a NaN, false otherwise
+     */
+    public boolean isNaN() {
+        return isNaN(mValue);
+    }
+
+    /**
+     * Compares this object against the specified object. The result is {@code true}
+     * if and only if the argument is not {@code null} and is a {@code Half} object
+     * that represents the same half-precision value as the this object. Two
+     * half-precision values are considered to be the same if and only if the method
+     * {@link #halfToIntBits(short)} returns an identical {@code int} value for both.
+     *
+     * @param o The object to compare
+     * @return True if the objects are the same, false otherwise
+     *
+     * @see #halfToIntBits(short)
+     */
+    @Override
+    public boolean equals(@Nullable Object o) {
+        return (o instanceof Half) &&
+                (halfToIntBits(((Half) o).mValue) == halfToIntBits(mValue));
+    }
+
+    /**
+     * Returns a hash code for this {@code Half} object. The result is the
+     * integer bit representation, exactly as produced by the method
+     * {@link #halfToIntBits(short)}, of the primitive half-precision float
+     * value represented by this {@code Half} object.
+     *
+     * @return A hash code value for this object
+     */
+    @Override
+    public int hashCode() {
+        return hashCode(mValue);
+    }
+
+    /**
+     * Returns a string representation of the specified half-precision
+     * float value. See {@link #toString(short)} for more information.
+     *
+     * @return A string representation of this {@code Half} object
+     */
+    @NonNull
+    @Override
+    public String toString() {
+        return toString(mValue);
+    }
+
+    /**
+     * <p>Compares the two specified half-precision float values. The following
+     * conditions apply during the comparison:</p>
+     *
+     * <ul>
+     * <li>{@link #NaN} is considered by this method to be equal to itself and greater
+     * than all other half-precision float values (including {@code #POSITIVE_INFINITY})</li>
+     * <li>{@link #POSITIVE_ZERO} is considered by this method to be greater than
+     * {@link #NEGATIVE_ZERO}.</li>
+     * </ul>
+     *
+     * @param h The half-precision float value to compare to the half-precision value
+     *          represented by this {@code Half} object
+     *
+     * @return  The value {@code 0} if {@code x} is numerically equal to {@code y}; a
+     *          value less than {@code 0} if {@code x} is numerically less than {@code y};
+     *          and a value greater than {@code 0} if {@code x} is numerically greater
+     *          than {@code y}
+     */
+    @Override
+    public int compareTo(@NonNull Half h) {
+        return compare(mValue, h.mValue);
+    }
+
+    /**
+     * Returns a hash code for a half-precision float value.
+     *
+     * @param h The value to hash
+     *
+     * @return A hash code value for a half-precision float value
+     */
+    public static int hashCode(@HalfFloat short h) {
+        return halfToIntBits(h);
+    }
+
+    /**
+     * <p>Compares the two specified half-precision float values. The following
+     * conditions apply during the comparison:</p>
+     *
+     * <ul>
+     * <li>{@link #NaN} is considered by this method to be equal to itself and greater
+     * than all other half-precision float values (including {@code #POSITIVE_INFINITY})</li>
+     * <li>{@link #POSITIVE_ZERO} is considered by this method to be greater than
+     * {@link #NEGATIVE_ZERO}.</li>
+     * </ul>
+     *
+     * @param x The first half-precision float value to compare.
+     * @param y The second half-precision float value to compare
+     *
+     * @return  The value {@code 0} if {@code x} is numerically equal to {@code y}, a
+     *          value less than {@code 0} if {@code x} is numerically less than {@code y},
+     *          and a value greater than {@code 0} if {@code x} is numerically greater
+     *          than {@code y}
+     */
+    public static int compare(@HalfFloat short x, @HalfFloat short y) {
+        if (less(x, y)) return -1;
+        if (greater(x, y)) return 1;
+
+        // Collapse NaNs, akin to halfToIntBits(), but we want to keep
+        // (signed) short value types to preserve the ordering of -0.0
+        // and +0.0
+        short xBits = (x & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : x;
+        short yBits = (y & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : y;
+
+        return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1));
+    }
+
+    /**
+     * <p>Returns a representation of the specified half-precision float value
+     * according to the bit layout described in {@link Half}.</p>
+     *
+     * <p>Similar to {@link #halfToIntBits(short)}, this method collapses all
+     * possible Not-a-Number values to a single canonical Not-a-Number value
+     * defined by {@link #NaN}.</p>
+     *
+     * @param h A half-precision float value
+     * @return The bits that represent the half-precision float value
+     *
+     * @see #halfToIntBits(short)
+     */
+    public static @HalfFloat short halfToShortBits(@HalfFloat short h) {
+        return (h & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : h;
+    }
+
+    /**
+     * <p>Returns a representation of the specified half-precision float value
+     * according to the bit layout described in {@link Half}.</p>
+     *
+     * <p>Unlike {@link #halfToRawIntBits(short)}, this method collapses all
+     * possible Not-a-Number values to a single canonical Not-a-Number value
+     * defined by {@link #NaN}.</p>
+     *
+     * @param h A half-precision float value
+     * @return The bits that represent the half-precision float value
+     *
+     * @see #halfToRawIntBits(short)
+     * @see #halfToShortBits(short)
+     * @see #intBitsToHalf(int)
+     */
+    public static int halfToIntBits(@HalfFloat short h) {
+        return (h & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : h & 0xffff;
+    }
+
+    /**
+     * <p>Returns a representation of the specified half-precision float value
+     * according to the bit layout described in {@link Half}.</p>
+     *
+     * <p>The argument is considered to be a representation of a half-precision
+     * float value according to the bit layout described in {@link Half}. The 16
+     * most significant bits of the returned value are set to 0.</p>
+     *
+     * @param h A half-precision float value
+     * @return The bits that represent the half-precision float value
+     *
+     * @see #halfToIntBits(short)
+     * @see #intBitsToHalf(int)
+     */
+    public static int halfToRawIntBits(@HalfFloat short h) {
+        return h & 0xffff;
+    }
+
+    /**
+     * <p>Returns the half-precision float value corresponding to a given
+     * bit representation.</p>
+     *
+     * <p>The argument is considered to be a representation of a half-precision
+     * float value according to the bit layout described in {@link Half}. The 16
+     * most significant bits of the argument are ignored.</p>
+     *
+     * @param bits An integer
+     * @return The half-precision float value with the same bit pattern
+     */
+    public static @HalfFloat short intBitsToHalf(int bits) {
+        return (short) (bits & 0xffff);
     }
 
     /**
@@ -509,7 +838,7 @@
      * infinity, false otherwise.
      *
      * @param h A half-precision float value
-     * @return true if the value is positive infinity or negative infinity,
+     * @return True if the value is positive infinity or negative infinity,
      *         false otherwise
      */
     public static boolean isInfinite(@HalfFloat short h) {
@@ -521,7 +850,7 @@
      * a Not-a-Number, false otherwise.
      *
      * @param h A half-precision float value
-     * @return true if the value is a NaN, false otherwise
+     * @return True if the value is a NaN, false otherwise
      */
     public static boolean isNaN(@HalfFloat short h) {
         return (h & FP16_COMBINED) > FP16_EXPONENT_MAX;
@@ -535,7 +864,7 @@
      * number, this method returns false.
      *
      * @param h A half-precision float value
-     * @return true if the value is normalized, false otherwise
+     * @return True if the value is normalized, false otherwise
      */
     public static boolean isNormalized(@HalfFloat short h) {
         return (h & FP16_EXPONENT_MAX) != 0 && (h & FP16_EXPONENT_MAX) != FP16_EXPONENT_MAX;
@@ -608,7 +937,7 @@
      * @return A half-precision float value
      */
     @SuppressWarnings("StatementWithEmptyBody")
-    public static @HalfFloat short valueOf(float f) {
+    public static @HalfFloat short toHalf(float f) {
         int bits = Float.floatToRawIntBits(f);
         int s = (bits >>> FP32_SIGN_SHIFT    );
         int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_EXPONENT_MASK;
@@ -650,6 +979,57 @@
     }
 
     /**
+     * Returns a {@code Half} instance representing the specified
+     * half-precision float value.
+     *
+     * @param h A half-precision float value
+     * @return a {@code Half} instance representing {@code h}
+     */
+    public static @NonNull Half valueOf(@HalfFloat short h) {
+        return new Half(h);
+    }
+
+    /**
+     * Returns a {@code Half} instance representing the specified float value.
+     *
+     * @param f A float value
+     * @return a {@code Half} instance representing {@code f}
+     */
+    public static @NonNull Half valueOf(float f) {
+        return new Half(f);
+    }
+
+    /**
+     * Returns a {@code Half} instance representing the specified string value.
+     * Calling this method is equivalent to calling
+     * <code>toHalf(Float.parseString(h))</code>. See {@link Float#valueOf(String)}
+     * for more information on the format of the string representation.
+     *
+     * @param s The string to be parsed
+     * @return a {@code Half} instance representing {@code h}
+     * @throws NumberFormatException if the string does not contain a parsable
+     *         half-precision float value
+     */
+    public static @NonNull Half valueOf(@NonNull String s) {
+        return new Half(s);
+    }
+
+    /**
+     * Returns the half-precision float value represented by the specified string.
+     * Calling this method is equivalent to calling
+     * <code>toHalf(Float.parseString(h))</code>. See {@link Float#valueOf(String)}
+     * for more information on the format of the string representation.
+     *
+     * @param s The string to be parsed
+     * @return A half-precision float value represented by the string
+     * @throws NumberFormatException if the string does not contain a parsable
+     *         half-precision float value
+     */
+    public static @HalfFloat short parseHalf(@NonNull String s) throws NumberFormatException {
+        return toHalf(FloatingDecimal.parseFloat(s));
+    }
+
+    /**
      * Returns a string representation of the specified half-precision
      * float value. Calling this method is equivalent to calling
      * <code>Float.toString(toFloat(h))</code>. See {@link Float#toString(float)}
@@ -658,6 +1038,7 @@
      * @param h A half-precision float value
      * @return A string representation of the specified value
      */
+    @NonNull
     public static String toString(@HalfFloat short h) {
         return Float.toString(toFloat(h));
     }
@@ -688,6 +1069,7 @@
      * @param h A half-precision float value
      * @return A hexadecimal string representation of the specified value
      */
+    @NonNull
     public static String toHexString(@HalfFloat short h) {
         StringBuilder o = new StringBuilder();
 
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 7fde8a6..ad06141 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -117,7 +117,7 @@
     public View findNextKeyboardNavigationCluster(
             @NonNull View root,
             @Nullable View currentCluster,
-            int direction) {
+            @View.FocusDirection int direction) {
         View next = null;
 
         final ArrayList<View> clusters = mTempList;
@@ -206,7 +206,7 @@
             View root,
             View currentCluster,
             List<View> clusters,
-            int direction) {
+            @View.FocusDirection int direction) {
         final int count = clusters.size();
 
         switch (direction) {
@@ -732,27 +732,17 @@
             getRect(first, mFirstRect);
             getRect(second, mSecondRect);
 
-            if (mFirstRect.top < mSecondRect.top) {
-                return -1;
-            } else if (mFirstRect.top > mSecondRect.top) {
-                return 1;
-            } else if (mFirstRect.left < mSecondRect.left) {
-                return mIsLayoutRtl ? 1 : -1;
-            } else if (mFirstRect.left > mSecondRect.left) {
-                return mIsLayoutRtl ? -1 : 1;
-            } else if (mFirstRect.bottom < mSecondRect.bottom) {
-                return -1;
-            } else if (mFirstRect.bottom > mSecondRect.bottom) {
-                return 1;
-            } else if (mFirstRect.right < mSecondRect.right) {
-                return mIsLayoutRtl ? 1 : -1;
-            } else if (mFirstRect.right > mSecondRect.right) {
-                return mIsLayoutRtl ? -1 : 1;
+            boolean overlapsVertically = (mFirstRect.top < mSecondRect.top
+                    && mFirstRect.bottom > mSecondRect.top)
+                    || (mFirstRect.top > mSecondRect.top
+                    && mFirstRect.top < mSecondRect.bottom);
+            boolean alignedVertically = (mFirstRect.left > mSecondRect.left)
+                    == (mFirstRect.right < mSecondRect.right);
+            if (overlapsVertically && !alignedVertically) {
+                int rtl = mIsLayoutRtl ? -1 : 1;
+                return rtl * (mFirstRect.left - mSecondRect.left);
             } else {
-                // The view are distinct but completely coincident so we consider
-                // them equal for our purposes.  Since the sort is stable, this
-                // means that the views will retain their layout order relative to one another.
-                return 0;
+                return mFirstRect.top - mSecondRect.top;
             }
         }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 66c394f..1338b05 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9433,7 +9433,8 @@
      * @return The nearest keyboard navigation cluster in the specified direction, or null if none
      *         can be found
      */
-    public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+    public View keyboardNavigationClusterSearch(View currentCluster,
+            @FocusDirection int direction) {
         if (isKeyboardNavigationCluster()) {
             currentCluster = this;
         }
@@ -20259,9 +20260,9 @@
      * @return the view of the specified id, null if cannot be found
      * @hide
      */
-    protected View findViewTraversal(@IdRes int id) {
+    protected <T extends View> T findViewTraversal(@IdRes int id) {
         if (id == mID) {
-            return this;
+            return (T) this;
         }
         return null;
     }
@@ -20271,9 +20272,9 @@
      * @return the view of specified tag, null if cannot be found
      * @hide
      */
-    protected View findViewWithTagTraversal(Object tag) {
+    protected <T extends View> T findViewWithTagTraversal(Object tag) {
         if (tag != null && tag.equals(mTag)) {
-            return this;
+            return (T) this;
         }
         return null;
     }
@@ -20284,9 +20285,10 @@
      * @return The first view that matches the predicate or null.
      * @hide
      */
-    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+    protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
+            View childToSkip) {
         if (predicate.test(this)) {
-            return this;
+            return (T) this;
         }
         return null;
     }
@@ -20299,7 +20301,7 @@
      * @return The view that has the given id in the hierarchy or null
      */
     @Nullable
-    public final View findViewById(@IdRes int id) {
+    public final <T extends View> T findViewById(@IdRes int id) {
         if (id < 0) {
             return null;
         }
@@ -20312,11 +20314,11 @@
      * @param accessibilityId The searched accessibility id.
      * @return The found view.
      */
-    final View findViewByAccessibilityId(int accessibilityId) {
+    final <T extends View> T  findViewByAccessibilityId(int accessibilityId) {
         if (accessibilityId < 0) {
             return null;
         }
-        View view = findViewByAccessibilityIdTraversal(accessibilityId);
+        T view = findViewByAccessibilityIdTraversal(accessibilityId);
         if (view != null) {
             return view.includeForAccessibility() ? view : null;
         }
@@ -20335,12 +20337,11 @@
      *
      * @param accessibilityId The accessibility id.
      * @return The found view.
-     *
      * @hide
      */
-    public View findViewByAccessibilityIdTraversal(int accessibilityId) {
+    public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) {
         if (getAccessibilityViewId() == accessibilityId) {
-            return this;
+            return (T) this;
         }
         return null;
     }
@@ -20352,7 +20353,7 @@
      * @param tag The tag to search for, using "tag.equals(getTag())".
      * @return The View that has the given tag in the hierarchy or null
      */
-    public final View findViewWithTag(Object tag) {
+    public final <T extends View> T findViewWithTag(Object tag) {
         if (tag == null) {
             return null;
         }
@@ -20367,7 +20368,7 @@
      * @return The first view that matches the predicate or null.
      * @hide
      */
-    public final View findViewByPredicate(Predicate<View> predicate) {
+    public final <T extends View> T findViewByPredicate(Predicate<View> predicate) {
         return findViewByPredicateTraversal(predicate, null);
     }
 
@@ -20387,10 +20388,11 @@
      * @return The first view that matches the predicate or null.
      * @hide
      */
-    public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) {
+    public final <T extends View> T findViewByPredicateInsideOut(
+            View start, Predicate<View> predicate) {
         View childToSkip = null;
         for (;;) {
-            View view = start.findViewByPredicateTraversal(predicate, childToSkip);
+            T view = start.findViewByPredicateTraversal(predicate, childToSkip);
             if (view != null || start == this) {
                 return view;
             }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7aa2168..ffa79bd 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4324,9 +4324,9 @@
      * {@hide}
      */
     @Override
-    protected View findViewTraversal(@IdRes int id) {
+    protected <T extends View> T findViewTraversal(@IdRes int id) {
         if (id == mID) {
-            return this;
+            return (T) this;
         }
 
         final View[] where = mChildren;
@@ -4339,7 +4339,7 @@
                 v = v.findViewById(id);
 
                 if (v != null) {
-                    return v;
+                    return (T) v;
                 }
             }
         }
@@ -4351,9 +4351,9 @@
      * {@hide}
      */
     @Override
-    protected View findViewWithTagTraversal(Object tag) {
+    protected <T extends View> T findViewWithTagTraversal(Object tag) {
         if (tag != null && tag.equals(mTag)) {
-            return this;
+            return (T) this;
         }
 
         final View[] where = mChildren;
@@ -4366,7 +4366,7 @@
                 v = v.findViewWithTag(tag);
 
                 if (v != null) {
-                    return v;
+                    return (T) v;
                 }
             }
         }
@@ -4378,9 +4378,10 @@
      * {@hide}
      */
     @Override
-    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+    protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
+            View childToSkip) {
         if (predicate.test(this)) {
-            return this;
+            return (T) this;
         }
 
         final View[] where = mChildren;
@@ -4393,7 +4394,7 @@
                 v = v.findViewByPredicate(predicate);
 
                 if (v != null) {
-                    return v;
+                    return (T) v;
                 }
             }
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 595e7a1..20d960f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -72,6 +72,7 @@
 import android.util.TypedValue;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
+import android.view.View.FocusDirection;
 import android.view.View.MeasureSpec;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.accessibility.AccessibilityEvent;
@@ -4304,11 +4305,11 @@
                 mTranslator.translateEventInScreenToAppWindow(event);
             }
 
-            // Enter touch mode on down or scroll.
+            // Enter touch mode on down or scroll, if it is coming from a touch screen device,
+            // exit otherwise.
             final int action = event.getAction();
-            if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
-                    && (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL)) {
-                ensureTouchMode(true);
+            if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
+                ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
             }
 
             if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
@@ -5975,7 +5976,8 @@
      * {@inheritDoc}
      */
     @Override
-    public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+    public View keyboardNavigationClusterSearch(View currentCluster,
+            @FocusDirection int direction) {
         checkThread();
         return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
                 mView, currentCluster, direction);
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 51587a7..9a39a17 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -250,7 +250,7 @@
         mDefaultActivityButton = (FrameLayout) findViewById(R.id.default_activity_button);
         mDefaultActivityButton.setOnClickListener(mCallbacks);
         mDefaultActivityButton.setOnLongClickListener(mCallbacks);
-        mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.image);
+        mDefaultActivityButtonImage = mDefaultActivityButton.findViewById(R.id.image);
 
         final FrameLayout expandButton = (FrameLayout) findViewById(R.id.expand_activities_button);
         expandButton.setOnClickListener(mCallbacks);
@@ -282,7 +282,7 @@
         mExpandActivityOverflowButton = expandButton;
 
         mExpandActivityOverflowButtonImage =
-            (ImageView) expandButton.findViewById(R.id.image);
+            expandButton.findViewById(R.id.image);
         mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
 
         mAdapter = new ActivityChooserViewAdapter();
@@ -760,7 +760,7 @@
                         convertView = LayoutInflater.from(getContext()).inflate(
                                 R.layout.activity_chooser_view_list_item, parent, false);
                         convertView.setId(ITEM_VIEW_TYPE_FOOTER);
-                        TextView titleView = (TextView) convertView.findViewById(R.id.title);
+                        TextView titleView = convertView.findViewById(R.id.title);
                         titleView.setText(mContext.getString(
                                 R.string.activity_chooser_view_see_all));
                     }
@@ -772,11 +772,11 @@
                     }
                     PackageManager packageManager = mContext.getPackageManager();
                     // Set the icon
-                    ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
+                    ImageView iconView = convertView.findViewById(R.id.icon);
                     ResolveInfo activity = (ResolveInfo) getItem(position);
                     iconView.setImageDrawable(activity.loadIcon(packageManager));
                     // Set the title.
-                    TextView titleView = (TextView) convertView.findViewById(R.id.title);
+                    TextView titleView = convertView.findViewById(R.id.title);
                     titleView.setText(activity.loadLabel(packageManager));
                     // Highlight the default.
                     if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 68e6809..06d4868 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -451,7 +451,7 @@
 
     private View getPermissionsView(int which, boolean showRevokeUI) {
         LinearLayout permsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null);
-        LinearLayout displayList = (LinearLayout) permsView.findViewById(R.id.perms_list);
+        LinearLayout displayList = permsView.findViewById(R.id.perms_list);
         View noPermsView = permsView.findViewById(R.id.no_permissions);
 
         displayPermissions(mPermGroupsList, displayList, which, showRevokeUI);
@@ -517,8 +517,8 @@
             CharSequence grpName, CharSequence permList, boolean dangerous, Drawable icon) {
         View permView = inflater.inflate(R.layout.app_permission_item_old, null);
 
-        TextView permGrpView = (TextView) permView.findViewById(R.id.permission_group);
-        TextView permDescView = (TextView) permView.findViewById(R.id.permission_list);
+        TextView permGrpView = permView.findViewById(R.id.permission_group);
+        TextView permDescView = permView.findViewById(R.id.permission_list);
 
         ImageView imgView = (ImageView)permView.findViewById(R.id.perm_icon);
         imgView.setImageDrawable(icon);
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index bbc50da..81f0d3d 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -388,7 +388,7 @@
                 text = (TextView) view;
             } else {
                 //  Otherwise, find the TextView field within the layout
-                text = (TextView) view.findViewById(mFieldId);
+                text = view.findViewById(mFieldId);
 
                 if (text == null) {
                     throw new RuntimeException("Failed to find view with ID "
diff --git a/core/java/android/widget/CalendarViewLegacyDelegate.java b/core/java/android/widget/CalendarViewLegacyDelegate.java
index 557d411..1b899db 100644
--- a/core/java/android/widget/CalendarViewLegacyDelegate.java
+++ b/core/java/android/widget/CalendarViewLegacyDelegate.java
@@ -316,9 +316,9 @@
         View content = layoutInflater.inflate(R.layout.calendar_view, null, false);
         mDelegator.addView(content);
 
-        mListView = (ListView) mDelegator.findViewById(R.id.list);
-        mDayNamesHeader = (ViewGroup) content.findViewById(R.id.day_names);
-        mMonthName = (TextView) content.findViewById(R.id.month_name);
+        mListView = mDelegator.findViewById(R.id.list);
+        mDayNamesHeader = content.findViewById(R.id.day_names);
+        mMonthName = content.findViewById(R.id.month_name);
 
         setUpHeader();
         setUpListView();
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index f712685..907250a 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -115,10 +115,10 @@
         mDelegator.addView(mContainer);
 
         // Set up header views.
-        final ViewGroup header = (ViewGroup) mContainer.findViewById(R.id.date_picker_header);
-        mHeaderYear = (TextView) header.findViewById(R.id.date_picker_header_year);
+        final ViewGroup header = mContainer.findViewById(R.id.date_picker_header);
+        mHeaderYear = header.findViewById(R.id.date_picker_header_year);
         mHeaderYear.setOnClickListener(mOnHeaderClickListener);
-        mHeaderMonthDay = (TextView) header.findViewById(R.id.date_picker_header_date);
+        mHeaderMonthDay = header.findViewById(R.id.date_picker_header_date);
         mHeaderMonthDay.setOnClickListener(mOnHeaderClickListener);
 
         // For the sake of backwards compatibility, attempt to extract the text
@@ -154,10 +154,10 @@
         a.recycle();
 
         // Set up picker container.
-        mAnimator = (ViewAnimator) mContainer.findViewById(R.id.animator);
+        mAnimator = mContainer.findViewById(R.id.animator);
 
         // Set up day picker view.
-        mDayPickerView = (DayPickerView) mAnimator.findViewById(R.id.date_picker_day_picker);
+        mDayPickerView = mAnimator.findViewById(R.id.date_picker_day_picker);
         mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
         mDayPickerView.setMinDate(mMinDate.getTimeInMillis());
         mDayPickerView.setMaxDate(mMaxDate.getTimeInMillis());
@@ -165,7 +165,7 @@
         mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
 
         // Set up year picker view.
-        mYearPickerView = (YearPickerView) mAnimator.findViewById(R.id.date_picker_year_picker);
+        mYearPickerView = mAnimator.findViewById(R.id.date_picker_year_picker);
         mYearPickerView.setRange(mMinDate, mMaxDate);
         mYearPickerView.setYear(mCurrentDate.get(Calendar.YEAR));
         mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener);
diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index 8d5bf8f..63621e1 100644
--- a/core/java/android/widget/DayPickerPagerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -225,7 +225,7 @@
     public Object instantiateItem(ViewGroup container, int position) {
         final View itemView = mInflater.inflate(mLayoutResId, container, false);
 
-        final SimpleMonthView v = (SimpleMonthView) itemView.findViewById(mCalendarViewId);
+        final SimpleMonthView v = itemView.findViewById(mCalendarViewId);
         v.setOnDayClickListener(mOnDayClickListener);
         v.setMonthTextAppearance(mMonthTextAppearance);
         v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance);
diff --git a/core/java/android/widget/DayPickerViewPager.java b/core/java/android/widget/DayPickerViewPager.java
index a27e022..1704ed7 100644
--- a/core/java/android/widget/DayPickerViewPager.java
+++ b/core/java/android/widget/DayPickerViewPager.java
@@ -137,9 +137,10 @@
     }
 
     @Override
-    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+    protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
+            View childToSkip) {
         if (predicate.test(this)) {
-            return this;
+            return (T) this;
         }
 
         // Always try the selected view first.
@@ -148,7 +149,7 @@
         if (current != childToSkip && current != null) {
             final View v = current.findViewByPredicate(predicate);
             if (v != null) {
-                return v;
+                return (T) v;
             }
         }
 
@@ -160,7 +161,7 @@
                 final View v = child.findViewByPredicate(predicate);
 
                 if (v != null) {
-                    return v;
+                    return (T) v;
                 }
             }
         }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index dd3b054..ade03e1 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2183,6 +2183,11 @@
     }
 
     void onTouchUpEvent(MotionEvent event) {
+        if (getSelectionActionModeHelper().resetOriginalSelection(
+                getTextView().getOffsetForPosition(event.getX(), event.getY()))) {
+            return;
+        }
+
         boolean selectAllGotFocus = mSelectAllOnFocus && mTextView.didTouchFocusSelect();
         hideCursorAndSpanControllers();
         stopTextActionMode();
@@ -3916,7 +3921,7 @@
         @Override
         public void onDestroyActionMode(ActionMode mode) {
             // Clear mTextActionMode not to recursively destroy action mode by clearing selection.
-            getSelectionActionModeHelper().cancelAsyncTask();
+            getSelectionActionModeHelper().onDestroyActionMode();
             mTextActionMode = null;
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 46e998a..1c0c4ef 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3740,20 +3740,21 @@
      * @removed For internal use only. This should have been hidden.
      */
     @Override
-    protected View findViewTraversal(@IdRes int id) {
-        View v;
-        v = super.findViewTraversal(id);
+    protected <T extends View> T findViewTraversal(@IdRes int id) {
+        // First look in our children, then in any header and footer views that
+        // may be scrolled off.
+        View v = super.findViewTraversal(id);
         if (v == null) {
             v = findViewInHeadersOrFooters(mHeaderViewInfos, id);
             if (v != null) {
-                return v;
+                return (T) v;
             }
             v = findViewInHeadersOrFooters(mFooterViewInfos, id);
             if (v != null) {
-                return v;
+                return (T) v;
             }
         }
-        return v;
+        return (T) v;
     }
 
     View findViewInHeadersOrFooters(ArrayList<FixedViewInfo> where, int id) {
@@ -3782,21 +3783,22 @@
      * @removed For internal use only. This should have been hidden.
      */
     @Override
-    protected View findViewWithTagTraversal(Object tag) {
-        View v;
-        v = super.findViewWithTagTraversal(tag);
+    protected <T extends View> T findViewWithTagTraversal(Object tag) {
+        // First look in our children, then in any header and footer views that
+        // may be scrolled off.
+        View v = super.findViewWithTagTraversal(tag);
         if (v == null) {
             v = findViewWithTagInHeadersOrFooters(mHeaderViewInfos, tag);
             if (v != null) {
-                return v;
+                return (T) v;
             }
 
             v = findViewWithTagInHeadersOrFooters(mFooterViewInfos, tag);
             if (v != null) {
-                return v;
+                return (T) v;
             }
         }
-        return v;
+        return (T) v;
     }
 
     View findViewWithTagInHeadersOrFooters(ArrayList<FixedViewInfo> where, Object tag) {
@@ -3829,21 +3831,21 @@
      * @hide
      */
     @Override
-    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
-        View v;
-        v = super.findViewByPredicateTraversal(predicate, childToSkip);
+    protected <T extends View> T findViewByPredicateTraversal(
+            Predicate<View> predicate, View childToSkip) {
+        View v = super.findViewByPredicateTraversal(predicate, childToSkip);
         if (v == null) {
             v = findViewByPredicateInHeadersOrFooters(mHeaderViewInfos, predicate, childToSkip);
             if (v != null) {
-                return v;
+                return (T) v;
             }
 
             v = findViewByPredicateInHeadersOrFooters(mFooterViewInfos, predicate, childToSkip);
             if (v != null) {
-                return v;
+                return (T) v;
             }
         }
-        return v;
+        return (T) v;
     }
 
     /**
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 8008637..8e04f1c 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -257,13 +257,13 @@
                 .getText(com.android.internal.R.string.lockscreen_transport_play_description);
         mPauseDescription = res
                 .getText(com.android.internal.R.string.lockscreen_transport_pause_description);
-        mPauseButton = (ImageButton) v.findViewById(com.android.internal.R.id.pause);
+        mPauseButton = v.findViewById(com.android.internal.R.id.pause);
         if (mPauseButton != null) {
             mPauseButton.requestFocus();
             mPauseButton.setOnClickListener(mPauseListener);
         }
 
-        mFfwdButton = (ImageButton) v.findViewById(com.android.internal.R.id.ffwd);
+        mFfwdButton = v.findViewById(com.android.internal.R.id.ffwd);
         if (mFfwdButton != null) {
             mFfwdButton.setOnClickListener(mFfwdListener);
             if (!mFromXml) {
@@ -271,7 +271,7 @@
             }
         }
 
-        mRewButton = (ImageButton) v.findViewById(com.android.internal.R.id.rew);
+        mRewButton = v.findViewById(com.android.internal.R.id.rew);
         if (mRewButton != null) {
             mRewButton.setOnClickListener(mRewListener);
             if (!mFromXml) {
@@ -280,16 +280,16 @@
         }
 
         // By default these are hidden. They will be enabled when setPrevNextListeners() is called
-        mNextButton = (ImageButton) v.findViewById(com.android.internal.R.id.next);
+        mNextButton = v.findViewById(com.android.internal.R.id.next);
         if (mNextButton != null && !mFromXml && !mListenersSet) {
             mNextButton.setVisibility(View.GONE);
         }
-        mPrevButton = (ImageButton) v.findViewById(com.android.internal.R.id.prev);
+        mPrevButton = v.findViewById(com.android.internal.R.id.prev);
         if (mPrevButton != null && !mFromXml && !mListenersSet) {
             mPrevButton.setVisibility(View.GONE);
         }
 
-        mProgress = (ProgressBar) v.findViewById(com.android.internal.R.id.mediacontroller_progress);
+        mProgress = v.findViewById(com.android.internal.R.id.mediacontroller_progress);
         if (mProgress != null) {
             if (mProgress instanceof SeekBar) {
                 SeekBar seeker = (SeekBar) mProgress;
@@ -298,8 +298,8 @@
             mProgress.setMax(1000);
         }
 
-        mEndTime = (TextView) v.findViewById(com.android.internal.R.id.time);
-        mCurrentTime = (TextView) v.findViewById(com.android.internal.R.id.time_current);
+        mEndTime = v.findViewById(com.android.internal.R.id.time);
+        mCurrentTime = v.findViewById(com.android.internal.R.id.time_current);
         mFormatBuilder = new StringBuilder();
         mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 359d04e..5505f2f 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1578,7 +1578,7 @@
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
             final Context context = root.getContext();
-            final ViewGroup target = (ViewGroup) root.findViewById(viewId);
+            final ViewGroup target = root.findViewById(viewId);
             if (target == null) return;
             if (nestedViews != null) {
                 // Inflate nested views and add as children
@@ -1757,7 +1757,7 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final TextView target = (TextView) root.findViewById(viewId);
+            final TextView target = root.findViewById(viewId);
             if (target == null) return;
             if (drawablesLoaded) {
                 if (isRelative) {
@@ -1857,7 +1857,7 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final TextView target = (TextView) root.findViewById(viewId);
+            final TextView target = root.findViewById(viewId);
             if (target == null) return;
             target.setTextSize(units, size);
         }
@@ -2045,7 +2045,7 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final TextView target = (TextView) root.findViewById(viewId);
+            final TextView target = root.findViewById(viewId);
             if (target == null) return;
             Drawable[] drawables = isRelative
                     ? target.getCompoundDrawablesRelative()
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 770d9ee..6790532 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -54,6 +54,8 @@
     private TextClassificationResult mTextClassificationResult;
     private AsyncTask mTextClassificationAsyncTask;
 
+    private final SelectionInfo mSelectionInfo = new SelectionInfo();
+
     SelectionActionModeHelper(@NonNull Editor editor) {
         mEditor = Preconditions.checkNotNull(editor);
         final TextView textView = mEditor.getTextView();
@@ -94,12 +96,12 @@
         }
     }
 
-    public void cancelAsyncTask() {
-        if (mTextClassificationAsyncTask != null) {
-            mTextClassificationAsyncTask.cancel(true);
-            mTextClassificationAsyncTask = null;
+    public boolean resetOriginalSelection(int textIndex) {
+        if (mSelectionInfo.resetOriginalSelection(textIndex, mEditor.getTextView().getText())) {
+            invalidateActionModeAsync();
+            return true;
         }
-        mTextClassificationResult = null;
+        return false;
     }
 
     @Nullable
@@ -107,12 +109,28 @@
         return mTextClassificationResult;
     }
 
+    public void onDestroyActionMode() {
+        mSelectionInfo.onSelectionDestroyed();
+        cancelAsyncTask();
+    }
+
+    private void cancelAsyncTask() {
+        if (mTextClassificationAsyncTask != null) {
+            mTextClassificationAsyncTask.cancel(true);
+            mTextClassificationAsyncTask = null;
+        }
+        mTextClassificationResult = null;
+    }
+
     private boolean isNoOpTextClassifier() {
         return mEditor.getTextView().getTextClassifier() == TextClassifier.NO_OP;
     }
 
     private void startActionMode(@Nullable SelectionResult result) {
-        final CharSequence text = mEditor.getTextView().getText();
+        final TextView textView = mEditor.getTextView();
+        final CharSequence text = textView.getText();
+        mSelectionInfo.setOriginalSelection(
+                textView.getSelectionStart(), textView.getSelectionEnd());
         if (result != null && text instanceof Spannable) {
             Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
             mTextClassificationResult = result.mResult;
@@ -124,6 +142,9 @@
             if (controller != null) {
                 controller.show();
             }
+            if (result != null) {
+                mSelectionInfo.onSelectionStarted(result.mStart, result.mEnd);
+            }
         }
         mEditor.setRestartActionModeOnNextRefresh(false);
         mTextClassificationAsyncTask = null;
@@ -135,6 +156,8 @@
         if (actionMode != null) {
             actionMode.invalidate();
         }
+        final TextView textView = mEditor.getTextView();
+        mSelectionInfo.onSelectionUpdated(textView.getSelectionStart(), textView.getSelectionEnd());
         mTextClassificationAsyncTask = null;
     }
 
@@ -145,6 +168,56 @@
     }
 
     /**
+     * Holds information about the selection and uses it to decide on whether or not to update
+     * the selection when resetOriginalSelection is called.
+     * The expected UX here is to allow the user to re-snap the selection back to the original word
+     * that was selected with one tap on that word.
+     */
+    private static final class SelectionInfo {
+
+        private int mOriginalStart;
+        private int mOriginalEnd;
+        private int mSelectionStart;
+        private int mSelectionEnd;
+
+        private boolean mResetOriginal;
+
+        public void setOriginalSelection(int selectionStart, int selectionEnd) {
+            mOriginalStart = selectionStart;
+            mOriginalEnd = selectionEnd;
+            mResetOriginal = false;
+        }
+
+        public void onSelectionStarted(int selectionStart, int selectionEnd) {
+            // Set the reset flag to true if the selection changed.
+            mSelectionStart = selectionStart;
+            mSelectionEnd = selectionEnd;
+            mResetOriginal = mSelectionStart != mOriginalStart || mSelectionEnd != mOriginalEnd;
+        }
+
+        public void onSelectionUpdated(int selectionStart, int selectionEnd) {
+            // If the selection did not change, maintain the reset state. Otherwise, disable reset.
+            mResetOriginal &= selectionStart == mSelectionStart && selectionEnd == mSelectionEnd;
+        }
+
+        public void onSelectionDestroyed() {
+            mResetOriginal = false;
+        }
+
+        public boolean resetOriginalSelection(int textIndex, CharSequence text) {
+            if (mResetOriginal
+                    && textIndex >= mOriginalStart && textIndex <= mOriginalEnd
+                    && text instanceof Spannable) {
+                Selection.setSelection((Spannable) text, mOriginalStart, mOriginalEnd);
+                // Only allow a reset once.
+                mResetOriginal = false;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
      * AsyncTask for running a query on a background thread and returning the result on the
      * UiThread. The AsyncTask times out after a specified time, returning a null result if the
      * query has not yet returned.
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index f833d1b..fbb8993 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -286,7 +286,7 @@
         v.setTag(new ChildViewCache(v));
 
         // Set up icon.
-        final ImageView iconRefine = (ImageView) v.findViewById(R.id.edit_query);
+        final ImageView iconRefine = v.findViewById(R.id.edit_query);
         iconRefine.setImageResource(mCommitIconResId);
 
         return v;
@@ -304,11 +304,11 @@
         public final ImageView mIconRefine;
 
         public ChildViewCache(View v) {
-            mText1 = (TextView) v.findViewById(com.android.internal.R.id.text1);
-            mText2 = (TextView) v.findViewById(com.android.internal.R.id.text2);
-            mIcon1 = (ImageView) v.findViewById(com.android.internal.R.id.icon1);
-            mIcon2 = (ImageView) v.findViewById(com.android.internal.R.id.icon2);
-            mIconRefine = (ImageView) v.findViewById(com.android.internal.R.id.edit_query);
+            mText1 = v.findViewById(com.android.internal.R.id.text1);
+            mText2 = v.findViewById(com.android.internal.R.id.text2);
+            mIcon1 = v.findViewById(com.android.internal.R.id.icon1);
+            mIcon2 = v.findViewById(com.android.internal.R.id.icon2);
+            mIconRefine = v.findViewById(com.android.internal.R.id.edit_query);
         }
     }
 
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 32418cd..7e2cadf 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -619,7 +619,7 @@
                     mTabWidget, // tab widget is the parent
                     false); // no inflate params
 
-            final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
+            final TextView tv = tabIndicator.findViewById(R.id.title);
             tv.setText(mLabel);
 
             if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
@@ -653,8 +653,8 @@
                     mTabWidget, // tab widget is the parent
                     false); // no inflate params
 
-            final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
-            final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
+            final TextView tv = tabIndicator.findViewById(R.id.title);
+            final ImageView iconView = tabIndicator.findViewById(R.id.icon);
 
             // when icon is gone by default, we're in exclusive mode
             final boolean exclusive = iconView.getVisibility() == View.GONE;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5e6e0f9..adc6f72 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -266,7 +266,7 @@
  * @attr ref android.R.styleable#TextView_fontFeatureSettings
  * @attr ref android.R.styleable#TextView_breakStrategy
  * @attr ref android.R.styleable#TextView_hyphenationFrequency
- * @attr ref android.R.styleable#TextView_autoSizeText
+ * @attr ref android.R.styleable#TextView_autoSizeTextType
  * @attr ref android.R.styleable#TextView_autoSizeMinTextSize
  * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
  * @attr ref android.R.styleable#TextView_autoSizeStepGranularity
@@ -691,18 +691,24 @@
      */
     private int mDeviceProvisionedState = DEVICE_PROVISIONED_UNKNOWN;
 
-    // The TextView does not auto-size text (default).
+    /**
+     * The TextView does not auto-size text (default).
+     */
     public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0;
-    // The TextView performs uniform horizontal and vertical text size scaling to fit within the
-    // container.
+
+    /**
+     * The TextView scales text size both horizontally and vertically to fit within the
+     * container.
+     */
     public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1;
+
     /** @hide */
     @IntDef({AUTO_SIZE_TEXT_TYPE_NONE, AUTO_SIZE_TEXT_TYPE_UNIFORM})
     @Retention(RetentionPolicy.SOURCE)
     public @interface AutoSizeTextType {}
-    // Default minimum size for auto-sizing text in scaled pixels. {@see #setAutoSizeMinTextSize}.
+    // Default minimum size for auto-sizing text in scaled pixels.
     private static final int DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP = 12;
-    // Default maximum size for auto-sizing text in scaled pixels. {@see #setAutoSizeMaxTextSize}.
+    // Default maximum size for auto-sizing text in scaled pixels.
     private static final int DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP = 112;
     // Default value for the step size in pixels.
     private static final int DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX = 1;
@@ -1308,7 +1314,7 @@
                     mHyphenationFrequency = a.getInt(attr, Layout.HYPHENATION_FREQUENCY_NONE);
                     break;
 
-                case com.android.internal.R.styleable.TextView_autoSizeText:
+                case com.android.internal.R.styleable.TextView_autoSizeTextType:
                     mAutoSizeTextType = a.getInt(attr, AUTO_SIZE_TEXT_TYPE_NONE);
                     break;
 
@@ -1660,7 +1666,7 @@
      *        {@link TextView#AUTO_SIZE_TEXT_TYPE_NONE} or
      *        {@link TextView#AUTO_SIZE_TEXT_TYPE_UNIFORM}
      *
-     * @attr ref android.R.styleable#TextView_autoSizeText
+     * @attr ref android.R.styleable#TextView_autoSizeTextType
      *
      * @see #getAutoSizeTextType()
      */
@@ -1709,7 +1715,7 @@
      *
      * @throws IllegalArgumentException if any of the configuration params are invalid.
      *
-     * @attr ref android.R.styleable#TextView_autoSizeText
+     * @attr ref android.R.styleable#TextView_autoSizeTextType
      * @attr ref android.R.styleable#TextView_autoSizeMinTextSize
      * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
      * @attr ref android.R.styleable#TextView_autoSizeStepGranularity
@@ -1753,7 +1759,7 @@
      *
      * @throws IllegalArgumentException if all of the <code>presetSizes</code> are invalid.
      *
-     * @attr ref android.R.styleable#TextView_autoSizeText
+     * @attr ref android.R.styleable#TextView_autoSizeTextType
      * @attr ref android.R.styleable#TextView_autoSizePresetSizes
      *
      * @see #setAutoSizeTextTypeWithDefaults(int)
@@ -1806,7 +1812,7 @@
      *         {@link TextView#AUTO_SIZE_TEXT_TYPE_NONE} or
      *         {@link TextView#AUTO_SIZE_TEXT_TYPE_UNIFORM}
      *
-     * @attr ref android.R.styleable#TextView_autoSizeText
+     * @attr ref android.R.styleable#TextView_autoSizeTextType
      *
      * @see #setAutoSizeTextTypeWithDefaults(int)
      * @see #setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int)
@@ -8208,7 +8214,7 @@
         // If we have a fixed width, we can just swap in a new text layout
         // if the text height stays the same or if the view height is fixed.
 
-        if (((mLayoutParams.width != LayoutParams.WRAP_CONTENT && mLayoutParams.width != 0)
+        if ((mLayoutParams.width != LayoutParams.WRAP_CONTENT
                 || (mMaxWidthMode == mMinWidthMode && mMaxWidth == mMinWidth))
                 && (mHint == null || mHintLayout != null)
                 && (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight() > 0)) {
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 7ef54a5..20a5512 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -86,7 +86,7 @@
         inflater.inflate(layoutResourceId, mDelegator, true);
 
         // hour
-        mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour);
+        mHourSpinner = delegator.findViewById(R.id.hour);
         mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
             public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
                 updateInputState();
@@ -100,17 +100,17 @@
                 onTimeChanged();
             }
         });
-        mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
+        mHourSpinnerInput = mHourSpinner.findViewById(R.id.numberpicker_input);
         mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         // divider (only for the new widget style)
-        mDivider = (TextView) mDelegator.findViewById(R.id.divider);
+        mDivider = mDelegator.findViewById(R.id.divider);
         if (mDivider != null) {
             setDividerText();
         }
 
         // minute
-        mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute);
+        mMinuteSpinner = mDelegator.findViewById(R.id.minute);
         mMinuteSpinner.setMinValue(0);
         mMinuteSpinner.setMaxValue(59);
         mMinuteSpinner.setOnLongPressUpdateInterval(100);
@@ -138,7 +138,7 @@
                 onTimeChanged();
             }
         });
-        mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
+        mMinuteSpinnerInput = mMinuteSpinner.findViewById(R.id.numberpicker_input);
         mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         // Get the localized am/pm strings and use them in the spinner.
@@ -173,13 +173,13 @@
                     onTimeChanged();
                 }
             });
-            mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
+            mAmPmSpinnerInput = mAmPmSpinner.findViewById(R.id.numberpicker_input);
             mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
         }
 
         if (isAmPmAtStart()) {
             // Move the am/pm view to the beginning
-            ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout);
+            ViewGroup amPmParent = delegator.findViewById(R.id.timePickerLayout);
             amPmParent.removeView(amPmView);
             amPmParent.addView(amPmView, 0);
             // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 789e60b..bf0601d 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -299,7 +299,7 @@
         if (mNextView == null) {
             throw new RuntimeException("This Toast was not created with Toast.makeText()");
         }
-        TextView tv = (TextView) mNextView.findViewById(com.android.internal.R.id.message);
+        TextView tv = mNextView.findViewById(com.android.internal.R.id.message);
         if (tv == null) {
             throw new RuntimeException("This Toast was not created with Toast.makeText()");
         }
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 69b79971..1a3ca86 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -264,7 +264,7 @@
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         inflater.inflate(com.android.internal.R.layout.zoom_container, container);
 
-        mControls = (ZoomControls) container.findViewById(com.android.internal.R.id.zoomControls);
+        mControls = container.findViewById(com.android.internal.R.id.zoomControls);
         mControls.setOnZoomInClickListener(new OnClickListener() {
             public void onClick(View v) {
                 dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 84c8f7a..79301aa 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -23,15 +23,21 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.LabeledIntent;
+import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
 import android.database.DataSetObserver;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
@@ -84,6 +90,14 @@
 public class ChooserActivity extends ResolverActivity {
     private static final String TAG = "ChooserActivity";
 
+    /**
+     * Boolean extra to change the following behavior: Normally, ChooserActivity finishes itself
+     * in onStop when launched in a new task. If this extra is set to true, we do not finish
+     * ourselves when onStop gets called.
+     */
+    public static final String EXTRA_PRIVATE_RETAIN_IN_ON_STOP
+            = "com.android.internal.app.ChooserActivity.EXTRA_PRIVATE_RETAIN_IN_ON_STOP";
+
     private static final boolean DEBUG = false;
 
     private static final int QUERY_TARGET_SERVICE_LIMIT = 5;
@@ -260,6 +274,7 @@
         }
 
         mPinnedSharedPrefs = getPinnedSharedPrefs(this);
+        setRetainInOnStop(intent.getBooleanExtra(EXTRA_PRIVATE_RETAIN_IN_ON_STOP, false));
         super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
                 null, false);
 
@@ -347,6 +362,7 @@
             mChooserListAdapter.addServiceResults(null, Lists.newArrayList(mCallerChooserTargets));
         }
         mChooserRowAdapter = new ChooserRowAdapter(mChooserListAdapter);
+        mChooserRowAdapter.updateRowScales();
         mChooserRowAdapter.registerDataSetObserver(new OffsetDataSetObserver(adapterView));
         adapterView.setAdapter(mChooserRowAdapter);
         if (listView != null) {
@@ -833,7 +849,9 @@
                 return false;
             }
             intent.setComponent(mChooserTarget.getComponentName());
-            intent.putExtras(mChooserTarget.getIntentExtras());
+            if (mChooserTarget.getIntentExtras() != null) {
+                intent.putExtras(mChooserTarget.getIntentExtras());
+            }
 
             // Important: we will ignore the target security checks in ActivityManager
             // if and only if the ChooserTarget's target package is the same package
@@ -916,6 +934,8 @@
         private static final int MAX_SERVICE_TARGETS = 8;
         private static final int MAX_TARGETS_PER_SERVICE = 4;
 
+        private boolean mAreChooserShortcutsRetrieved;
+
         private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
         private final List<TargetInfo> mCallerTargets = new ArrayList<>();
         private boolean mShowServiceTargets;
@@ -1007,6 +1027,20 @@
             if (mServiceTargets != null) {
                 pruneServiceTargets();
             }
+
+            if (DEBUG) Log.d(TAG, "Adding pushed chooser targets");
+
+            if (!mAreChooserShortcutsRetrieved) {
+                LauncherApps launcherApps = getLauncherApps();
+                LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery();
+                query.setIntent(getTargetIntent());
+                query.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_CHOOSER);
+                List<ShortcutInfo> shortcuts = launcherApps.getShortcuts(query, UserHandle.SYSTEM);
+                if (DEBUG) Log.d(TAG, "Adding " + shortcuts.size() + " chooser shortcuts");
+                addShortcuts(shortcuts);
+                mAreChooserShortcutsRetrieved = true;
+            }
+
             if (DEBUG) Log.d(TAG, "List built querying services");
             queryTargetServices(this);
         }
@@ -1032,6 +1066,7 @@
 
         public int getServiceTargetCount() {
             if (!mShowServiceTargets) {
+                if (DEBUG) Log.d("TAG", "Hiding service targets");
                 return 0;
             }
             return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS);
@@ -1123,6 +1158,71 @@
             notifyDataSetChanged();
         }
 
+        // TODO: Pushed targets need to be scored correctly
+        public void addShortcuts(List<ShortcutInfo> infos) {
+            for (ShortcutInfo info : infos) {
+                List<ChooserTarget> newTargets = new ArrayList<>();
+                final ComponentName cn = info.getActivity();
+                ActivityInfo ai;
+                ResolveInfo ri = new ResolveInfo();
+                if (cn != null) {
+                    try {
+                        ai = getPackageManager().getActivityInfo(cn, 0);
+                        ri.activityInfo = ai;
+                        UserManager userManager =
+                                (UserManager) getSystemService(Context.USER_SERVICE);
+                        ri.iconResourceId = ai.icon;
+                        ri.labelRes = ai.labelRes;
+                        ri.resolvePackageName = ai.packageName;
+                        ri.activityInfo.applicationInfo = new ApplicationInfo(
+                                ri.activityInfo.applicationInfo);
+                        ri.activityInfo.applicationInfo = ai.applicationInfo;
+                        ri.activityInfo.applicationInfo.uid = getUserId();
+                    } catch (PackageManager.NameNotFoundException ignored) {
+                        if (DEBUG) Log.d(TAG, "Package not found, skipping this shortcut");
+                        continue;
+                    }
+                }
+
+                DisplayResolveInfo resolveInfo = new DisplayResolveInfo(getTargetIntent(),
+                        ri,
+                        info.getShortLabel(),
+                        info.getLongLabel(),
+                        getTargetIntent());
+
+                int bestMatch = 0;
+                ComponentName bestComponent = null;
+                for (int i = 0; i < info.getChooserIntentFilters().length; i++) {
+                    int newMatch = info.getChooserIntentFilters()[i]
+                            .match(getContentResolver(), getTargetIntent(), false, TAG);
+                    if (DEBUG) Log.d(TAG, "A match was found with value: " + newMatch);
+                    if (newMatch > bestMatch) {
+                        bestMatch = newMatch;
+                        bestComponent = info.getChooserComponentNames()[i];
+                    }
+                }
+                if (bestMatch == 0) {
+                    Log.e(TAG, "Unexpectedly, no match was found for the provided chooser intent");
+                    return;
+                }
+
+                Bundle extrasToAdd =
+                        info.getChooserExtras() == null ? null: new Bundle(info.getChooserExtras());
+                if (DEBUG) Log.d(TAG, "Adding service target " + info.getShortLabel());
+                newTargets.add(new ChooserTarget(
+                        info.getShortLabel(),
+                        info.getIcon(),
+                        1,
+                        bestComponent,
+                        extrasToAdd));
+                addServiceResults(resolveInfo, newTargets);
+            }
+            if (mChooserRowAdapter != null) {
+                mChooserRowAdapter.updateRowScales();
+            }
+            setShowServiceTargets(true);
+        }
+
         /**
          * Set to true to reveal all service targets at once.
          */
@@ -1237,37 +1337,7 @@
                 @Override
                 public void onChanged() {
                     super.onChanged();
-                    final int rcount = getServiceTargetRowCount();
-                    if (mServiceTargetScale == null
-                            || mServiceTargetScale.length != rcount) {
-                        RowScale[] old = mServiceTargetScale;
-                        int oldRCount = old != null ? old.length : 0;
-                        mServiceTargetScale = new RowScale[rcount];
-                        if (old != null && rcount > 0) {
-                            System.arraycopy(old, 0, mServiceTargetScale, 0,
-                                    Math.min(old.length, rcount));
-                        }
-
-                        for (int i = rcount; i < oldRCount; i++) {
-                            old[i].cancelAnimation();
-                        }
-
-                        for (int i = oldRCount; i < rcount; i++) {
-                            final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f)
-                                    .setInterpolator(mInterpolator);
-                            mServiceTargetScale[i] = rs;
-                        }
-
-                        // Start the animations in a separate loop.
-                        // The process of starting animations will result in
-                        // binding views to set up initial values, and we must
-                        // have ALL of the new RowScale objects created above before
-                        // we get started.
-                        for (int i = oldRCount; i < rcount; i++) {
-                            mServiceTargetScale[i].startAnimation();
-                        }
-                    }
-
+                    updateRowScales();
                     notifyDataSetChanged();
                 }
 
@@ -1284,6 +1354,40 @@
             });
         }
 
+         void updateRowScales() {
+            final int rcount = getServiceTargetRowCount();
+            if (mServiceTargetScale == null
+                    || mServiceTargetScale.length != rcount) {
+                if (DEBUG) Log.d(TAG, "Row scales need adjusting to " + rcount + " rows.");
+                RowScale[] old = mServiceTargetScale;
+                int oldRCount = old != null ? old.length : 0;
+                mServiceTargetScale = new RowScale[rcount];
+                if (old != null && rcount > 0) {
+                    System.arraycopy(old, 0, mServiceTargetScale, 0,
+                            Math.min(old.length, rcount));
+                }
+
+                for (int i = rcount; i < oldRCount; i++) {
+                    old[i].cancelAnimation();
+                }
+
+                for (int i = oldRCount; i < rcount; i++) {
+                    final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f)
+                            .setInterpolator(mInterpolator);
+                    mServiceTargetScale[i] = rs;
+                }
+
+                // Start the animations in a separate loop.
+                // The process of starting animations will result in
+                // binding views to set up initial values, and we must
+                // have ALL of the new RowScale objects created above before
+                // we get started.
+                for (int i = oldRCount; i < rcount; i++) {
+                    mServiceTargetScale[i].startAnimation();
+                }
+            }
+        }
+
         private float getRowScale(int rowPosition) {
             final int start = getCallerTargetRowCount();
             final int end = start + getServiceTargetRowCount();
@@ -1554,6 +1658,10 @@
         }
     }
 
+    public LauncherApps getLauncherApps() {
+        return (LauncherApps) getSystemService(Context.LAUNCHER_APPS_SERVICE);
+    }
+
     static class ServiceResultInfo {
         public final DisplayResolveInfo originalTarget;
         public final List<ChooserTarget> resultTargets;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0b1f0aa..9fb9cb6 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -116,6 +116,10 @@
     private Runnable mPostListReadyRunnable;
 
     private boolean mRegistered;
+
+    /** See {@link #setRetainInOnStop}. */
+    private boolean mRetainInOnStop;
+
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         @Override public void onSomePackagesChanged() {
             mAdapter.handlePackagesChanged();
@@ -502,7 +506,7 @@
         }
         final Intent intent = getIntent();
         if ((intent.getFlags() & FLAG_ACTIVITY_NEW_TASK) != 0 && !isVoiceInteraction()
-                && !mResolvingHome) {
+                && !mResolvingHome && !mRetainInOnStop) {
             // This resolver is in the unusual situation where it has been
             // launched at the top of a new task.  We don't let it be added
             // to the recent tasks shown to the user, and we need to make sure
@@ -1029,6 +1033,14 @@
     }
 
     /**
+     * If {@code retainInOnStop} is set to true, we will not finish ourselves when onStop gets
+     * called and we are launched in a new task.
+     */
+    protected void setRetainInOnStop(boolean retainInOnStop) {
+        mRetainInOnStop = retainInOnStop;
+    }
+
+    /**
      * Check a simple match for the component of two ResolveInfos.
      */
     static boolean resolveInfoMatch(ResolveInfo lhs, ResolveInfo rhs) {
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
new file mode 100644
index 0000000..3ac5a72
--- /dev/null
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.content;
+
+import android.annotation.CallSuper;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.os.FileObserver;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsProvider;
+import android.provider.MediaStore;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.webkit.MimeTypeMap;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A helper class for {@link android.provider.DocumentsProvider} to perform file operations on local
+ * files.
+ */
+public abstract class FileSystemProvider extends DocumentsProvider {
+
+    private static final String TAG = "FileSystemProvider";
+
+    private static final boolean LOG_INOTIFY = false;
+
+    private String[] mDefaultProjection;
+
+    @GuardedBy("mObservers")
+    private final ArrayMap<File, DirectoryObserver> mObservers = new ArrayMap<>();
+
+    private Handler mHandler;
+
+    protected abstract File getFileForDocId(String docId, boolean visible)
+            throws FileNotFoundException;
+
+    protected abstract String getDocIdForFile(File file) throws FileNotFoundException;
+
+    protected abstract Uri buildNotificationUri(String docId);
+
+    @Override
+    public boolean onCreate() {
+        throw new UnsupportedOperationException(
+                "Subclass should override this and call onCreate(defaultDocumentProjection)");
+    }
+
+    @CallSuper
+    protected void onCreate(String[] defaultProjection) {
+        mHandler = new Handler();
+        mDefaultProjection = defaultProjection;
+    }
+
+    @Override
+    public boolean isChildDocument(String parentDocId, String docId) {
+        try {
+            final File parent = getFileForDocId(parentDocId).getCanonicalFile();
+            final File doc = getFileForDocId(docId).getCanonicalFile();
+            return FileUtils.contains(parent, doc);
+        } catch (IOException e) {
+            throw new IllegalArgumentException(
+                    "Failed to determine if " + docId + " is child of " + parentDocId + ": " + e);
+        }
+    }
+
+    protected final List<String> findDocumentPath(File parent, File doc)
+            throws FileNotFoundException {
+
+        if (!doc.exists()) {
+            throw new FileNotFoundException(doc + " is not found.");
+        }
+
+        if (!FileUtils.contains(parent, doc)) {
+            throw new FileNotFoundException(doc + " is not found under " + parent);
+        }
+
+        LinkedList<String> path = new LinkedList<>();
+        while (doc != null && FileUtils.contains(parent, doc)) {
+            path.addFirst(getDocIdForFile(doc));
+
+            doc = doc.getParentFile();
+        }
+
+        return path;
+    }
+
+    @Override
+    public String createDocument(String docId, String mimeType, String displayName)
+            throws FileNotFoundException {
+        displayName = FileUtils.buildValidFatFilename(displayName);
+
+        final File parent = getFileForDocId(docId);
+        if (!parent.isDirectory()) {
+            throw new IllegalArgumentException("Parent document isn't a directory");
+        }
+
+        final File file = FileUtils.buildUniqueFile(parent, mimeType, displayName);
+        if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+            if (!file.mkdir()) {
+                throw new IllegalStateException("Failed to mkdir " + file);
+            }
+        } else {
+            try {
+                if (!file.createNewFile()) {
+                    throw new IllegalStateException("Failed to touch " + file);
+                }
+            } catch (IOException e) {
+                throw new IllegalStateException("Failed to touch " + file + ": " + e);
+            }
+        }
+
+        return getDocIdForFile(file);
+    }
+
+    @Override
+    public String renameDocument(String docId, String displayName) throws FileNotFoundException {
+        // Since this provider treats renames as generating a completely new
+        // docId, we're okay with letting the MIME type change.
+        displayName = FileUtils.buildValidFatFilename(displayName);
+
+        final File before = getFileForDocId(docId);
+        final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
+        final File visibleFileBefore = getFileForDocId(docId, true);
+        if (!before.renameTo(after)) {
+            throw new IllegalStateException("Failed to rename to " + after);
+        }
+        removeFromMediaStore(visibleFileBefore);
+
+        final String afterDocId = getDocIdForFile(after);
+        scanFile(getFileForDocId(afterDocId, true));
+
+        if (!TextUtils.equals(docId, afterDocId)) {
+            return afterDocId;
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void deleteDocument(String docId) throws FileNotFoundException {
+        final File file = getFileForDocId(docId);
+        final File visibleFile = getFileForDocId(docId, true);
+
+        final boolean isDirectory = file.isDirectory();
+        if (isDirectory) {
+            FileUtils.deleteContents(file);
+        }
+        if (!file.delete()) {
+            throw new IllegalStateException("Failed to delete " + file);
+        }
+
+        removeFromMediaStore(visibleFile);
+    }
+
+    @Override
+    public String moveDocument(String sourceDocumentId, String sourceParentDocumentId,
+            String targetParentDocumentId)
+            throws FileNotFoundException {
+        final File before = getFileForDocId(sourceDocumentId);
+        final File after = new File(getFileForDocId(targetParentDocumentId), before.getName());
+        final File visibleFileBefore = getFileForDocId(sourceDocumentId, true);
+
+        if (after.exists()) {
+            throw new IllegalStateException("Already exists " + after);
+        }
+        if (!before.renameTo(after)) {
+            throw new IllegalStateException("Failed to move to " + after);
+        }
+
+        // Notify media store to update its content
+        removeFromMediaStore(visibleFileBefore);
+        final String docId = getDocIdForFile(after);
+        scanFile(getFileForDocId(docId, true));
+
+        return docId;
+    }
+
+    private void removeFromMediaStore(File visibleFile) throws FileNotFoundException {
+        if (visibleFile != null) {
+            final ContentResolver resolver = getContext().getContentResolver();
+            final Uri externalUri = MediaStore.Files.getContentUri("external");
+
+            // Remove media store entries for any files inside this directory, using
+            // path prefix match. Logic borrowed from MtpDatabase.
+            if (visibleFile.isDirectory()) {
+                final String path = visibleFile.getAbsolutePath() + "/";
+                resolver.delete(externalUri,
+                        "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
+                        new String[] { path + "%", Integer.toString(path.length()), path });
+            }
+
+            // Remove media store entry for this exact file.
+            final String path = visibleFile.getAbsolutePath();
+            resolver.delete(externalUri,
+                    "_data LIKE ?1 AND lower(_data)=lower(?2)",
+                    new String[] { path, path });
+        }
+    }
+
+    @Override
+    public Cursor queryDocument(String documentId, String[] projection)
+            throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(resolveProjection(projection));
+        includeFile(result, documentId, null);
+        return result;
+    }
+
+    @Override
+    public Cursor queryChildDocuments(
+            String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+
+        final File parent = getFileForDocId(parentDocumentId);
+        final MatrixCursor result = new DirectoryCursor(
+                resolveProjection(projection), parentDocumentId, parent);
+        for (File file : parent.listFiles()) {
+            includeFile(result, null, file);
+        }
+        return result;
+    }
+
+    /**
+     * Searches documents under the given folder.
+     *
+     * To avoid runtime explosion only returns the at most 23 items.
+     *
+     * @param folder the root folder where recursive search begins
+     * @param query the search condition used to match file names
+     * @param projection projection of the returned cursor
+     * @param exclusion absolute file paths to exclude from result
+     * @return cursor containing search result
+     * @throws FileNotFoundException when root folder doesn't exist or search fails
+     */
+    protected final Cursor querySearchDocuments(
+            File folder, String query, String[] projection, Set<String> exclusion)
+            throws FileNotFoundException {
+
+        query = query.toLowerCase();
+        final MatrixCursor result = new MatrixCursor(resolveProjection(projection));
+        final LinkedList<File> pending = new LinkedList<>();
+        pending.add(folder);
+        while (!pending.isEmpty() && result.getCount() < 24) {
+            final File file = pending.removeFirst();
+            if (file.isDirectory()) {
+                for (File child : file.listFiles()) {
+                    pending.add(child);
+                }
+            }
+            if (file.getName().toLowerCase().contains(query)
+                    && !exclusion.contains(file.getAbsolutePath())) {
+                includeFile(result, null, file);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public String getDocumentType(String documentId) throws FileNotFoundException {
+        final File file = getFileForDocId(documentId);
+        return getTypeForFile(file);
+    }
+
+    @Override
+    public ParcelFileDescriptor openDocument(
+            String documentId, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        final File file = getFileForDocId(documentId);
+        final File visibleFile = getFileForDocId(documentId, true);
+
+        final int pfdMode = ParcelFileDescriptor.parseMode(mode);
+        if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY || visibleFile == null) {
+            return ParcelFileDescriptor.open(file, pfdMode);
+        } else {
+            try {
+                // When finished writing, kick off media scanner
+                return ParcelFileDescriptor.open(
+                        file, pfdMode, mHandler, (IOException e) -> scanFile(visibleFile));
+            } catch (IOException e) {
+                throw new FileNotFoundException("Failed to open for writing: " + e);
+            }
+        }
+    }
+
+    private void scanFile(File visibleFile) {
+        final Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+        intent.setData(Uri.fromFile(visibleFile));
+        getContext().sendBroadcast(intent);
+    }
+
+    @Override
+    public AssetFileDescriptor openDocumentThumbnail(
+            String documentId, Point sizeHint, CancellationSignal signal)
+            throws FileNotFoundException {
+        final File file = getFileForDocId(documentId);
+        return DocumentsContract.openImageThumbnail(file);
+    }
+
+    protected RowBuilder includeFile(MatrixCursor result, String docId, File file)
+            throws FileNotFoundException {
+        if (docId == null) {
+            docId = getDocIdForFile(file);
+        } else {
+            file = getFileForDocId(docId);
+        }
+
+        int flags = 0;
+
+        if (file.canWrite()) {
+            if (file.isDirectory()) {
+                flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
+                flags |= Document.FLAG_SUPPORTS_DELETE;
+                flags |= Document.FLAG_SUPPORTS_RENAME;
+                flags |= Document.FLAG_SUPPORTS_MOVE;
+            } else {
+                flags |= Document.FLAG_SUPPORTS_WRITE;
+                flags |= Document.FLAG_SUPPORTS_DELETE;
+                flags |= Document.FLAG_SUPPORTS_RENAME;
+                flags |= Document.FLAG_SUPPORTS_MOVE;
+            }
+        }
+
+        final String mimeType = getTypeForFile(file);
+        final String displayName = file.getName();
+        if (mimeType.startsWith("image/")) {
+            flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
+        }
+
+        final RowBuilder row = result.newRow();
+        row.add(Document.COLUMN_DOCUMENT_ID, docId);
+        row.add(Document.COLUMN_DISPLAY_NAME, displayName);
+        row.add(Document.COLUMN_SIZE, file.length());
+        row.add(Document.COLUMN_MIME_TYPE, mimeType);
+        row.add(Document.COLUMN_FLAGS, flags);
+
+        // Only publish dates reasonably after epoch
+        long lastModified = file.lastModified();
+        if (lastModified > 31536000000L) {
+            row.add(Document.COLUMN_LAST_MODIFIED, lastModified);
+        }
+
+        // Return the row builder just in case any subclass want to add more stuff to it.
+        return row;
+    }
+
+    private static String getTypeForFile(File file) {
+        if (file.isDirectory()) {
+            return Document.MIME_TYPE_DIR;
+        } else {
+            return getTypeForName(file.getName());
+        }
+    }
+
+    private static String getTypeForName(String name) {
+        final int lastDot = name.lastIndexOf('.');
+        if (lastDot >= 0) {
+            final String extension = name.substring(lastDot + 1).toLowerCase();
+            final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+            if (mime != null) {
+                return mime;
+            }
+        }
+
+        return "application/octet-stream";
+    }
+
+    protected final File getFileForDocId(String docId) throws FileNotFoundException {
+        return getFileForDocId(docId, false);
+    }
+
+    private String[] resolveProjection(String[] projection) {
+        return projection == null ? mDefaultProjection : projection;
+    }
+
+    private void startObserving(File file, Uri notifyUri) {
+        synchronized (mObservers) {
+            DirectoryObserver observer = mObservers.get(file);
+            if (observer == null) {
+                observer = new DirectoryObserver(
+                        file, getContext().getContentResolver(), notifyUri);
+                observer.startWatching();
+                mObservers.put(file, observer);
+            }
+            observer.mRefCount++;
+
+            if (LOG_INOTIFY) Log.d(TAG, "after start: " + observer);
+        }
+    }
+
+    private void stopObserving(File file) {
+        synchronized (mObservers) {
+            DirectoryObserver observer = mObservers.get(file);
+            if (observer == null) return;
+
+            observer.mRefCount--;
+            if (observer.mRefCount == 0) {
+                mObservers.remove(file);
+                observer.stopWatching();
+            }
+
+            if (LOG_INOTIFY) Log.d(TAG, "after stop: " + observer);
+        }
+    }
+
+    private static class DirectoryObserver extends FileObserver {
+        private static final int NOTIFY_EVENTS = ATTRIB | CLOSE_WRITE | MOVED_FROM | MOVED_TO
+                | CREATE | DELETE | DELETE_SELF | MOVE_SELF;
+
+        private final File mFile;
+        private final ContentResolver mResolver;
+        private final Uri mNotifyUri;
+
+        private int mRefCount = 0;
+
+        public DirectoryObserver(File file, ContentResolver resolver, Uri notifyUri) {
+            super(file.getAbsolutePath(), NOTIFY_EVENTS);
+            mFile = file;
+            mResolver = resolver;
+            mNotifyUri = notifyUri;
+        }
+
+        @Override
+        public void onEvent(int event, String path) {
+            if ((event & NOTIFY_EVENTS) != 0) {
+                if (LOG_INOTIFY) Log.d(TAG, "onEvent() " + event + " at " + path);
+                mResolver.notifyChange(mNotifyUri, null, false);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "DirectoryObserver{file=" + mFile.getAbsolutePath() + ", ref=" + mRefCount + "}";
+        }
+    }
+
+    private class DirectoryCursor extends MatrixCursor {
+        private final File mFile;
+
+        public DirectoryCursor(String[] columnNames, String docId, File file) {
+            super(columnNames);
+
+            final Uri notifyUri = buildNotificationUri(docId);
+            setNotificationUri(getContext().getContentResolver(), notifyUri);
+
+            mFile = file;
+            startObserving(mFile, notifyUri);
+        }
+
+        @Override
+        public void close() {
+            super.close();
+            stopObserving(mFile);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index be10608df..d67cef3 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -23,6 +23,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -1495,7 +1497,7 @@
     }
 
     /**
-     * @return number of log records
+     * @return the number of log records currently readable
      */
     public final int getLogRecSize() {
         // mSmHandler can be null if the state machine has quit.
@@ -1505,6 +1507,17 @@
     }
 
     /**
+     * @return the number of log records we can store
+     */
+    @VisibleForTesting
+    public final int getLogRecMaxSize() {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return 0;
+        return smh.mLogRecords.mMaxSize;
+    }
+
+    /**
      * @return the total number of records processed
      */
     public final int getLogRecCount() {
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 43005e6..919cf99 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -115,7 +115,6 @@
         setEnabled(itemData.isEnabled());
         setSubMenuArrowVisible(itemData.hasSubMenu());
         setContentDescription(itemData.getContentDescription());
-        setTooltipText(itemData.getTooltipText());
     }
 
     public void setForceShowIcon(boolean forceShow) {
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 817b186..79b0cd1 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -1195,6 +1195,8 @@
                     }
 
                     setButtonTagAndClickListener(menuItemButton, menuItem);
+                    // Set tooltips for main panel items, but not overflow items (b/35726766).
+                    menuItemButton.setTooltipText(menuItem.getTooltipText());
                     mMainPanel.addView(menuItemButton);
                     final ViewGroup.LayoutParams params = menuItemButton.getLayoutParams();
                     params.width = menuItemButtonWidth + extraPadding / 2;
@@ -1635,7 +1637,6 @@
                 buttonText.setPaddingRelative(iconTextSpacing, 0, 0, 0);
             }
         }
-        menuItemButton.setTooltipText(menuItem.getTooltipText());
         final CharSequence contentDescription = menuItem.getContentDescription();
         if (TextUtils.isEmpty(contentDescription)) {
             menuItemButton.setContentDescription(menuItem.getTitle());
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index ae2e0ac..cc1c65e 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -278,7 +278,8 @@
     public LockPatternView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView,
+                R.attr.lockPatternStyle, R.style.Widget_LockPatternView);
 
         final String aspect = a.getString(R.styleable.LockPatternView_aspect);
 
@@ -298,12 +299,9 @@
         mPathPaint.setAntiAlias(true);
         mPathPaint.setDither(true);
 
-        mRegularColor = context.getColor(R.color.lock_pattern_view_regular_color);
-        mErrorColor = context.getColor(R.color.lock_pattern_view_error_color);
-        mSuccessColor = context.getColor(R.color.lock_pattern_view_success_color);
-        mRegularColor = a.getColor(R.styleable.LockPatternView_regularColor, mRegularColor);
-        mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, mErrorColor);
-        mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, mSuccessColor);
+        mRegularColor = a.getColor(R.styleable.LockPatternView_regularColor, 0);
+        mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, 0);
+        mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, 0);
 
         int pathColor = a.getColor(R.styleable.LockPatternView_pathColor, mRegularColor);
         mPathPaint.setColor(pathColor);
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index e84cc27..e224b17 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -748,6 +748,10 @@
         final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
         final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
         final int widthPadding = getPaddingLeft() + getPaddingRight();
+
+        // Currently we allot more height than is really needed so that the entirety of the
+        // sheet may be pulled up.
+        // TODO: Restrict the height here to be the right value.
         int heightUsed = getPaddingTop() + getPaddingBottom();
 
         // Measure always-show children first.
@@ -757,7 +761,7 @@
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             if (lp.alwaysShow && child.getVisibility() != GONE) {
                 measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
-                heightUsed += getHeightUsed(child);
+                heightUsed += child.getMeasuredHeight();
             }
         }
 
@@ -769,7 +773,7 @@
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             if (!lp.alwaysShow && child.getVisibility() != GONE) {
                 measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
-                heightUsed += getHeightUsed(child);
+                heightUsed += child.getMeasuredHeight();
             }
         }
 
@@ -785,36 +789,6 @@
         setMeasuredDimension(sourceWidth, heightSize);
     }
 
-    private int getHeightUsed(View child) {
-        // This method exists because we're taking a fast path at measuring ListViews that
-        // lets us get away with not doing the more expensive wrap_content measurement which
-        // imposes double child view measurement costs. If we're looking at a ListView, we can
-        // check against the lowest child view plus padding and margin instead of the actual
-        // measured height of the ListView. This lets the ListView hang off the edge when
-        // all of the content would fit on-screen.
-
-        int heightUsed = child.getMeasuredHeight();
-        if (child instanceof AbsListView) {
-            final AbsListView lv = (AbsListView) child;
-            final int lvPaddingBottom = lv.getPaddingBottom();
-
-            int lowest = 0;
-            for (int i = 0, N = lv.getChildCount(); i < N; i++) {
-                final int bottom = lv.getChildAt(i).getBottom() + lvPaddingBottom;
-                if (bottom > lowest) {
-                    lowest = bottom;
-                }
-            }
-
-            if (lowest < heightUsed) {
-                heightUsed = lowest;
-            }
-        }
-
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        return lp.topMargin + heightUsed + lp.bottomMargin;
-    }
-
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int width = getWidth();
diff --git a/core/java/com/android/internal/widget/WatchHeaderListView.java b/core/java/com/android/internal/widget/WatchHeaderListView.java
index 7e91537..0654454 100644
--- a/core/java/com/android/internal/widget/WatchHeaderListView.java
+++ b/core/java/com/android/internal/widget/WatchHeaderListView.java
@@ -91,13 +91,14 @@
     }
 
     @Override
-    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+    protected <T extends View> T findViewByPredicateTraversal(
+            Predicate<View> predicate, View childToSkip) {
         View v = super.findViewByPredicateTraversal(predicate, childToSkip);
         if (v == null && mTopPanel != null && mTopPanel != childToSkip
                 && !mTopPanel.isRootNamespace()) {
-            return mTopPanel.findViewByPredicate(predicate);
+            return (T) mTopPanel.findViewByPredicate(predicate);
         }
-        return v;
+        return (T) v;
     }
 
     @Override
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 3d012bf..67f9f8f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -59,6 +59,7 @@
     private static final int ALLOW_LIBS = 0x02;
     private static final int ALLOW_PERMISSIONS = 0x04;
     private static final int ALLOW_APP_CONFIGS = 0x08;
+    private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10;
     private static final int ALLOW_ALL = ~0;
 
     // Group-ids that are given to all packages as read from etc/permissions/*.xml.
@@ -225,6 +226,13 @@
         // Read configuration from the old permissions dir
         readPermissions(Environment.buildPath(
                 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
+        // Allow Vendor to customize system configs around libs, features, permissions and apps
+        int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
+                ALLOW_APP_CONFIGS;
+        readPermissions(Environment.buildPath(
+                Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
+        readPermissions(Environment.buildPath(
+                Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
         // Allow ODM to customize system configs around libs, features and apps
         int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
         readPermissions(Environment.buildPath(
@@ -313,6 +321,7 @@
             boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
             boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
             boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
+            boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0;
             while (true) {
                 XmlUtils.nextElement(parser);
                 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
@@ -553,7 +562,7 @@
                         associatedPkgs.add(pkgname);
                     }
                     XmlUtils.skipCurrentTag(parser);
-                } else if ("privapp-permissions".equals(name) && allowAppConfigs) {
+                } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
                     readPrivAppPermissions(parser);
                 } else {
                     XmlUtils.skipCurrentTag(parser);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 3dd2498..cb60c62 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -283,11 +283,16 @@
     libhidltransport \
     libhwbinder \
     libvintf \
+    libnativewindow \
 
 LOCAL_SHARED_LIBRARIES += \
     libhwui \
     libdl \
 
+# our headers include libnativewindow's public headers
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
+    libnativewindow \
+
 # we need to access the private Bionic header
 # <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
 LOCAL_C_INCLUDES += bionic/libc/private
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index c090a75..49024b6 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -63,27 +63,27 @@
         return 0;
     }
     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-    minikin::FontFamily* family = new minikin::FontFamily(
-            builder->langId, builder->variant, std::move(builder->fonts));
+    FontFamilyWrapper* family = new FontFamilyWrapper(
+            std::make_shared<minikin::FontFamily>(
+                    builder->langId, builder->variant, std::move(builder->fonts)));
     delete builder;
     return reinterpret_cast<jlong>(family);
 }
 
 static void FontFamily_abort(jlong builderPtr) {
     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-    minikin::Font::clearElementsWithLock(&builder->fonts);
     delete builder;
 }
 
 static void FontFamily_unref(jlong familyPtr) {
-    minikin::FontFamily* fontFamily = reinterpret_cast<minikin::FontFamily*>(familyPtr);
-    fontFamily->Unref();
+    FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
+    delete family;
 }
 
 static void addSkTypeface(jlong builderPtr, sk_sp<SkTypeface> face, const void* fontData,
         size_t fontSize, int ttcIndex, jint givenWeight, jboolean givenItalic) {
-    minikin::MinikinFont* minikinFont =
-            new MinikinFontSkia(std::move(face), fontData, fontSize, ttcIndex,
+    std::shared_ptr<minikin::MinikinFont> minikinFont =
+            std::make_shared<MinikinFontSkia>(std::move(face), fontData, fontSize, ttcIndex,
                     std::vector<minikin::FontVariation>());
     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
     int weight = givenWeight / 100;
@@ -96,8 +96,8 @@
         }
     }
 
-    builder->fonts.push_back(minikin::Font(minikinFont, minikin::FontStyle(weight, italic)));
-    minikinFont->Unref();
+    builder->fonts.push_back(minikin::Font(
+            std::move(minikinFont), minikin::FontStyle(weight, italic)));
 }
 
 static void release_global_ref(const void* /*data*/, void* context) {
@@ -208,13 +208,12 @@
         ALOGE("addFont failed to create font, invalid request");
         return false;
     }
-    minikin::MinikinFont* minikinFont =
-            new MinikinFontSkia(std::move(face), fontPtr, fontSize, ttcIndex,
+    std::shared_ptr<minikin::MinikinFont> minikinFont =
+            std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
                     std::vector<minikin::FontVariation>());
     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-    builder->fonts.push_back(minikin::Font(minikinFont,
+    builder->fonts.push_back(minikin::Font(std::move(minikinFont),
             minikin::FontStyle(weight / 100, isItalic)));
-    minikinFont->Unref();
     return true;
 }
 
diff --git a/core/jni/android/graphics/FontUtils.h b/core/jni/android/graphics/FontUtils.h
index 8f44b1e..9eaaa49 100644
--- a/core/jni/android/graphics/FontUtils.h
+++ b/core/jni/android/graphics/FontUtils.h
@@ -18,9 +18,19 @@
 #define _ANDROID_GRAPHICS_FONT_UTILS_H_
 
 #include <jni.h>
+#include <memory>
+
+namespace minikin {
+class FontFamily;
+}  // namespace minikin
 
 namespace android {
 
+struct FontFamilyWrapper {
+  FontFamilyWrapper(std::shared_ptr<minikin::FontFamily>&& family) : family(family) {}
+  std::shared_ptr<minikin::FontFamily> family;
+};
+
 // Utility wrapper for java.util.List
 class ListHelper {
 public:
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index bdf79d3..1846237 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -300,8 +300,8 @@
 
     static void getTextPath(JNIEnv* env, Paint* paint, Typeface* typeface, const jchar* text,
             jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
-        minikin::Layout layout;
-        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
+        minikin::Layout layout = MinikinUtils::doLayout(
+                paint, bidiFlags, typeface, text, 0, count, count);
         size_t nGlyphs = layout.nGlyphs();
         uint16_t* glyphs = new uint16_t[nGlyphs];
         SkPoint* pos = new SkPoint[nGlyphs];
@@ -344,8 +344,8 @@
         SkRect  r;
         SkIRect ir;
 
-        minikin::Layout layout;
-        MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
+        minikin::Layout layout = MinikinUtils::doLayout(
+                &paint, bidiFlags, typeface, text, 0, count, count);
         minikin::MinikinRect rect;
         layout.getBounds(&rect);
         r.fLeft = rect.mLeft;
@@ -459,9 +459,8 @@
             nChars++;
             prevCp = cp;
         }
-        minikin::Layout layout;
-        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, str.get(), 0, str.size(),
-                str.size());
+        minikin::Layout layout = MinikinUtils::doLayout(
+                paint, bidiFlags, typeface, str.get(), 0, str.size(), str.size());
         size_t nGlyphs = countNonSpaceGlyphs(layout);
         if (nGlyphs != 1 && nChars > 1) {
             // multiple-character input, and was not a ligature
@@ -480,8 +479,8 @@
             // since ZZ is reserved for unknown or invalid territory.
             // U+1F1FF (REGIONAL INDICATOR SYMBOL LETTER Z) is \uD83C\uDDFF in UTF16.
             static const jchar ZZ_FLAG_STR[] = { 0xD83C, 0xDDFF, 0xD83C, 0xDDFF };
-            minikin::Layout zzLayout;
-            MinikinUtils::doLayout(&zzLayout, paint, bidiFlags, typeface, ZZ_FLAG_STR, 0, 4, 4);
+            minikin::Layout zzLayout = MinikinUtils::doLayout(
+                    paint, bidiFlags, typeface, ZZ_FLAG_STR, 0, 4, 4);
             if (zzLayout.nGlyphs() != 1 || layoutContainsNotdef(zzLayout)) {
                 // The font collection doesn't have a glyph for unknown flag. Just return true.
                 return true;
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 0a0fce3e..0cdc74f 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -67,9 +67,7 @@
 
 static void Typeface_unref(JNIEnv* env, jobject obj, jlong faceHandle) {
     Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
-    if (face != NULL) {
-        face->unref();
-    }
+    delete face;
 }
 
 static jint Typeface_getStyle(JNIEnv* env, jobject obj, jlong faceHandle) {
@@ -79,12 +77,13 @@
 
 static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray) {
     ScopedLongArrayRO families(env, familyArray);
-    std::vector<minikin::FontFamily*> familyVec;
+    std::vector<std::shared_ptr<minikin::FontFamily>> familyVec;
+    familyVec.reserve(families.size());
     for (size_t i = 0; i < families.size(); i++) {
-        minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(families[i]);
-        familyVec.push_back(family);
+        FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(families[i]);
+        familyVec.emplace_back(family->family);
     }
-    return reinterpret_cast<jlong>(Typeface::createFromFamilies(familyVec));
+    return reinterpret_cast<jlong>(Typeface::createFromFamilies(std::move(familyVec)));
 }
 
 static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) {
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index 5f0664b..b26b6e1 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -26,15 +26,17 @@
 #include <android_runtime/android_hardware_HardwareBuffer.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
+#include <private/android/AHardwareBufferHelpers.h>
 
 #include <binder/Parcel.h>
+
+#include <ui/GraphicBuffer.h>
 #include <gui/IGraphicBufferAlloc.h>
 #include <gui/ISurfaceComposer.h>
-#include <hardware/gralloc1.h>
-#include <ui/GraphicBuffer.h>
-
 #include <private/gui/ComposerService.h>
 
+#include <hardware/gralloc1.h>
+
 #include "core_jni_helpers.h"
 
 using namespace android;
@@ -64,15 +66,6 @@
     sp<GraphicBuffer> buffer;
 };
 
-
-// ----------------------------------------------------------------------------
-// Helper functions
-// ----------------------------------------------------------------------------
-
-static inline bool containsBits(uint64_t mask, uint64_t bitsToCheck) {
-    return (mask & bitsToCheck) == bitsToCheck;
-}
-
 // ----------------------------------------------------------------------------
 // HardwareBuffer lifecycle
 // ----------------------------------------------------------------------------
@@ -121,8 +114,7 @@
     delete wrapper;
 }
 
-static jlong android_hardware_HardwareBuffer_getNativeFinalizer(JNIEnv* env,
-        jobject clazz) {
+static jlong android_hardware_HardwareBuffer_getNativeFinalizer(JNIEnv* env, jobject clazz) {
     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyWrapper));
 }
 
@@ -203,7 +195,8 @@
     if (env->IsInstanceOf(hardwareBufferObj, gHardwareBufferClassInfo.clazz)) {
         GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(
                 env->GetLongField(hardwareBufferObj, gHardwareBufferClassInfo.mNativeObject));
-        return reinterpret_cast<AHardwareBuffer*>(buffer);
+        return AHardwareBuffer_from_GraphicBuffer(buffer);
+
     } else {
         return nullptr;
     }
@@ -211,7 +204,7 @@
 
 jobject android_hardware_HardwareBuffer_createFromAHardwareBuffer(
         JNIEnv* env, AHardwareBuffer* hardwareBuffer) {
-    GraphicBuffer* buffer = reinterpret_cast<GraphicBuffer*>(hardwareBuffer);
+    GraphicBuffer* buffer = AHardwareBuffer_to_GraphicBuffer(hardwareBuffer);
     GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
     jobject hardwareBufferObj = env->NewObject(gHardwareBufferClassInfo.clazz,
             gHardwareBufferClassInfo.ctor, reinterpret_cast<jlong>(wrapper));
@@ -228,103 +221,22 @@
 }
 
 uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat(uint32_t format) {
-    switch (format) {
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-            return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
-        case HAL_PIXEL_FORMAT_RGBX_8888:
-            return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
-        case HAL_PIXEL_FORMAT_RGB_565:
-            return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
-        case HAL_PIXEL_FORMAT_RGB_888:
-            return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
-        case HAL_PIXEL_FORMAT_RGBA_FP16:
-            return AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT;
-        case HAL_PIXEL_FORMAT_RGBA_1010102:
-            return AHARDWAREBUFFER_FORMAT_A2R10G10B10_UNORM_PACK32;
-        case HAL_PIXEL_FORMAT_BLOB:
-            return AHARDWAREBUFFER_FORMAT_BLOB;
-        default:
-            ALOGE("Unknown pixel format %u", format);
-            return 0;
-    }
+    return AHardwareBuffer_convertFromPixelFormat(format);
 }
 
 uint32_t android_hardware_HardwareBuffer_convertToPixelFormat(uint32_t format) {
-    switch (format) {
-        case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
-            return HAL_PIXEL_FORMAT_RGBA_8888;
-        case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
-            return HAL_PIXEL_FORMAT_RGBX_8888;
-        case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
-            return HAL_PIXEL_FORMAT_RGB_565;
-        case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
-            return HAL_PIXEL_FORMAT_RGB_888;
-        case AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT:
-            return HAL_PIXEL_FORMAT_RGBA_FP16;
-        case AHARDWAREBUFFER_FORMAT_A2R10G10B10_UNORM_PACK32:
-            return HAL_PIXEL_FORMAT_RGBA_1010102;
-        case AHARDWAREBUFFER_FORMAT_BLOB:
-            return HAL_PIXEL_FORMAT_BLOB;
-        default:
-            ALOGE("Unknown AHardwareBuffer format %u", format);
-            return 0;
-    }
+    return AHardwareBuffer_convertToPixelFormat(format);
 }
 
 void android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage0,
-        uint64_t usage1, uint64_t* outProducerUsage,
+        uint64_t /*usage1*/, uint64_t* outProducerUsage,
         uint64_t* outConsumerUsage) {
-    *outProducerUsage = 0;
-    *outConsumerUsage = 0;
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ))
-        *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN))
-        *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE))
-        *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN))
-        *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE))
-        *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT))
-        *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
-    // Not sure what this should be.
-    //if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_CUBEMAP)) bits |= 0;
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER))
-        *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE))
-        *outConsumerUsage |= GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER;
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT))
-        *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_PROTECTED;
-    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA))
-        *outProducerUsage |= GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA;
+    AHardwareBuffer_convertToGrallocUsageBits(usage0, outProducerUsage, outConsumerUsage);
 }
 
 uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
         uint64_t producerUsage, uint64_t consumerUsage) {
-    uint64_t bits = 0;
-    if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_CPU_READ))
-        bits |= AHARDWAREBUFFER_USAGE0_CPU_READ;
-    if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN))
-        bits |= AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN;
-    if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_CPU_WRITE))
-        bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE;
-    if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN))
-        bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN;
-    if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE))
-        bits |= AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE;
-    if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET))
-        bits |= AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT;
-    if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER))
-        bits |= AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER;
-    if (containsBits(consumerUsage, GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER))
-        bits |= AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE;
-    if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_PROTECTED))
-        bits |= AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT;
-    if (containsBits(producerUsage, GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA))
-        bits |= AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA;
-
-    return bits;
+    return AHardwareBuffer_convertFromGrallocUsageBits(producerUsage, consumerUsage);
 }
 
 }  // namespace android
@@ -336,19 +248,21 @@
 const char* const kClassPathName = "android/hardware/HardwareBuffer";
 
 static const JNINativeMethod gMethods[] = {
-    { "nCreateHardwareBuffer",  "(IIIIJ)J", (void*) android_hardware_HardwareBuffer_create },
-    { "nGetNativeFinalizer", "()J",          (void*) android_hardware_HardwareBuffer_getNativeFinalizer },
+    { "nCreateHardwareBuffer",  "(IIIIJ)J",
+            (void*) android_hardware_HardwareBuffer_create },
+    { "nGetNativeFinalizer", "()J",
+            (void*) android_hardware_HardwareBuffer_getNativeFinalizer },
     { "nWriteHardwareBufferToParcel",  "(JLandroid/os/Parcel;)V",
             (void*) android_hardware_HardwareBuffer_write },
     { "nReadHardwareBufferFromParcel", "(Landroid/os/Parcel;)J",
             (void*) android_hardware_HardwareBuffer_read },
 
     // --------------- @FastNative ----------------------
-    { "nGetWidth", "(J)I",                   (void*) android_hardware_HardwareBuffer_getWidth },
-    { "nGetHeight", "(J)I",                  (void*) android_hardware_HardwareBuffer_getHeight },
-    { "nGetFormat", "(J)I",                  (void*) android_hardware_HardwareBuffer_getFormat },
-    { "nGetLayers", "(J)I",                  (void*) android_hardware_HardwareBuffer_getLayers },
-    { "nGetUsage", "(J)J",                  (void*) android_hardware_HardwareBuffer_getUsage },
+    { "nGetWidth", "(J)I",      (void*) android_hardware_HardwareBuffer_getWidth },
+    { "nGetHeight", "(J)I",     (void*) android_hardware_HardwareBuffer_getHeight },
+    { "nGetFormat", "(J)I",     (void*) android_hardware_HardwareBuffer_getFormat },
+    { "nGetLayers", "(J)I",     (void*) android_hardware_HardwareBuffer_getLayers },
+    { "nGetUsage", "(J)J",      (void*) android_hardware_HardwareBuffer_getUsage },
 };
 
 int register_android_hardware_HardwareBuffer(JNIEnv* env) {
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index eaf9e91..4322105 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -1021,17 +1021,13 @@
         env->ReleaseStringCritical(fileName, str);
     }
 
-    int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666);  /* -rw-rw-rw- */
+    int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_APPEND, 0666);
     if (fd < 0) {
         fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno));
         return;
     }
 
-    if (lseek(fd, 0, SEEK_END) < 0) {
-        fprintf(stderr, "lseek: %s\n", strerror(errno));
-    } else {
-        dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
-    }
+    dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
 
     close(fd);
 }
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index c05ef26..90ed6eb 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -159,11 +159,12 @@
     minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
     Paint* paint = reinterpret_cast<Paint*>(nativePaint);
     Typeface* typeface = reinterpret_cast<Typeface*>(nativeTypeface);
-    minikin::FontCollection *font;
     minikin::MinikinPaint minikinPaint;
-    minikin::FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, &font, paint,
+    Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
+    minikin::FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, paint,
             typeface);
-    return b->addStyleRun(&minikinPaint, font, style, start, end, isRtl);
+    return b->addStyleRun(&minikinPaint, resolvedTypeface->fFontCollection, style, start, end,
+            isRtl);
 }
 
 // Accept width measurements for the run, passed in from Java
diff --git a/core/proto/android/os/looper.proto b/core/proto/android/os/looper.proto
new file mode 100644
index 0000000..9fcc781
--- /dev/null
+++ b/core/proto/android/os/looper.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/os/messagequeue.proto";
+
+message LooperProto {
+    string thread_name = 1;
+    int64 thread_id = 2;
+    int32 identity_hash_code = 3;
+    android.os.MessageQueueProto queue = 4;
+}
diff --git a/core/proto/android/os/message.proto b/core/proto/android/os/message.proto
new file mode 100644
index 0000000..604935d
--- /dev/null
+++ b/core/proto/android/os/message.proto
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+message MessageProto {
+    int64 when = 1;
+    // Name of callback class.
+    string callback = 2;
+    // User-defined message code so that the recipient can identify what this
+    // message is about.
+    int32 what = 3;
+    int32 arg1 = 4;
+    int32 arg2 = 5;
+    // String representation of an arbitrary object to send to the recipient.
+    string obj = 6;
+    // Name of target class.
+    string target = 7;
+    int32 barrier = 8;
+}
diff --git a/core/proto/android/os/messagequeue.proto b/core/proto/android/os/messagequeue.proto
new file mode 100644
index 0000000..9bff13e
--- /dev/null
+++ b/core/proto/android/os/messagequeue.proto
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/os/message.proto";
+
+message MessageQueueProto {
+    repeated android.os.MessageProto messages = 1;
+    bool is_polling_locked = 2;
+    bool is_quitting = 3;
+}
diff --git a/core/proto/android/os/worksource.proto b/core/proto/android/os/worksource.proto
new file mode 100644
index 0000000..c2aa5cb
--- /dev/null
+++ b/core/proto/android/os/worksource.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+message WorkSourceProto {
+    message WorkSourceContentProto {
+        int32 uid = 1;
+        string name = 2;
+    }
+
+    repeated WorkSourceContentProto work_source_contents = 1;
+}
\ No newline at end of file
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
new file mode 100644
index 0000000..326b0eb
--- /dev/null
+++ b/core/proto/android/service/package.proto
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.service.pm;
+
+option java_multiple_files = true;
+option java_outer_classname = "PackageServiceProto";
+
+message PackageServiceDumpProto {
+    message PackageShortProto {
+        // Name of package. e.g. "com.android.providers.telephony".
+        string name = 1;
+        // UID for this package as assigned by Android OS.
+        int32 uid = 2;
+    }
+    message SharedLibraryProto {
+        string name = 1;
+        // True if library path is not null (jar), false otherwise (apk)
+        bool is_jar = 2;
+        // Should be filled if is_jar is true
+        string path = 3;
+        // Should be filled if is_jar is false
+        string apk = 4;
+    }
+    message FeatureProto {
+        string name = 1;
+        int32 version = 2;
+    }
+    message SharedUserProto {
+        int32 user_id = 1;
+        string name = 2;
+    }
+
+    // Installed packages.
+    PackageShortProto required_verifier_package = 1;
+    PackageShortProto verifier_package = 2;
+    repeated SharedLibraryProto shared_libraries = 3;
+    repeated FeatureProto features = 4;
+    repeated PackageProto packages = 5;
+    repeated SharedUserProto shared_users = 6;
+    // Messages from the settings problem file
+    repeated string messages = 7;
+}
+
+message PackageProto {
+    message SplitProto {
+        string name = 1;
+        int32 revision_code = 2;
+    }
+    message UserInfoProto {
+        enum InstallType {
+            NOT_INSTALLED_FOR_USER = 0;
+            FULL_APP_INSTALL = 1;
+            INSTANT_APP_INSTALL = 2;
+        }
+        // Enum values gotten from PackageManger.java
+        enum EnabledState {
+            // This component or application is in its default enabled state
+            // (as specified in its manifest).
+            COMPONENT_ENABLED_STATE_DEFAULT = 0;
+            // This component or application has been explictily enabled, regardless
+            // of what it has specified in its manifest.
+            COMPONENT_ENABLED_STATE_ENABLED = 1;
+            // This component or application has been explicitly disabled, regardless of
+            // what it has specified in its manifest.
+            COMPONENT_ENABLED_STATE_DISABLED = 2;
+            // The user has explicitly disabled the application, regardless of what it has
+            // specified in its manifest.
+            COMPONENT_ENABLED_STATE_DISABLED_USER = 3;
+            // This application should be considered, until the point where the user actually
+            // wants to use it.
+            COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4;
+        }
+
+        int32 id = 1;
+        InstallType install_type = 2;
+        // Is the app restricted by owner / admin
+        bool is_hidden = 3;
+        bool is_suspended = 4;
+        bool is_stopped = 5;
+        bool is_launched = 6;
+        EnabledState enabled_state = 7;
+        string last_disabled_app_caller = 8;
+    }
+
+    // Name of package. e.g. "com.android.providers.telephony".
+    string name = 1;
+    // UID for this package as assigned by Android OS.
+    int32 uid = 2;
+    // Package's reported version.
+    int32 version_code = 3;
+    // Package's reported version string (what's displayed to the user).
+    string version_string = 4;
+    // UTC timestamp of install
+    int64 install_time_ms = 5;
+    // Millisecond UTC timestamp of latest update adjusted to Google's server clock.
+    int64 update_time_ms = 6;
+    // From "dumpsys package" - name of package which installed this one.
+    // Typically "" if system app or "com.android.vending" if Play Store.
+    string installer_name = 7;
+    // Split APKs.
+    repeated SplitProto splits = 8;
+    // Per-user package info.
+    repeated UserInfoProto users = 9;
+}
diff --git a/core/proto/android/service/power.proto b/core/proto/android/service/power.proto
new file mode 100644
index 0000000..1830dbf
--- /dev/null
+++ b/core/proto/android/service/power.proto
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.service.power;
+
+option java_multiple_files = true;
+option java_outer_classname = "PowerServiceProto";
+
+import "frameworks/base/core/proto/android/os/looper.proto";
+import "frameworks/base/core/proto/android/os/worksource.proto";
+import "frameworks/base/core/proto/android/service/wirelesschargerdetector.proto";
+
+message PowerServiceDumpProto {
+    message ConstantsProto {
+        bool is_no_cached_wake_locks = 1;
+    }
+    message ActiveWakeLocksProto {
+        bool is_cpu = 1;
+        bool is_screen_bright = 2;
+        bool is_screen_dim = 3;
+        bool is_button_bright = 4;
+        bool is_proximity_screen_off = 5;
+        // only set if already awake
+        bool is_stay_awake = 6;
+        bool is_doze = 7;
+        bool is_draw = 8;
+    }
+    message UserActivityProto {
+        bool is_screen_bright = 1;
+        bool is_screen_dim = 2;
+        bool is_screen_dream = 3;
+    }
+    message UidProto {
+        // Enum values gotten from ActivityManager.java
+        enum ProcessState {
+            // Process is a persistent system process.
+            PROCESS_STATE_PERSISTENT = 0;
+            // Process is a persistent system process and is doing UI.
+            PROCESS_STATE_PERSISTENT_UI = 1;
+            // Process is hosting the current top activities. Note that this
+            // covers all activities that are visible to the user.
+            PROCESS_STATE_TOP = 2;
+            // Process is hosting a foreground service due to a system binding.
+            PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 3;
+            // Process is hosting a foreground service.
+            PROCESS_STATE_FOREGROUND_SERVICE = 4;
+            // Same as {@link #PROCESS_STATE_TOP} but while device is sleeping.
+            PROCESS_STATE_TOP_SLEEPING = 5;
+            // Process is important to the user, and something they are aware of.
+            PROCESS_STATE_IMPORTANT_FOREGROUND = 6;
+            // Process is important to the user, but not something they are aware of.
+            PROCESS_STATE_IMPORTANT_BACKGROUND = 7;
+            // Process is in the background running a backup/restore operation.
+            PROCESS_STATE_BACKUP = 8;
+            // Process is in the background, but it can't restore its state so
+            // we want to try to avoid killing it.
+            PROCESS_STATE_HEAVY_WEIGHT = 9;
+            // Process is in the background running a service.
+            PROCESS_STATE_SERVICE = 10;
+            // Process is in the background running a receiver.
+            PROCESS_STATE_RECEIVER = 11;
+            // Process is in the background but hosts the home activity.
+            PROCESS_STATE_HOME = 12;
+            // Process is in the background but hosts the last shown activity.
+            PROCESS_STATE_LAST_ACTIVITY = 13;
+            // Process is being cached for later use and contains activities.
+            PROCESS_STATE_CACHED_ACTIVITY = 14;
+            // Process is being cached for later use and is a client of another
+            // cached process that contains activities.
+            PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 15;
+            // Process is being cached for later use and is empty.
+            PROCESS_STATE_CACHED_EMPTY = 16;
+            // Process does not exist.
+            PROCESS_STATE_NONEXISTENT = 17;
+        }
+        int32 uid = 1;
+        string uid_string = 2;
+        bool is_active = 3;
+        int32 num_wake_locks = 4;
+        bool is_process_state_unknown = 5;
+        ProcessState process_state = 6;
+    }
+
+    // Enum values gotten from PowerManagerInternal.java
+    enum Wakefulness {
+        WAKEFULNESS_ASLEEP = 0;
+        WAKEFULNESS_AWAKE = 1;
+        WAKEFULNESS_DREAMING = 2;
+        WAKEFULNESS_DOZING = 3;
+        WAKEFULNESS_UNKNOWN = 4;
+    }
+    // Enum values gotten from BatteryManager.java
+    enum PlugType {
+        PLUG_TYPE_NONE = 0;
+        PLUG_TYPE_PLUGGED_AC = 1;
+        PLUG_TYPE_PLUGGED_USB = 2;
+        PLUG_TYPE_PLUGGED_WIRELESS = 4;
+    }
+    // Enum values gotten from Intent.java
+    enum DockState {
+        DOCK_STATE_UNDOCKED = 0;
+        DOCK_STATE_DESK = 1;
+        DOCK_STATE_CAR = 2;
+        DOCK_STATE_LE_DESK = 3;
+        DOCK_STATE_HE_DESK = 4;
+    }
+
+    ConstantsProto constants = 1;
+    // A bitfield that indicates what parts of the power state have
+    // changed and need to be recalculated.
+    int32 dirty = 2;
+    // Indicates whether the device is awake or asleep or somewhere in between.
+    Wakefulness wakefulness = 3;
+    bool is_wakefulness_changing = 4;
+    // True if the device is plugged into a power source.
+    bool is_powered = 5;
+    // The current plug type
+    PlugType plug_type = 6;
+    // The current battery level percentage.
+    int32 battery_level = 7;
+    // The battery level percentage at the time the dream started.
+    int32 battery_level_when_dream_started = 8;
+    // The current dock state.
+    DockState dock_state = 9;
+    // True if the device should stay on.
+    bool is_stay_on = 10;
+    // True if the proximity sensor reads a positive result.
+    bool is_proximity_positive = 11;
+    // True if boot completed occurred.  We keep the screen on until this happens.
+    bool is_boot_completed = 12;
+    // True if systemReady() has been called.
+    bool is_system_ready = 13;
+    // True if auto-suspend mode is enabled.
+    bool is_hal_auto_suspend_mode_enabled = 14;
+    // True if interactive mode is enabled.
+    bool is_hal_auto_interactive_mode_enabled = 15;
+    // Summarizes the state of all active wakelocks.
+    ActiveWakeLocksProto active_wake_locks = 16;
+    // Have we scheduled a message to check for long wake locks?  This is when
+    // we will check. (In milliseconds timestamp)
+    int64 notify_long_scheduled_ms = 17;
+    // Last time we checked for long wake locks. (In milliseconds timestamp)
+    int64 notify_long_dispatched_ms = 18;
+    // The time we decided to do next long check. (In milliseconds timestamp)
+    int64 notify_long_next_check_ms = 19;
+    // Summarizes the effect of the user activity timer.
+    UserActivityProto user_activity = 20;
+    // If true, instructs the display controller to wait for the proximity
+    // sensor to go negative before turning the screen on.
+    bool is_request_wait_for_negative_proximity = 21;
+    // True if MSG_SANDMAN has been scheduled.
+    bool is_sandman_scheduled = 22;
+    // True if the sandman has just been summoned for the first time since entering
+    // the dreaming or dozing state.  Indicates whether a new dream should begin.
+    bool is_sandman_summoned = 23;
+    // If true, the device is in low power mode.
+    bool is_low_power_mode_enabled = 24;
+    // True if the battery level is currently considered low.
+    bool is_battery_level_low = 25;
+    // True if we are currently in light device idle mode.
+    bool is_light_device_idle_mode = 26;
+    // True if we are currently in device idle mode.
+    bool is_device_idle_mode = 27;
+    // Set of app ids that we will always respect the wake locks for.
+    repeated int32 device_idle_whitelist = 28;
+    // Set of app ids that are temporarily allowed to acquire wakelocks due to
+    // high-pri message
+    repeated int32 device_idle_temp_whitelist = 29;
+    // Timestamp of the last time the device was awoken.
+    int64 last_wake_time_ms = 30;
+    // Timestamp of the last time the device was put to sleep.
+    int64 last_sleep_time_ms = 31;
+    // Timestamp of the last call to user activity.
+    int64 last_user_activity_time_ms = 32;
+    int64 last_user_activity_time_no_change_lights_ms = 33;
+    // Timestamp of last interactive power hint.
+    int64 last_interactive_power_hint_time_ms = 34;
+    // Timestamp of the last screen brightness boost.
+    int64 last_screen_brightness_boost_time_ms = 35;
+    // True if screen brightness boost is in progress.
+    bool is_screen_brightness_boost_in_progress = 36;
+    // True if the display power state has been fully applied, which means the
+    // display is actually on or actually off or whatever was requested.
+    bool is_display_ready = 37;
+    // True if the wake lock suspend blocker has been acquired.
+    bool is_holding_wake_lock_suspend_blocker = 38;
+    // The suspend blocker used to keep the CPU alive when the display is on, the
+    // display is getting ready or there is user activity (in which case the
+    // display must be on).
+    bool is_holding_display_suspend_blocker = 39;
+    // Settings and configuration
+    PowerServiceSettingsAndConfigurationDumpProto settings_and_configuration = 40;
+    // Sleep timeout in ms
+    sint32 sleep_timeout_ms = 41;
+    // Screen off timeout in ms
+    int32 screen_off_timeout_ms = 42;
+    // Screen dim duration in ms
+    int32 screen_dim_duration_ms = 43;
+    // We are currently in the middle of a batch change of uids.
+    bool are_uids_changing = 44;
+    // Some uids have actually changed while mUidsChanging was true.
+    bool are_uids_changed = 45;
+    // List of UIDs and their states
+    repeated UidProto uids = 46;
+    android.os.LooperProto looper = 47;
+    // List of all wake locks acquired by applications.
+    repeated WakeLockProto wake_locks = 48;
+    // List of all suspend blockers.
+    repeated SuspendBlockerProto suspend_blockers = 49;
+    WirelessChargerDetectorProto wireless_charger_detector = 50;
+}
+
+message SuspendBlockerProto {
+    string name = 1;
+    int32 reference_count = 2;
+}
+
+message WakeLockProto {
+    message WakeLockFlagsProto {
+        // Turn the screen on when the wake lock is acquired.
+        bool is_acquire_causes_wakeup = 1;
+        // When this wake lock is released, poke the user activity timer
+        // so the screen stays on for a little longer.
+        bool is_on_after_release = 2;
+    }
+
+    // Enum values gotten from PowerManager.java
+    enum LockLevel {
+        WAKE_LOCK_INVALID = 0;
+        // Ensures that the CPU is running.
+        PARTIAL_WAKE_LOCK = 1;
+        // Ensures that the screen is on (but may be dimmed).
+        SCREEN_DIM_WAKE_LOCK = 6;
+        // Ensures that the screen is on at full brightness.
+        SCREEN_BRIGHT_WAKE_LOCK = 10;
+        // Ensures that the screen and keyboard backlight are on at full brightness.
+        FULL_WAKE_LOCK = 26;
+        // Turns the screen off when the proximity sensor activates.
+        PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
+        // Put the screen in a low power state and allow the CPU to suspend
+        // if no other wake locks are held.
+        DOZE_WAKE_LOCK = 64;
+        // Keep the device awake enough to allow drawing to occur.
+        DRAW_WAKE_LOCK = 128;
+    }
+
+    LockLevel lock_level = 1;
+    string tag = 2;
+    WakeLockFlagsProto flags = 3;
+    bool is_disabled = 4;
+    // Acquire time in ms
+    int64 acq_ms = 5;
+    bool is_notified_long = 6;
+    // Owner UID
+    int32 uid = 7;
+    // Owner PID
+    int32 pid = 8;
+    android.os.WorkSourceProto work_source = 9;
+}
+
+message PowerServiceSettingsAndConfigurationDumpProto {
+    message StayOnWhilePluggedInProto {
+        bool is_stay_on_while_plugged_in_ac = 1;
+        bool is_stay_on_while_plugged_in_usb = 2;
+        bool is_stay_on_while_plugged_in_wireless = 3;
+    }
+    message ScreenBrightnessSettingLimitsProto {
+        int32 setting_minimum = 1;
+        int32 setting_maximum = 2;
+        int32 setting_default = 3;
+        int32 setting_for_vr_default = 4;
+    }
+
+    // Enum values gotten from Settings.java
+    enum ScreenBrightnessMode {
+        SCREEN_BRIGHTNESS_MODE_MANUAL = 0;
+        SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
+    }
+    // Enum values gotten from Display.java
+    enum DisplayState {
+        DISPLAY_STATE_UNKNOWN = 0;
+        DISPLAY_STATE_OFF = 1;
+        DISPLAY_STATE_ON = 2;
+        DISPLAY_STATE_DOZE = 3;
+        DISPLAY_STATE_DOZE_SUSPEND = 4;
+        DISPLAY_STATE_VR = 5;
+    }
+
+
+    // True to decouple auto-suspend mode from the display state.
+    bool is_decouple_hal_auto_suspend_mode_from_display_config = 1;
+    // True to decouple interactive mode from the display state.
+    bool is_decouple_hal_interactive_mode_from_display_config = 2;
+    // True if the device should wake up when plugged or unplugged.
+    bool is_wake_up_when_plugged_or_unplugged_config = 3;
+    // True if the device should wake up when plugged or unplugged in theater mode.
+    bool is_wake_up_when_plugged_or_unplugged_in_theater_mode_config = 4;
+    // True if theater mode is enabled
+    bool is_theater_mode_enabled = 5;
+    // True if the device should suspend when the screen is off due to proximity.
+    bool is_suspend_when_screen_off_due_to_proximity_config = 6;
+    // True if dreams are supported on this device.
+    bool are_dreams_supported_config = 7;
+    // Default value for dreams enabled
+    bool are_dreams_enabled_by_default_config = 8;
+    // Default value for dreams activate-on-sleep
+    bool are_dreams_activated_on_sleep_by_default_config = 9;
+    // Default value for dreams activate-on-dock
+    bool are_dreams_activated_on_dock_by_default_config = 10;
+    // True if dreams can run while not plugged in.
+    bool are_dreams_enabled_on_battery_config = 11;
+    // Minimum battery level to allow dreaming when powered.
+    // Use -1 to disable this safety feature.
+    sint32 dreams_battery_level_minimum_when_powered_config = 12;
+    // Minimum battery level to allow dreaming when not powered.
+    // Use -1 to disable this safety feature.
+    sint32 dreams_battery_level_minimum_when_not_powered_config = 13;
+    // If the battery level drops by this percentage and the user activity
+    // timeout has expired, then assume the device is receiving insufficient
+    // current to charge effectively and terminate the dream.  Use -1 to disable
+    // this safety feature.
+    sint32 dreams_battery_level_drain_cutoff_config = 14;
+    // True if dreams are enabled by the user.
+    bool are_dreams_enabled_setting = 15;
+    // True if dreams should be activated on sleep.
+    bool are_dreams_activate_on_sleep_setting = 16;
+    // True if dreams should be activated on dock.
+    bool are_dreams_activate_on_dock_setting = 17;
+    // True if doze should not be started until after the screen off transition.
+    bool is_doze_after_screen_off_config = 18;
+    // If true, the device is in low power mode.
+    bool is_low_power_mode_setting = 19;
+    // Current state of whether the settings are allowing auto low power mode.
+    bool is_auto_low_power_mode_configured = 20;
+    // The user turned off low power mode below the trigger level
+    bool is_auto_low_power_mode_snoozing = 21;
+    // The minimum screen off timeout, in milliseconds.
+    int32 minimum_screen_off_timeout_config_ms = 22;
+    // The screen dim duration, in milliseconds.
+    int32 maximum_screen_dim_duration_config_ms = 23;
+    // The maximum screen dim time expressed as a ratio relative to the screen off timeout.
+    float maximum_screen_dim_ratio_config = 24;
+    // The screen off timeout setting value in milliseconds.
+    int32 screen_off_timeout_setting_ms = 25;
+    // The sleep timeout setting value in milliseconds.
+    sint32 sleep_timeout_setting_ms = 26;
+    // The maximum allowable screen off timeout according to the device administration policy.
+    int32 maximum_screen_off_timeout_from_device_admin_ms = 27;
+    bool is_maximum_screen_off_timeout_from_device_admin_enforced_locked = 28;
+    // The stay on while plugged in setting.
+    // A set of battery conditions under which to make the screen stay on.
+    StayOnWhilePluggedInProto stay_on_while_plugged_in = 29;
+    // The screen brightness setting, from 0 to 255.
+    // Use -1 if no value has been set.
+    sint32 screen_brightness_setting = 30;
+    // The screen auto-brightness adjustment setting, from -1 to 1.
+    // Use 0 if there is no adjustment.
+    float screen_auto_brightness_adjustment_setting = 31;
+    // The screen brightness mode.
+    ScreenBrightnessMode screen_brightness_mode_setting = 32;
+    // The screen brightness setting override from the window manager
+    // to allow the current foreground activity to override the brightness.
+    // Use -1 to disable.
+    sint32 screen_brightness_override_from_window_manager = 33;
+    // The user activity timeout override from the window manager
+    // to allow the current foreground activity to override the user activity
+    // timeout. Use -1 to disable.
+    sint64 user_activity_timeout_override_from_window_manager_ms = 34;
+    // The window manager has determined the user to be inactive via other means.
+    // Set this to false to disable.
+    bool is_user_inactive_override_from_window_manager = 35;
+    // The screen brightness setting override from the settings application
+    // to temporarily adjust the brightness until next updated,
+    // Use -1 to disable.
+    sint32 temporary_screen_brightness_setting_override = 36;
+    // The screen brightness adjustment setting override from the settings
+    // application to temporarily adjust the auto-brightness adjustment factor
+    // until next updated, in the range -1..1.
+    // Use NaN to disable.
+    float temporary_screen_auto_brightness_adjustment_setting_override = 37;
+    // The screen state to use while dozing.
+    DisplayState doze_screen_state_override_from_dream_manager = 38;
+    // The screen brightness to use while dozing.
+    float dozed_screen_brightness_override_from_dream_manager = 39;
+    // Screen brightness settings limits.
+    ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 40;
+    // The screen brightness setting, from 0 to 255, to be used while in VR Mode.
+    int32 screen_brightness_for_vr_setting = 41;
+    // True if double tap to wake is enabled
+    bool is_double_tap_wake_enabled = 42;
+    // True if we are currently in VR Mode.
+    bool is_vr_mode_enabled = 43;
+}
diff --git a/core/proto/android/service/wirelesschargerdetector.proto b/core/proto/android/service/wirelesschargerdetector.proto
new file mode 100644
index 0000000..7ba7c17
--- /dev/null
+++ b/core/proto/android/service/wirelesschargerdetector.proto
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+package android.service.power;
+
+option java_multiple_files = true;
+
+message WirelessChargerDetectorProto {
+    message VectorProto {
+        float x = 1;
+        float y = 2;
+        float z = 3;
+    }
+
+    // Previously observed wireless power state.
+    bool is_powered_wirelessly = 1;
+    // True if the device is thought to be at rest on a wireless charger.
+    bool is_at_rest = 2;
+    // The gravity vector most recently observed while at rest.
+    VectorProto rest = 3;
+    // True if detection is in progress.
+    bool is_detection_in_progress = 4;
+    // The time when detection was last performed.
+    int64 detection_start_time_ms = 5;
+    // True if the rest position should be updated if at rest.
+    bool is_must_update_rest_position = 6;
+    // The total number of samples collected.
+    int32 total_samples = 7;
+    // The number of samples collected that showed evidence of not being at rest.
+    int32 moving_samples = 8;
+    // The value of the first sample that was collected.
+    VectorProto first_sample = 9;
+    // The value of the last sample that was collected.
+    VectorProto last_sample = 10;
+}
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ef3cf47..054fad2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2138,7 +2138,7 @@
          runtime resource overlays.
          @hide -->
     <permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
-        android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
diff --git a/core/res/res/layout/app_permission_item_money.xml b/core/res/res/layout/app_permission_item_money.xml
index 2056285..764c883 100644
--- a/core/res/res/layout/app_permission_item_money.xml
+++ b/core/res/res/layout/app_permission_item_money.xml
@@ -57,14 +57,14 @@
             android:layout_alignParentStart="true"
             android:layout_alignBottom="@+id/perm_money_label"
             android:scaleType="fitCenter"
-            android:tint="@color/perms_costs_money"
+            android:tint="?android:attr/colorError"
             android:tintMode="src_in"
             android:src="@android:drawable/ic_coins_s" />
         <TextView
             android:id="@+id/perm_money_label"
             android:textAppearance="?android:attr/textAppearanceSmall"
             android:textSize="16sp"
-            android:textColor="@color/perms_costs_money"
+            android:textColor="?android:attr/colorError"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_toEndOf="@id/perm_money_icon"
diff --git a/core/res/res/layout/autofill_dataset_picker.xml b/core/res/res/layout/autofill_dataset_picker.xml
index 40cce7b..9b90de6 100644
--- a/core/res/res/layout/autofill_dataset_picker.xml
+++ b/core/res/res/layout/autofill_dataset_picker.xml
@@ -15,7 +15,7 @@
 -->
 
 <ListView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/list"
+    android:id="@+id/autofill_dataset_picker"
     android:layout_width="wrap_content"
     android:layout_height="fill_parent"
     android:divider="?android:attr/listDivider"
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index 8453cd35..dad9aad 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -16,6 +16,7 @@
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/autofill_save"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:paddingStart="16dip"
@@ -39,6 +40,13 @@
             android:singleLine="true">
         </TextView>
 
+        <TextView
+            android:id="@+id/autofill_save_subtitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:visibility="invisible">
+        </TextView>
+
         <Space
             android:layout_width="0dp"
             android:layout_height="0dp"
diff --git a/core/res/res/layout/time_picker_text_input_material.xml b/core/res/res/layout/time_picker_text_input_material.xml
index f17b80e..632a4c1 100644
--- a/core/res/res/layout/time_picker_text_input_material.xml
+++ b/core/res/res/layout/time_picker_text_input_material.xml
@@ -77,7 +77,7 @@
             android:layout_height="wrap_content"
             android:layout_below="@id/input_hour"
             android:layout_alignStart="@id/input_hour"
-            android:textColor="?attr/textColorError"
+            android:textColor="?attr/colorError"
             android:text="@string/time_picker_input_error" />
     </RelativeLayout>
     <Spinner
@@ -87,4 +87,4 @@
         android:layout_alignBaseline="@id/input_block"
         android:layout_alignParentEnd="true"/>
 
-</merge>
\ No newline at end of file
+</merge>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8031f19..be77603 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -66,6 +66,9 @@
         <attr name="primaryContentAlpha" format="float" />
         <!-- The alpha applied to the foreground color to create the secondary text color. -->
         <attr name="secondaryContentAlpha" format="float" />
+        <!-- Color used for error states and things that need to be drawn to
+             the users attention.. -->
+        <attr name="colorError" format="reference|color" />
         <!-- Default background dim amount when a menu, dialog, or something similar pops up. -->
         <attr name="backgroundDimAmount" format="float" />
         <!-- Control whether dimming behind the window is enabled.  The default
@@ -135,9 +138,6 @@
         <!-- Color of list item text in alert dialogs. -->
         <attr name="textColorAlertDialogListItem" format="reference|color" />
 
-        <!-- Text color for errors. -->
-        <attr name="textColorError" format="reference|color" />
-
         <!-- Search widget more corpus result item background. -->
         <attr name="searchWidgetCorpusItemBackground" format="reference|color" />
 
@@ -4721,18 +4721,19 @@
         </attr>
         <!-- Specify the type of auto-size. Note that this feature is not supported by EditText,
         works only for TextView -->
-        <attr name="autoSizeText" format="enum">
+        <attr name="autoSizeTextType" format="enum">
             <!-- No auto-sizing (default). -->
             <enum name="none" value="0" />
-            <!-- Uniform horizontal and vertical scaling. -->
+            <!-- Uniform horizontal and vertical text size scaling to fit within the
+            container -->
             <enum name="uniform" value="1" />
         </attr>
-        <!-- Specify the auto-size step size if <code>autoSizeText</code> is set to
-        <code>xy</code>. The default is 1px. Overwrites
+        <!-- Specify the auto-size step size if <code>autoSizeTextType</code> is set to
+        <code>uniform</code>. The default is 1px. Overwrites
         <code>autoSizePresetSizes</code> if set. -->
         <attr name="autoSizeStepGranularity" format="dimension" />
-        <!-- Array of dimensions to be used in conjunction with
-        <code>autoSizeText</code> set to <code>xy</code>. Overwrites
+        <!-- Resource array of dimensions to be used in conjunction with
+        <code>autoSizeTextType</code> set to <code>uniform</code>. Overrides
         <code>autoSizeStepGranularity</code> if set. -->
         <attr name="autoSizePresetSizes"/>
         <!-- The minimum text size constraint to be used when auto-sizing text -->
@@ -8531,4 +8532,6 @@
         <attr name="reverseLayout" format="boolean" />
         <attr name="stackFromEnd" format="boolean" />
     </declare-styleable>
+
+    <attr name="lockPatternStyle" format="reference" />
 </resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index b28c6f2..6015ed5 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -75,8 +75,6 @@
     <drawable name="input_method_fullscreen_background">#fff9f9f9</drawable>
     <color name="input_method_navigation_guard">#ff000000</color>
 
-    <color name="system_error">#fff4511e</color> <!-- deep orange 600 -->
-
     <!-- For date picker widget -->
     <drawable name="selected_day_background">#ff0092f4</drawable>
 
@@ -88,7 +86,6 @@
     <color name="perms_dangerous_grp_color">#33b5e5</color>
     <color name="perms_dangerous_perm_color">#33b5e5</color>
     <color name="shadow">#cc222222</color>
-    <color name="perms_costs_money">#fff4511e</color>
 
     <!-- For search-related UIs -->
     <color name="search_url_text_normal">#7fa87f</color>
@@ -121,7 +118,6 @@
     <!-- LockPatternView -->
     <color name="lock_pattern_view_regular_color">#ffffffff</color>
     <color name="lock_pattern_view_success_color">#ffffffff</color>
-    <color name="lock_pattern_view_error_color">@color/system_error</color>
 
     <!-- FaceLock -->
     <color name="facelock_spotlight_mask">#CC000000</color>
@@ -156,7 +152,6 @@
     <color name="accessibility_focus_highlight">#bf39b500</color>
 
     <color name="system_notification_accent_color">#ff607D8B</color>
-    <color name="battery_saver_mode_color">#fff4511e</color><!-- deep orange 600 -->
 
     <!-- Default user icon colors -->
     <color name="user_icon_1">#ff00bcd4</color><!-- cyan 500 -->
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 0a24565..e0cc5b5 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -46,6 +46,7 @@
 
     <color name="button_material_dark">#ff5a595b</color>
     <color name="button_material_light">#ffd6d7d7</color>
+    <color name="error_color_material">#F4511E</color>
 
     <color name="switch_thumb_normal_material_dark">#ffbdbdbd</color>
     <color name="switch_thumb_normal_material_light">#fff1f1f1</color>
@@ -65,9 +66,6 @@
     <!-- 70% white -->
     <color name="secondary_text_default_material_dark">#b3ffffff</color>
 
-    <color name="error_text_material_light">@color/material_red_A700</color>
-    <color name="error_text_material_dark">@color/material_red_A100</color>
-
     <item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item>
     <item name="hint_alpha_material_light" format="float" type="dimen">0.38</item>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d233e24..35aff80 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2748,8 +2748,8 @@
     <!-- Flag indicates that whether non-system apps can be installed on internal storage. -->
     <bool name="config_allow3rdPartyAppOnInternal">true</bool>
 
-    <!-- Component name of the default cell broadcast receiver -->
-    <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
+    <!-- Package name of the default cell broadcast receiver -->
+    <string name="config_defaultCellBroadcastReceiverPkg" translatable="false">com.android.cellbroadcastreceiver</string>
 
     <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
     <string name="config_icon_mask" translatable="false">"M50,0L100,0 100,100 0,100 0,0z"</string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 78549b5..01737e7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2765,7 +2765,7 @@
         <public name="font" />
         <public name="fontWeight" />
         <public name="tooltipText" />
-        <public name="autoSizeText" />
+        <public name="autoSizeTextType" />
         <public name="autoSizeStepGranularity" />
         <public name="autoSizePresetSizes" />
         <public name="autoSizeMinTextSize" />
@@ -2780,7 +2780,7 @@
         <public name="targetProcess" />
         <public name="nextClusterForward" />
         <public name="__removed1" />
-        <public name="textColorError" />
+        <public name="colorError" />
         <public name="focusedByDefault" />
         <public name="appCategory" />
         <public name="autoSizeMaxTextSize" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6abc009..b0c532c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4510,11 +4510,22 @@
     <!-- Accessibility string used for describing the button in time picker that changes the dialog to circular clock mode. [CHAR LIMIT=NONE] -->
     <string name="time_picker_radial_mode_description">Switch to clock mode for the time input.</string>
 
-    <!-- Title for the auto-fill save dialog shown when the user entered savable text [CHAR LIMIT=NONE] -->
+    <!-- Title for the auto-fill save dialog shown when the the contents of the activity can be saved
+         by an auto-fill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
     <string name="autofill_save_title">Save to <xliff:g id="label" example="MyPass">%1$s</xliff:g>?</string>
+    <!-- Title for the auto-fill save dialog shown when the the contents of the activity can be saved
+         by an auto-fill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
+    <string name="autofill_save_title_with_type">Save <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to <xliff:g id="label" example="MyPass">%2$s</xliff:g>?</string>
     <!-- Label for the auto-fill save button [CHAR LIMIT=NONE] -->
     <string name="autofill_save_yes">Save</string>
     <!-- Label for the auto-fill cancel button [CHAR LIMIT=NONE] -->
     <string name="autofill_save_no">No thanks</string>
 
+    <!-- Label for the type of data being saved for auto-fill when it represent user credentials with a password [CHAR LIMIT=NONE] -->
+    <string name="autofill_save_type_password">password</string>
+    <!-- Label for the type of data being saved for auto-fill when it represent an address (street, city, etc.) [CHAR LIMIT=NONE] -->
+    <string name="autofill_save_type_address">address</string>
+    <!-- Label for the type of data being saved for auto-fill when it represents a credit card [CHAR LIMIT=NONE] -->
+    <string name="autofill_save_type_credit_card">credit card</string>
+
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index faf451b..25873d2 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1475,4 +1475,10 @@
         <item name="padding">16dp</item>
     </style>
 
+    <style name="Widget.LockPatternView">
+        <item name="regularColor">@color/lock_pattern_view_regular_color</item>
+        <item name="errorColor">?attr/colorError</item>
+        <item name="successColor">@color/lock_pattern_view_success_color</item>
+    </style>
+
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e7d3ec9..6995d9a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1195,7 +1195,6 @@
   <java-symbol type="drawable" name="btn_check_off" />
   <java-symbol type="color" name="lock_pattern_view_regular_color" />
   <java-symbol type="color" name="lock_pattern_view_success_color" />
-  <java-symbol type="color" name="lock_pattern_view_error_color" />
   <java-symbol type="dimen" name="lock_pattern_dot_line_width" />
   <java-symbol type="dimen" name="lock_pattern_dot_size" />
   <java-symbol type="dimen" name="lock_pattern_dot_size_activated" />
@@ -2310,7 +2309,6 @@
   <java-symbol type="layout" name="select_dialog_singlechoice_material" />
   <java-symbol type="layout" name="select_dialog_multichoice_material" />
   <java-symbol type="array" name="no_ems_support_sim_operators" />
-  <java-symbol type="color" name="battery_saver_mode_color" />
   <java-symbol type="color" name="system_notification_accent_color" />
   <java-symbol type="dimen" name="text_handle_min_size" />
   <java-symbol type="id" name="transitionTransform" />
@@ -2798,7 +2796,7 @@
   <java-symbol type="drawable" name="lockscreen_selected" />
 
   <java-symbol type="string" name="notification_header_divider_symbol_with_spaces" />
-  <java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
+  <java-symbol type="string" name="config_defaultCellBroadcastReceiverPkg" />
 
   <java-symbol type="color" name="notification_primary_text_color_light" />
   <java-symbol type="color" name="notification_primary_text_color_dark" />
@@ -2840,12 +2838,17 @@
   <java-symbol type="layout" name="autofill_save"/>
   <java-symbol type="layout" name="autofill_dataset_picker"/>
   <java-symbol type="id" name="autofill_save_title" />
+  <java-symbol type="id" name="autofill_save_subtitle" />
   <java-symbol type="id" name="autofill_save_no" />
   <java-symbol type="id" name="autofill_save_yes" />
   <java-symbol type="id" name="autofill_save_close" />
   <java-symbol type="string" name="autofill_save_title" />
+  <java-symbol type="string" name="autofill_save_title_with_type" />
   <java-symbol type="string" name="autofill_save_yes" />
   <java-symbol type="string" name="autofill_save_no" />
+  <java-symbol type="string" name="autofill_save_type_password" />
+  <java-symbol type="string" name="autofill_save_type_address" />
+  <java-symbol type="string" name="autofill_save_type_credit_card" />
 
   <!-- Accessibility fingerprint gestures -->
   <java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
@@ -2853,7 +2856,7 @@
 
   <!-- android.service.trust -->
   <java-symbol type="bool" name="config_allowEscrowTokenForTrustAgent"/>
-  
+
   <!-- Time picker -->
   <java-symbol type="id" name="toggle_mode"/>
   <java-symbol type="id" name="input_mode"/>
@@ -2880,6 +2883,8 @@
   <java-symbol type="string" name="alert_windows_notification_message" />
   <java-symbol type="string" name="alert_windows_notification_turn_off_action" />
   <java-symbol type="drawable" name="alert_window_layer" />
+  <java-symbol type="style" name="Widget.LockPatternView" />
+  <java-symbol type="attr" name="lockPatternStyle" />
 
   <!-- Colon separated list of package names that should be granted Notification Listener access -->
   <java-symbol type="string" name="config_defaultListenerAccessPackages" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index e357678..d100c63 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -63,6 +63,7 @@
         <item name="colorControlHighlight">@color/legacy_button_pressed</item>
         <item name="colorButtonNormal">@color/legacy_button_normal</item>
         <item name="colorEdgeEffect">?attr/colorPrimary</item>
+        <item name="colorError">@color/red</item>
 
         <item name="disabledAlpha">0.5</item>
         <item name="backgroundDimAmount">0.6</item>
@@ -93,7 +94,6 @@
         <item name="textColorLink">@color/link_text_dark</item>
         <item name="textColorLinkInverse">@color/link_text_light</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_light_disable_only</item>
-        <item name="textColorError">@color/red</item>
 
         <item name="textAppearanceLarge">@style/TextAppearance.Large</item>
         <item name="textAppearanceMedium">@style/TextAppearance.Medium</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 400fb47..008c817 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -51,6 +51,7 @@
         <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
         <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item>
         <item name="backgroundDimAmount">0.6</item>
+        <item name="colorError">@color/error_color_material</item>
 
         <!-- Text styles -->
         <item name="textAppearance">@style/TextAppearance.Material</item>
@@ -73,7 +74,6 @@
         <item name="textColorLinkInverse">?attr/colorAccent</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_material_dark</item>
-        <item name="textColorError">@color/error_text_material_dark</item>
 
         <item name="textAppearanceLarge">@style/TextAppearance.Material.Large</item>
         <item name="textAppearanceLargeInverse">@style/TextAppearance.Material.Large.Inverse</item>
@@ -441,7 +441,6 @@
         <item name="textColorLinkInverse">?attr/colorAccent</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_light</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
-        <item name="textColorError">@color/error_text_material_light</item>
 
         <item name="textAppearanceLarge">@style/TextAppearance.Material.Large</item>
         <item name="textAppearanceLargeInverse">@style/TextAppearance.Material.Large.Inverse</item>
@@ -823,7 +822,6 @@
         <item name="textColorHighlightInverse">@color/highlighted_text_material</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_light</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
-        <item name="textColorError">@color/error_text_material_light</item>
 
         <item name="textCheckMark">@drawable/indicator_check_mark_light</item>
         <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
@@ -856,7 +854,6 @@
         <item name="textColorHighlightInverse">@color/highlighted_text_material</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_material_dark</item>
-        <item name="textColorError">@color/error_text_material_dark</item>
 
         <item name="textCheckMark">@drawable/indicator_check_mark_dark</item>
         <item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item>
diff --git a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
index bdc0200..497bc5c 100644
--- a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
+++ b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
@@ -3,61 +3,62 @@
 import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
 import static android.net.NetworkRecommendationProvider.EXTRA_SEQUENCE;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.Assert.fail;
+import static junit.framework.TestCase.assertEquals;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+
+import android.Manifest.permission;
 import android.content.Context;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IRemoteCallback;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 /**
  * Unit test for the {@link NetworkRecommendationProvider}.
  */
-public class NetworkRecommendationProviderTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class NetworkRecommendationProviderTest {
     @Mock private IRemoteCallback mMockRemoteCallback;
+    @Mock private Context mContext;
     private NetworkRecProvider mRecProvider;
-    private Handler mHandler;
     private INetworkRecommendationProvider mStub;
     private CountDownLatch mRecRequestLatch;
     private CountDownLatch mScoreRequestLatch;
     private NetworkKey[] mTestNetworkKeys;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-
-        // Configuration needed to make mockito/dexcache work.
-        final Context context = getInstrumentation().getTargetContext();
-        System.setProperty("dexmaker.dexcache",
-                context.getCacheDir().getPath());
-        ClassLoader newClassLoader = getInstrumentation().getClass().getClassLoader();
-        Thread.currentThread().setContextClassLoader(newClassLoader);
-
         MockitoAnnotations.initMocks(this);
 
-        HandlerThread thread = new HandlerThread("NetworkRecommendationProviderTest");
-        thread.start();
+        Executor executor = Executors.newSingleThreadExecutor();
         mRecRequestLatch = new CountDownLatch(1);
         mScoreRequestLatch = new CountDownLatch(1);
-        mHandler = new Handler(thread.getLooper());
-        mRecProvider = new NetworkRecProvider(mHandler, mRecRequestLatch, mScoreRequestLatch);
+        mRecProvider = new NetworkRecProvider(mContext, executor, mRecRequestLatch,
+                mScoreRequestLatch);
         mStub = INetworkRecommendationProvider.Stub.asInterface(mRecProvider.getBinder());
         mTestNetworkKeys = new NetworkKey[2];
         mTestNetworkKeys[0] = new NetworkKey(new WifiKey("\"ssid_01\"", "00:00:00:00:00:11"));
         mTestNetworkKeys[1] = new NetworkKey(new WifiKey("\"ssid_02\"", "00:00:00:00:00:22"));
     }
 
-    @MediumTest
+    @Test
     public void testRecommendationRequestReceived() throws Exception {
         final RecommendationRequest request = new RecommendationRequest.Builder().build();
         final int sequence = 100;
@@ -71,7 +72,23 @@
         assertEquals(expectedResultCallback, mRecProvider.mCapturedCallback);
     }
 
-    @SmallTest
+    @Test
+    public void testRecommendationRequest_permissionsEnforced() throws Exception {
+        final RecommendationRequest request = new RecommendationRequest.Builder().build();
+        final int sequence = 100;
+        Mockito.doThrow(new SecurityException())
+                .when(mContext)
+                .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES), anyString());
+
+        try {
+            mStub.requestRecommendation(request, mMockRemoteCallback, sequence);
+            fail("SecurityException expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
     public void testResultCallbackOnResult() throws Exception {
         final int sequence = 100;
         final NetworkRecommendationProvider.ResultCallback callback =
@@ -87,7 +104,7 @@
         assertSame(result, capturedBundle.getParcelable(EXTRA_RECOMMENDATION_RESULT));
     }
 
-    @SmallTest
+    @Test
     public void testResultCallbackOnResult_runTwice_throwsException() throws Exception {
         final int sequence = 100;
         final NetworkRecommendationProvider.ResultCallback callback =
@@ -104,7 +121,7 @@
         }
     }
 
-    @MediumTest
+    @Test
     public void testScoreRequestReceived() throws Exception {
         mStub.requestScores(mTestNetworkKeys);
 
@@ -114,7 +131,7 @@
         assertSame(mTestNetworkKeys, mRecProvider.mCapturedNetworks);
     }
 
-    @MediumTest
+    @Test
     public void testScoreRequest_nullInput() throws Exception {
         mStub.requestScores(null);
 
@@ -122,7 +139,7 @@
         assertFalse(mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS));
     }
 
-    @MediumTest
+    @Test
     public void testScoreRequest_emptyInput() throws Exception {
         mStub.requestScores(new NetworkKey[0]);
 
@@ -130,6 +147,20 @@
         assertFalse(mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS));
     }
 
+    @Test
+    public void testScoreRequest_permissionsEnforced() throws Exception {
+        Mockito.doThrow(new SecurityException())
+                .when(mContext)
+                .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES), anyString());
+
+        try {
+            mStub.requestScores(mTestNetworkKeys);
+            fail("SecurityException expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
     private static class NetworkRecProvider extends NetworkRecommendationProvider {
         private final CountDownLatch mRecRequestLatch;
         private final CountDownLatch mScoreRequestLatch;
@@ -137,9 +168,9 @@
         ResultCallback mCapturedCallback;
         NetworkKey[] mCapturedNetworks;
 
-        NetworkRecProvider(Handler handler, CountDownLatch recRequestLatch,
+        NetworkRecProvider(Context context, Executor executor, CountDownLatch recRequestLatch,
             CountDownLatch networkRequestLatch) {
-            super(handler);
+            super(context, executor);
             mRecRequestLatch = recRequestLatch;
             mScoreRequestLatch = networkRequestLatch;
         }
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index da6a294..b718263 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -393,6 +393,7 @@
                  Settings.Secure.BACKUP_TRANSPORT,
                  Settings.Secure.BLUETOOTH_HCI_LOG,
                  Settings.Secure.CARRIER_APPS_HANDLED,
+                 Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG,
                  Settings.Secure.COMPLETED_CATEGORY_PREFIX,
                  Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
                  Settings.Secure.DEFAULT_INPUT_METHOD,
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 1080a9f..3dfecc6 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -16,6 +16,17 @@
 
 package com.android.internal.app;
 
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.graphics.drawable.Icon;
+import android.os.SystemClock;
 import com.android.internal.R;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 
@@ -48,25 +59,31 @@
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.isA;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 /**
  * Chooser activity instrumentation tests
  */
 @RunWith(AndroidJUnit4.class)
 public class ChooserActivityTest {
+    private Instrumentation instrumentation;
+
+    @Before
+    public void setUp() {
+        instrumentation = InstrumentationRegistry.getInstrumentation();
+        sOverrides.reset();
+    }
+
     @Rule
     public ActivityTestRule<ChooserWrapperActivity> mActivityRule =
             new ActivityTestRule<>(ChooserWrapperActivity.class, false,
                     false);
 
-    @Before
-    public void cleanOverrideData() {
-        sOverrides.reset();
-    }
-
     @Test
     public void customTitle() throws InterruptedException {
         Intent sendIntent = createSendImageIntent();
@@ -235,7 +252,6 @@
             chosen[0] = targetInfo.getResolveInfo();
             return true;
         };
-
         // Make a stable copy of the components as the original list may be modified
         List<ResolvedComponentInfo> stableCopy =
                 createResolvedComponentsForTestWithOtherProfile(2);
@@ -324,6 +340,32 @@
         assertThat(chosen[0], is(toChoose));
     }
 
+    public void pushedChooserTarget() {
+        ResolveInfo[] chosen = new ResolveInfo[1];
+        sOverrides.onSafelyStartCallback = targetInfo -> {
+            chosen[0] = targetInfo.getResolveInfo();
+            return true;
+        };
+
+        setChooserShortcuts(1);
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+
+        Intent sendIntent = createSendImageIntent();
+        final ChooserWrapperActivity activity = mActivityRule
+                .launchActivity(Intent.createChooser(sendIntent, null));
+
+        waitForIdle();
+
+        onView(withText("short chooser label 0"))
+                .perform(click());
+        waitForIdle();
+        assertThat(chosen[0].resolvePackageName,
+                is(ResolverDataProvider.createActivityInfo(0).packageName));
+    }
+
     private Intent createSendImageIntent() {
         Intent sendIntent = new Intent();
         sendIntent.setAction(Intent.ACTION_SEND);
@@ -371,4 +413,48 @@
         }
         return packageStats.mChooserCounts.get(action).getOrDefault(annotation, 0);
     }
+
+    private void setChooserShortcuts(int numShortcuts) {
+        ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
+        for (int i = 0; i < numShortcuts; i++) {
+           shortcuts.add(makeShortcut(i));
+        }
+        when(sOverrides.launcherApps.getShortcuts(
+                Mockito.isA(LauncherApps.ShortcutQuery.class),
+                Mockito.eq(UserHandle.SYSTEM)))
+                .thenReturn(shortcuts);
+    }
+
+    private ShortcutInfo makeShortcut(int i) {
+        try {
+            IntentFilter filter = new IntentFilter(Intent.ACTION_SEND, "image/jpeg");
+
+            ComponentName component = new ComponentName("foo.bar", "foo.bar" + ".MainActivity");
+            ShortcutInfo.Builder b = new ShortcutInfo.Builder(instrumentation.getContext(), "" + i)
+                    .setActivity(component)
+                    .setShortLabel("short chooser label " + i)
+                    .setLongLabel("long chooser label" + i)
+                    .setRank(i)
+                    .setIntent(createSendImageIntent())
+                    .setIcon(Icon.createWithResource(instrumentation.getContext(),
+                            android.R.drawable.ic_menu_add))
+                    .addChooserIntentFilter(
+                            filter,
+                            component);
+
+            sOverrides.createPackageManager = pm -> {
+                final PackageManager spied = spy(pm);
+                try {
+                    doAnswer(invocation -> ResolverDataProvider.createActivityInfo(i))
+                            .when(spied).getActivityInfo(
+                            Mockito.isA(ComponentName.class), Mockito.anyInt());
+                } catch (Exception e) {
+                    // this is ok, just not found
+                    e.printStackTrace();
+                }
+                return spied;
+            };
+            return b.build();
+        } catch (Exception e) {return null;}
+    }
 }
\ No newline at end of file
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index c446f3c..0dac260 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -18,6 +18,7 @@
 
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
+import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 
 import java.util.function.Function;
@@ -74,6 +75,11 @@
         return super.getPackageManager();
     }
 
+    @Override
+    public LauncherApps getLauncherApps() {
+        return sOverrides.launcherApps;
+    }
+
     /**
      * We cannot directly mock the activity created since instrumentation creates it.
      * <p>
@@ -82,6 +88,7 @@
     static class OverrideData {
         @SuppressWarnings("Since15")
         public Function<PackageManager, PackageManager> createPackageManager;
+        public LauncherApps launcherApps;
         public Function<TargetInfo, Boolean> onSafelyStartCallback;
         public ResolverListController resolverListController;
         public Boolean isVoiceInteraction;
@@ -90,6 +97,7 @@
             onSafelyStartCallback = null;
             isVoiceInteraction = null;
             createPackageManager = null;
+            launcherApps = mock(LauncherApps.class);
             resolverListController = mock(ResolverListController.class);
         }
     }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 5226fe5..bf3e793 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -253,6 +253,7 @@
         <permission name="android.permission.BIND_APPWIDGET"/>
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
         <permission name="android.permission.CHANGE_CONFIGURATION"/>
+        <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
         <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
         <permission name="android.permission.DELETE_CACHE_FILES"/>
         <permission name="android.permission.DELETE_PACKAGES"/>
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index ff21cac..33d19d4 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -1023,9 +1023,9 @@
                     "The color space must use a color model with at most 3 components");
         }
 
-        @HalfFloat short r = Half.valueOf(red);
-        @HalfFloat short g = Half.valueOf(green);
-        @HalfFloat short b = Half.valueOf(blue);
+        @HalfFloat short r = Half.toHalf(red);
+        @HalfFloat short g = Half.toHalf(green);
+        @HalfFloat short b = Half.toHalf(blue);
 
         int a = (int) (Math.max(0.0f, Math.min(alpha, 1.0f)) * 1023.0f + 0.5f);
 
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index ec00c45..b1a433c 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -805,7 +805,8 @@
      */
     public enum Adaptation {
         /**
-         * Bradford matrix for the von Kries chromatic adaptation transform.
+         * Bradford chromatic adaptation transform, as defined in the
+         * CIECAM97s color appearance model.
          */
         BRADFORD(new float[] {
                  0.8951f, -0.7502f,  0.0389f,
@@ -813,12 +814,21 @@
                 -0.1614f,  0.0367f,  1.0296f
         }),
         /**
-         * von Kries matrix for the von Kries chromatic adaptation transform.
+         * von Kries chromatic adaptation transform.
          */
         VON_KRIES(new float[] {
                  0.40024f, -0.22630f, 0.00000f,
                  0.70760f,  1.16532f, 0.00000f,
                 -0.08081f,  0.04570f, 0.91822f
+        }),
+        /**
+         * CIECAT02 chromatic adaption transform, as defined in the
+         * CIECAM02 color appearance model.
+         */
+        CIECAT02(new float[] {
+                 0.7328f, -0.7036f,  0.0030f,
+                 0.4296f,  1.6975f,  0.0136f,
+                -0.1624f,  0.0061f,  0.9834f
         });
 
         final float[] mTransform;
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index fe82a93..a24b970 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -16,9 +16,11 @@
 
 package android.graphics.drawable;
 
+import android.annotation.NonNull;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
@@ -31,10 +33,10 @@
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.drawable.shapes.Shape;
-import android.content.res.Resources.Theme;
 import android.util.AttributeSet;
 
 import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -69,7 +71,7 @@
  * @attr ref android.R.styleable#ShapeDrawable_height
  */
 public class ShapeDrawable extends Drawable {
-    private ShapeState mShapeState;
+    private @NonNull ShapeState mShapeState;
     private PorterDuffColorFilter mTintFilter;
     private boolean mMutated;
 
@@ -77,7 +79,7 @@
      * ShapeDrawable constructor.
      */
     public ShapeDrawable() {
-        this(new ShapeState(null), null);
+        this(new ShapeState(), null);
     }
 
     /**
@@ -86,7 +88,7 @@
      * @param s the Shape that this ShapeDrawable should be
      */
     public ShapeDrawable(Shape s) {
-        this(new ShapeState(null), null);
+        this(new ShapeState(), null);
 
         mShapeState.mShape = s;
     }
@@ -402,7 +404,7 @@
         }
 
         // Update local properties.
-        updateLocalState(r);
+        updateLocalState();
     }
 
     @Override
@@ -426,7 +428,7 @@
         }
 
         // Update local properties.
-        updateLocalState(t.getResources());
+        updateLocalState();
     }
 
     private void updateStateFromTypedArray(TypedArray a) {
@@ -447,10 +449,10 @@
         dither = a.getBoolean(R.styleable.ShapeDrawable_dither, dither);
         paint.setDither(dither);
 
-        setIntrinsicWidth((int) a.getDimension(
-                R.styleable.ShapeDrawable_width, state.mIntrinsicWidth));
-        setIntrinsicHeight((int) a.getDimension(
-                R.styleable.ShapeDrawable_height, state.mIntrinsicHeight));
+        state.mIntrinsicWidth = (int) a.getDimension(
+                R.styleable.ShapeDrawable_width, state.mIntrinsicWidth);
+        state.mIntrinsicHeight = (int) a.getDimension(
+                R.styleable.ShapeDrawable_height, state.mIntrinsicHeight);
 
         final int tintMode = a.getInt(R.styleable.ShapeDrawable_tintMode, -1);
         if (tintMode != -1) {
@@ -494,21 +496,8 @@
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
-            if (mShapeState.mPaint != null) {
-                mShapeState.mPaint = new Paint(mShapeState.mPaint);
-            } else {
-                mShapeState.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-            }
-            if (mShapeState.mPadding != null) {
-                mShapeState.mPadding = new Rect(mShapeState.mPadding);
-            } else {
-                mShapeState.mPadding = new Rect();
-            }
-            try {
-                mShapeState.mShape = mShapeState.mShape.clone();
-            } catch (CloneNotSupportedException e) {
-                return null;
-            }
+            mShapeState = new ShapeState(mShapeState);
+            updateLocalState();
             mMutated = true;
         }
         return this;
@@ -525,12 +514,13 @@
     /**
      * Defines the intrinsic properties of this ShapeDrawable's Shape.
      */
-    final static class ShapeState extends ConstantState {
-        int[] mThemeAttrs;
+    static final class ShapeState extends ConstantState {
+        final @NonNull Paint mPaint;
+
         @Config int mChangingConfigurations;
-        Paint mPaint;
+        int[] mThemeAttrs;
         Shape mShape;
-        ColorStateList mTint = null;
+        ColorStateList mTint;
         Mode mTintMode = DEFAULT_TINT_MODE;
         Rect mPadding;
         int mIntrinsicWidth;
@@ -538,21 +528,43 @@
         int mAlpha = 255;
         ShaderFactory mShaderFactory;
 
-        ShapeState(ShapeState orig) {
-            if (orig != null) {
-                mThemeAttrs = orig.mThemeAttrs;
-                mPaint = orig.mPaint;
-                mShape = orig.mShape;
-                mTint = orig.mTint;
-                mTintMode = orig.mTintMode;
-                mPadding = orig.mPadding;
-                mIntrinsicWidth = orig.mIntrinsicWidth;
-                mIntrinsicHeight = orig.mIntrinsicHeight;
-                mAlpha = orig.mAlpha;
-                mShaderFactory = orig.mShaderFactory;
-            } else {
-                mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        /**
+         * Constructs a new ShapeState.
+         */
+        ShapeState() {
+            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        }
+
+        /**
+         * Constructs a new ShapeState that contains a deep copy of the
+         * specified ShapeState.
+         *
+         * @param orig the state to create a deep copy of
+         */
+        ShapeState(@NonNull ShapeState orig) {
+            mChangingConfigurations = orig.mChangingConfigurations;
+            mPaint = new Paint(orig.mPaint);
+            mThemeAttrs = orig.mThemeAttrs;
+            if (mShape != null) {
+                try {
+                    mShape = orig.mShape.clone();
+                } catch (CloneNotSupportedException e) {
+                    // Well, at least we tried.
+                    mShape = orig.mShape;
+                }
             }
+            mTint = orig.mTint;
+            mTintMode = orig.mTintMode;
+            if (orig.mPadding != null) {
+                mPadding = new Rect(orig.mPadding);
+            }
+            mIntrinsicWidth = orig.mIntrinsicWidth;
+            mIntrinsicHeight = orig.mIntrinsicHeight;
+            mAlpha = orig.mAlpha;
+
+            // We don't have any way to clone a shader factory, so hopefully
+            // this class doesn't contain any local state.
+            mShaderFactory = orig.mShaderFactory;
         }
 
         @Override
@@ -585,7 +597,7 @@
     private ShapeDrawable(ShapeState state, Resources res) {
         mShapeState = state;
 
-        updateLocalState(res);
+        updateLocalState();
     }
 
     /**
@@ -593,7 +605,7 @@
      * after significant state changes, e.g. from the One True Constructor and
      * after inflating or applying a theme.
      */
-    private void updateLocalState(Resources res) {
+    private void updateLocalState() {
         mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, mShapeState.mTintMode);
     }
 
@@ -617,8 +629,4 @@
          */
         public abstract Shader resize(int width, int height);
     }
-
-    // other subclass could wack the Shader's localmatrix based on the
-    // resize params (e.g. scaletofit, etc.). This could be used to scale
-    // a bitmap to fill the bounds without needing any other special casing.
 }
diff --git a/graphics/java/android/graphics/drawable/shapes/ArcShape.java b/graphics/java/android/graphics/drawable/shapes/ArcShape.java
index c4b239f..85ba0a9 100644
--- a/graphics/java/android/graphics/drawable/shapes/ArcShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/ArcShape.java
@@ -21,31 +21,47 @@
 import android.graphics.Paint;
 
 /**
- * Creates an arc shape. The arc shape starts at a specified
- * angle and sweeps clockwise, drawing slices of pie.
- * The arc can be drawn to a Canvas with its own draw() method,
- * but more graphical control is available if you instead pass
- * the ArcShape to a {@link android.graphics.drawable.ShapeDrawable}.
+ * Creates an arc shape. The arc shape starts at a specified angle and sweeps
+ * clockwise, drawing slices of pie.
+ * <p>
+ * The arc can be drawn to a {@link Canvas} with its own
+ * {@link #draw(Canvas, Paint)} method, but more graphical control is available
+ * if you instead pass the ArcShape to a
+ * {@link android.graphics.drawable.ShapeDrawable}.
  */
 public class ArcShape extends RectShape {
-    private float mStart;
-    private float mSweep;
-    
+    private final float mStartAngle;
+    private final float mSweepAngle;
+
     /**
-     * ArcShape constructor. 
-     * 
+     * ArcShape constructor.
+     *
      * @param startAngle the angle (in degrees) where the arc begins
-     * @param sweepAngle the sweep angle (in degrees). Anything equal to or 
+     * @param sweepAngle the sweep angle (in degrees). Anything equal to or
      *                   greater than 360 results in a complete circle/oval.
      */
     public ArcShape(float startAngle, float sweepAngle) {
-        mStart = startAngle;
-        mSweep = sweepAngle;
+        mStartAngle = startAngle;
+        mSweepAngle = sweepAngle;
     }
-    
+
+    /**
+     * @return the angle (in degrees) where the arc begins
+     */
+    public final float getStartAngle() {
+        return mStartAngle;
+    }
+
+    /**
+     * @return the sweep angle (in degrees)
+     */
+    public final float getSweepAngle() {
+        return mSweepAngle;
+    }
+
     @Override
     public void draw(Canvas canvas, Paint paint) {
-        canvas.drawArc(rect(), mStart, mSweep, true, paint);
+        canvas.drawArc(rect(), mStartAngle, mSweepAngle, true, paint);
     }
 
     @Override
@@ -53,5 +69,10 @@
         // Since we don't support concave outlines, arc shape does not attempt
         // to provide an outline.
     }
+
+    @Override
+    public ArcShape clone() throws CloneNotSupportedException {
+        return (ArcShape) super.clone();
+    }
 }
 
diff --git a/graphics/java/android/graphics/drawable/shapes/OvalShape.java b/graphics/java/android/graphics/drawable/shapes/OvalShape.java
index c9473f0..fb87d28 100644
--- a/graphics/java/android/graphics/drawable/shapes/OvalShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/OvalShape.java
@@ -22,7 +22,8 @@
 import android.graphics.RectF;
 
 /**
- * Defines an oval shape. 
+ * Defines an oval shape.
+ * <p>
  * The oval can be drawn to a Canvas with its own draw() method,
  * but more graphical control is available if you instead pass
  * the OvalShape to a {@link android.graphics.drawable.ShapeDrawable}.
@@ -42,5 +43,10 @@
         outline.setOval((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
                 (int) Math.floor(rect.right), (int) Math.floor(rect.bottom));
     }
+
+    @Override
+    public OvalShape clone() throws CloneNotSupportedException {
+        return (OvalShape) super.clone();
+    }
 }
 
diff --git a/graphics/java/android/graphics/drawable/shapes/PathShape.java b/graphics/java/android/graphics/drawable/shapes/PathShape.java
index 30b7347..ce5552b 100644
--- a/graphics/java/android/graphics/drawable/shapes/PathShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/PathShape.java
@@ -16,41 +16,44 @@
 
 package android.graphics.drawable.shapes;
 
+import android.annotation.NonNull;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Path;
 
 /**
  * Creates geometric paths, utilizing the {@link android.graphics.Path} class.
+ * <p>
  * The path can be drawn to a Canvas with its own draw() method,
  * but more graphical control is available if you instead pass
  * the PathShape to a {@link android.graphics.drawable.ShapeDrawable}.
  */
 public class PathShape extends Shape {
-    private Path    mPath;
-    private float   mStdWidth;
-    private float   mStdHeight;
-    
-    private float   mScaleX;    // cached from onResize
-    private float   mScaleY;    // cached from onResize
-    
+    private final float mStdWidth;
+    private final float mStdHeight;
+
+    private Path mPath;
+
+    private float mScaleX; // cached from onResize
+    private float mScaleY; // cached from onResize
+
     /**
      * PathShape constructor.
-     * 
-     * @param path       a Path that defines the geometric paths for this shape
-     * @param stdWidth   the standard width for the shape. Any changes to the 
-     *                   width with resize() will result in a width scaled based
-     *                   on the new width divided by this width.
-     * @param stdHeight  the standard height for the shape. Any changes to the 
-     *                   height with resize() will result in a height scaled based
-     *                   on the new height divided by this height.
+     *
+     * @param path a Path that defines the geometric paths for this shape
+     * @param stdWidth the standard width for the shape. Any changes to the
+     *                 width with resize() will result in a width scaled based
+     *                 on the new width divided by this width.
+     * @param stdHeight the standard height for the shape. Any changes to the
+     *                  height with resize() will result in a height scaled based
+     *                  on the new height divided by this height.
      */
-    public PathShape(Path path, float stdWidth, float stdHeight) {
+    public PathShape(@NonNull Path path, float stdWidth, float stdHeight) {
         mPath = path;
         mStdWidth = stdWidth;
         mStdHeight = stdHeight;
     }
-    
+
     @Override
     public void draw(Canvas canvas, Paint paint) {
         canvas.save();
@@ -58,7 +61,7 @@
         canvas.drawPath(mPath, paint);
         canvas.restore();
     }
-    
+
     @Override
     protected void onResize(float width, float height) {
         mScaleX = width / mStdWidth;
@@ -67,7 +70,7 @@
 
     @Override
     public PathShape clone() throws CloneNotSupportedException {
-        PathShape shape = (PathShape) super.clone();
+        final PathShape shape = (PathShape) super.clone();
         shape.mPath = new Path(mPath);
         return shape;
     }
diff --git a/graphics/java/android/graphics/drawable/shapes/RectShape.java b/graphics/java/android/graphics/drawable/shapes/RectShape.java
index 04cf293..e339a21 100644
--- a/graphics/java/android/graphics/drawable/shapes/RectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RectShape.java
@@ -23,6 +23,7 @@
 
 /**
  * Defines a rectangle shape.
+ * <p>
  * The rectangle can be drawn to a Canvas with its own draw() method,
  * but more graphical control is available if you instead pass
  * the RectShape to a {@link android.graphics.drawable.ShapeDrawable}.
diff --git a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
index e5253b8..f5cbb24 100644
--- a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable.shapes;
 
+import android.annotation.Nullable;
 import android.graphics.Canvas;
 import android.graphics.Outline;
 import android.graphics.Paint;
@@ -24,40 +25,41 @@
 
 /**
  * Creates a rounded-corner rectangle. Optionally, an inset (rounded) rectangle
- * can be included (to make a sort of "O" shape). 
+ * can be included (to make a sort of "O" shape).
+ * <p>
  * The rounded rectangle can be drawn to a Canvas with its own draw() method,
  * but more graphical control is available if you instead pass
  * the RoundRectShape to a {@link android.graphics.drawable.ShapeDrawable}.
  */
 public class RoundRectShape extends RectShape {
     private float[] mOuterRadii;
-    private RectF   mInset;
+    private RectF mInset;
     private float[] mInnerRadii;
     
     private RectF mInnerRect;
-    private Path  mPath;    // this is what we actually draw
+    private Path mPath; // this is what we actually draw
     
     /**
      * RoundRectShape constructor.
+     * <p>
      * Specifies an outer (round)rect and an optional inner (round)rect.
      *
      * @param outerRadii An array of 8 radius values, for the outer roundrect. 
-     *                   The first two floats are for the 
-     *                   top-left corner (remaining pairs correspond clockwise). 
-     *                   For no rounded corners on the outer rectangle, 
-     *                   pass null.
-     * @param inset      A RectF that specifies the distance from the inner 
-     *                   rect to each side of the outer rect. 
-     *                   For no inner, pass null.
+     *                   The first two floats are for the top-left corner
+     *                   (remaining pairs correspond clockwise). For no rounded
+     *                   corners on the outer rectangle, pass {@code null}.
+     * @param inset A RectF that specifies the distance from the inner
+     *              rect to each side of the outer rect. For no inner, pass
+     *              {@code null}.
      * @param innerRadii An array of 8 radius values, for the inner roundrect.
-     *                   The first two floats are for the 
-     *                   top-left corner (remaining pairs correspond clockwise). 
-     *                   For no rounded corners on the inner rectangle, 
-     *                   pass null.
-     *                   If inset parameter is null, this parameter is ignored. 
+     *                   The first two floats are for the top-left corner
+     *                   (remaining pairs correspond clockwise). For no rounded
+     *                   corners on the inner rectangle, pass {@code null}. If
+     *                   inset parameter is {@code null}, this parameter is
+     *                   ignored.
      */
-    public RoundRectShape(float[] outerRadii, RectF inset,
-                          float[] innerRadii) {
+    public RoundRectShape(@Nullable float[] outerRadii, @Nullable RectF inset,
+            @Nullable float[] innerRadii) {
         if (outerRadii != null && outerRadii.length < 8) {
             throw new ArrayIndexOutOfBoundsException("outer radii must have >= 8 values");
         }
@@ -97,8 +99,7 @@
 
         final RectF rect = rect();
         outline.setRoundRect((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
-                (int) Math.floor(rect.right), (int) Math.floor(rect.bottom),
-                radius);
+                (int) Math.floor(rect.right), (int) Math.floor(rect.bottom), radius);
     }
 
     @Override
@@ -128,7 +129,7 @@
 
     @Override
     public RoundRectShape clone() throws CloneNotSupportedException {
-        RoundRectShape shape = (RoundRectShape) super.clone();
+        final RoundRectShape shape = (RoundRectShape) super.clone();
         shape.mOuterRadii = mOuterRadii != null ? mOuterRadii.clone() : null;
         shape.mInnerRadii = mInnerRadii != null ? mInnerRadii.clone() : null;
         shape.mInset = new RectF(mInset);
diff --git a/graphics/java/android/graphics/drawable/shapes/Shape.java b/graphics/java/android/graphics/drawable/shapes/Shape.java
index eab8666..30b28f3 100644
--- a/graphics/java/android/graphics/drawable/shapes/Shape.java
+++ b/graphics/java/android/graphics/drawable/shapes/Shape.java
@@ -23,21 +23,25 @@
 
 /**
  * Defines a generic graphical "shape."
- * Any Shape can be drawn to a Canvas with its own draw() method,
- * but more graphical control is available if you instead pass
- * it to a {@link android.graphics.drawable.ShapeDrawable}.
+ * <p>
+ * Any Shape can be drawn to a Canvas with its own draw() method, but more
+ * graphical control is available if you instead pass it to a
+ * {@link android.graphics.drawable.ShapeDrawable}.
+ * <p>
+ * Custom Shape classes must implement {@link #clone()} and return an instance
+ * of the custom Shape class.
  */
 public abstract class Shape implements Cloneable {
     private float mWidth;
     private float mHeight;
-    
+
     /**
      * Returns the width of the Shape.
      */
     public final float getWidth() {
         return mWidth;
     }
-    
+
     /**
      * Returns the height of the Shape.
      */
@@ -46,9 +50,10 @@
     }
 
     /**
-     * Draw this shape into the provided Canvas, with the provided Paint.
+     * Draws this shape into the provided Canvas, with the provided Paint.
+     * <p>
      * Before calling this, you must call {@link #resize(float,float)}.
-     * 
+     *
      * @param canvas the Canvas within which this shape should be drawn
      * @param paint  the Paint object that defines this shape's characteristics
      */
@@ -56,8 +61,9 @@
 
     /**
      * Resizes the dimensions of this shape.
+     * <p>
      * Must be called before {@link #draw(Canvas,Paint)}.
-     * 
+     *
      * @param width the width of the shape (in pixels)
      * @param height the height of the shape (in pixels)
      */
@@ -74,30 +80,34 @@
             onResize(width, height);
         }
     }
-    
+
     /**
      * Checks whether the Shape is opaque.
-     * Default impl returns true. Override if your subclass can be opaque.
-     * 
-     * @return true if any part of the drawable is <em>not</em> opaque. 
+     * <p>
+     * Default impl returns {@code true}. Override if your subclass can be
+     * opaque.
+     *
+     * @return true if any part of the drawable is <em>not</em> opaque.
      */
     public boolean hasAlpha() {
         return true;
     }
-    
+
     /**
      * Callback method called when {@link #resize(float,float)} is executed.
-     * 
+     *
      * @param width the new width of the Shape
      * @param height the new height of the Shape
      */
     protected void onResize(float width, float height) {}
 
     /**
-     * Compute the Outline of the shape and return it in the supplied Outline
-     * parameter. The default implementation does nothing and {@code outline} is not changed.
+     * Computes the Outline of the shape and return it in the supplied Outline
+     * parameter. The default implementation does nothing and {@code outline}
+     * is not changed.
      *
-     * @param outline The Outline to be populated with the result. Should not be null.
+     * @param outline the Outline to be populated with the result. Must be
+     *                non-{@code null}.
      */
     public void getOutline(@NonNull Outline outline) {}
 
@@ -105,5 +115,4 @@
     public Shape clone() throws CloneNotSupportedException {
         return (Shape) super.clone();
     }
-
 }
diff --git a/keystore/java/android/security/IKeyChainAliasCallback.aidl b/keystore/java/android/security/IKeyChainAliasCallback.aidl
index 1ea9521..b9d3753 100644
--- a/keystore/java/android/security/IKeyChainAliasCallback.aidl
+++ b/keystore/java/android/security/IKeyChainAliasCallback.aidl
@@ -20,7 +20,7 @@
  *
  * @hide
  */
-interface IKeyChainAliasCallback {
+oneway interface IKeyChainAliasCallback {
 
     void alias(String alias);
 }
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 2931255..aad81df 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -213,10 +213,13 @@
     char prop[PROPERTY_VALUE_MAX];
     property_get(PROPERTY_RENDERER, prop, "opengl");
     if (!strcmp(prop, "skiagl") ) {
+        ALOGD("Skia GL Pipeline");
         sRenderPipelineType = RenderPipelineType::SkiaGL;
     } else if (!strcmp(prop, "skiavk") ) {
+        ALOGD("Skia Vulkan Pipeline");
         sRenderPipelineType = RenderPipelineType::SkiaVulkan;
     } else { //"opengl"
+        ALOGD("HWUI GL Pipeline");
         sRenderPipelineType = RenderPipelineType::OpenGL;
     }
     return sRenderPipelineType;
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index c365b5d..c64a89d 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -153,8 +153,8 @@
     // minikin may modify the original paint
     Paint paint(origPaint);
 
-    minikin::Layout layout;
-    MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);
+    minikin::Layout layout = MinikinUtils::doLayout(
+            &paint, bidiFlags, typeface, text, start, count, contextCount);
 
     size_t nGlyphs = layout.nGlyphs();
     std::unique_ptr<uint16_t[]> glyphs(new uint16_t[nGlyphs]);
@@ -205,8 +205,8 @@
 void Canvas::drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path,
         float hOffset, float vOffset, const Paint& paint, Typeface* typeface) {
     Paint paintCopy(paint);
-    minikin::Layout layout;
-    MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count);
+    minikin::Layout layout = MinikinUtils::doLayout(
+            &paintCopy, bidiFlags, typeface, text, 0, count, count);
     hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
 
     // Set align to left for drawing, as we don't want individual
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index cbae0a0..ba4e3a4 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -91,7 +91,7 @@
     return mAxes;
 }
 
-minikin::MinikinFont* MinikinFontSkia::createFontWithVariation(
+std::shared_ptr<minikin::MinikinFont> MinikinFontSkia::createFontWithVariation(
         const std::vector<minikin::FontVariation>& variations) const {
     SkFontMgr::FontParameters params;
 
@@ -110,7 +110,8 @@
     sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
     sk_sp<SkTypeface> face(fm->createFromStream(stream, params));
 
-    return new MinikinFontSkia(std::move(face), mFontData, mFontSize, ttcIndex, variations);
+    return std::make_shared<MinikinFontSkia>(std::move(face), mFontData, mFontSize, ttcIndex,
+            variations);
 }
 
 uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
index db59fe5..6c12485 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -45,7 +45,7 @@
     size_t GetFontSize() const;
     int GetFontIndex() const;
     const std::vector<minikin::FontVariation>& GetAxes() const;
-    minikin::MinikinFont* createFontWithVariation(
+    std::shared_ptr<minikin::MinikinFont> createFontWithVariation(
             const std::vector<minikin::FontVariation>&) const;
 
     static uint32_t packPaintFlags(const SkPaint* paint);
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index 713e509..d1871ff 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -27,9 +27,8 @@
 namespace android {
 
 minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
-        minikin::FontCollection** pFont, const Paint* paint, Typeface* typeface) {
+        const Paint* paint, Typeface* typeface) {
     const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
-    *pFont = resolvedFace->fFontCollection;
     minikin::FontStyle resolved = resolvedFace->fStyle;
 
     /* Prepare minikin FontStyle */
@@ -54,23 +53,23 @@
     return minikinStyle;
 }
 
-void MinikinUtils::doLayout(minikin::Layout* layout, const Paint* paint, int bidiFlags,
+minikin::Layout MinikinUtils::doLayout(const Paint* paint, int bidiFlags,
         Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
         size_t bufSize) {
-    minikin::FontCollection *font;
     minikin::MinikinPaint minikinPaint;
-    minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
-    layout->setFontCollection(font);
-    layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
+    minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
+    minikin::Layout layout(Typeface::resolveDefault(typeface)->fFontCollection);
+    layout.doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
+    return layout;
 }
 
 float MinikinUtils::measureText(const Paint* paint, int bidiFlags, Typeface* typeface,
         const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances) {
-    minikin::FontCollection *font;
     minikin::MinikinPaint minikinPaint;
-    minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
+    minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
+    Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
     return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle,
-            minikinPaint, font, advances);
+            minikinPaint, resolvedTypeface->fFontCollection, advances);
 }
 
 bool MinikinUtils::hasVariationSelector(Typeface* typeface, uint32_t codepoint, uint32_t vs) {
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index d6f64d2..0f22adc 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -35,9 +35,9 @@
 class MinikinUtils {
 public:
     ANDROID_API static minikin::FontStyle prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
-            minikin::FontCollection** pFont, const Paint* paint, Typeface* typeface);
+            const Paint* paint, Typeface* typeface);
 
-    ANDROID_API static void doLayout(minikin::Layout* layout, const Paint* paint, int bidiFlags,
+    ANDROID_API static minikin::Layout doLayout(const Paint* paint, int bidiFlags,
             Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
             size_t bufSize);
 
@@ -56,11 +56,11 @@
     ANDROID_API static void forFontRun(const minikin::Layout& layout, Paint* paint, F& f) {
         float saveSkewX = paint->getTextSkewX();
         bool savefakeBold = paint->isFakeBoldText();
-        minikin::MinikinFont* curFont = NULL;
+        const minikin::MinikinFont* curFont = nullptr;
         size_t start = 0;
         size_t nGlyphs = layout.nGlyphs();
         for (size_t i = 0; i < nGlyphs; i++) {
-          minikin::MinikinFont* nextFont = layout.getFont(i);
+            const minikin::MinikinFont* nextFont = layout.getFont(i);
             if (i > 0 && nextFont != curFont) {
                 MinikinFontSkia::populateSkPaint(paint, curFont, layout.getFakery(start));
                 f(start, i);
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 9f9fac6..4b8575a 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -64,7 +64,6 @@
     Typeface* result = new Typeface;
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fFontCollection->Ref();
         result->fSkiaStyle = style;
         result->fBaseWeight = resolvedFace->fBaseWeight;
         resolveStyle(result);
@@ -83,7 +82,6 @@
             // None of passed axes are supported by this collection.
             // So we will reuse the same collection with incrementing reference count.
             result->fFontCollection = resolvedFace->fFontCollection;
-            result->fFontCollection->Ref();
         }
         result->fSkiaStyle = resolvedFace->fSkiaStyle;
         result->fBaseWeight = resolvedFace->fBaseWeight;
@@ -97,7 +95,6 @@
     Typeface* result = new Typeface;
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fFontCollection->Ref();
         result->fSkiaStyle = resolvedFace->fSkiaStyle;
         result->fBaseWeight = weight;
         resolveStyle(result);
@@ -105,18 +102,19 @@
     return result;
 }
 
-Typeface* Typeface::createFromFamilies(const std::vector<minikin::FontFamily*>& families) {
+Typeface* Typeface::createFromFamilies(
+        std::vector<std::shared_ptr<minikin::FontFamily>>&& families) {
     Typeface* result = new Typeface;
-    result->fFontCollection = new minikin::FontCollection(families);
+    result->fFontCollection.reset(new minikin::FontCollection(families));
     if (families.empty()) {
         ALOGW("createFromFamilies creating empty collection");
         result->fSkiaStyle = SkTypeface::kNormal;
     } else {
         const minikin::FontStyle defaultStyle;
-        minikin::FontFamily* firstFamily = reinterpret_cast<minikin::FontFamily*>(families[0]);
-        minikin::MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
-        if (mf != NULL) {
-            SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
+        const std::shared_ptr<minikin::FontFamily>& firstFamily = families[0];
+        const minikin::MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
+        if (mf != nullptr) {
+            SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface();
             // TODO: probably better to query more precise style from family, will be important
             // when we open up API to access 100..900 weights
             result->fSkiaStyle = skTypeface->style();
@@ -129,11 +127,6 @@
     return result;
 }
 
-void Typeface::unref() {
-    fFontCollection->Unref();
-    delete this;
-}
-
 void Typeface::setDefault(Typeface* face) {
     gDefaultTypeface = face;
 }
@@ -150,15 +143,12 @@
     sk_sp<SkTypeface> typeface = SkTypeface::MakeFromStream(fontData.release());
     LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", kRobotoFont);
 
-    minikin::MinikinFont* font = new MinikinFontSkia(std::move(typeface), data, st.st_size, 0,
-            std::vector<minikin::FontVariation>());
-    minikin::FontFamily* family = new minikin::FontFamily(
-                 std::vector<minikin::Font>({ minikin::Font(font, minikin::FontStyle()) }));
-    font->Unref();
-
-    std::vector<minikin::FontFamily*> typefaces = { family };
-    minikin::FontCollection *collection = new minikin::FontCollection(typefaces);
-    family->Unref();
+    std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
+            std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
+    std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
+            std::vector<minikin::Font>({ minikin::Font(std::move(font), minikin::FontStyle()) }));
+    std::shared_ptr<minikin::FontCollection> collection =
+            std::make_shared<minikin::FontCollection>(std::move(family));
 
     Typeface* hwTypeface = new Typeface();
     hwTypeface->fFontCollection = collection;
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index 4392ebc..19a4f6c5 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -23,11 +23,12 @@
 #include <cutils/compiler.h>
 #include <minikin/FontCollection.h>
 #include <vector>
+#include <memory>
 
 namespace android {
 
 struct ANDROID_API Typeface {
-  minikin::FontCollection *fFontCollection;
+    std::shared_ptr<minikin::FontCollection> fFontCollection;
 
     // style used for constructing and querying Typeface objects
     SkTypeface::Style fSkiaStyle;
@@ -37,8 +38,6 @@
     // resolved style actually used for rendering
     minikin::FontStyle fStyle;
 
-    void unref();
-
     static Typeface* resolveDefault(Typeface* src);
 
     static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style);
@@ -48,7 +47,8 @@
 
     static Typeface* createWeightAlias(Typeface* src, int baseweight);
 
-    static Typeface* createFromFamilies(const std::vector<minikin::FontFamily*>& families);
+    static Typeface* createFromFamilies(
+            std::vector<std::shared_ptr<minikin::FontFamily>>&& families);
 
     static void setDefault(Typeface* face);
 
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index f2b0eb3..ae13131 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -26,7 +26,6 @@
 #include "SkiaProfileRenderer.h"
 #include "utils/TraceUtils.h"
 
-#include <android/native_window.h>
 #include <cutils/properties.h>
 #include <strings.h>
 
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index c63dce1..d28e605 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -31,7 +31,6 @@
 #include <GrTypes.h>
 #include <vk/GrVkTypes.h>
 
-#include <android/native_window.h>
 #include <cutils/properties.h>
 #include <strings.h>
 
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index acd6110..e1ae585 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -24,7 +24,6 @@
 #include "renderstate/RenderState.h"
 #include "OpenGLReadback.h"
 
-#include <android/native_window.h>
 #include <cutils/properties.h>
 #include <strings.h>
 
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
index 2bbfdcc..e824275 100644
--- a/libs/input/Android.mk
+++ b/libs/input/Android.mk
@@ -28,7 +28,8 @@
     libgui \
     libui \
     libinput \
-    libinputflinger
+    libinputflinger \
+    libnativewindow
 
 LOCAL_C_INCLUDES := \
     frameworks/native/services
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index fc31f32..8f341a8 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -113,5 +113,6 @@
     // for reporting callback completion
     void locationCallbackFinished(ILocationListener listener);
 
-
+    // used by gts tests to verify throttling whitelist
+    String[] getBackgroundThrottlingWhitelist();
 }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index ddd8a65..7f5d3a0 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -79,6 +79,7 @@
  */
 public class AudioTrack extends PlayerBase
                         implements AudioRouting
+                                 , VolumeAutomation
 {
     //---------------------------------------------------------
     // Constants
@@ -1753,6 +1754,12 @@
         return native_getVolumeShaperState(id);
     }
 
+    @Override
+    public @NonNull VolumeShaper createVolumeShaper(
+            @NonNull VolumeShaper.Configuration configuration) {
+        return new VolumeShaper(configuration, this);
+    }
+
     /**
      * Sets the playback sample rate for this track. This sets the sampling rate at which
      * the audio data will be consumed and played back
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 4791cf0..e77c00b 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -53,6 +53,7 @@
  *         time-interval between key frames.
  *         Float support added in {@link android.os.Build.VERSION_CODES#N_MR1}</td></tr>
  * <tr><td>{@link #KEY_INTRA_REFRESH_PERIOD}</td><td>Integer</td><td><b>encoder-only</b>, optional</td></tr>
+ * <tr><td>{@link #KEY_LATENCY}</td><td>Integer</td><td><b>encoder-only</b>, optional</td></tr>
  * <tr><td>{@link #KEY_MAX_WIDTH}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution width</td></tr>
  * <tr><td>{@link #KEY_MAX_HEIGHT}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution height</td></tr>
  * <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>encoder in surface-mode
@@ -577,6 +578,18 @@
     public static final String KEY_LEVEL = "level";
 
     /**
+    * An optional key describing the desired encoder latency in frames. This is an optional
+    * parameter that applies only to video encoders. If encoder supports it, it should ouput
+    * at least one output frame after being queued the specified number of frames. This key
+    * is ignored if the video encoder does not support the latency feature. Use the output
+    * format to verify that this feature was enabled and the actual value used by the encoder.
+    * <p>
+    * If the key is not specified, the default latency will be implenmentation specific.
+    * The associated value is an integer.
+    */
+    public static final String KEY_LATENCY = "latency";
+
+    /**
      * A key describing the desired clockwise rotation on an output surface.
      * This key is only used when the codec is configured using an output surface.
      * The associated value is an integer, representing degrees. Supported values
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 5008a5f..1ebbe85 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -579,6 +579,7 @@
  */
 public class MediaPlayer extends PlayerBase
                          implements SubtitleController.Listener
+                                  , VolumeAutomation
 {
     /**
        Constant to retrieve only the new metadata since the last
@@ -1373,6 +1374,12 @@
         return native_getVolumeShaperState(id);
     }
 
+    @Override
+    public @NonNull VolumeShaper createVolumeShaper(
+            @NonNull VolumeShaper.Configuration configuration) {
+        return new VolumeShaper(configuration, this);
+    }
+
     private native int native_applyVolumeShaper(
             @NonNull VolumeShaper.Configuration configuration,
             @NonNull VolumeShaper.Operation operation);
diff --git a/media/java/android/media/VolumeAutomation.java b/media/java/android/media/VolumeAutomation.java
new file mode 100644
index 0000000..dff8801
--- /dev/null
+++ b/media/java/android/media/VolumeAutomation.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+import android.media.VolumeShaper.Configuration;
+
+/**
+ * {@code VolumeAutomation} defines an interface for automatic volume control
+ * of {@link AudioTrack} and {@link MediaPlayer} objects.
+ */
+public interface VolumeAutomation {
+    /**
+     * Returns a {@link VolumeShaper} object that can be used modify the volume envelope
+     * of the player or track.
+     *
+     * @param configuration the {@link VolumeShaper.Configuration configuration}
+     *        that specifies the curve and duration to use.
+     * @return a {@code VolumeShaper} object
+     * @throws IllegalArgumentException if the configuration is not allowed by the player.
+     * @throws IllegalStateException if too many VolumeShapers are requested or the state of
+     * the player does not permit its creation (e.g. player is released).
+     */
+    public @NonNull VolumeShaper createVolumeShaper(
+            @NonNull VolumeShaper.Configuration configuration);
+}
diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java
index 4a2c4d8..cb27d10 100644
--- a/media/java/android/media/VolumeShaper.java
+++ b/media/java/android/media/VolumeShaper.java
@@ -23,78 +23,25 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.AutoCloseable;
 import java.lang.ref.WeakReference;
 import java.util.Objects;
 
 /**
- * TODO: remove @hide
  * The {@code VolumeShaper} class is used to automatically control audio volume during media
- * playback, allowing for simple implementation of transition effects and ducking.
+ * playback, allowing simple implementation of transition effects and ducking.
  *
  * The {@link VolumeShaper} appears as an additional scaling on the audio output,
- * and can be used independently of track or stream volume controls.
+ * and adjusts independently of track or stream volume controls.
  */
-public final class VolumeShaper {
+public final class VolumeShaper implements AutoCloseable {
     /* member variables */
     private int mId;
     private final WeakReference<PlayerBase> mWeakPlayerBase;
-    private final WeakReference<PlayerProxy> mWeakPlayerProxy;
-    private PlayerProxy mPlayerProxy;
-
-    /**
-     * Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and an
-     * {@link AudioTrack}.
-     *
-     * @param configuration
-     * @param audioTrack
-     */
-    public VolumeShaper(@NonNull Configuration configuration, @NonNull AudioTrack audioTrack) {
-        this(configuration, (PlayerBase)audioTrack);
-    }
-
-    /**
-     * Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and a
-     * {@link MediaPlayer}.
-     *
-     * @param configuration
-     * @param mediaPlayer
-     */
-    public VolumeShaper(@NonNull Configuration configuration, @NonNull MediaPlayer mediaPlayer) {
-        this(configuration, (PlayerBase)mediaPlayer);
-    }
 
     /* package */ VolumeShaper(
             @NonNull Configuration configuration, @NonNull PlayerBase playerBase) {
         mWeakPlayerBase = new WeakReference<PlayerBase>(playerBase);
-        mPlayerProxy = null;
-        mWeakPlayerProxy = null;
-        mId = applyPlayer(configuration, new Operation.Builder().defer().build());
-    }
-
-    /**
-     * @hide
-     * Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and a
-     * {@code PlayerProxy} object.  The PlayerProxy object requires that the configuration
-     * be set with a system VolumeShaper id (this is a reserved value).
-     *
-     * @param configuration
-     * @param playerProxy
-     */
-    public VolumeShaper(
-            @NonNull Configuration configuration,
-            @NonNull PlayerProxy playerProxy,
-            boolean keepReference) {
-        if (configuration.getId() < 0) {
-            throw new IllegalArgumentException("playerProxy configuration id must be specified");
-        }
-        if (keepReference) {
-            mPlayerProxy = playerProxy;
-            mWeakPlayerProxy = null;
-        } else {
-            mWeakPlayerProxy = new WeakReference<PlayerProxy>(playerProxy);
-            mPlayerProxy = null;
-        }
-        mWeakPlayerBase = null;
         mId = applyPlayer(configuration, new Operation.Builder().defer().build());
     }
 
@@ -104,7 +51,7 @@
 
     /**
      * Applies the {@link VolumeShaper.Operation} to the {@code VolumeShaper}.
-     * @param operation
+     * @param operation the {@code operation} to apply.
      */
     public void apply(@NonNull Operation operation) {
         /* void */ applyPlayer(new VolumeShaper.Configuration(mId), operation);
@@ -112,17 +59,16 @@
 
     /**
      * Replaces the current {@code VolumeShaper}
-     * configuration with a new configuration.
+     * {@code configuration} with a new {@code configuration}.
      *
-     * This can be used to dynamically change the {@code VolumeShaper}
-     * configuration by joining several
-     * {@code VolumeShaper} configurations together.
-     * This is useful if the user changes the volume while the
-     * {@code VolumeShaper} is in effect.
+     * This allows the user to change the volume shape
+     * while the existing {@code VolumeShaper} is in effect.
      *
-     * @param configuration
-     * @param operation
-     * @param join
+     * @param configuration the new {@code configuration} to use.
+     * @param operation the operation to apply to the {@code VolumeShaper}
+     * @param join if true, match the start volume of the
+     *             new {@code configuration} to the current volume of the existing
+     *             {@code VolumeShaper}, to avoid discontinuity.
      */
     public void replace(
             @NonNull Configuration configuration, @NonNull Operation operation, boolean join) {
@@ -141,10 +87,11 @@
     }
 
     /**
-     * Releases the {@code VolumeShaper}. Any volume scale due to the
+     * Releases the {@code VolumeShaper} object; any volume scale due to the
      * {@code VolumeShaper} is removed.
      */
-    public void release() {
+    @Override
+    public void close() {
         try {
             /* void */ applyPlayer(
                     new VolumeShaper.Configuration(mId),
@@ -155,15 +102,11 @@
         if (mWeakPlayerBase != null) {
             mWeakPlayerBase.clear();
         }
-        if (mWeakPlayerProxy != null) {
-            mWeakPlayerProxy.clear();
-        }
-        mPlayerProxy = null;
     }
 
     @Override
     protected void finalize() {
-        release(); // ensure we remove the native volume shaper
+        close(); // ensure we remove the native volume shaper
     }
 
     /**
@@ -177,20 +120,7 @@
             @NonNull VolumeShaper.Configuration configuration,
             @NonNull VolumeShaper.Operation operation) {
         final int id;
-        if (mPlayerProxy != null || mWeakPlayerProxy != null) {
-            // The PlayerProxy accepts only one way transactions so
-            // the Configuration must have an id set to one of the system
-            // ids (a positive value less than 16).
-            PlayerProxy player = mWeakPlayerProxy != null ? mWeakPlayerProxy.get() : mPlayerProxy;
-            if (player == null) {
-                throw new IllegalStateException("player deallocated");
-            }
-            id = configuration.getId();
-            if (id < 0) {
-                throw new IllegalArgumentException("proxy requires configuration with id");
-            }
-            player.applyVolumeShaper(configuration, operation);
-        } else if (mWeakPlayerBase != null) {
+        if (mWeakPlayerBase != null) {
             PlayerBase player = mWeakPlayerBase.get();
             if (player == null) {
                 throw new IllegalStateException("player deallocated");
@@ -220,9 +150,7 @@
      */
     private @NonNull VolumeShaper.State getStatePlayer(int id) {
         final VolumeShaper.State state;
-        if (mPlayerProxy != null || mWeakPlayerProxy != null) {
-            throw new IllegalStateException("getStatePlayer not permitted through proxy");
-        } else if (mWeakPlayerBase != null) {
+        if (mWeakPlayerBase != null) {
             PlayerBase player = mWeakPlayerBase.get();
             if (player == null) {
                 throw new IllegalStateException("player deallocated");
@@ -238,11 +166,17 @@
     }
 
     /**
-     * The {@code VolumeShaper.Configuration} class contains curve shape
-     * and parameter information for constructing a {@code VolumeShaper}.
-     * This curve shape and parameter information is specified
-     * on {@code VolumeShaper} creation
-     * and may be replaced through {@link VolumeShaper#replace}.
+     * The {@code VolumeShaper.Configuration} class contains curve
+     * and duration information.
+     * It is constructed by the {@link VolumeShaper.Configuration.Builder}.
+     * <p>
+     * A {@code VolumeShaper.Configuration} is used by
+     * {@link VolumeAutomation#createVolumeShaper(Configuration)
+     * VolumeAutomation#createVolumeShaper(Configuration)} to create
+     * a {@code VolumeShaper} and
+     * by {@link VolumeShaper#replace(Configuration, Operation, boolean)
+     * VolumeShaper#replace(Configuration, Operation, boolean)}
+     * to replace an existing {@code configuration}.
      */
     public static final class Configuration implements Parcelable {
         private static final int MAXIMUM_CURVE_POINTS = 16;
@@ -310,9 +244,9 @@
 
         /**
          * Cubic interpolated volume curve
-         * with local monotonicity preservation.
+         * that preserves local monotonicity.
          * So long as the control points are locally monotonic,
-         * the curve interpolation will also be locally monotonic.
+         * the curve interpolation between those points are monotonic.
          * This is useful for cubic spline interpolated
          * volume ramps and ducks.
          */
@@ -328,6 +262,7 @@
         public @interface OptionFlag {}
 
         /**
+         * @hide
          * Use a dB full scale volume range for the volume curve.
          *<p>
          * The volume scale is typically from 0.f to 1.f on a linear scale;
@@ -337,6 +272,7 @@
         public static final int OPTION_FLAG_VOLUME_IN_DBFS = (1 << 0);
 
         /**
+         * @hide
          * Use clock time instead of media time.
          *<p>
          * The default implementation of {@code VolumeShaper} is to apply
@@ -354,7 +290,8 @@
 
         /**
          * A one second linear ramp from silence to full volume.
-         * Use {@link VolumeShaper.Builder#reflectTimes()} to generate
+         * Use {@link VolumeShaper.Builder#reflectTimes()}
+         * or {@link VolumeShaper.Builder#invertVolumes()} to generate
          * the matching linear duck.
          */
         public static final Configuration LINEAR_RAMP = new VolumeShaper.Configuration.Builder()
@@ -366,7 +303,8 @@
 
         /**
          * A one second cubic ramp from silence to full volume.
-         * Use {@link VolumeShaper.Builder#reflectTimes()} to generate
+         * Use {@link VolumeShaper.Builder#reflectTimes()}
+         * or {@link VolumeShaper.Builder#invertVolumes()} to generate
          * the matching cubic duck.
          */
         public static final Configuration CUBIC_RAMP = new VolumeShaper.Configuration.Builder()
@@ -377,17 +315,19 @@
                 .build();
 
         /**
-         * A one second sine curve for energy preserving cross fades.
+         * A one second sine curve
+         * from silence to full volume for energy preserving cross fades.
          * Use {@link VolumeShaper.Builder#reflectTimes()} to generate
          * the matching cosine duck.
          */
         public static final Configuration SINE_RAMP;
 
         /**
-         * A one second sine-squared s-curve ramp.
+         * A one second sine-squared s-curve ramp
+         * from silence to full volume.
          * Use {@link VolumeShaper.Builder#reflectTimes()}
          * or {@link VolumeShaper.Builder#invertVolumes()} to generate
-         * the matching s-curve duck.
+         * the matching sine-squared s-curve duck.
          */
         public static final Configuration SCURVE_RAMP;
 
@@ -510,6 +450,7 @@
         };
 
         /**
+         * @hide
          * Constructs a volume shaper from an id.
          *
          * This is an opaque handle for controlling a {@code VolumeShaper} that has
@@ -522,7 +463,7 @@
          * @param id
          * @throws IllegalArgumentException if id is negative.
          */
-        private Configuration(int id) {
+        public Configuration(int id) {
             if (id < 0) {
                 throw new IllegalArgumentException("negative id " + id);
             }
@@ -557,6 +498,7 @@
         }
 
         /**
+         * @hide
          * Returns the {@code VolumeShaper} type.
          */
         public @Type int getType() {
@@ -579,6 +521,7 @@
         }
 
         /**
+         * @hide
          * Returns the option flags
          */
         public @OptionFlag int getOptionFlags() {
@@ -590,7 +533,7 @@
         }
 
         /**
-         * Returns the duration of the effect in milliseconds.
+         * Returns the duration of the volume shape in milliseconds.
          */
         public double getDurationMs() {
             return mDurationMs;
@@ -712,21 +655,22 @@
             private int mType = TYPE_SCALE;
             private int mId = -1; // invalid
             private int mInterpolatorType = INTERPOLATOR_TYPE_CUBIC;
-            private int mOptionFlags = 0;
+            private int mOptionFlags = OPTION_FLAG_CLOCK_TIME;
             private double mDurationMs = 1000.;
             private float[] mTimes = null;
             private float[] mVolumes = null;
 
             /**
-             * Constructs a new Builder with the defaults.
+             * Constructs a new {@code Builder} with the defaults.
              */
             public Builder() {
             }
 
             /**
-             * Constructs a new Builder from a given {@code VolumeShaper.Configuration}
+             * Constructs a new {@code Builder} with settings
+             * copied from a given {@code VolumeShaper.Configuration}.
              * @param configuration prototypical configuration
-             *        which will be reused in the new Builder.
+             *        which will be reused in the new {@code Builder}.
              */
             public Builder(@NonNull Configuration configuration) {
                 mType = configuration.getType();
@@ -740,8 +684,6 @@
 
             /**
              * @hide
-             * TODO make SystemApi
-             *
              * Set the id for system defined shapers.
              * @param id
              * @return
@@ -757,7 +699,11 @@
              * If omitted the interplator type is {@link #INTERPOLATOR_TYPE_CUBIC}.
              *
              * @param interpolatorType method of interpolation used for the volume curve.
-             * @return the same Builder instance.
+             *        One of {@link #INTERPOLATOR_TYPE_STEP},
+             *        {@link #INTERPOLATOR_TYPE_LINEAR},
+             *        {@link #INTERPOLATOR_TYPE_CUBIC},
+             *        {@link #INTERPOLATOR_TYPE_CUBIC_MONOTONIC}.
+             * @return the same {@code Builder} instance.
              * @throws IllegalArgumentException if {@code interpolatorType} is not valid.
              */
             public @NonNull Builder setInterpolatorType(@InterpolatorType int interpolatorType) {
@@ -776,6 +722,7 @@
             }
 
             /**
+             * @hide
              * Sets the optional flags
              *
              * If omitted, flags are 0. If {@link #OPTION_FLAG_VOLUME_IN_DBFS} has
@@ -783,7 +730,7 @@
              * volume domain has changed.
              *
              * @param optionFlags new value to replace the old {@code optionFlags}.
-             * @return the same Builder instance.
+             * @return the same {@code Builder} instance.
              * @throws IllegalArgumentException if flag is not recognized.
              */
             public @NonNull Builder setOptionFlags(@OptionFlag int optionFlags) {
@@ -800,8 +747,9 @@
              * If omitted, the default duration is 1 second.
              *
              * @param durationMs
-             * @return the same Builder instance.
-             * @throws IllegalArgumentException if duration is not positive.
+             * @return the same {@code Builder} instance.
+             * @throws IllegalArgumentException if {@code durationMs}
+             *         is not strictly positive.
              */
             public @NonNull Builder setDurationMs(double durationMs) {
                 if (durationMs <= 0.) {
@@ -823,19 +771,23 @@
              * and no greater than {@link VolumeShaper.Configuration#getMaximumCurvePoints()}.
              * <p>
              * The volume curve is normalized as follows:
-             * (1) time (x) coordinates should be monotonically increasing, from 0.f to 1.f;
-             * (2) volume (y) coordinates must be within 0.f to 1.f for linear and be non-positive
-             *     for log scaling.
+             * time (x) coordinates should be monotonically increasing, from 0.f to 1.f;
+             * volume (y) coordinates must be within 0.f to 1.f.
              * <p>
-             * The time scale is set by {@link #setDurationMs} in seconds.
+             * The time scale is set by {@link #setDurationMs}.
              * <p>
              * @param times an array of float values representing
              *        the time line of the volume curve.
              * @param volumes an array of float values representing
              *        the amplitude of the volume curve.
-             * @return the same Builder instance.
+             * @return the same {@code Builder} instance.
              * @throws IllegalArgumentException if {@code times} or {@code volumes} is invalid.
              */
+
+            /* Note: volume (y) coordinates must be non-positive for log scaling,
+             * if {@link VolumeShaper.Configuration#OPTION_FLAG_VOLUME_IN_DBFS} is set.
+             */
+
             public @NonNull Builder setCurve(@NonNull float[] times, @NonNull float[] volumes) {
                 String error = checkCurveForErrors(
                         times, volumes, (mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0);
@@ -852,7 +804,7 @@
              * the shaper changes volume from the end
              * to the start.
              *
-             * @return the same Builder instance.
+             * @return the same {@code Builder} instance.
              */
             public @NonNull Builder reflectTimes() {
                 int i;
@@ -871,7 +823,7 @@
              * Inverts the volume curve so that the max volume
              * becomes the min volume and vice versa.
              *
-             * @return the same Builder instance.
+             * @return the same {@code Builder} instance.
              */
             public @NonNull Builder invertVolumes() {
                 if (mVolumes.length >= 2) {
@@ -899,8 +851,9 @@
              * Keeps the start volume the same.
              * This works best if the volume curve is monotonic.
              *
-             * @return the same Builder instance.
-             * @throws IllegalArgumentException if volume is not valid.
+             * @param volume the target end volume to use.
+             * @return the same {@code Builder} instance.
+             * @throws IllegalArgumentException if {@code volume} is not valid.
              */
             public @NonNull Builder scaleToEndVolume(float volume) {
                 final boolean log = (mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0;
@@ -930,8 +883,9 @@
              * Keeps the end volume the same.
              * This works best if the volume curve is monotonic.
              *
-             * @return the same Builder instance.
-             * @throws IllegalArgumentException if volume is not valid.
+             * @param volume the target start volume to use.
+             * @return the same {@code Builder} instance.
+             * @throws IllegalArgumentException if {@code volume} is not valid.
              */
             public @NonNull Builder scaleToStartVolume(float volume) {
                 final boolean log = (mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0;
@@ -978,6 +932,8 @@
     public static final class Operation implements Parcelable {
         /**
          * Forward playback from current volume time position.
+         * At the end of the {@code VolumeShaper} curve,
+         * the last volume value persists.
          */
         public static final Operation PLAY =
                 new VolumeShaper.Operation.Builder()
@@ -985,6 +941,8 @@
 
         /**
          * Reverse playback from current volume time position.
+         * When the position reaches the start of the {@code VolumeShaper} curve,
+         * the first volume value persists.
          */
         public static final Operation REVERSE =
                 new VolumeShaper.Operation.Builder()
@@ -1039,6 +997,13 @@
          */
         private static final int FLAG_DEFER = 1 << 3;
 
+        /**
+         * Use the id specified in the configuration, creating
+         * VolumeShaper as needed; the configuration should be
+         * TYPE_SCALE.
+         */
+        private static final int FLAG_CREATE_IF_NEEDED = 1 << 4;
+
         private static final int FLAG_PUBLIC_ALL = FLAG_REVERSE | FLAG_TERMINATE;
 
         private final int mFlags;
@@ -1126,15 +1091,13 @@
             }
 
             /**
-             * Replaces the previous {@code VolumeShaper}.
+             * Replaces the previous {@code VolumeShaper} specified by id.
              * It has no other effect if the {@code VolumeShaper} is
-             * already expired. If the replaceId is the same as the id associated with
-             * the {@code VolumeShaper} in a {@code setVolumeShaper()} call,
-             * an error is returned.
-             * @param handle is a previous volumeShaper {@code VolumeShaper}.
-             * @param join the start to match the current volume of the previous
-             * shaper.
-             * @return the same Builder instance.
+             * already expired.
+             * @param id the id of the previous {@code VolumeShaper}.
+             * @param join if true, match the volume of the previous
+             * shaper to the start volume of the new {@code VolumeShaper}.
+             * @return the same {@code Builder} instance.
              */
             public @NonNull Builder replace(int id, boolean join) {
                 mReplaceId = id;
@@ -1148,7 +1111,7 @@
 
             /**
              * Defers all operations.
-             * @return the same Builder instance.
+             * @return the same {@code Builder} instance.
              */
             public @NonNull Builder defer() {
                 mFlags |= FLAG_DEFER;
@@ -1158,7 +1121,7 @@
             /**
              * Terminates the VolumeShaper.
              * Do not call directly, use {@link VolumeShaper#release()}.
-             * @return the same Builder instance.
+             * @return the same {@code Builder} instance.
              */
             public @NonNull Builder terminate() {
                 mFlags |= FLAG_TERMINATE;
@@ -1167,7 +1130,7 @@
 
             /**
              * Reverses direction.
-             * @return the same Builder instance.
+             * @return the same {@code Builder} instance.
              */
             public @NonNull Builder reverse() {
                 mFlags ^= FLAG_REVERSE;
@@ -1175,11 +1138,22 @@
             }
 
             /**
+             * Use the id specified in the configuration, creating
+             * VolumeShaper as needed; the configuration should be
+             * TYPE_SCALE.
+             * @return the same {@code Builder} instance.
+             */
+            public @NonNull Builder createIfNeeded() {
+                mFlags |= FLAG_CREATE_IF_NEEDED;
+                return this;
+            }
+
+            /**
              * Sets the operation flag.  Do not call this directly but one of the
              * other builder methods.
              *
              * @param flags new value for {@code flags}, consisting of ORed flags.
-             * @return the same Builder instance.
+             * @return the same {@code Builder} instance.
              */
             private @NonNull Builder setFlags(@Flag int flags) {
                 if ((flags & ~FLAG_PUBLIC_ALL) != 0) {
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 6d8296a..1b53d72 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -25,6 +25,7 @@
 import android.content.ContentUris;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.provider.BaseColumns;
 import android.text.TextUtils;
@@ -72,6 +73,98 @@
     private static final String PATH_PASSTHROUGH = "passthrough";
 
     /**
+     * The method name to get existing columns in the given table of the specified content provider.
+     *
+     * <p>The method caller must provide the following parameter:
+     * <ul>
+     *     <li>{@code arg}: The content URI of the target table as a {@link String}.</li>
+     * </ul>
+
+     * <p>On success, the returned {@link android.os.Bundle} will include existing column names
+     * with the key {@link #EXTRA_EXISTING_COLUMN_NAMES}. Otherwise, the return value will be {@code null}.
+     *
+     * @see ContentResolver#call(Uri, String, String, Bundle)
+     * @see #EXTRA_EXISTING_COLUMN_NAMES
+     * @hide
+     */
+    @SystemApi
+    public static final String METHOD_GET_COLUMNS = "get_columns";
+
+    /**
+     * The method name to add a new column in the given table of the specified content provider.
+     *
+     * <p>The method caller must provide the following parameter:
+     * <ul>
+     *     <li>{@code arg}: The content URI of the target table as a {@link String}.</li>
+     *     <li>{@code extra}: Name, data type, and default value of the new column in a Bundle:
+     *         <ul>
+     *             <li>{@link #EXTRA_COLUMN_NAME} the column name as a {@link String}.</li>
+     *             <li>{@link #EXTRA_DATA_TYPE} the data type as a {@link String}.</li>
+     *             <li>{@link #EXTRA_DEFAULT_VALUE} the default value as a {@link String}.
+     *                 (optional)</li>
+     *         </ul>
+     *     </li>
+     * </ul>
+     *
+     * <p>On success, the returned {@link android.os.Bundle} will include current colum names after
+     * the addition operation with the key {@link #EXTRA_EXISTING_COLUMN_NAMES}. Otherwise, the
+     * return value will be {@code null}.
+     *
+     * @see ContentResolver#call(Uri, String, String, Bundle)
+     * @see #EXTRA_COLUMN_NAME
+     * @see #EXTRA_DATA_TYPE
+     * @see #EXTRA_DEFAULT_VALUE
+     * @see #EXTRA_EXISTING_COLUMN_NAMES
+     * @hide
+     */
+    @SystemApi
+    public static final String METHOD_ADD_COLUMN = "add_column";
+
+    /**
+     * The key for a returned {@link Bundle} value containing existing column names in the given
+     * table as an {@link ArrayList} of {@link String}.
+     *
+     * @see #METHOD_GET_COLUMNS
+     * @see #METHOD_ADD_COLUMN
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_EXISTING_COLUMN_NAMES =
+            "android.media.tv.extra.EXISTING_COLUMN_NAMES";
+
+    /**
+     * The key for a {@link Bundle} parameter containing the new column name to be added in the
+     * given table as a non-empty {@link CharSequence}.
+     *
+     * @see #METHOD_ADD_COLUMN
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
+
+    /**
+     * The key for a {@link Bundle} parameter containing the data type of the new column to be added
+     * in the given table as a non-empty {@link CharSequence}, which should be one of the following
+     * values: {@code "TEXT"}, {@code "INTEGER"}, {@code "REAL"}, or {@code "BLOB"}.
+     *
+     * @see #METHOD_ADD_COLUMN
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
+
+    /**
+     * The key for a {@link Bundle} parameter containing the default value of the new column to be
+     * added in the given table as a {@link CharSequence}, which represents a valid default value
+     * according to the data type provided with {@link #EXTRA_DATA_TYPE}.
+     *
+     * @see #METHOD_ADD_COLUMN
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
+
+    /**
      * An optional query, update or delete URI parameter that allows the caller to specify TV input
      * ID to filter channels.
      * @hide
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 69544f5..1c1ff82 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -11,12 +11,10 @@
     asset_manager.cpp \
     choreographer.cpp \
     configuration.cpp \
-    hardware_buffer.cpp \
     hardware_buffer_jni.cpp \
     input.cpp \
     looper.cpp \
     native_activity.cpp \
-    native_window.cpp \
     native_window_jni.cpp \
     net.c \
     obb.cpp \
@@ -38,7 +36,10 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libstorage \
-    libarect
+    libarect \
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+    libnativewindow
 
 LOCAL_C_INCLUDES += \
     frameworks/base/native/include \
@@ -46,7 +47,9 @@
     bionic/libc/dns/include \
     system/netd/include \
 
-LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libarect
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := \
+    libarect \
+    libnativewindow \
 
 LOCAL_MODULE := libandroid
 
diff --git a/native/android/hardware_buffer.cpp b/native/android/hardware_buffer.cpp
deleted file mode 100644
index 77ebd52..0000000
--- a/native/android/hardware_buffer.cpp
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#define LOG_TAG "AHardwareBuffer"
-
-#include <android/hardware_buffer.h>
-
-#include <errno.h>
-#include <sys/socket.h>
-
-#include <memory>
-
-#include <cutils/native_handle.h>
-
-#include <utils/Log.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <binder/IServiceManager.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/IGraphicBufferAlloc.h>
-
-#include <android_runtime/android_hardware_HardwareBuffer.h>
-
-
-static constexpr int kDataBufferSize = 64 * sizeof(int);  // 64 ints
-
-using namespace android;
-
-static inline const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(
-        const AHardwareBuffer* buffer) {
-    return reinterpret_cast<const GraphicBuffer*>(buffer);
-}
-
-static inline GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(
-        AHardwareBuffer* buffer) {
-    return reinterpret_cast<GraphicBuffer*>(buffer);
-}
-
-static inline AHardwareBuffer* GraphicBuffer_to_AHardwareBuffer(
-        GraphicBuffer* buffer) {
-    return reinterpret_cast<AHardwareBuffer*>(buffer);
-}
-
-// ----------------------------------------------------------------------------
-// Public functions
-// ----------------------------------------------------------------------------
-
-int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
-        AHardwareBuffer** outBuffer) {
-    if (!outBuffer || !desc) return BAD_VALUE;
-
-    // The holder is used to destroy the buffer if an error occurs.
-    sp<IServiceManager> sm = defaultServiceManager();
-    if (sm == nullptr) {
-        ALOGE("Unable to connect to ServiceManager");
-        return PERMISSION_DENIED;
-    }
-
-    // Get the SurfaceFlingerService.
-    sp<ISurfaceComposer> composer = interface_cast<ISurfaceComposer>(
-            sm->getService(String16("SurfaceFlinger")));
-    if (composer == nullptr) {
-        ALOGE("Unable to connect to surface composer");
-        return PERMISSION_DENIED;
-    }
-    // Get an IGraphicBufferAlloc to create the buffer.
-    sp<IGraphicBufferAlloc> allocator = composer->createGraphicBufferAlloc();
-    if (allocator == nullptr) {
-        ALOGE("Unable to obtain a buffer allocator");
-        return PERMISSION_DENIED;
-    }
-
-    int format = android_hardware_HardwareBuffer_convertToPixelFormat(
-            desc->format);
-    if (format == 0) {
-        ALOGE("Invalid pixel format");
-        return BAD_VALUE;
-    }
-
-    if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB && desc->height != 1) {
-        ALOGE("Height must be 1 when using the AHARDWAREBUFFER_FORMAT_BLOB "
-                "format");
-        return BAD_VALUE;
-    }
-
-    status_t err;
-    uint64_t producerUsage = 0;
-    uint64_t consumerUsage = 0;
-    android_hardware_HardwareBuffer_convertToGrallocUsageBits(desc->usage0,
-            desc->usage1, &producerUsage, &consumerUsage);
-    sp<GraphicBuffer> gbuffer = allocator->createGraphicBuffer(desc->width,
-            desc->height, format, desc->layers, producerUsage, consumerUsage,
-            std::string("AHardwareBuffer pid [") + std::to_string(getpid()) +
-            "]", &err);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    *outBuffer = GraphicBuffer_to_AHardwareBuffer(gbuffer.get());
-    // Ensure the buffer doesn't get destroyed with the sp<> goes away.
-    AHardwareBuffer_acquire(*outBuffer);
-    return NO_ERROR;
-}
-
-void AHardwareBuffer_acquire(AHardwareBuffer* buffer) {
-    AHardwareBuffer_to_GraphicBuffer(buffer)->incStrong(
-            (void*)AHardwareBuffer_acquire);
-}
-
-void AHardwareBuffer_release(AHardwareBuffer* buffer) {
-    AHardwareBuffer_to_GraphicBuffer(buffer)->decStrong(
-            (void*)AHardwareBuffer_acquire);
-}
-
-void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
-        AHardwareBuffer_Desc* outDesc) {
-    if (!buffer || !outDesc) return;
-
-    const GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
-
-    outDesc->width = gbuffer->getWidth();
-    outDesc->height = gbuffer->getHeight();
-    outDesc->layers = gbuffer->getLayerCount();
-    outDesc->usage0 =
-            android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
-                    gbuffer->getUsage(), gbuffer->getUsage());
-    outDesc->usage1 = 0;
-    outDesc->format = android_hardware_HardwareBuffer_convertFromPixelFormat(
-            static_cast<uint32_t>(gbuffer->getPixelFormat()));
-}
-
-int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage0,
-        int32_t fence, const ARect* rect, void** outVirtualAddress) {
-    if (!buffer) return BAD_VALUE;
-
-    if (usage0 & ~(AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN |
-            AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN)) {
-        ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
-                " AHARDWAREBUFFER_USAGE0_CPU_* flags are allowed");
-        return BAD_VALUE;
-    }
-
-    uint64_t producerUsage = 0;
-    uint64_t consumerUsage = 0;
-    android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage0, 0,
-            &producerUsage, &consumerUsage);
-    GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
-    Rect bounds;
-    if (!rect) {
-        bounds.set(Rect(gBuffer->getWidth(), gBuffer->getHeight()));
-    } else {
-        bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
-    }
-    return gBuffer->lockAsync(producerUsage, consumerUsage, bounds,
-            outVirtualAddress, fence);
-}
-
-int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) {
-    if (!buffer) return BAD_VALUE;
-
-    GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
-    return gBuffer->unlockAsync(fence);
-}
-
-int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer,
-        int socketFd) {
-    if (!buffer) return BAD_VALUE;
-    const GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
-
-    size_t flattenedSize = gBuffer->getFlattenedSize();
-    size_t fdCount = gBuffer->getFdCount();
-
-    std::unique_ptr<uint8_t[]> data(new uint8_t[flattenedSize]);
-    std::unique_ptr<int[]> fds(new int[fdCount]);
-
-    // Make copies of needed items since flatten modifies them, and we don't
-    // want to send anything if there's an error during flatten.
-    size_t flattenedSizeCopy = flattenedSize;
-    size_t fdCountCopy = fdCount;
-    void* dataStart = data.get();
-    int* fdsStart = fds.get();
-    status_t err = gBuffer->flatten(dataStart, flattenedSizeCopy, fdsStart,
-                fdCountCopy);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    struct iovec iov[1];
-    iov[0].iov_base = data.get();
-    iov[0].iov_len = flattenedSize;
-
-    char buf[CMSG_SPACE(kDataBufferSize)];
-    struct msghdr msg = {
-        .msg_control = buf,
-        .msg_controllen = sizeof(buf),
-        .msg_iov = &iov[0],
-        .msg_iovlen = 1,
-    };
-
-    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
-    cmsg->cmsg_level = SOL_SOCKET;
-    cmsg->cmsg_type = SCM_RIGHTS;
-    cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fdCount);
-    int* fdData = reinterpret_cast<int*>(CMSG_DATA(cmsg));
-    memcpy(fdData, fds.get(), sizeof(int) * fdCount);
-    msg.msg_controllen = cmsg->cmsg_len;
-
-    int result = sendmsg(socketFd, &msg, 0);
-    if (result <= 0) {
-        ALOGE("Error writing AHardwareBuffer to socket: error %#x (%s)",
-                result, strerror(errno));
-        return result;
-    }
-    return NO_ERROR;
-}
-
-int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
-        AHardwareBuffer** outBuffer) {
-    if (!outBuffer) return BAD_VALUE;
-
-    char dataBuf[CMSG_SPACE(kDataBufferSize)];
-    char fdBuf[CMSG_SPACE(kDataBufferSize)];
-    struct iovec iov[1];
-    iov[0].iov_base = dataBuf;
-    iov[0].iov_len = sizeof(dataBuf);
-
-    struct msghdr msg = {
-        .msg_control = fdBuf,
-        .msg_controllen = sizeof(fdBuf),
-        .msg_iov = &iov[0],
-        .msg_iovlen = 1,
-    };
-
-    int result = recvmsg(socketFd, &msg, 0);
-    if (result <= 0) {
-        ALOGE("Error reading AHardwareBuffer from socket: error %#x (%s)",
-                result, strerror(errno));
-        return result;
-    }
-
-    if (msg.msg_iovlen != 1) {
-        ALOGE("Error reading AHardwareBuffer from socket: bad data length");
-        return INVALID_OPERATION;
-    }
-
-    if (msg.msg_controllen % sizeof(int) != 0) {
-        ALOGE("Error reading AHardwareBuffer from socket: bad fd length");
-        return INVALID_OPERATION;
-    }
-
-    size_t dataLen = msg.msg_iov[0].iov_len;
-    const void* data = static_cast<const void*>(msg.msg_iov[0].iov_base);
-    if (!data) {
-        ALOGE("Error reading AHardwareBuffer from socket: no buffer data");
-        return INVALID_OPERATION;
-    }
-
-    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
-    if (!cmsg) {
-        ALOGE("Error reading AHardwareBuffer from socket: no fd header");
-        return INVALID_OPERATION;
-    }
-
-    size_t fdCount = msg.msg_controllen >> 2;
-    const int* fdData = reinterpret_cast<const int*>(CMSG_DATA(cmsg));
-    if (!fdData) {
-        ALOGE("Error reading AHardwareBuffer from socket: no fd data");
-        return INVALID_OPERATION;
-    }
-
-    GraphicBuffer* gBuffer = new GraphicBuffer();
-    status_t err = gBuffer->unflatten(data, dataLen, fdData, fdCount);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    *outBuffer = GraphicBuffer_to_AHardwareBuffer(gBuffer);
-    // Ensure the buffer has a positive ref-count.
-    AHardwareBuffer_acquire(*outBuffer);
-
-    return NO_ERROR;
-}
-
-const struct native_handle* AHardwareBuffer_getNativeHandle(
-        const AHardwareBuffer* buffer) {
-    if (!buffer) return nullptr;
-    const GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
-    return gbuffer->handle;
-}
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
deleted file mode 100644
index 8c080d7..0000000
--- a/native/android/native_window.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#define LOG_TAG "Surface"
-
-#include <android/native_window.h>
-#include <system/window.h>
-
-void ANativeWindow_acquire(ANativeWindow* window) {
-    window->incStrong((void*)ANativeWindow_acquire);
-}
-
-void ANativeWindow_release(ANativeWindow* window) {
-    window->decStrong((void*)ANativeWindow_acquire);
-}
-
-static int32_t getWindowProp(ANativeWindow* window, int what) {
-    int value;
-    int res = window->query(window, what, &value);
-    return res < 0 ? res : value;
-}
-
-int32_t ANativeWindow_getWidth(ANativeWindow* window) {
-    return getWindowProp(window, NATIVE_WINDOW_WIDTH);
-}
-
-int32_t ANativeWindow_getHeight(ANativeWindow* window) {
-    return getWindowProp(window, NATIVE_WINDOW_HEIGHT);
-}
-
-int32_t ANativeWindow_getFormat(ANativeWindow* window) {
-    return getWindowProp(window, NATIVE_WINDOW_FORMAT);
-}
-
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
-        int32_t height, int32_t format) {
-    int32_t err = native_window_set_buffers_format(window, format);
-    if (!err) {
-        err = native_window_set_buffers_user_dimensions(window, width, height);
-        if (!err) {
-            int mode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
-            if (width && height) {
-                mode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
-            }
-            err = native_window_set_scaling_mode(window, mode);
-         }
-    }
-    return err;
-}
-
-int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
-        ARect* inOutDirtyBounds) {
-    return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds);
-}
-
-int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
-    return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
-}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 22a5b7f..3cc9f65e 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -56,6 +56,7 @@
 import android.webkit.MimeTypeMap;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.FileSystemProvider;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.File;
@@ -63,15 +64,15 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 
-public class ExternalStorageProvider extends DocumentsProvider {
+public class ExternalStorageProvider extends FileSystemProvider {
     private static final String TAG = "ExternalStorage";
 
     private static final boolean DEBUG = false;
-    private static final boolean LOG_INOTIFY = false;
 
     public static final String AUTHORITY = "com.android.externalstorage.documents";
 
@@ -105,20 +106,17 @@
     private static final String ROOT_ID_HOME = "home";
 
     private StorageManager mStorageManager;
-    private Handler mHandler;
 
     private final Object mRootsLock = new Object();
 
     @GuardedBy("mRootsLock")
     private ArrayMap<String, RootInfo> mRoots = new ArrayMap<>();
 
-    @GuardedBy("mObservers")
-    private ArrayMap<File, DirectoryObserver> mObservers = new ArrayMap<>();
-
     @Override
     public boolean onCreate() {
+        super.onCreate(DEFAULT_DOCUMENT_PROJECTION);
+
         mStorageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
-        mHandler = new Handler();
 
         updateVolumes();
         return true;
@@ -274,11 +272,8 @@
         return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
     }
 
-    private static String[] resolveDocumentProjection(String[] projection) {
-        return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
-    }
-
-    private String getDocIdForFile(File file) throws FileNotFoundException {
+    @Override
+    protected String getDocIdForFile(File file) throws FileNotFoundException {
         return getDocIdForFileMaybeCreate(file, false);
     }
 
@@ -344,11 +339,8 @@
         return mostSpecificRoot;
     }
 
-    private File getFileForDocId(String docId) throws FileNotFoundException {
-        return getFileForDocId(docId, false);
-    }
-
-    private File getFileForDocId(String docId, boolean visible) throws FileNotFoundException {
+    @Override
+    protected File getFileForDocId(String docId, boolean visible) throws FileNotFoundException {
         RootInfo root = getRootFromDocId(docId);
         return buildFile(root, docId, visible);
     }
@@ -393,48 +385,9 @@
         return target;
     }
 
-    private void includeFile(MatrixCursor result, String docId, File file)
-            throws FileNotFoundException {
-        if (docId == null) {
-            docId = getDocIdForFile(file);
-        } else {
-            file = getFileForDocId(docId);
-        }
-
-        int flags = 0;
-
-        if (file.canWrite()) {
-            if (file.isDirectory()) {
-                flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
-                flags |= Document.FLAG_SUPPORTS_DELETE;
-                flags |= Document.FLAG_SUPPORTS_RENAME;
-                flags |= Document.FLAG_SUPPORTS_MOVE;
-            } else {
-                flags |= Document.FLAG_SUPPORTS_WRITE;
-                flags |= Document.FLAG_SUPPORTS_DELETE;
-                flags |= Document.FLAG_SUPPORTS_RENAME;
-                flags |= Document.FLAG_SUPPORTS_MOVE;
-            }
-        }
-
-        final String mimeType = getTypeForFile(file);
-        final String displayName = file.getName();
-        if (mimeType.startsWith("image/")) {
-            flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
-        }
-
-        final RowBuilder row = result.newRow();
-        row.add(Document.COLUMN_DOCUMENT_ID, docId);
-        row.add(Document.COLUMN_DISPLAY_NAME, displayName);
-        row.add(Document.COLUMN_SIZE, file.length());
-        row.add(Document.COLUMN_MIME_TYPE, mimeType);
-        row.add(Document.COLUMN_FLAGS, flags);
-
-        // Only publish dates reasonably after epoch
-        long lastModified = file.lastModified();
-        if (lastModified > 31536000000L) {
-            row.add(Document.COLUMN_LAST_MODIFIED, lastModified);
-        }
+    @Override
+    protected Uri buildNotificationUri(String docId) {
+        return DocumentsContract.buildChildDocumentsUri(AUTHORITY, docId);
     }
 
     @Override
@@ -455,22 +408,8 @@
     }
 
     @Override
-    public boolean isChildDocument(String parentDocId, String docId) {
-        try {
-            final File parent = getFileForDocId(parentDocId).getCanonicalFile();
-            final File doc = getFileForDocId(docId).getCanonicalFile();
-            return FileUtils.contains(parent, doc);
-        } catch (IOException e) {
-            throw new IllegalArgumentException(
-                    "Failed to determine if " + docId + " is child of " + parentDocId + ": " + e);
-        }
-    }
-
-    @Override
     public Path findDocumentPath(String childDocId, @Nullable String parentDocId)
             throws FileNotFoundException {
-        LinkedList<String> path = new LinkedList<>();
-
         final Pair<RootInfo, File> resolvedDocId = resolveDocId(childDocId, false);
         final RootInfo root = resolvedDocId.first;
         File child = resolvedDocId.second;
@@ -479,49 +418,7 @@
                         ? root.path
                         : getFileForDocId(parentDocId);
 
-        if (!child.exists()) {
-            throw new FileNotFoundException(childDocId + " is not found.");
-        }
-
-        if (!child.getAbsolutePath().startsWith(parent.getAbsolutePath())) {
-            throw new FileNotFoundException(childDocId + " is not found under " + parentDocId);
-        }
-
-        while (child != null && child.getAbsolutePath().startsWith(parent.getAbsolutePath())) {
-            path.addFirst(getDocIdForFile(child));
-
-            child = child.getParentFile();
-        }
-
-        return new Path(parentDocId == null ? root.rootId : null, path);
-    }
-
-    @Override
-    public String createDocument(String docId, String mimeType, String displayName)
-            throws FileNotFoundException {
-        displayName = FileUtils.buildValidFatFilename(displayName);
-
-        final File parent = getFileForDocId(docId);
-        if (!parent.isDirectory()) {
-            throw new IllegalArgumentException("Parent document isn't a directory");
-        }
-
-        final File file = FileUtils.buildUniqueFile(parent, mimeType, displayName);
-        if (Document.MIME_TYPE_DIR.equals(mimeType)) {
-            if (!file.mkdir()) {
-                throw new IllegalStateException("Failed to mkdir " + file);
-            }
-        } else {
-            try {
-                if (!file.createNewFile()) {
-                    throw new IllegalStateException("Failed to touch " + file);
-                }
-            } catch (IOException e) {
-                throw new IllegalStateException("Failed to touch " + file + ": " + e);
-            }
-        }
-
-        return getDocIdForFile(file);
+        return new Path(parentDocId == null ? root.rootId : null, findDocumentPath(parent, child));
     }
 
     private Uri getDocumentUri(String path, List<UriPermission> accessUriPermissions)
@@ -587,120 +484,14 @@
     }
 
     @Override
-    public String renameDocument(String docId, String displayName) throws FileNotFoundException {
-        // Since this provider treats renames as generating a completely new
-        // docId, we're okay with letting the MIME type change.
-        displayName = FileUtils.buildValidFatFilename(displayName);
-
-        final File before = getFileForDocId(docId);
-        final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
-        if (!before.renameTo(after)) {
-            throw new IllegalStateException("Failed to rename to " + after);
-        }
-        final String afterDocId = getDocIdForFile(after);
-        if (!TextUtils.equals(docId, afterDocId)) {
-            return afterDocId;
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public void deleteDocument(String docId) throws FileNotFoundException {
-        final File file = getFileForDocId(docId);
-        final File visibleFile = getFileForDocId(docId, true);
-
-        final boolean isDirectory = file.isDirectory();
-        if (isDirectory) {
-            FileUtils.deleteContents(file);
-        }
-        if (!file.delete()) {
-            throw new IllegalStateException("Failed to delete " + file);
-        }
-
-        if (visibleFile != null) {
-            final ContentResolver resolver = getContext().getContentResolver();
-            final Uri externalUri = MediaStore.Files.getContentUri("external");
-
-            // Remove media store entries for any files inside this directory, using
-            // path prefix match. Logic borrowed from MtpDatabase.
-            if (isDirectory) {
-                final String path = visibleFile.getAbsolutePath() + "/";
-                resolver.delete(externalUri,
-                        "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
-                        new String[] { path + "%", Integer.toString(path.length()), path });
-            }
-
-            // Remove media store entry for this exact file.
-            final String path = visibleFile.getAbsolutePath();
-            resolver.delete(externalUri,
-                    "_data LIKE ?1 AND lower(_data)=lower(?2)",
-                    new String[] { path, path });
-        }
-    }
-
-    @Override
-    public String moveDocument(String sourceDocumentId, String sourceParentDocumentId,
-            String targetParentDocumentId)
-            throws FileNotFoundException {
-        final File before = getFileForDocId(sourceDocumentId);
-        final File after = new File(getFileForDocId(targetParentDocumentId), before.getName());
-
-        if (after.exists()) {
-            throw new IllegalStateException("Already exists " + after);
-        }
-        if (!before.renameTo(after)) {
-            throw new IllegalStateException("Failed to move to " + after);
-        }
-        return getDocIdForFile(after);
-    }
-
-    @Override
-    public Cursor queryDocument(String documentId, String[] projection)
-            throws FileNotFoundException {
-        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
-        includeFile(result, documentId, null);
-        return result;
-    }
-
-    @Override
-    public Cursor queryChildDocuments(
-            String parentDocumentId, String[] projection, String sortOrder)
-            throws FileNotFoundException {
-        final File parent = getFileForDocId(parentDocumentId);
-        final MatrixCursor result = new DirectoryCursor(
-                resolveDocumentProjection(projection), parentDocumentId, parent);
-        for (File file : parent.listFiles()) {
-            includeFile(result, null, file);
-        }
-        return result;
-    }
-
-    @Override
     public Cursor querySearchDocuments(String rootId, String query, String[] projection)
             throws FileNotFoundException {
-        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
-
-        query = query.toLowerCase();
         final File parent;
         synchronized (mRootsLock) {
             parent = mRoots.get(rootId).path;
         }
 
-        final LinkedList<File> pending = new LinkedList<>();
-        pending.add(parent);
-        while (!pending.isEmpty() && result.getCount() < 24) {
-            final File file = pending.removeFirst();
-            if (file.isDirectory()) {
-                for (File child : file.listFiles()) {
-                    pending.add(child);
-                }
-            }
-            if (file.getName().toLowerCase().contains(query)) {
-                includeFile(result, null, file);
-            }
-        }
-        return result;
+        return querySearchDocuments(parent, query, projection, Collections.emptySet());
     }
 
     @Override
@@ -722,48 +513,6 @@
     }
 
     @Override
-    public String getDocumentType(String documentId) throws FileNotFoundException {
-        final File file = getFileForDocId(documentId);
-        return getTypeForFile(file);
-    }
-
-    @Override
-    public ParcelFileDescriptor openDocument(
-            String documentId, String mode, CancellationSignal signal)
-            throws FileNotFoundException {
-        final File file = getFileForDocId(documentId);
-        final File visibleFile = getFileForDocId(documentId, true);
-
-        final int pfdMode = ParcelFileDescriptor.parseMode(mode);
-        if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY || visibleFile == null) {
-            return ParcelFileDescriptor.open(file, pfdMode);
-        } else {
-            try {
-                // When finished writing, kick off media scanner
-                return ParcelFileDescriptor.open(file, pfdMode, mHandler, new OnCloseListener() {
-                    @Override
-                    public void onClose(IOException e) {
-                        final Intent intent = new Intent(
-                                Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
-                        intent.setData(Uri.fromFile(visibleFile));
-                        getContext().sendBroadcast(intent);
-                    }
-                });
-            } catch (IOException e) {
-                throw new FileNotFoundException("Failed to open for writing: " + e);
-            }
-        }
-    }
-
-    @Override
-    public AssetFileDescriptor openDocumentThumbnail(
-            String documentId, Point sizeHint, CancellationSignal signal)
-            throws FileNotFoundException {
-        final File file = getFileForDocId(documentId);
-        return DocumentsContract.openImageThumbnail(file);
-    }
-
-    @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ", 160);
         synchronized (mRootsLock) {
@@ -826,107 +575,4 @@
         }
         return bundle;
     }
-
-    private static String getTypeForFile(File file) {
-        if (file.isDirectory()) {
-            return Document.MIME_TYPE_DIR;
-        } else {
-            return getTypeForName(file.getName());
-        }
-    }
-
-    private static String getTypeForName(String name) {
-        final int lastDot = name.lastIndexOf('.');
-        if (lastDot >= 0) {
-            final String extension = name.substring(lastDot + 1).toLowerCase();
-            final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
-            if (mime != null) {
-                return mime;
-            }
-        }
-
-        return "application/octet-stream";
-    }
-
-    private void startObserving(File file, Uri notifyUri) {
-        synchronized (mObservers) {
-            DirectoryObserver observer = mObservers.get(file);
-            if (observer == null) {
-                observer = new DirectoryObserver(
-                        file, getContext().getContentResolver(), notifyUri);
-                observer.startWatching();
-                mObservers.put(file, observer);
-            }
-            observer.mRefCount++;
-
-            if (LOG_INOTIFY) Log.d(TAG, "after start: " + observer);
-        }
-    }
-
-    private void stopObserving(File file) {
-        synchronized (mObservers) {
-            DirectoryObserver observer = mObservers.get(file);
-            if (observer == null) return;
-
-            observer.mRefCount--;
-            if (observer.mRefCount == 0) {
-                mObservers.remove(file);
-                observer.stopWatching();
-            }
-
-            if (LOG_INOTIFY) Log.d(TAG, "after stop: " + observer);
-        }
-    }
-
-    private static class DirectoryObserver extends FileObserver {
-        private static final int NOTIFY_EVENTS = ATTRIB | CLOSE_WRITE | MOVED_FROM | MOVED_TO
-                | CREATE | DELETE | DELETE_SELF | MOVE_SELF;
-
-        private final File mFile;
-        private final ContentResolver mResolver;
-        private final Uri mNotifyUri;
-
-        private int mRefCount = 0;
-
-        public DirectoryObserver(File file, ContentResolver resolver, Uri notifyUri) {
-            super(file.getAbsolutePath(), NOTIFY_EVENTS);
-            mFile = file;
-            mResolver = resolver;
-            mNotifyUri = notifyUri;
-        }
-
-        @Override
-        public void onEvent(int event, String path) {
-            if ((event & NOTIFY_EVENTS) != 0) {
-                if (LOG_INOTIFY) Log.d(TAG, "onEvent() " + event + " at " + path);
-                mResolver.notifyChange(mNotifyUri, null, false);
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "DirectoryObserver{file=" + mFile.getAbsolutePath() + ", ref=" + mRefCount + "}";
-        }
-    }
-
-    private class DirectoryCursor extends MatrixCursor {
-        private final File mFile;
-
-        public DirectoryCursor(String[] columnNames, String docId, File file) {
-            super(columnNames);
-
-            final Uri notifyUri = DocumentsContract.buildChildDocumentsUri(
-                    AUTHORITY, docId);
-            setNotificationUri(getContext().getContentResolver(), notifyUri);
-
-            mFile = file;
-            startObserving(mFile, notifyUri);
-        }
-
-        @Override
-        public void close() {
-            super.close();
-            stopObserving(mFile);
-        }
-    }
 }
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index d207c35..9ff22c7 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -538,7 +538,7 @@
         <item>100</item>
     </array>
     <array name="batterymeter_color_values">
-        <item>@*android:color/battery_saver_mode_color</item>
+        <item>?android:attr/colorError</item>
         <item>@android:color/white</item>
     </array>
     <array name="batterymeter_bolt_points">
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 99d7f1e..49fc2ea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -16,6 +16,11 @@
 
 package com.android.settingslib;
 
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.AppGlobals;
 import android.app.admin.DevicePolicyManager;
@@ -29,6 +34,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
 import android.text.Spanned;
 import android.text.SpannableStringBuilder;
 import android.text.style.ForegroundColorSpan;
@@ -108,47 +114,68 @@
     }
 
     /**
-     * Checks if keyguard features are disabled by policy.
+     * Checks whether keyguard features are disabled by policy.
      *
-     * @param keyguardFeatures Could be any of keyguard features that can be
+     * @param context {@link Context} for the calling user.
+     *
+     * @param keyguardFeatures Any one of keyguard features that can be
      * disabled by {@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures}.
+     *
+     * @param userId User to check enforced admin status for.
+     *
      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
      * or {@code null} If the notification features are not disabled. If the restriction is set by
      * multiple admins, then the admin component will be set to {@code null} and userId to
      * {@link UserHandle#USER_NULL}.
      */
     public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
-            int keyguardFeatures, int userId) {
-        final LockSettingCheck check =
-                (DevicePolicyManager dpm, ComponentName admin, @UserIdInt int checkUser) ->
-                        (dpm.getKeyguardDisabledFeatures(admin, checkUser) & keyguardFeatures) != 0;
+            int keyguardFeatures, final @UserIdInt int userId) {
+        final LockSettingCheck check = (dpm, admin, checkUser) -> {
+            int effectiveFeatures = dpm.getKeyguardDisabledFeatures(admin, checkUser);
+            if (checkUser != userId) {
+                effectiveFeatures &= PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+            }
+            return (effectiveFeatures & keyguardFeatures) != KEYGUARD_DISABLE_FEATURES_NONE;
+        };
+        if (UserManager.get(context).getUserInfo(userId).isManagedProfile()) {
+            DevicePolicyManager dpm =
+                    (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+            return findEnforcedAdmin(dpm.getActiveAdminsAsUser(userId), dpm, userId, check);
+        }
+        return checkForLockSetting(context, userId, check);
+    }
 
-        final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
-                Context.DEVICE_POLICY_SERVICE);
-        if (dpm == null) {
+    /**
+     * Filter a set of device admins based on a predicate {@code check}. This is equivalent to
+     * {@code admins.stream().filter(check).map(x → new EnforcedAdmin(admin, userId)} except it's
+     * returning a zero/one/many-type thing.
+     *
+     * @param admins set of candidate device admins identified by {@link ComponentName}.
+     * @param userId user to create the resultant {@link EnforcedAdmin} as.
+     * @param check filter predicate.
+     *
+     * @return {@code null} if none of the {@param admins} match.
+     *         An {@link EnforcedAdmin} if exactly one of the admins matches.
+     *         Otherwise, {@link EnforcedAdmin#MULTIPLE_ENFORCED_ADMIN} for multiple matches.
+     */
+    @Nullable
+    private static EnforcedAdmin findEnforcedAdmin(@Nullable List<ComponentName> admins,
+            @NonNull DevicePolicyManager dpm, @UserIdInt int userId,
+            @NonNull LockSettingCheck check) {
+        if (admins == null) {
             return null;
         }
-
-        final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        if (um.getUserInfo(userId).isManagedProfile()) {
-            final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
-            if (admins == null) {
-                return null;
-            }
-            EnforcedAdmin enforcedAdmin = null;
-            for (ComponentName admin : admins) {
-                if (check.isEnforcing(dpm, admin, userId)) {
-                    if (enforcedAdmin == null) {
-                        enforcedAdmin = new EnforcedAdmin(admin, userId);
-                    } else {
-                        return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
-                    }
+        EnforcedAdmin enforcedAdmin = null;
+        for (ComponentName admin : admins) {
+            if (check.isEnforcing(dpm, admin, userId)) {
+                if (enforcedAdmin == null) {
+                    enforcedAdmin = new EnforcedAdmin(admin, userId);
+                } else {
+                    return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
                 }
             }
-            return enforcedAdmin;
-        } else {
-            return checkForLockSetting(context, userId, check);
         }
+        return enforcedAdmin;
     }
 
     public static EnforcedAdmin checkIfUninstallBlocked(Context context,
@@ -361,7 +388,7 @@
         }
 
         LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
-        if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+        if (sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userId)) {
             // userId is managed profile and has a separate challenge, only consider
             // the admins in that user.
             final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
@@ -428,7 +455,7 @@
                 if (userInfo.isManagedProfile()) {
                     // If userInfo.id is a managed profile, we also need to look at
                     // the policies set on the parent.
-                    final DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
+                    DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
                     if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
                         if (enforcedAdmin == null) {
                             enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
@@ -448,8 +475,9 @@
 
     /**
      * Checks whether any of the user's profiles enforce the lock setting. A managed profile is only
-     * included if it does not have a separate challenege but the settings for it's parent (i.e. the
-     * user being checked) are always included.
+     * included if it does not have a separate challenge.
+     *
+     * The user identified by {@param userId} is always included.
      */
     private static EnforcedAdmin checkForLockSetting(
             Context context, @UserIdInt int userId, LockSettingCheck check) {
@@ -468,7 +496,7 @@
                 continue;
             }
             final boolean isSeparateProfileChallengeEnabled =
-                    lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
+                    sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userInfo.id);
             for (ComponentName admin : admins) {
                 if (!isSeparateProfileChallengeEnabled) {
                     if (check.isEnforcing(dpm, admin, userInfo.id)) {
@@ -487,7 +515,7 @@
                 if (userInfo.isManagedProfile()) {
                     // If userInfo.id is a managed profile, we also need to look at
                     // the policies set on the parent.
-                    final DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
+                    DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
                     if (check.isEnforcing(parentDpm, admin, userInfo.id)) {
                         if (enforcedAdmin == null) {
                             enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
@@ -733,4 +761,23 @@
             other.userId = userId;
         }
     }
+
+    /**
+     * Static {@link LockPatternUtils} and {@link DevicePolicyManager} wrapper for testing purposes.
+     * {@link LockPatternUtils} is an internal API not supported by robolectric.
+     * {@link DevicePolicyManager} has a {@code getProfileParent} not yet suppored by robolectric.
+     */
+    @VisibleForTesting
+    static Proxy sProxy = new Proxy();
+
+    @VisibleForTesting
+    static class Proxy {
+        public boolean isSeparateProfileChallengeEnabled(LockPatternUtils utils, int userHandle) {
+            return utils.isSeparateProfileChallengeEnabled(userHandle);
+        }
+
+        public DevicePolicyManager getParentProfileInstance(DevicePolicyManager dpm, UserInfo ui) {
+            return dpm.getParentProfileInstance(ui);
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 7a4514a..7e7b391 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -184,10 +184,7 @@
 
     @ColorInt
     public static int getColorError(Context context) {
-        TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.textColorError});
-        @ColorInt int colorError = ta.getColor(0, 0);
-        ta.recycle();
-        return colorError;
+        return getColorAttr(context, android.R.attr.colorError);
     }
 
     @ColorInt
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index fd2e7ca..6764a6b 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -29,7 +29,8 @@
 import android.graphics.RectF;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
-import android.provider.Settings;
+import android.util.TypedValue;
+
 import com.android.settingslib.R;
 import com.android.settingslib.Utils;
 
@@ -97,9 +98,13 @@
 
         final int N = levels.length();
         mColors = new int[2 * N];
-        for (int i = 0; i < N; i++) {
+        for (int i=0; i < N; i++) {
             mColors[2 * i] = levels.getInt(i, 0);
-            mColors[2 * i + 1] = colors.getColor(i, 0);
+            if (colors.getType(i) == TypedValue.TYPE_ATTRIBUTE) {
+                mColors[2 * i + 1] = Utils.getColorAttr(context, colors.getResourceId(i, 0));
+            } else {
+                mColors[2 * i + 1] = colors.getColor(i, 0);
+            }
         }
         levels.recycle();
         colors.recycle();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 2dcbf90..26ca3d4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -265,6 +265,9 @@
     public String toString() {
         StringBuilder builder = new StringBuilder().append("AccessPoint(")
                 .append(ssid);
+        if (bssid != null) {
+            builder.append(":").append(bssid);
+        }
         if (isSaved()) {
             builder.append(',').append("saved");
         }
@@ -280,6 +283,7 @@
         if (security != SECURITY_NONE) {
             builder.append(',').append(securityToString(security, pskType));
         }
+        builder.append(",level=").append(getLevel());
         builder.append(",rankingScore=").append(mRankingScore);
         builder.append(",badge=").append(mBadge);
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 11bcdca..8421c2c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -271,7 +271,6 @@
         if (mWifiManager.isWifiEnabled()) {
             mScanner.resume();
         }
-        mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
     }
 
     /**
@@ -715,9 +714,9 @@
 
                 mMainHandler.sendEmptyMessage(MainHandler.MSG_CONNECTED_CHANGED);
 
-                mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
                 mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_NETWORK_INFO, info)
                         .sendToTarget();
+                mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
             }
         }
     };
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 2018c13..e100884 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.settingslib.wifi;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -28,6 +30,7 @@
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.NetworkBadging;
+import android.net.NetworkInfo;
 import android.net.NetworkKey;
 import android.net.NetworkScoreManager;
 import android.net.ScoredNetwork;
@@ -35,6 +38,7 @@
 import android.net.WifiKey;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkScoreCache;
 import android.net.wifi.WifiSsid;
@@ -68,6 +72,8 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+// TODO(sghuman): Change these to robolectric tests b/35766684.
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class WifiTrackerTest {
@@ -115,9 +121,10 @@
 
     @Before
     public void setUp() {
-        mContext = InstrumentationRegistry.getTargetContext();
         MockitoAnnotations.initMocks(this);
 
+        mContext = InstrumentationRegistry.getTargetContext();
+
         mWorkerThread = new HandlerThread("TestHandlerWorkerThread");
         mWorkerThread.start();
         mLooper = mWorkerThread.getLooper();
@@ -221,9 +228,15 @@
                 SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
     }
 
-    private WifiTracker createTrackerAndInjectInitialScanResults() throws InterruptedException {
+    private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
+                    Intent ... intents)
+            throws InterruptedException {
         WifiTracker tracker = createMockedWifiTracker();
+
         startTracking(tracker);
+        for (Intent intent : intents) {
+            tracker.mReceiver.onReceive(mContext, intent);
+        }
 
         mAccessPointsChangedLatch = new CountDownLatch(1);
         sendScanResultsAndProcess(tracker);
@@ -235,16 +248,16 @@
     private WifiTracker createMockedWifiTracker() {
         WifiTracker tracker =
                 new WifiTracker(
-                    mContext,
-                    mockWifiListener,
-                    mLooper,
-                    true,
-                    true,
-                    true,
-                    mockWifiManager,
-                    mockConnectivityManager,
-                    mockNetworkScoreManager,
-                    mMainLooper
+                        mContext,
+                        mockWifiListener,
+                        mLooper,
+                        true,
+                        true,
+                        true,
+                        mockWifiManager,
+                        mockConnectivityManager,
+                        mockNetworkScoreManager,
+                        mMainLooper
                 );
 
         return tracker;
@@ -294,6 +307,31 @@
         scoreCache.updateScores(Arrays.asList(sc1, sc2));
     }
 
+    private WifiTracker createTrackerWithScanResultsAndAccessPoint1Connected()
+            throws InterruptedException {
+        int networkId = 123;
+
+        WifiInfo wifiInfo = new WifiInfo();
+        wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(SSID_1));
+        wifiInfo.setBSSID(BSSID_1);
+        wifiInfo.setNetworkId(networkId);
+        when(mockWifiManager.getConnectionInfo()).thenReturn(wifiInfo);
+
+        WifiConfiguration configuration = new WifiConfiguration();
+        configuration.SSID = SSID_1;
+        configuration.BSSID = BSSID_1;
+        configuration.networkId = networkId;
+        when(mockWifiManager.getConfiguredNetworks()).thenReturn(Arrays.asList(configuration));
+
+        NetworkInfo networkInfo = new NetworkInfo(
+                ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
+        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
+
+        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
+        return createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(intent);
+    }
+
     @Test
     public void testAccessPointListenerSetWhenLookingUpUsingScanResults() {
         ScanResult scanResult = new ScanResult();
@@ -357,12 +395,21 @@
     }
 
     @Test
+    public void startTrackingShouldSetConnectedAccessPointAsActive() throws InterruptedException {
+        WifiTracker tracker =  createTrackerWithScanResultsAndAccessPoint1Connected();
+
+        List<AccessPoint> aps = tracker.getAccessPoints();
+
+        assertThat(aps).hasSize(2);
+        assertThat(aps.get(0).isActive()).isTrue();
+    }
+
+    @Test
     public void startTrackingShouldRequestScoresForCurrentAccessPoints() throws InterruptedException {
         // Start the tracker and inject the initial scan results and then stop tracking
-        WifiTracker tracker =  createTrackerAndInjectInitialScanResults();
+        WifiTracker tracker =  createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
 
         tracker.stopTracking();
-        android.util.Log.d("WifiTrackerTest", "Clearing previously captured requested keys");
         mRequestedKeys.clear();
 
         mRequestScoresLatch = new CountDownLatch(1);
@@ -370,7 +417,6 @@
         assertTrue("Latch timed out",
                 mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
 
-        android.util.Log.d("WifiTrackerTest", "requested keys: " + mRequestedKeys);
         assertTrue(mRequestedKeys.contains(NETWORK_KEY_1));
         assertTrue(mRequestedKeys.contains(NETWORK_KEY_2));
     }
@@ -394,7 +440,7 @@
 
     @Test
     public void scoreCacheUpdateScoresShouldChangeSortOrder() throws InterruptedException {
-        WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+        WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
         List<AccessPoint> aps = tracker.getAccessPoints();
         assertTrue(aps.size() == 2);
         assertEquals(aps.get(0).getSsidStr(), SSID_1);
@@ -416,7 +462,7 @@
                 Settings.Global.NETWORK_SCORING_UI_ENABLED,
                 0 /* disabled */);
 
-        WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+        WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
         List<AccessPoint> aps = tracker.getAccessPoints();
         assertTrue(aps.size() == 2);
         assertEquals(aps.get(0).getSsidStr(), SSID_1);
@@ -432,7 +478,7 @@
 
     @Test
     public void scoreCacheUpdateScoresShouldInsertBadgeIntoAccessPoint() throws InterruptedException {
-        WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+        WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
         updateScoresAndWaitForAccessPointsChangedCallback();
 
         List<AccessPoint> aps = tracker.getAccessPoints();
@@ -454,7 +500,7 @@
                 Settings.Global.NETWORK_SCORING_UI_ENABLED,
                 0 /* disabled */);
 
-        WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+        WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
         updateScoresAndWaitForAccessPointsChangedCallback();
 
         List<AccessPoint> aps = tracker.getAccessPoints();
@@ -473,7 +519,7 @@
         // Scores can be requested together or serially depending on how the scan results are
         // processed.
         mRequestScoresLatch = new CountDownLatch(2);
-        WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+        WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
         mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
         mRequestedKeys.clear();
 
@@ -503,7 +549,7 @@
     @Test
     public void scoreCacheAndListenerShouldBeUnregisteredWhenStopTrackingIsCalled() throws Exception
     {
-        WifiTracker tracker =  createTrackerAndInjectInitialScanResults();
+        WifiTracker tracker =  createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
         WifiNetworkScoreCache cache = mScoreCacheCaptor.getValue();
 
         tracker.stopTracking();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index 2958740..c506358 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -16,6 +16,17 @@
 
 package com.android.settingslib;
 
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -25,18 +36,13 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
 import java.util.Arrays;
 
-import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
-import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.when;
-
 @RunWith(SettingLibRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class RestrictedLockUtilsTest {
@@ -47,8 +53,11 @@
     private DevicePolicyManager mDevicePolicyManager;
     @Mock
     private UserManager mUserManager;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private RestrictedLockUtils.Proxy mProxy;
 
     private static final int mUserId = 194;
+    private static final int mProfileId = 160;
     private static final ComponentName mAdmin1 = new ComponentName("admin1", "admin1class");
     private static final ComponentName mAdmin2 = new ComponentName("admin2", "admin2class");
 
@@ -60,12 +69,13 @@
                 .thenReturn(mDevicePolicyManager);
         when(mContext.getSystemService(Context.USER_SERVICE))
                 .thenReturn(mUserManager);
+
+        RestrictedLockUtils.sProxy = mProxy;
     }
 
     @Test
     public void checkIfKeyguardFeaturesDisabled_noEnforcedAdminForManagedProfile() {
-        setUpManagedProfile(mUserId);
-        setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+        setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
 
         final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
                 mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
@@ -75,8 +85,7 @@
 
     @Test
     public void checkIfKeyguardFeaturesDisabled_oneEnforcedAdminForManagedProfile() {
-        setUpManagedProfile(mUserId);
-        setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+        setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
 
         when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
                 .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
@@ -89,8 +98,7 @@
 
     @Test
     public void checkIfKeyguardFeaturesDisabled_multipleEnforcedAdminForManagedProfile() {
-        setUpManagedProfile(mUserId);
-        setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+        setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
 
         when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
                 .thenReturn(KEYGUARD_DISABLE_REMOTE_INPUT);
@@ -103,9 +111,129 @@
         assertThat(enforcedAdmin).isEqualTo(EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN);
     }
 
-    private UserInfo setUpManagedProfile(int userId) {
-        final UserInfo userInfo = new UserInfo(userId, "myuser", UserInfo.FLAG_MANAGED_PROFILE);
+    @Test
+    public void checkIfKeyguardFeaturesAreDisabled_doesMatchAllowedFeature_unifiedManagedProfile() {
+        UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+        UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+        when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+                userInfo, profileInfo}));
+
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+                .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+                .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+        // Querying the parent should return the policy, since it affects the parent.
+        EnforcedAdmin parent = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+        assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+
+        // Querying the child should return that too.
+        EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
+        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+
+        // Querying for some unrelated feature should return nothing. Nothing!
+        assertThat(RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_REMOTE_INPUT, mUserId)).isNull();
+        assertThat(RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_REMOTE_INPUT, mProfileId)).isNull();
+    }
+
+    @Test
+    public void checkIfKeyguardFeaturesAreDisabled_notMatchOtherFeatures_unifiedManagedProfile() {
+        UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+        UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+        when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+                userInfo, profileInfo}));
+
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+                .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+                .thenReturn(KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+
+        // Querying the parent should not return the policy, because it's not a policy that should
+        // affect parents even when the lock screen is unified.
+        EnforcedAdmin primary = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS, mUserId);
+        assertThat(primary).isNull();
+
+        // Querying the child should still return the policy.
+        EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS, mProfileId);
+        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+    }
+
+    @Test
+    public void checkIfKeyguardFeaturesAreDisabled_onlyMatchesProfile_separateManagedProfile() {
+        UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+        UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+        when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+                userInfo, profileInfo}));
+
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+                .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+                .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+        // Crucially for this test, isSeparateWorkChallengeEnabled => true.
+        doReturn(true).when(mProxy).isSeparateProfileChallengeEnabled(any(), eq(mProfileId));
+
+        // Querying the parent should not return the policy, even though it's shared by default,
+        // because the parent doesn't share a lock screen with the profile any more.
+        EnforcedAdmin parent = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+        assertThat(parent).isNull();
+
+        // Querying the child should still return the policy.
+        EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
+        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+    }
+
+    /**
+     * This test works great. The real world implementation is sketchy though.
+     * <p>
+     * DevicePolicyManager.getParentProfileInstance(UserInfo) does not do what it looks like it does
+     * (which would be to get an instance for the parent of the user that's passed in to it.)
+     * <p>
+     * Instead it just always returns a parent instance for the current user.
+     * <p>
+     * Still, the test works.
+     */
+    @Test
+    public void checkIfKeyguardFeaturesAreDisabled_onlyMatchesParent_profileParentPolicy() {
+        UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+        UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+        when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+                userInfo, profileInfo}));
+
+        when(mProxy.getParentProfileInstance(any(DevicePolicyManager.class), any())
+                .getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+                .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+        // Parent should get the policy.
+        EnforcedAdmin parent = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+        assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+
+        // Profile should not get the policy.
+        EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
+        assertThat(profile).isNull();
+    }
+
+    private UserInfo setUpUser(int userId, ComponentName[] admins) {
+        UserInfo userInfo = new UserInfo(userId, "primary", 0);
         when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
+        setUpActiveAdmins(userId, admins);
+        return userInfo;
+    }
+
+    private UserInfo setUpManagedProfile(int userId, ComponentName[] admins) {
+        UserInfo userInfo = new UserInfo(userId, "profile", UserInfo.FLAG_MANAGED_PROFILE);
+        when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
+        setUpActiveAdmins(userId, admins);
         return userInfo;
     }
 
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 12d0c03..1df626f 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -44,6 +44,7 @@
 import libcore.io.Streams;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ChooserActivity;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.FastPrintWriter;
@@ -943,8 +944,13 @@
     }
 
     static void sendShareIntent(Context context, Intent intent) {
-        context.startActivity(Intent.createChooser(intent,
-                context.getResources().getText(R.string.bugreport_intent_chooser_title)));
+        final Intent chooserIntent = Intent.createChooser(intent,
+                context.getResources().getText(R.string.bugreport_intent_chooser_title));
+
+        // Since we may be launched behind lockscreen, make sure that ChooserActivity doesn't finish
+        // itself in onStop.
+        chooserIntent.putExtra(ChooserActivity.EXTRA_PRIVATE_RETAIN_IN_ON_STOP, true);
+        context.startActivity(chooserIntent);
     }
 
     /**
diff --git a/packages/SystemUI/res/drawable/ic_fingerprint_error.xml b/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
index 11e83a1..a7fb1a1 100644
--- a/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
+++ b/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
@@ -19,12 +19,12 @@
         android:viewportWidth="32.0"
         android:viewportHeight="32.0">
     <path
-        android:fillColor="@color/system_warning_color"
+        android:fillColor="?android:attr/colorError"
         android:pathData="M15.99,2.5C8.53,2.5 2.5,8.54 2.5,16.0s6.03,13.5 13.49,13.5S29.5,23.46 29.5,16.0S23.45,2.5 15.99,2.5zM16.0,26.8c-5.97,0.0 -10.8,-4.83 -10.8,-10.8S10.03,5.2 16.0,5.2S26.8,10.03 26.8,16.0S21.97,26.8 16.0,26.8z"/>
     <path
-        android:fillColor="@color/system_warning_color"
+        android:fillColor="?android:attr/colorError"
         android:pathData="M14.65,20.05l2.7,0.0l0.0,2.7l-2.7,0.0z"/>
     <path
-        android:fillColor="@color/system_warning_color"
+        android:fillColor="?android:attr/colorError"
         android:pathData="M14.65,9.25l2.7,0.0l0.0,8.1l-2.7,0.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_network_logging.xml b/packages/SystemUI/res/drawable/ic_qs_network_logging.xml
index 87b5a14..7bdf50c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_network_logging.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_network_logging.xml
@@ -20,8 +20,7 @@
   android:width="12.0dp"
   android:height="12.0dp"
   android:viewportWidth="24.0"
-  android:viewportHeight="24.0"
-  android:tint="#4DFFFFFF" >
+  android:viewportHeight="24.0">
     <path
       android:fillColor="#FFFFFFFF"
       android:pathData="M2,24v-4h12v4H2z M2,16v-4h20v4H2z M5,7 12,0 19,7 14,7 14,15 10,15 10,7z"/>
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
index e207cb3..3af2f7f 100644
--- a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
@@ -98,11 +98,11 @@
             <path
                 android:name="path_2"
                 android:pathData="M 1.35900878906,6.76104736328 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-2.69995117188 0.0,-2.69995117188 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,2.69995117188 0.0,2.69995117188 Z"
-                android:fillColor="@*android:color/system_error" />
+                android:fillColor="?android:attr/colorError" />
             <path
                 android:name="path_1"
                 android:pathData="M 1.35363769531,1.36633300781 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-8.09997558594 0.0,-8.09997558594 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,8.09997558594 0.0,8.09997558594 Z"
-                android:fillColor="@*android:color/system_error" />
+                android:fillColor="?android:attr/colorError" />
         </group>
     </group>
     <group
@@ -117,7 +117,7 @@
             <path
                 android:name="path_3"
                 android:pathData="M 0.0101470947266,10.8087768555 c -5.96701049805,0.0 -10.8000183105,-4.8330078125 -10.8000183105,-10.8000488281 c 0.0,-5.96691894531 4.8330078125,-10.7999267578 10.8000183105,-10.7999267578 c 5.96697998047,0.0 10.799987793,4.8330078125 10.799987793,10.7999267578 c 0.0,5.96704101562 -4.8330078125,10.8000488281 -10.799987793,10.8000488281 Z"
-                android:strokeColor="@*android:color/system_error"
+                android:strokeColor="?android:attr/colorError"
                 android:strokeWidth="2"
                 android:trimPathStart="0"
                 android:trimPathEnd="1" />
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
index 2b4babc..a577afc 100644
--- a/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
@@ -96,7 +96,7 @@
                 <path
                     android:name="ridge_5_path_0"
                     android:pathData="M -25.3591003418,-24.4138946533 c -0.569000244141,0.106399536133 -1.12660217285,0.140594482422 -1.45460510254,0.140594482422 c -1.29689025879,0.0 -2.53239440918,-0.343307495117 -3.62019348145,-1.12400817871 c -1.67700195312,-1.20349121094 -2.76950073242,-3.17008972168 -2.76950073242,-5.39189147949"
-                    android:strokeColor="@*android:color/system_error"
+                    android:strokeColor="?android:attr/colorError"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -106,7 +106,7 @@
                 <path
                     android:name="ridge_7_path_0"
                     android:pathData="M -36.1409912109,-21.7843475342 c -1.00540161133,-1.19300842285 -1.57499694824,-1.9181060791 -2.36520385742,-3.50170898438 c -0.827560424805,-1.65869140625 -1.31352233887,-3.49159240723 -1.31352233887,-5.48489379883 c 0.0,-3.66279602051 2.96932983398,-6.63220214844 6.63221740723,-6.63220214844 c 3.6628112793,0.0 6.63220214844,2.96940612793 6.63220214844,6.63220214844"
-                    android:strokeColor="@*android:color/system_error"
+                    android:strokeColor="?android:attr/colorError"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -116,7 +116,7 @@
                 <path
                     android:name="ridge_6_path_0"
                     android:pathData="M -42.1907958984,-25.6756896973 c -0.758117675781,-2.14370727539 -0.896545410156,-3.86891174316 -0.896545410156,-5.12921142578 c 0.0,-1.46069335938 0.249176025391,-2.84799194336 0.814682006836,-4.09748840332 c 1.56153869629,-3.45030212402 5.03434753418,-5.85076904297 9.0679473877,-5.85076904297 c 5.49430847168,0.0 9.94830322266,4.4539642334 9.94830322266,9.94825744629 c 0.0,1.83151245117 -1.48460388184,3.31610107422 -3.31610107422,3.31610107422 c -1.83149719238,0.0 -3.31610107422,-1.48469543457 -3.31610107422,-3.31610107422 c 0.0,-1.83139038086 -1.48458862305,-3.31610107422 -3.31610107422,-3.31610107422 c -1.83149719238,0.0 -3.31610107422,1.48471069336 -3.31610107422,3.31610107422 c 0.0,2.57020568848 0.989517211914,4.88710021973 2.60510253906,6.5865020752 c 1.22210693359,1.28550720215 2.43139648438,2.09950256348 4.47590637207,2.69030761719"
-                    android:strokeColor="@*android:color/system_error"
+                    android:strokeColor="?android:attr/colorError"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -126,7 +126,7 @@
                 <path
                     android:name="ridge_2_path_0"
                     android:pathData="M -44.0646514893,-38.1672973633 c 1.19026184082,-1.77430725098 2.67503356934,-3.24531555176 4.55902099609,-4.27278137207 c 1.88395690918,-1.0274810791 4.04466247559,-1.61137390137 6.34175109863,-1.61137390137 c 2.28761291504,0.0 4.43991088867,0.579071044922 6.31831359863,1.59861755371 c 1.8784942627,1.01954650879 3.36059570312,2.4796295166 4.55279541016,4.24153137207"
-                    android:strokeColor="@*android:color/system_error"
+                    android:strokeColor="?android:attr/colorError"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathStart="1" />
@@ -138,7 +138,7 @@
                 <path
                     android:name="ridge_1_path_0"
                     android:pathData="M 71.7812347412,97.0507202148 c -2.27149963379,-1.31344604492 -4.71360778809,-2.07006835938 -7.56221008301,-2.07006835938 c -2.84869384766,0.0 -5.23320007324,0.779556274414 -7.34411621094,2.07006835938"
-                    android:strokeColor="@*android:color/system_error"
+                    android:strokeColor="?android:attr/colorError"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -157,11 +157,11 @@
             <path
                 android:name="path_2"
                 android:pathData="M -1.3705291748,4.06730651855 c 0.0,0.0 0.036376953125,-0.0102386474609 0.036376953125,-0.0102386474609 c 0.0,0.0 -0.00682067871094,0.0040283203125 -0.00682067871093,0.0040283203125 c 0.0,0.0 -0.0161437988281,0.00479125976562 -0.0161437988281,0.00479125976563 c 0.0,0.0 -0.0134124755859,0.00141906738281 -0.0134124755859,0.00141906738281 Z"
-                android:fillColor="@*android:color/system_error" />
+                android:fillColor="?android:attr/colorError" />
             <path
                 android:name="path_1"
                 android:pathData="M -1.3737487793,-6.77532958984 c 0.0,0.0 0.00604248046875,0.0166625976562 0.00604248046876,0.0166625976562 c 0.0,0.0 0.0213623046875,0.0250244140625 0.0213623046875,0.0250244140625 c 0.0,0.0 -0.00604248046875,-0.0166625976562 -0.00604248046876,-0.0166625976562 c 0.0,0.0 -0.0213623046875,-0.0250244140625 -0.0213623046875,-0.0250244140625 Z"
-                android:fillColor="@*android:color/system_error" />
+                android:fillColor="?android:attr/colorError" />
         </group>
     </group>
     <group
@@ -176,7 +176,7 @@
             <path
                 android:name="path_3"
                 android:pathData="M 0.0101470947266,10.8087768555 c -5.96701049805,0.0 -10.8000183105,-4.8330078125 -10.8000183105,-10.8000488281 c 0.0,-5.96691894531 4.8330078125,-10.7999267578 10.8000183105,-10.7999267578 c 5.96697998047,0.0 10.799987793,4.8330078125 10.799987793,10.7999267578 c 0.0,5.96704101562 -4.8330078125,10.8000488281 -10.799987793,10.8000488281 Z"
-                android:strokeColor="@*android:color/system_error"
+                android:strokeColor="?android:attr/colorError"
                 android:strokeWidth="2"
                 android:trimPathStart="1" />
         </group>
diff --git a/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml b/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml
index b7da30b..bf405fa 100644
--- a/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml
+++ b/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml
@@ -20,10 +20,10 @@
     android:viewportHeight="72.0"
     android:tint="?android:attr/textColorPrimary">
     <group
-        android:translateX="52.0"
-        android:translateY="42.0" >
+        android:translateX="28.0"
+        android:translateY="10.5" >
         <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.76 -2.24,-5.0 -5.0,-5.0S7.0,3.24 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.0 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-6.0,9.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0 2.0,0.9 2.0,2.0 -0.9,2.0 -2.0,2.0zm3.1,-9.0L8.9,8.0L8.9,6.0c0.0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0.0 3.1,1.39 3.1,3.1l0.0,2.0z"/>
+            android:pathData="M36 16l-2 0 0 -4C34 6.48 29.52 2 24 2 18.48 2 14 6.48 14 12l0 4 -2 0c-2.21 0 -4 1.79 -4 4l0 20c0 2.21 1.79 4 4 4l24 0c2.21 0 4 -1.79 4 -4l0 -20c0 -2.21 -1.79 -4 -4 -4zM24 34c-2.21 0 -4 -1.79 -4 -4 0 -2.21 1.79 -4 4 -4 2.21 0 4 1.79 4 4 0 2.21 -1.79 4 -4 4zm6.2 -18l-12.4 0 0 -4c0 -3.42 2.78 -6.2 6.2 -6.2 3.42 0 6.2 2.78 6.2 6.2l0 4z"
+            android:fillColor="#FFFFFF" />
     </group>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_in.xml b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
new file mode 100644
index 0000000..7e6e09b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="17dp"
+        android:height="17dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="in"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
new file mode 100644
index 0000000..b7b6f0f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="17dp"
+        android:height="17dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="in"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
+    <path
+        android:name="out"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_out.xml b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
new file mode 100644
index 0000000..910c035
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="17dp"
+        android:height="17dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="out"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
new file mode 100644
index 0000000..666127b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="18.41dp"
+        android:height="17dp"
+        android:viewportWidth="26.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="in"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
new file mode 100644
index 0000000..eeba030
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="18.41dp"
+        android:height="17dp"
+        android:viewportWidth="26.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="in"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
+    <path
+        android:name="out"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
new file mode 100644
index 0000000..d577d1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="18.41dp"
+        android:height="17dp"
+        android:viewportWidth="26.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="out"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 8b10074..d988acc 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -54,4 +54,10 @@
         android:src="@drawable/stat_sys_roaming"
         android:contentDescription="@string/accessibility_data_connection_roaming"
         android:visibility="gone" />
+    <ImageView
+        android:id="@+id/mobile_inout"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:visibility="gone"
+        />
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml
index 6edf135..6544f0d 100644
--- a/packages/SystemUI/res/layout/qs_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_detail_item.xml
@@ -63,7 +63,6 @@
         android:focusable="true"
         android:scaleType="center"
         android:contentDescription="@*android:string/media_route_controller_disconnect"
-        android:tint="?android:attr/textColorPrimary"
-        android:src="@drawable/ic_qs_cancel" />
+        android:tint="?android:attr/textColorPrimary" />
 
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 222a31d..4d03f0f 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -70,6 +70,11 @@
             android:layout_width="wrap_content"
             android:alpha="0.0"
             />
+        <ImageView
+            android:id="@+id/wifi_inout"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            />
     </FrameLayout>
     <View
         android:id="@+id/wifi_signal_spacer"
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
index 08b1ab1..e52c5db 100644
--- a/packages/SystemUI/res/values/arrays_tv.xml
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -17,9 +17,13 @@
  */
 -->
 <resources>
-    <!-- List of package name or class name which are considered as Settings,
+    <!-- List of package names or class names which are considered as Settings,
          so PIP location should be adjusted to the left of the side panel.
-         This can be overriden in an overlay -->
+         If it should be applied for all activities in a package, add the package name.
+         If it should be applied for an activity in a package, add its class name with package name.
+         The class name must follow format 'package_name/.class_name' ('/.' in between).
+         This can be overriden in an overlay.
+         -->
     <string-array name="tv_pip_settings_class_name" translatable="false">
         <item>com.android.tv.settings</item>
         <item>com.google.android.leanbacklauncher/.settings.HomeScreenSettingsActivity</item>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 407cddf..f461bb3 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -27,7 +27,6 @@
     <color name="notification_list_shadow_top">#80000000</color>
     <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
     <color name="qs_batterymeter_frame_color">#FF404040</color>
-    <color name="system_warning_color">@*android:color/system_error</color>
     <color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
     <color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
     <color name="qs_detail_button">@*android:color/quaternary_device_default_settings</color>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 48b7664..9168256 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -30,7 +30,7 @@
 
     <!-- Recents theme -->
     <style name="RecentsTheme.Wallpaper">
-        <item name="android:windowBackground">@color/transparent</item>
+        <item name="android:windowBackground">@*android:color/transparent</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
         <item name="android:windowShowWallpaper">true</item>
         <item name="android:windowDisablePreview">true</item>
@@ -52,7 +52,7 @@
     <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
     <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
         <item name="android:windowBackground">@drawable/forced_resizable_background</item>
-        <item name="android:statusBarColor">@color/transparent</item>
+        <item name="android:statusBarColor">@*android:color/transparent</item>
         <item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
     </style>
 
@@ -70,7 +70,7 @@
         <item name="android:windowContentOverlay">@null</item>
         <item name="android:windowBackground">@null</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
-        <item name="android:statusBarColor">@color/transparent</item>
+        <item name="android:statusBarColor">@*android:color/transparent</item>
         <item name="android:windowAnimationStyle">@style/Animation.PipPhoneOverlayControl</item>
     </style>
 
@@ -164,7 +164,7 @@
 
     <style name="TextAppearance.QS.Warning">
         <item name="android:textSize">14sp</item>
-        <item name="android:textColor">@color/system_warning_color</item>
+        <item name="android:textColor">?android:attr/colorError</item>
     </style>
 
     <style name="TextAppearance.QS.DetailButton">
@@ -366,7 +366,7 @@
     </style>
 
     <style name="TextAppearance.NotificationGuts.SecondaryWarning">
-        <item name="android:textColor">@color/system_warning_color</item>
+        <item name="android:textColor">?android:attr/colorError</item>
         <item name="android:textSize">12sp</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index f1e7d53..ac7ab9d 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -47,6 +47,8 @@
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -233,6 +235,9 @@
         mProviders.put(FragmentService.class, () ->
                 new FragmentService(mContext));
 
+        mProviders.put(ExtensionController.class, () ->
+                new ExtensionControllerImpl());
+
         // Put all dependencies above here so the factory can override them if it wants.
         SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index df01aab..8f7a81c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -242,12 +242,17 @@
                             entry = Pair.<String, String>create(packageAndClassName[0], null);
                             break;
                         case 2:
-                            entry = Pair.<String, String>create(
-                                    packageAndClassName[0],
-                                    packageAndClassName[0] + packageAndClassName[1]);
+                            if (packageAndClassName[1] != null
+                                    && packageAndClassName[1].startsWith(".")) {
+                                entry = Pair.<String, String>create(
+                                        packageAndClassName[0],
+                                        packageAndClassName[0] + packageAndClassName[1]);
+                            }
                     }
                     if (entry != null) {
                         sSettingsPackageAndClassNamePairList.add(entry);
+                    } else {
+                        Log.w(TAG, "Ignoring malformed settings name " + settings[i]);
                     }
                 }
             }
@@ -332,12 +337,11 @@
      * Moves the PIPed activity to the fullscreen and closes PIP system UI.
      */
     void movePipToFullscreen() {
-        mState = STATE_NO_PIP;
         mPipTaskId = TASK_ID_NO_PIP;
         for (int i = mListeners.size() - 1; i >= 0; --i) {
             mListeners.get(i).onMoveToFullscreen();
         }
-        resizePinnedStack(mState);
+        resizePinnedStack(STATE_NO_PIP);
         updatePipVisibility(false);
     }
 
@@ -383,6 +387,7 @@
         if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state);
         boolean wasRecentsShown =
                 (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED);
+        boolean wasStateNoPip = (mState == STATE_NO_PIP);
         mState = state;
         for (int i = mListeners.size() - 1; i >= 0; --i) {
             mListeners.get(i).onPipResizeAboutToStart();
@@ -396,6 +401,11 @@
         switch (mState) {
             case STATE_NO_PIP:
                 mCurrentPipBounds = null;
+                // If the state was already STATE_NO_PIP, then do not resize the stack below as it
+                // will not exist
+                if (wasStateNoPip) {
+                    return;
+                }
                 break;
             case STATE_PIP_MENU:
                 mCurrentPipBounds = mMenuModePipBounds;
@@ -413,18 +423,16 @@
                 mCurrentPipBounds = mPipBounds;
                 break;
         }
-        if (mCurrentPipBounds != null) {
-            try {
-                int animationDurationMs = -1;
-                if (wasRecentsShown
-                        && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
-                    animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
-                }
-                mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
-                        true, true, true, animationDurationMs);
-            } catch (RemoteException e) {
-                Log.e(TAG, "resizeStack failed", e);
+        try {
+            int animationDurationMs = -1;
+            if (wasRecentsShown
+                    && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
+                animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
             }
+            mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
+                    true, true, true, animationDurationMs);
+        } catch (RemoteException e) {
+            Log.e(TAG, "resizeStack failed", e);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
index 8b4bd7b..0c3e40c 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
@@ -133,14 +133,7 @@
 
     public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls,
             boolean allowMultiple) {
-        ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
-        if (info == null) {
-            throw new RuntimeException(cls + " doesn't provide an interface");
-        }
-        if (TextUtils.isEmpty(info.action())) {
-            throw new RuntimeException(cls + " doesn't provide an action");
-        }
-        addPluginListener(info.action(), listener, cls, allowMultiple);
+        addPluginListener(getAction(cls), listener, cls, allowMultiple);
     }
 
     public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
@@ -285,6 +278,17 @@
         return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
     }
 
+    public static <P> String getAction(Class<P> cls) {
+        ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
+        if (info == null) {
+            throw new RuntimeException(cls + " doesn't provide an interface");
+        }
+        if (TextUtils.isEmpty(info.action())) {
+            throw new RuntimeException(cls + " doesn't provide an action");
+        }
+        return info.action();
+    }
+
     private class AllPluginClassLoader extends ClassLoader {
         public AllPluginClassLoader(ClassLoader classLoader) {
             super(classLoader);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 09ce2ad..daf0622 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -39,6 +39,7 @@
 import android.util.Slog;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -175,8 +176,7 @@
                         .setOnlyAlertOnce(true)
                         .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
                         .setVisibility(Notification.VISIBILITY_PUBLIC)
-                        .setColor(mContext.getColor(
-                                com.android.internal.R.color.battery_saver_mode_color));
+                        .setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
         if (hasBatterySettings()) {
             nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
         }
@@ -245,8 +245,7 @@
                         .setVisibility(Notification.VISIBILITY_PUBLIC)
                         .setContentIntent(pendingBroadcast(ACTION_CLICKED_TEMP_WARNING))
                         .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_TEMP_WARNING))
-                        .setColor(mContext.getColor(
-                                com.android.internal.R.color.battery_saver_mode_color));
+                        .setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
         SystemUI.overrideNotificationAppName(mContext, nb);
         final Notification n = nb.build();
         mNoMan.notifyAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, n, UserHandle.ALL);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
index dad8bea..65238b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
@@ -203,16 +203,28 @@
                     }
                 }
             });
-            final ImageView disconnect = (ImageView) view.findViewById(android.R.id.icon2);
-            disconnect.setVisibility(item.canDisconnect ? VISIBLE : GONE);
-            disconnect.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    if (mCallback != null) {
-                        mCallback.onDetailItemDisconnect(item);
+
+            final ImageView icon2 = (ImageView) view.findViewById(android.R.id.icon2);
+            if (item.canDisconnect) {
+                icon2.setImageResource(R.drawable.ic_qs_cancel);
+                icon2.setVisibility(VISIBLE);
+                icon2.setClickable(true);
+                icon2.setOnClickListener(new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        if (mCallback != null) {
+                            mCallback.onDetailItemDisconnect(item);
+                        }
                     }
-                }
-            });
+                });
+            } else if (item.icon2 != -1) {
+                icon2.setVisibility(VISIBLE);
+                icon2.setImageResource(item.icon2);
+                icon2.setClickable(false);
+            } else {
+                icon2.setVisibility(GONE);
+            }
+
             return view;
         }
     };
@@ -245,6 +257,7 @@
         public CharSequence line2;
         public Object tag;
         public boolean canDisconnect;
+        public int icon2 = -1;
     }
 
     public interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index dea56aa1..cdde6ea 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -87,7 +87,7 @@
     private void setTileIcon() {
         try {
             PackageManager pm = mContext.getPackageManager();
-            int flags = PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+            int flags = PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DIRECT_BOOT_AWARE;
             if (isSystemApp(pm)) {
                 flags |= PackageManager.MATCH_DISABLED_COMPONENTS;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
index c7b6aea..9cd79f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -91,7 +91,7 @@
                     formatBytes(info.usageLevel));
             bottom = res.getString(R.string.quick_settings_cellular_detail_data_limit,
                     formatBytes(info.limitLevel));
-            usageColor = mContext.getColor(R.color.system_warning_color);
+            usageColor = Utils.getDefaultColor(mContext, android.R.attr.colorError);
         }
 
         if (usageColor == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 90a9db6..796967c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -372,9 +372,9 @@
                     item.icon = mWifiController.getIcon(ap);
                     item.line1 = ap.getSsid();
                     item.line2 = ap.isActive() ? ap.getSummary() : null;
-                    item.overlay = ap.getSecurity() != AccessPoint.SECURITY_NONE
-                            ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock)
-                            : null;
+                    item.icon2 = ap.getSecurity() != AccessPoint.SECURITY_NONE
+                            ? R.drawable.qs_ic_wifi_lock
+                            : -1;
                     items[i] = item;
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 02b0113..e0dac09 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -197,6 +197,7 @@
                     bm.getHeight() - thumbnailData.insets.top - thumbnailData.insets.bottom);
             mThumbnailData = thumbnailData;
             updateThumbnailMatrix();
+            updateThumbnailPaintFilter();
         } else {
             mBitmapShader = null;
             mDrawPaint.setShader(null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index bc992d8..fb92a67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -42,6 +42,7 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
@@ -365,7 +366,7 @@
             if (!updateMonitor.isUnlockingWithFingerprintAllowed()) {
                 return;
             }
-            int errorColor = mContext.getResources().getColor(R.color.system_warning_color, null);
+            int errorColor = Utils.getColorError(mContext);
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(helpString, errorColor);
             } else if (updateMonitor.isDeviceInteractive()
@@ -388,7 +389,7 @@
                     || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
                 return;
             }
-            int errorColor = mContext.getResources().getColor(R.color.system_warning_color, null);
+            int errorColor = Utils.getColorError(mContext);
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 // When swiping up right after receiving a fingerprint error, the bouncer calls
                 // authenticate leading to the same message being shown again on the bouncer.
@@ -411,8 +412,7 @@
         @Override
         public void onScreenTurnedOn() {
             if (mMessageToShowOnScreenOn != null) {
-                int errorColor = mContext.getResources().getColor(R.color.system_warning_color,
-                        null);
+                int errorColor = Utils.getColorError(mContext);
                 showTransientIndication(mMessageToShowOnScreenOn, errorColor);
                 // We want to keep this message around in case the screen was off
                 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 89041f9..67be99e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -83,6 +83,8 @@
     private int mWifiStrengthId = 0;
     private int mLastWifiBadgeId = -1;
     private int mLastWifiStrengthId = -1;
+    private int mWifiActivityId = 0;
+    private int mLastWifiActivityId = -1;
     private boolean mIsAirplaneMode = false;
     private int mAirplaneIconId = 0;
     private int mLastAirplaneIconId = -1;
@@ -97,6 +99,7 @@
     ViewGroup mEthernetGroup, mWifiGroup;
     View mNoSimsCombo;
     ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark;
+    ImageView mWifiActivity;
     View mWifiAirplaneSpacer;
     View mWifiSignalSpacer;
     LinearLayout mMobileSignalGroup;
@@ -177,6 +180,7 @@
         mWifiGroup      = (ViewGroup) findViewById(R.id.wifi_combo);
         mWifi           = (ImageView) findViewById(R.id.wifi_signal);
         mWifiDark       = (ImageView) findViewById(R.id.wifi_signal_dark);
+        mWifiActivity   = (ImageView) findViewById(R.id.wifi_inout);
         mAirplane       = (ImageView) findViewById(R.id.airplane);
         mNoSims         = (ImageView) findViewById(R.id.no_sims);
         mNoSimsDark     = (ImageView) findViewById(R.id.no_sims_dark);
@@ -267,6 +271,10 @@
         mWifiStrengthId = statusIcon.icon;
         mWifiBadgeId = statusIcon.iconOverlay;
         mWifiDescription = statusIcon.contentDescription;
+        mWifiActivityId = activityIn && activityOut ? R.drawable.stat_sys_wifi_inout
+                : activityIn ? R.drawable.stat_sys_wifi_in
+                : activityOut ? R.drawable.stat_sys_wifi_out
+                : 0;
 
         apply();
     }
@@ -286,6 +294,10 @@
         state.mMobileTypeDescription = typeContentDescription;
         state.mIsMobileTypeIconWide = statusType != 0 && isWide;
         state.mRoaming = roaming;
+        state.mMobileActivityId = activityIn && activityOut ? R.drawable.stat_sys_signal_inout
+                : activityIn ? R.drawable.stat_sys_signal_in
+                : activityOut ? R.drawable.stat_sys_signal_out
+                : 0;
 
         apply();
     }
@@ -409,6 +421,10 @@
             mLastWifiStrengthId = -1;
             mLastWifiBadgeId = -1;
         }
+        if (mWifiActivity !=  null) {
+            mWifiActivity.setImageDrawable(null);
+            mLastWifiActivityId = -1;
+        }
 
         for (PhoneState state : mPhoneStates) {
             if (state.mMobile != null) {
@@ -425,6 +441,10 @@
                 state.mMobileType.setImageDrawable(null);
                 state.mLastMobileTypeId = -1;
             }
+            if (state.mMobileActivity != null) {
+                state.mMobileActivity.setImageDrawable(null);
+                state.mLastMobileActivityId = -1;
+            }
         }
 
         if (mAirplane != null) {
@@ -484,6 +504,12 @@
                 mLastWifiStrengthId = mWifiStrengthId;
                 mLastWifiBadgeId = mWifiBadgeId;
             }
+            if (mWifiActivityId != mLastWifiActivityId) {
+                if (mWifiActivityId != 0) {
+                    setIconForView(mWifiActivity, mWifiActivityId);
+                }
+                mLastWifiActivityId = mWifiActivityId;
+            }
             mWifiGroup.setContentDescription(mWifiDescription);
             mWifiGroup.setVisibility(View.VISIBLE);
         } else {
@@ -495,6 +521,8 @@
                     (mWifiVisible ? "VISIBLE" : "GONE"),
                     mWifiStrengthId));
 
+        mWifiActivity.setVisibility(mWifiActivityId != 0 ? View.VISIBLE : View.GONE);
+
         boolean anyMobileVisible = false;
         int firstMobileTypeId = 0;
         for (PhoneState state : mPhoneStates) {
@@ -603,6 +631,8 @@
         applyDarkIntensity(
                 DarkIconDispatcher.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
                 mWifi, mWifiDark);
+        setTint(mWifiActivity,
+                DarkIconDispatcher.getTint(mTintArea, mWifiActivity, mIconTint));
         applyDarkIntensity(
                 DarkIconDispatcher.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
                 mEthernet, mEthernetDark);
@@ -627,15 +657,17 @@
     private class PhoneState {
         private final int mSubId;
         private boolean mMobileVisible = false;
-        private int mMobileStrengthId = 0, mMobileTypeId = 0;
+        private int mMobileStrengthId = 0, mMobileTypeId = 0, mMobileActivityId = 0;
         private int mLastMobileStrengthId = -1;
         private int mLastMobileTypeId = -1;
+        private int mLastMobileActivityId = -1;
         private boolean mIsMobileTypeIconWide;
         private String mMobileDescription, mMobileTypeDescription;
 
         private ViewGroup mMobileGroup;
         private ImageView mMobile, mMobileDark, mMobileType, mMobileRoaming;
         public boolean mRoaming;
+        private ImageView mMobileActivity;
 
         public PhoneState(int subId, Context context) {
             ViewGroup root = (ViewGroup) LayoutInflater.from(context)
@@ -650,6 +682,7 @@
             mMobileDark     = (ImageView) root.findViewById(R.id.mobile_signal_dark);
             mMobileType     = (ImageView) root.findViewById(R.id.mobile_type);
             mMobileRoaming  = (ImageView) root.findViewById(R.id.mobile_roaming);
+            mMobileActivity = (ImageView) root.findViewById(R.id.mobile_inout);
         }
 
         public boolean apply(boolean isSecondaryIcon) {
@@ -664,6 +697,11 @@
                     mMobileType.setImageResource(mMobileTypeId);
                     mLastMobileTypeId = mMobileTypeId;
                 }
+
+                if (mLastMobileActivityId != mMobileActivityId) {
+                    mMobileActivity.setImageResource(mMobileActivityId);
+                    mLastMobileActivityId = mMobileActivityId;
+                }
                 mMobileGroup.setContentDescription(mMobileTypeDescription
                         + " " + mMobileDescription);
                 mMobileGroup.setVisibility(View.VISIBLE);
@@ -686,6 +724,7 @@
 
             mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
             mMobileRoaming.setVisibility(mRoaming ? View.VISIBLE : View.GONE);
+            mMobileActivity.setVisibility(mMobileActivityId != 0 ? View.VISIBLE : View.GONE);
 
             return mMobileVisible;
         }
@@ -747,6 +786,8 @@
             setTint(mMobileType, DarkIconDispatcher.getTint(tintArea, mMobileType, tint));
             setTint(mMobileRoaming, DarkIconDispatcher.getTint(tintArea, mMobileRoaming,
                     tint));
+            setTint(mMobileActivity,
+                    DarkIconDispatcher.getTint(tintArea, mMobileActivity, tint));
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index ed71e57..f3c2bc5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -33,6 +33,7 @@
 import android.util.Log;
 import android.view.View;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
@@ -167,7 +168,7 @@
                 mSemiTransparent = context.getColor(
                         com.android.internal.R.color.system_bar_background_semi_transparent);
                 mTransparent = context.getColor(R.color.system_bar_background_transparent);
-                mWarning = context.getColor(com.android.internal.R.color.battery_saver_mode_color);
+                mWarning = Utils.getColorAttr(context, android.R.attr.colorError);
             }
             mGradient = context.getDrawable(gradientResourceId);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 8f63d45..2538bdd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,9 +19,10 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
+import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
+import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_UNLOCK;
-import static com.android.systemui.tuner.LockscreenFragment.getIntentButton;
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -79,9 +80,12 @@
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.policy.AccessibilityController;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionController.Extension;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.PreviewInflater;
 import com.android.systemui.tuner.LockscreenFragment;
+import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -91,8 +95,7 @@
  */
 public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
         UnlockMethodCache.OnUnlockMethodChangedListener,
-        AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener,
-        Tunable {
+        AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {
 
     final static String TAG = "StatusBar/KeyguardBottomAreaView";
 
@@ -159,12 +162,10 @@
     private Drawable mLeftAssistIcon;
 
     private IntentButton mRightButton = new DefaultRightButton();
-    private IntentButton mRightDefault = mRightButton;
-    private IntentButton mRightPlugin;
+    private Extension<IntentButton> mRightExtension;
     private String mRightButtonStr;
     private IntentButton mLeftButton = new DefaultLeftButton();
-    private IntentButton mLeftDefault = mLeftButton;
-    private IntentButton mLeftPlugin;
+    private Extension<IntentButton> mLeftExtension;
     private String mLeftButtonStr;
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mDozing;
@@ -261,21 +262,28 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mAccessibilityController.addStateChangedCallback(this);
-        Dependency.get(PluginManager.class).addPluginListener(RIGHT_BUTTON_PLUGIN,
-                mRightListener, IntentButtonProvider.class, false /* Only allow one */);
-        Dependency.get(PluginManager.class).addPluginListener(LEFT_BUTTON_PLUGIN,
-                mLeftListener, IntentButtonProvider.class, false /* Only allow one */);
-        Dependency.get(TunerService.class).addTunable(this, LockscreenFragment.LOCKSCREEN_LEFT_BUTTON,
-                LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON);
+        mRightExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class)
+                .withPlugin(IntentButtonProvider.class, RIGHT_BUTTON_PLUGIN,
+                        p -> p.getIntentButton())
+                .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_RIGHT_BUTTON))
+                .withDefault(() -> new DefaultRightButton())
+                .withCallback(button -> setRightButton(button))
+                .build();
+        mLeftExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class)
+                .withPlugin(IntentButtonProvider.class, LEFT_BUTTON_PLUGIN,
+                        p -> p.getIntentButton())
+                .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_LEFT_BUTTON))
+                .withDefault(() -> new DefaultLeftButton())
+                .withCallback(button -> setLeftButton(button))
+                .build();
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         mAccessibilityController.removeStateChangedCallback(this);
-        Dependency.get(PluginManager.class).removePluginListener(mRightListener);
-        Dependency.get(PluginManager.class).removePluginListener(mLeftListener);
-        Dependency.get(TunerService.class).removeTunable(this);
+        mRightExtension.destroy();
+        mLeftExtension.destroy();
     }
 
     private void initAccessibility() {
@@ -790,63 +798,21 @@
         inflateCameraPreview();
     }
 
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (LockscreenFragment.LOCKSCREEN_LEFT_BUTTON.equals(key)) {
-            mLeftButtonStr = newValue;
-            mLeftIsVoiceAssist = TextUtils.isEmpty(mLeftButtonStr) && mLeftPlugin == null;
-            mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault);
-            updateLeftAffordance();
-        } else {
-            mRightButtonStr = newValue;
-            mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault);
-            updateRightAffordanceIcon();
-            updateCameraVisibility();
-            inflateCameraPreview();
-        }
-    }
-
     private void setRightButton(IntentButton button) {
-        mRightPlugin = button;
-        mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault);
+        mRightButton = button;
         updateRightAffordanceIcon();
         updateCameraVisibility();
         inflateCameraPreview();
     }
 
     private void setLeftButton(IntentButton button) {
-        mLeftPlugin = button;
-        mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault);
-        mLeftIsVoiceAssist = false;
+        mLeftButton = button;
+        if (!(mLeftButton instanceof DefaultLeftButton)) {
+            mLeftIsVoiceAssist = false;
+        }
         updateLeftAffordance();
     }
 
-    private final PluginListener<IntentButtonProvider> mRightListener =
-            new PluginListener<IntentButtonProvider>() {
-        @Override
-        public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) {
-            setRightButton(plugin.getIntentButton());
-        }
-
-        @Override
-        public void onPluginDisconnected(IntentButtonProvider plugin) {
-            setRightButton(null);
-        }
-    };
-
-    private final PluginListener<IntentButtonProvider> mLeftListener =
-            new PluginListener<IntentButtonProvider>() {
-        @Override
-        public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) {
-            setLeftButton(plugin.getIntentButton());
-        }
-
-        @Override
-        public void onPluginDisconnected(IntentButtonProvider plugin) {
-            setLeftButton(null);
-        }
-    };
-
     public void setDozing(boolean dozing, boolean animate) {
         mDozing = dozing;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 0e7b2f3..c070869 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -29,6 +29,7 @@
 import android.os.UserManager;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
+import android.telephony.SubscriptionInfo;
 import android.util.AttributeSet;
 import android.util.SparseBooleanArray;
 import android.view.View;
@@ -64,6 +65,8 @@
 import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
 import com.android.systemui.tuner.TunerService;
 
+import java.util.List;
+
 public class QuickStatusBarHeader extends BaseStatusBarHeader implements
         NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
         SignalCallback {
@@ -440,10 +443,20 @@
         }
     }
 
+    @Override
+    public void setSubs(List<SubscriptionInfo> subs) {
+        mRoamingsBySubId.clear();
+        updateRoaming();
+    }
+
     public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
             int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
             String description, boolean isWide, int subId, boolean roaming) {
         mRoamingsBySubId.put(subId, roaming);
+        updateRoaming();
+    }
+
+    private void updateRoaming() {
         boolean isRoaming = calculateRoaming();
         if (mIsRoaming != isRoaming) {
             mIsRoaming = isRoaming;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 213b0aa..a6b145e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5742,9 +5742,8 @@
         if (snoozeOption.criterion != null) {
             mNotificationListener.snoozeNotification(sbn.getKey(), snoozeOption.criterion.getId());
         } else {
-            GregorianCalendar snoozeUntil = new GregorianCalendar();
-            snoozeUntil.add(Calendar.MINUTE, snoozeOption.snoozeForMinutes);
-            mNotificationListener.snoozeNotification(sbn.getKey(), snoozeUntil.getTimeInMillis());
+            mNotificationListener.snoozeNotification(sbn.getKey(),
+                    snoozeOption.snoozeForMinutes * 60 * 1000);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
new file mode 100644
index 0000000..eaf8925
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.Plugin;
+
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Utility class used to select between a plugin, tuner settings, and a default implementation
+ * of an interface.
+ */
+public interface ExtensionController {
+
+    <T> ExtensionBuilder<T> newExtension(Class<T> cls);
+
+    interface Extension<T> {
+        T get();
+        void destroy();
+    }
+
+    interface ExtensionBuilder<T> {
+        ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory);
+        <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls);
+        <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls, String action);
+        <P> ExtensionBuilder<T> withPlugin(Class<P> cls, String action,
+                PluginConverter<T, P> converter);
+        ExtensionBuilder<T> withDefault(Supplier<T> def);
+        ExtensionBuilder<T> withCallback(Consumer<T> callback);
+        Extension build();
+    }
+
+    public interface PluginConverter<T, P> {
+        T getInterfaceFromPlugin(P plugin);
+    }
+
+    public interface TunerFactory<T> {
+        String[] keys();
+        T create(Map<String, String> settings);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
new file mode 100644
index 0000000..fefbaa3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
+
+import android.content.Context;
+import android.util.ArrayMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class ExtensionControllerImpl implements ExtensionController {
+
+    @Override
+    public <T> ExtensionBuilder<T> newExtension(Class<T> cls) {
+        return new ExtensionBuilder<>();
+    }
+
+    private interface Producer<T> {
+        T get();
+        void destroy();
+    }
+
+    private class ExtensionBuilder<T> implements ExtensionController.ExtensionBuilder<T> {
+
+        private ExtensionImpl<T> mExtension = new ExtensionImpl<>();
+
+        @Override
+        public ExtensionController.ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory) {
+            mExtension.addTunerFactory(factory, factory.keys());
+            return this;
+        }
+
+        @Override
+        public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls) {
+            return withPlugin(cls, PluginManager.getAction(cls));
+        }
+
+        @Override
+        public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls,
+                String action) {
+            return withPlugin(cls, action, null);
+        }
+
+        @Override
+        public <P> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls,
+                String action, PluginConverter<T, P> converter) {
+            mExtension.addPlugin(action, cls, converter);
+            return this;
+        }
+
+        @Override
+        public ExtensionController.ExtensionBuilder<T> withDefault(Supplier<T> def) {
+            mExtension.addDefault(def);
+            return this;
+        }
+
+        @Override
+        public ExtensionController.ExtensionBuilder<T> withCallback(
+                Consumer<T> callback) {
+            mExtension.mCallbacks.add(callback);
+            return this;
+        }
+
+        @Override
+        public ExtensionController.Extension build() {
+            // Manually sort, plugins first, tuners second, defaults last.
+            Collections.sort(mExtension.mProducers, (o1, o2) -> {
+                if (o1 instanceof ExtensionImpl.PluginItem) {
+                    if (o2 instanceof ExtensionImpl.PluginItem) {
+                        return 0;
+                    } else {
+                        return -1;
+                    }
+                }
+                if (o1 instanceof ExtensionImpl.TunerItem) {
+                    if (o2 instanceof ExtensionImpl.PluginItem) {
+                        return 1;
+                    } else if (o2 instanceof ExtensionImpl.TunerItem) {
+                        return 0;
+                    } else {
+                        return -1;
+                    }
+                }
+                return 0;
+            });
+            mExtension.notifyChanged();
+            return mExtension;
+        }
+    }
+
+    private class ExtensionImpl<T> implements ExtensionController.Extension<T> {
+        private final ArrayList<Producer<T>> mProducers = new ArrayList<>();
+        private final ArrayList<Consumer<T>> mCallbacks = new ArrayList<>();
+        private T mItem;
+
+        @Override
+        public T get() {
+            return mItem;
+        }
+
+        @Override
+        public void destroy() {
+            for (int i = 0; i < mProducers.size(); i++) {
+                mProducers.get(i).destroy();
+            }
+        }
+
+        private void notifyChanged() {
+            for (int i = 0; i < mProducers.size(); i++) {
+                final T item = mProducers.get(i).get();
+                if (item != null) {
+                    mItem = item;
+                    break;
+                }
+            }
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                mCallbacks.get(i).accept(mItem);
+            }
+        }
+
+        public void addDefault(Supplier<T> def) {
+            mProducers.add(new Default(def));
+        }
+
+        public <P> void addPlugin(String action, Class<P> cls, PluginConverter<T, P> converter) {
+            mProducers.add(new PluginItem(action, cls, converter));
+        }
+
+        public void addTunerFactory(TunerFactory<T> factory, String[] keys) {
+            mProducers.add(new TunerItem(factory, factory.keys()));
+        }
+
+        private class PluginItem<P extends Plugin> implements Producer<T>, PluginListener<P> {
+            private final PluginConverter<T, P> mConverter;
+            private T mItem;
+
+            public PluginItem(String action, Class<P> cls, PluginConverter<T, P> converter) {
+                mConverter = converter;
+                Dependency.get(PluginManager.class).addPluginListener(action, this, cls);
+            }
+
+            @Override
+            public void onPluginConnected(P plugin, Context pluginContext) {
+                if (mConverter != null) {
+                    mItem = mConverter.getInterfaceFromPlugin(plugin);
+                } else {
+                    mItem = (T) plugin;
+                }
+                notifyChanged();
+            }
+
+            @Override
+            public void onPluginDisconnected(P plugin) {
+                mItem = null;
+                notifyChanged();
+            }
+
+            @Override
+            public T get() {
+                return mItem;
+            }
+
+            @Override
+            public void destroy() {
+                Dependency.get(PluginManager.class).removePluginListener(this);
+            }
+        }
+
+        private class TunerItem<T> implements Producer<T>, Tunable {
+            private final TunerFactory<T> mFactory;
+            private final ArrayMap<String, String> mSettings = new ArrayMap<>();
+            private T mItem;
+
+            public TunerItem(TunerFactory<T> factory, String... setting) {
+                mFactory = factory;
+                Dependency.get(TunerService.class).addTunable(this, setting);
+            }
+
+            @Override
+            public T get() {
+                return mItem;
+            }
+
+            @Override
+            public void destroy() {
+                Dependency.get(TunerService.class).removeTunable(this);
+            }
+
+            @Override
+            public void onTuningChanged(String key, String newValue) {
+                mSettings.put(key, newValue);
+                mItem = mFactory.create(mSettings);
+                notifyChanged();
+            }
+        }
+
+        private class Default<T> implements Producer<T> {
+            private final Supplier<T> mSupplier;
+
+            public Default(Supplier<T> supplier) {
+                mSupplier = supplier;
+            }
+
+            @Override
+            public T get() {
+                return mSupplier.get();
+            }
+
+            @Override
+            public void destroy() {
+
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index a85426c..51d931e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -717,6 +717,7 @@
             mDemoMode = true;
             mDemoInetCondition = mInetCondition;
             mDemoWifiState = mWifiSignalController.getState();
+            mDemoWifiState.ssid = "DemoMode";
         } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
             if (DEBUG) Log.d(TAG, "Exiting demo mode");
             mDemoMode = false;
@@ -762,6 +763,25 @@
                             : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
                     mDemoWifiState.connected = mDemoWifiState.level >= 0;
                 }
+                String activity = args.getString("activity");
+                if (activity != null) {
+                    switch (activity) {
+                        case "inout":
+                            mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_INOUT);
+                            break;
+                        case "in":
+                            mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_IN);
+                            break;
+                        case "out":
+                            mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_OUT);
+                            break;
+                        default:
+                            mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
+                            break;
+                    }
+                } else {
+                    mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
+                }
                 mDemoWifiState.enabled = show;
                 mWifiSignalController.notifyListeners();
             }
@@ -831,7 +851,23 @@
                 }
                 String activity = args.getString("activity");
                 if (activity != null) {
-                    controller.setActivity(Integer.parseInt(activity));
+                    controller.getState().dataConnected = true;
+                    switch (activity) {
+                        case "inout":
+                            controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
+                            break;
+                        case "in":
+                            controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN);
+                            break;
+                        case "out":
+                            controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT);
+                            break;
+                        default:
+                            controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
+                            break;
+                    }
+                } else {
+                    controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
                 }
                 controller.getState().enabled = show;
                 controller.notifyListeners();
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index 0a962f1..7c98e13 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -163,7 +163,7 @@
         intent.putExtra("sims", "1");
         intent.putExtra("nosim", "false");
         intent.putExtra("level", "4");
-        intent.putExtra("datatypel", "");
+        intent.putExtra("datatype", "lte");
         getContext().sendBroadcast(intent);
 
         // Need to send this after so that the sim controller already exists.
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
index 410d3d2..2df1793 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
@@ -52,11 +52,13 @@
 import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
 import com.android.systemui.statusbar.ScalingDrawableWrapper;
 import com.android.systemui.statusbar.phone.ExpandableIndicator;
+import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory;
 import com.android.systemui.tuner.ShortcutParser.Shortcut;
 import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.function.Consumer;
 
 public class LockscreenFragment extends PreferenceFragment {
@@ -313,26 +315,39 @@
         }
     }
 
-    public static IntentButton getIntentButton(Context context, String buttonStr,
-            IntentButton plugin, IntentButton def) {
-        // Plugin wins.
-        if (plugin != null) return plugin;
-        // Then tuner options.
-        if (!TextUtils.isEmpty(buttonStr)) {
-            if (buttonStr.contains("::")) {
-                Shortcut shortcut = getShortcutInfo(context, buttonStr);
-                if (shortcut != null) {
-                    return new ShortcutButton(context, shortcut);
-                }
-            } else if (buttonStr.contains("/")) {
-                ActivityInfo info = getActivityinfo(context, buttonStr);
-                if (info != null) {
-                    return new ActivityButton(context, info);
+    public static class LockButtonFactory implements TunerFactory<IntentButton> {
+
+        private final String mKey;
+        private final Context mContext;
+
+        public LockButtonFactory(Context context, String key) {
+            mContext = context;
+            mKey = key;
+        }
+
+        @Override
+        public String[] keys() {
+            return new String[]{mKey};
+        }
+
+        @Override
+        public IntentButton create(Map<String, String> settings) {
+            String buttonStr = settings.get(mKey);
+            if (!TextUtils.isEmpty(buttonStr)) {
+                if (buttonStr.contains("::")) {
+                    Shortcut shortcut = getShortcutInfo(mContext, buttonStr);
+                    if (shortcut != null) {
+                        return new ShortcutButton(mContext, shortcut);
+                    }
+                } else if (buttonStr.contains("/")) {
+                    ActivityInfo info = getActivityinfo(mContext, buttonStr);
+                    if (info != null) {
+                        return new ActivityButton(mContext, info);
+                    }
                 }
             }
+            return null;
         }
-        // Then default.
-        return def;
     }
 
     private static class ShortcutButton implements IntentButton {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 6c454e1..c0e7e80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -23,7 +23,6 @@
 import android.os.MessageQueue;
 import android.support.test.InstrumentationRegistry;
 import android.util.ArrayMap;
-import android.util.Log;
 
 import com.android.systemui.Dependency.DependencyKey;
 import com.android.systemui.utils.TestableContext;
@@ -32,8 +31,6 @@
 import org.junit.After;
 import org.junit.Before;
 
-import java.lang.Thread.UncaughtExceptionHandler;
-
 /**
  * Base class that does System UI specific setup.
  */
@@ -92,8 +89,10 @@
         return null;
     }
 
-    public <T> void injectMockDependency(Class<T> cls) {
-        injectTestDependency(cls, mock(cls));
+    public <T> T injectMockDependency(Class<T> cls) {
+        final T mock = mock(cls);
+        mDependency.injectTestDependency(cls, mock);
+        return mock;
     }
 
     public <T> void injectTestDependency(Class<T> cls, T obj) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
index 72f6ca8..b8be4fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
@@ -25,7 +25,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(SysUIRunner.class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 public class NotificationMenuRowTest extends LeakCheckedTest {
 
     @Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStatusBarHeaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStatusBarHeaderTest.java
new file mode 100644
index 0000000..99cecff
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStatusBarHeaderTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.R.layout;
+import com.android.systemui.SysUIRunner;
+import com.android.systemui.utils.TestableLooper;
+import com.android.systemui.utils.TestableLooper.RunWithLooper;
+import com.android.systemui.utils.ViewUtils;
+import com.android.systemui.utils.leaks.LeakCheckedTest;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(SysUIRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+public class QuickStatusBarHeaderTest extends LeakCheckedTest {
+
+    @Before
+    public void setup() throws NoSuchFieldException, IllegalAccessException {
+        injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
+    }
+
+    @Test
+    @Ignore("Flaky")
+    public void testRoamingStuck() throws Exception {
+        TestableLooper looper = TestableLooper.get(this);
+        assertEquals(Looper.myLooper(), looper.getLooper());
+        assertEquals(Looper.myLooper(), Looper.getMainLooper());
+        QuickStatusBarHeader header = (QuickStatusBarHeader) LayoutInflater.from(mContext).inflate(
+                layout.quick_status_bar_expanded_header, null);
+        header.setExpanded(true);
+
+        ViewUtils.attachView(header);
+        looper.processMessages(1);
+        TextView emergencyText = (TextView) header.findViewById(
+                R.id.header_emergency_calls_only);
+        int subId = 0;
+        header.setMobileDataIndicators(null, null, 0, 0, false,
+                false, null, null, false, subId, true);
+        looper.processAllMessages();
+        assertEquals(mContext.getString(R.string.accessibility_data_connection_roaming),
+                emergencyText.getText());
+        assertEquals(View.VISIBLE, emergencyText.getVisibility());
+
+        header.setSubs(new ArrayList<>());
+        subId = 1;
+        header.setMobileDataIndicators(null, null, 0, 0, false,
+                false, null, null, false, subId, false);
+        looper.processAllMessages();
+
+        assertNotEquals(View.VISIBLE, emergencyText.getVisibility());
+        assertEquals(Looper.myLooper(), Looper.getMainLooper());
+        ViewUtils.detachView(header);
+        looper.processAllMessages();
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerTest.java
new file mode 100644
index 0000000..e3a5ef0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.OverlayPlugin;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.statusbar.policy.ExtensionController.Extension;
+import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory;
+import com.android.systemui.tuner.TunerService;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Map;
+import java.util.function.Consumer;
+
+public class ExtensionControllerTest extends SysuiTestCase {
+
+    private PluginManager mPluginManager;
+    private TunerService mTunerService;
+    private ExtensionController mExtensionController;
+
+    @Before
+    public void setup() {
+        mPluginManager = injectMockDependency(PluginManager.class);
+        mTunerService = injectMockDependency(TunerService.class);
+        mExtensionController = Dependency.get(ExtensionController.class);
+    }
+
+    @Test
+    public void testPlugin() {
+        Extension ext = mExtensionController.newExtension(OverlayPlugin.class)
+                .withPlugin(OverlayPlugin.class)
+                .build();
+        verify(mPluginManager).addPluginListener(eq(OverlayPlugin.ACTION), any(),
+                eq(OverlayPlugin.class));
+
+        ext.destroy();
+        verify(mPluginManager).removePluginListener(any());
+    }
+
+    @Test
+    public void testTuner() {
+        String[] keys = new String[] { "key1", "key2" };
+        TunerFactory<Object> factory = new ExtensionController.TunerFactory() {
+            @Override
+            public String[] keys() {
+                return keys;
+            }
+
+            @Override
+            public Object create(Map settings) {
+                return null;
+            }
+        };
+        Extension ext = mExtensionController.newExtension(Object.class)
+                .withTunerFactory(factory)
+                .build();
+        verify(mTunerService).addTunable(any(), eq(keys[0]), eq(keys[1]));
+
+        ext.destroy();
+        verify(mTunerService).removeTunable(any());
+    }
+
+    @Test
+    public void testDefault() {
+        Object o = new Object();
+        Extension ext = mExtensionController.newExtension(Object.class)
+                .withDefault(() -> o)
+                .build();
+        assertEquals(o, ext.get());
+    }
+
+    @Test
+    public void testCallback() {
+        Consumer<Object> callback = mock(Consumer.class);
+        final Object o = new Object();
+        mExtensionController.newExtension(Object.class)
+                .withDefault(() -> o)
+                .withCallback(callback)
+                .build();
+        verify(callback).accept(eq(o));
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java
index d275973..8902e0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableLooper.java
@@ -244,9 +244,11 @@
                 mLooper.setAsMainLooper();
             }
 
-            mBase.evaluate();
-
-            mLooper.destroy();
+            try {
+                mBase.evaluate();
+            } finally {
+                mLooper.destroy();
+            }
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java b/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
index 07e5f66..678b9f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/ViewUtils.java
@@ -14,9 +14,11 @@
 
 package com.android.systemui.utils;
 
+import android.content.pm.ApplicationInfo;
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.Looper;
+import android.util.Log;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
@@ -27,18 +29,19 @@
 public class ViewUtils {
 
     public static void attachView(View view) {
+        // Make sure hardware acceleration isn't turned on.
+        view.getContext().getApplicationInfo().flags &=
+                ~(ApplicationInfo.FLAG_HARDWARE_ACCELERATED);
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
                 LayoutParams.TYPE_APPLICATION_OVERLAY,
                 0, PixelFormat.TRANSLUCENT);
-        Handler handler = new Handler(Looper.getMainLooper());
-        handler.post(() -> InstrumentationRegistry.getContext()
-                .getSystemService(WindowManager.class).addView(view, lp));
+        InstrumentationRegistry.getContext()
+                .getSystemService(WindowManager.class).addView(view, lp);
     }
 
     public static void detachView(View view) {
-        Handler handler = new Handler(Looper.getMainLooper());
-        handler.post(() -> InstrumentationRegistry.getContext()
-                .getSystemService(WindowManager.class).removeView(view));
+        InstrumentationRegistry.getContext()
+                .getSystemService(WindowManager.class).removeViewImmediate(view);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
new file mode 100644
index 0000000..c0f5783
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils.leaks;
+
+import static org.mockito.Mockito.mock;
+
+import com.android.systemui.statusbar.policy.ExtensionController;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class FakeExtensionController implements ExtensionController {
+
+    private final Tracker mTracker;
+
+    public FakeExtensionController(LeakCheckedTest test) {
+        mTracker = test.getTracker("extension");
+    }
+
+    @Override
+    public <T> ExtensionBuilder<T> newExtension(Class<T> cls) {
+        final Object o = new Object();
+        mTracker.getLeakInfo(o).addAllocation(new Throwable());
+        return new FakeExtensionBuilder(o);
+    }
+
+    private class FakeExtensionBuilder<T> implements ExtensionBuilder<T> {
+        private final Object mAllocation;
+
+        public FakeExtensionBuilder(Object o) {
+            mAllocation = o;
+        }
+
+        @Override
+        public ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory) {
+            return this;
+        }
+
+        @Override
+        public <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls) {
+            return this;
+        }
+
+        @Override
+        public <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls, String action) {
+            return this;
+        }
+
+        @Override
+        public <P> ExtensionBuilder<T> withPlugin(Class<P> cls, String action, PluginConverter<T, P> converter) {
+            return this;
+        }
+
+        @Override
+        public ExtensionBuilder<T> withDefault(Supplier<T> def) {
+            return this;
+        }
+
+        @Override
+        public ExtensionBuilder<T> withCallback(Consumer<T> callback) {
+            return this;
+        }
+
+        @Override
+        public Extension build() {
+            return new FakeExtension(mAllocation);
+        }
+    }
+
+    private class FakeExtension<T> implements Extension<T> {
+        private final Object mAllocation;
+
+        public FakeExtension(Object allocation) {
+            mAllocation = allocation;
+        }
+
+        @Override
+        public T get() {
+            // TODO: Support defaults or things.
+            return null;
+        }
+
+        @Override
+        public void destroy() {
+            mTracker.getLeakInfo(mAllocation).clearAllocations();
+        }
+    }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index c7f518c..c1c385a 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3466,6 +3466,12 @@
     // OS: O
     ENCRYPTION_AND_CREDENTIAL = 846;
 
+    // ACTION: Settings > About device > Build number
+    ACTION_SETTINGS_BUILD_NUMBER_PREF = 847;
+
+    // FIELD: Whether developer mode has already been enabled when clicking build number preference
+    FIELD_SETTINGS_BUILD_NUMBER_DEVELOPER_MODE_ENABLED = 848;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index bf3681b..447a47d 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -19,22 +19,17 @@
 
 LOCAL_STATIC_LIBRARIES :=
 
-rs_generated_include_dir := $(call intermediates-dir-for,SHARED_LIBRARIES,libRS,,)
-
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE) \
     frameworks/rs \
     frameworks/base/core/jni \
-    frameworks/base/libs/hwui \
-    $(rs_generated_include_dir)
+    frameworks/base/libs/hwui
 
 LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
-LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
 LOCAL_MODULE:= librs_jni
-LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
 LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRS libRSDriver
+LOCAL_REQUIRED_MODULES := libRS
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index af370ff..2300da3 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -35,8 +35,8 @@
 #include "android_runtime/android_util_AssetManager.h"
 #include "android/graphics/GraphicsJNI.h"
 
-#include <rs.h>
 #include <rsEnv.h>
+#include <rsApiStubs.h>
 #include <gui/Surface.h>
 #include <gui/GLConsumer.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
@@ -1134,7 +1134,7 @@
     // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
     assert(dataSize == 5);
 
-    uintptr_t elementData[5];
+    uint32_t elementData[5];
     rsaElementGetNativeData((RsContext)con, (RsElement)id, elementData, dataSize);
 
     for(jint i = 0; i < dataSize; i ++) {
@@ -1157,7 +1157,7 @@
 
     uintptr_t *ids = (uintptr_t*)malloc(dataSize * sizeof(uintptr_t));
     const char **names = (const char **)malloc(dataSize * sizeof(const char *));
-    uint32_t *arraySizes = (uint32_t *)malloc(dataSize * sizeof(uint32_t));
+    size_t *arraySizes = (size_t *)malloc(dataSize * sizeof(size_t));
 
     rsaElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes,
                              (uint32_t)dataSize);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 4d2b106..c50623e 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -709,7 +709,7 @@
     }
 
     private boolean isUserRunningAndUnlocked(@UserIdInt int userId) {
-        return mUserManager.isUserRunning(userId) && StorageManager.isUserKeyUnlocked(userId);
+        return mUserManager.isUserUnlockingOrUnlocked(userId);
     }
 
     @Override
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index f7cb010..bfc6e83 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -56,6 +56,7 @@
 import android.service.autofill.Dataset;
 import android.service.autofill.FillResponse;
 import android.service.autofill.IAutoFillService;
+import android.service.autofill.SaveInfo;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -719,18 +720,19 @@
                 }
                 return;
             }
-            final ArraySet<AutoFillId> savableIds = mCurrentResponse.getSavableIds();
+            final SaveInfo saveInfo = mCurrentResponse.getSaveInfo();
             if (DEBUG) {
-                Slog.d(TAG, "showSaveLocked(): savableIds=" + savableIds);
+                Slog.d(TAG, "showSaveLocked(): saveInfo=" + saveInfo);
             }
 
-            if (savableIds == null || savableIds.isEmpty()) {
+            if (saveInfo == null || saveInfo.getSavableIds() == null
+                    || saveInfo.getSavableIds().isEmpty()) {
                 return;
             }
 
-            final int size = savableIds.size();
+            final int size = saveInfo.getSavableIds().size();
             for (int i = 0; i < size; i++) {
-                final AutoFillId id = savableIds.valueAt(i);
+                final AutoFillId id = saveInfo.getSavableIds().valueAt(i);
                 final ViewState state = mViewStates.get(id);
                 if (state != null && state.mValueUpdated) {
                     final AutoFillValue filledValue = findValue(mAutoFilledDataset, id);
@@ -741,8 +743,9 @@
                         Slog.d(TAG, "finishSessionLocked(): found a change on " + id + ": "
                                 + state.mAutoFillValue);
                     }
-                    getUiForShowing().showSaveUi(mInfo.getServiceInfo()
-                            .loadLabel(mContext.getPackageManager()));
+                    getUiForShowing().showSaveUi(
+                            mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()),
+                            saveInfo);
                     return;
                 }
             }
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index cc0baa3..949a80c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -24,6 +24,7 @@
 import android.os.IBinder;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillResponse;
+import android.service.autofill.SaveInfo;
 import android.text.TextUtils;
 import android.view.autofill.AutoFillId;
 import android.widget.Toast;
@@ -172,13 +173,13 @@
     /**
      * Shows the UI asking the user to save for auto-fill.
      */
-    public void showSaveUi(@NonNull CharSequence providerLabel) {
+    public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info) {
         mHandler.post(() -> {
             if (!hasCallback()) {
                 return;
             }
             hideAllUiThread();
-            mSaveUi = new SaveUi(mContext, providerLabel,
+            mSaveUi = new SaveUi(mContext, providerLabel, info,
                     new SaveUi.OnSaveListener() {
                 @Override
                 public void onSave() {
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index b7215d6..afe93c7 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -20,6 +20,7 @@
 import android.app.Dialog;
 import android.content.Context;
 import android.os.Handler;
+import android.service.autofill.SaveInfo;
 import android.text.format.DateUtils;
 import android.view.Gravity;
 import android.view.Window;
@@ -50,15 +51,41 @@
 
     private boolean mDestroyed;
 
-    SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel,
+    SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info,
             @NonNull OnSaveListener listener) {
         mListener = listener;
 
         final LayoutInflater inflater = LayoutInflater.from(context);
         final View view = inflater.inflate(R.layout.autofill_save, null);
 
-        final TextView title = (TextView) view.findViewById(R.id.autofill_save_title);
-        title.setText(context.getString(R.string.autofill_save_title, providerLabel));
+        final TextView titleView = (TextView) view.findViewById(R.id.autofill_save_title);
+        final String type;
+
+        switch(info.getType()) {
+            case SaveInfo.SAVE_DATA_TYPE_PASSWORD:
+                type = context.getString(R.string.autofill_save_type_password);
+                break;
+            case SaveInfo.SAVE_DATA_TYPE_ADDRESS:
+                type = context.getString(R.string.autofill_save_type_address);
+                break;
+            case SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD:
+                type = context.getString(R.string.autofill_save_type_credit_card);
+                break;
+            default:
+                type = null;
+        }
+
+        final String title = (type == null)
+                ? context.getString(R.string.autofill_save_title, providerLabel)
+                : context.getString(R.string.autofill_save_title_with_type, type, providerLabel);
+
+        titleView.setText(title);
+        final CharSequence subTitle = info.getDescription();
+        if (subTitle != null) {
+            final TextView subTitleView = (TextView) view.findViewById(R.id.autofill_save_subtitle);
+            subTitleView.setText(subTitle);
+            subTitleView.setVisibility(View.VISIBLE);
+        }
 
         final View noButton = view.findViewById(R.id.autofill_save_no);
         noButton.setOnClickListener((v) -> mListener.onCancel());
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index ef7780c..979096e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.annotation.NonNull;
 import android.content.pm.PackageManagerInternal;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
@@ -104,6 +105,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
@@ -225,6 +227,12 @@
 
     private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
 
+    private final ArrayMap<IGnssMeasurementsListener, Identity> mGnssMeasurementsListeners =
+            new ArrayMap<>();
+
+    private final ArrayMap<IGnssNavigationMessageListener, Identity>
+            mGnssNavigationMessageListeners = new ArrayMap<>();
+
     // current active user on the device - other users are denied location data
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
     private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
@@ -315,17 +323,17 @@
                     boolean foreground = isImportanceForeground(importance);
                     HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
                     synchronized (mLock) {
-                        for (Map.Entry<String, ArrayList<UpdateRecord>> entry
+                        for (Entry<String, ArrayList<UpdateRecord>> entry
                                 : mRecordsByProvider.entrySet()) {
                             String provider = entry.getKey();
                             for (UpdateRecord record : entry.getValue()) {
-                                if (record.mReceiver.mUid == uid
+                                if (record.mReceiver.mIdentity.mUid == uid
                                         && record.mIsForegroundUid != foreground) {
                                     if (D) Log.d(TAG, "request from uid " + uid + " is now "
                                             + (foreground ? "foreground" : "background)"));
                                     record.mIsForegroundUid = foreground;
 
-                                    if (!isThrottlingExemptLocked(record.mReceiver)) {
+                                    if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
                                         affectedProviders.add(provider);
                                     }
                                 }
@@ -334,6 +342,33 @@
                         for (String provider : affectedProviders) {
                             applyRequirementsLocked(provider);
                         }
+
+                        for (Entry<IGnssMeasurementsListener, Identity> entry
+                                : mGnssMeasurementsListeners.entrySet()) {
+                            if (entry.getValue().mUid == uid) {
+                                if (D) Log.d(TAG, "gnss measurements listener from uid " + uid
+                                    + " is now " + (foreground ? "foreground" : "background)"));
+                                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+                                    mGnssMeasurementsProvider.addListener(entry.getKey());
+                                } else {
+                                    mGnssMeasurementsProvider.removeListener(entry.getKey());
+                                }
+                            }
+                        }
+
+                        for (Entry<IGnssNavigationMessageListener, Identity> entry
+                            : mGnssNavigationMessageListeners.entrySet()) {
+                            if (entry.getValue().mUid == uid) {
+                                if (D) Log.d(TAG, "gnss navigation message listener from uid "
+                                    + uid + " is now "
+                                    + (foreground ? "foreground" : "background)"));
+                                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+                                    mGnssNavigationMessageProvider.addListener(entry.getKey());
+                                } else {
+                                    mGnssNavigationMessageProvider.removeListener(entry.getKey());
+                                }
+                            }
+                        }
                     }
 
                 }
@@ -344,7 +379,7 @@
             mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
             updateUserProfiles(mCurrentUserId);
 
-            updateThrottlingWhitelistLocked();
+            updateBackgroundThrottlingWhitelistLocked();
 
             // prepare providers
             loadProvidersLocked();
@@ -381,7 +416,7 @@
                 @Override
                 public void onChange(boolean selfChange) {
                     synchronized (mLock) {
-                        updateThrottlingWhitelistLocked();
+                        updateBackgroundThrottlingWhitelistLocked();
                         updateProvidersLocked();
                     }
                 }
@@ -721,14 +756,24 @@
         }
     }
 
+    private static final class Identity {
+        final int mUid;
+        final int mPid;
+        final String mPackageName;
+
+        Identity(int uid, int pid, String packageName) {
+            mUid = uid;
+            mPid = pid;
+            mPackageName = packageName;
+        }
+    }
+
     /**
      * A wrapper class holding either an ILocationListener or a PendingIntent to receive
      * location updates.
      */
     private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
-        final int mUid;  // uid of receiver
-        final int mPid;  // pid of receiver
-        final String mPackageName;  // package name of receiver
+        final Identity mIdentity;
         final int mAllowedResolutionLevel;  // resolution level allowed to receiver
 
         final ILocationListener mListener;
@@ -756,9 +801,7 @@
                 mKey = intent;
             }
             mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
-            mUid = uid;
-            mPid = pid;
-            mPackageName = packageName;
+            mIdentity = new Identity(uid, pid, packageName);
             if (workSource != null && workSource.size() <= 0) {
                 workSource = null;
             }
@@ -770,7 +813,7 @@
             // construct/configure wakelock
             mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
             if (workSource == null) {
-                workSource = new WorkSource(mUid, mPackageName);
+                workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
             }
             mWakeLock.setWorkSource(workSource);
         }
@@ -865,13 +908,14 @@
                 int op) {
             if (!currentlyMonitoring) {
                 if (allowMonitoring) {
-                    return mAppOps.startOpNoThrow(op, mUid, mPackageName)
+                    return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
                             == AppOpsManager.MODE_ALLOWED;
                 }
             } else {
-                if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
+                if (!allowMonitoring
+                        || mAppOps.checkOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
                         != AppOpsManager.MODE_ALLOWED) {
-                    mAppOps.finishOp(op, mUid, mPackageName);
+                    mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
                     return false;
                 }
             }
@@ -1628,7 +1672,7 @@
         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
         if (records != null) {
             for (UpdateRecord record : records) {
-                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
+                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                     // Sends a notification message to the receiver
                     if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
                         if (deadReceivers == null) {
@@ -1673,16 +1717,16 @@
 
         if (records != null) {
             for (UpdateRecord record : records) {
-                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
+                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                     if (checkLocationAccess(
-                            record.mReceiver.mPid,
-                            record.mReceiver.mUid,
-                            record.mReceiver.mPackageName,
+                            record.mReceiver.mIdentity.mPid,
+                            record.mReceiver.mIdentity.mUid,
+                            record.mReceiver.mIdentity.mPackageName,
                             record.mReceiver.mAllowedResolutionLevel)) {
                         LocationRequest locationRequest = record.mRequest;
                         long interval = locationRequest.getInterval();
 
-                        if (!isThrottlingExemptLocked(record.mReceiver)) {
+                        if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
                             if (!record.mIsForegroundUid) {
                                 interval = Math.max(interval, backgroundThrottleInterval);
                             }
@@ -1709,7 +1753,7 @@
                 // under that threshold.
                 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
                 for (UpdateRecord record : records) {
-                    if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
+                    if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                         LocationRequest locationRequest = record.mRequest;
 
                         // Don't assign battery blame for update records whose
@@ -1728,8 +1772,8 @@
                             } else {
                                 // Assign blame to caller.
                                 worksource.add(
-                                        record.mReceiver.mUid,
-                                        record.mReceiver.mPackageName);
+                                        record.mReceiver.mIdentity.mUid,
+                                        record.mReceiver.mIdentity.mPackageName);
                             }
                         }
                     }
@@ -1741,7 +1785,15 @@
         p.setRequest(providerRequest, worksource);
     }
 
-    private void updateThrottlingWhitelistLocked() {
+    @Override
+    public String[] getBackgroundThrottlingWhitelist() {
+        synchronized (mLock) {
+            return mBackgroundThrottlePackageWhitelist.toArray(
+                new String[mBackgroundThrottlePackageWhitelist.size()]);
+        }
+    }
+
+    private void updateBackgroundThrottlingWhitelistLocked() {
         String setting = Settings.Global.getString(
             mContext.getContentResolver(),
             Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
@@ -1756,17 +1808,17 @@
             Arrays.asList(setting.split(",")));
     }
 
-    private boolean isThrottlingExemptLocked(Receiver receiver) {
-        if (receiver.mUid == Process.SYSTEM_UID) {
+    private boolean isThrottlingExemptLocked(Identity identity) {
+        if (identity.mUid == Process.SYSTEM_UID) {
             return true;
         }
 
-        if (mBackgroundThrottlePackageWhitelist.contains(receiver.mPackageName)) {
+        if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
             return true;
         }
 
         for (LocationProviderProxy provider : mProxyProviders) {
-            if (receiver.mPackageName.equals(provider.getConnectedPackageName())) {
+            if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
                 return true;
             }
         }
@@ -1790,7 +1842,7 @@
             mRequest = request;
             mReceiver = receiver;
             mIsForegroundUid = isImportanceForeground(
-                    mActivityManager.getPackageImportance(mReceiver.mPackageName));
+                    mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
 
             ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
             if (records == null) {
@@ -1803,14 +1855,14 @@
 
             // Update statistics for historical location requests by package/provider
             mRequestStatistics.startRequesting(
-                    mReceiver.mPackageName, provider, request.getInterval());
+                    mReceiver.mIdentity.mPackageName, provider, request.getInterval());
         }
 
         /**
          * Method to be called when a record will no longer be used.
          */
         void disposeLocked(boolean removeReceiver) {
-            mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
+            mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
 
             // remove from mRecordsByProvider
             ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
@@ -1834,8 +1886,8 @@
 
         @Override
         public String toString() {
-            return "UpdateRecord[" + mProvider + " " + mReceiver.mPackageName
-                    + "(" + mReceiver.mUid + (mIsForegroundUid ? " foreground" : " background")
+            return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
+                    + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground" : " background")
                     + ")" + " " + mRequest + "]";
         }
     }
@@ -1994,7 +2046,8 @@
         if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
                 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
                 + (record.mIsForegroundUid ? "foreground" : "background")
-                + (isThrottlingExemptLocked(receiver) ? " [whitelisted]" : "") + ")");
+                + (isThrottlingExemptLocked(receiver.mIdentity)
+                    ? " [whitelisted]" : "") + ")");
 
         UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
         if (oldRecord != null) {
@@ -2227,13 +2280,33 @@
         if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
             return false;
         }
-        return mGnssMeasurementsProvider.addListener(listener);
+
+        synchronized (mLock) {
+            Identity callerIdentity
+                    = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+            mGnssMeasurementsListeners.put(listener, callerIdentity);
+            long identity = Binder.clearCallingIdentity();
+            try {
+                if (isThrottlingExemptLocked(callerIdentity)
+                        || isImportanceForeground(
+                                mActivityManager.getPackageImportance(packageName))) {
+                    return mGnssMeasurementsProvider.addListener(listener);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+
+            return true;
+        }
     }
 
     @Override
     public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
         if (mGnssMeasurementsProvider != null) {
-            mGnssMeasurementsProvider.removeListener(listener);
+            synchronized (mLock) {
+                mGnssMeasurementsListeners.remove(listener);
+                mGnssMeasurementsProvider.removeListener(listener);
+            }
         }
     }
 
@@ -2244,13 +2317,33 @@
         if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
             return false;
         }
-        return mGnssNavigationMessageProvider.addListener(listener);
+
+        synchronized (mLock) {
+            Identity callerIdentity
+                = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+            mGnssNavigationMessageListeners.put(listener, callerIdentity);
+            long identity = Binder.clearCallingIdentity();
+            try {
+                if (isThrottlingExemptLocked(callerIdentity)
+                        || isImportanceForeground(
+                                mActivityManager.getPackageImportance(packageName))) {
+                    return mGnssNavigationMessageProvider.addListener(listener);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+
+            return true;
+        }
     }
 
     @Override
     public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
         if (mGnssNavigationMessageProvider != null) {
-            mGnssNavigationMessageProvider.removeListener(listener);
+            synchronized (mLock) {
+                mGnssNavigationMessageListeners.remove(listener);
+                mGnssNavigationMessageProvider.removeListener(listener);
+            }
         }
     }
 
@@ -2529,26 +2622,30 @@
             Receiver receiver = r.mReceiver;
             boolean receiverDead = false;
 
-            int receiverUserId = UserHandle.getUserId(receiver.mUid);
-            if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
+            int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
+            if (!isCurrentProfile(receiverUserId)
+                    && !isUidALocationProvider(receiver.mIdentity.mUid)) {
                 if (D) {
                     Log.d(TAG, "skipping loc update for background user " + receiverUserId +
                             " (current user: " + mCurrentUserId + ", app: " +
-                            receiver.mPackageName + ")");
+                            receiver.mIdentity.mPackageName + ")");
                 }
                 continue;
             }
 
-            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
+            if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
                 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
-                        receiver.mPackageName);
+                        receiver.mIdentity.mPackageName);
                 continue;
             }
 
-            if (!reportLocationAccessNoThrow(receiver.mPid, receiver.mUid, receiver.mPackageName,
+            if (!reportLocationAccessNoThrow(
+                    receiver.mIdentity.mPid,
+                    receiver.mIdentity.mUid,
+                    receiver.mIdentity.mPackageName,
                     receiver.mAllowedResolutionLevel)) {
                 if (D) Log.d(TAG, "skipping loc update for no op app: " +
-                        receiver.mPackageName);
+                        receiver.mIdentity.mPackageName);
                 continue;
             }
 
@@ -2671,7 +2768,7 @@
                 ArrayList<Receiver> deadReceivers = null;
 
                 for (Receiver receiver : mReceivers.values()) {
-                    if (receiver.mPackageName.equals(packageName)) {
+                    if (receiver.mIdentity.mPackageName.equals(packageName)) {
                         if (deadReceivers == null) {
                             deadReceivers = new ArrayList<>();
                         }
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index b33538cb..d54ebaa 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -35,8 +35,7 @@
 import android.net.INetworkScoreService;
 import android.net.NetworkKey;
 import android.net.NetworkScoreManager;
-import android.net.NetworkScorerAppManager;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScorerAppData;
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
@@ -132,10 +131,10 @@
      * manages the service connection.
      */
     private class NetworkScorerPackageMonitor extends PackageMonitor {
-        final List<String> mPackagesToWatch;
+        final String mPackageToWatch;
 
-        private NetworkScorerPackageMonitor(List<String> packagesToWatch) {
-            mPackagesToWatch = packagesToWatch;
+        private NetworkScorerPackageMonitor(String packageToWatch) {
+            mPackageToWatch = packageToWatch;
         }
 
         @Override
@@ -168,37 +167,27 @@
             evaluateBinding(packageName, true /* forceUnbind */);
         }
 
-        private void evaluateBinding(String scorerPackageName, boolean forceUnbind) {
-            if (!mPackagesToWatch.contains(scorerPackageName)) {
+        private void evaluateBinding(String changedPackageName, boolean forceUnbind) {
+            if (!mPackageToWatch.equals(changedPackageName)) {
                 // Early exit when we don't care about the package that has changed.
                 return;
             }
 
             if (DBG) {
-                Log.d(TAG, "Evaluating binding for: " + scorerPackageName
+                Log.d(TAG, "Evaluating binding for: " + changedPackageName
                         + ", forceUnbind=" + forceUnbind);
             }
+
             final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
             if (activeScorer == null) {
                 // Package change has invalidated a scorer, this will also unbind any service
                 // connection.
                 if (DBG) Log.d(TAG, "No active scorers available.");
-                unbindFromScoringServiceIfNeeded();
-            } else if (activeScorer.getRecommendationServicePackageName().equals(scorerPackageName))
-            {
-                // The active scoring service changed in some way.
-                if (DBG) {
-                    Log.d(TAG, "Possible change to the active scorer: "
-                            + activeScorer.getRecommendationServicePackageName());
-                }
+                refreshBinding();
+            } else { // The scoring service changed in some way.
                 if (forceUnbind) {
                     unbindFromScoringServiceIfNeeded();
                 }
-                bindToScoringServiceIfNeeded(activeScorer);
-            } else {
-                // One of the scoring apps on the device has changed and we may no longer be
-                // bound to the correct scoring app. The logic in bindToScoringServiceIfNeeded()
-                // will sort that out to leave us bound to the most recent active scorer.
                 if (DBG) {
                     Log.d(TAG, "Binding to " + activeScorer.getRecommendationServiceComponent()
                             + " if needed.");
@@ -272,60 +261,71 @@
     /** Called when the system is ready to run third-party code but before it actually does so. */
     void systemReady() {
         if (DBG) Log.d(TAG, "systemReady");
-        registerPackageMonitorIfNeeded();
         registerRecommendationSettingsObserver();
-        refreshRecommendationRequestTimeoutMs();
     }
 
     /** Called when the system is ready for us to start third-party code. */
     void systemRunning() {
         if (DBG) Log.d(TAG, "systemRunning");
-        bindToScoringServiceIfNeeded();
     }
 
-    private void onUserUnlocked(int userId) {
+    @VisibleForTesting
+    void onUserUnlocked(int userId) {
+        if (DBG) Log.d(TAG, "onUserUnlocked(" + userId + ")");
+        refreshBinding();
+    }
+
+    private void refreshBinding() {
+        if (DBG) Log.d(TAG, "refreshBinding()");
+        // Apply the default package name if the Setting isn't set.
+        mNetworkScorerAppManager.revertToDefaultIfNoActive();
         registerPackageMonitorIfNeeded();
         bindToScoringServiceIfNeeded();
     }
 
     private void registerRecommendationSettingsObserver() {
-        final List<String> providerPackages =
-            mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
-        if (!providerPackages.isEmpty()) {
-            final Uri enabledUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_ENABLED);
-            mContentObserver.observe(enabledUri,
-                    ServiceHandler.MSG_RECOMMENDATIONS_ENABLED_CHANGED);
-        }
+        final Uri packageNameUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_PACKAGE);
+        mContentObserver.observe(packageNameUri,
+                ServiceHandler.MSG_RECOMMENDATIONS_PACKAGE_CHANGED);
 
         final Uri timeoutUri = Global.getUriFor(Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS);
         mContentObserver.observe(timeoutUri,
                 ServiceHandler.MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED);
     }
 
+    /**
+     * Ensures the package manager is registered to monitor the current active scorer.
+     * If a discrepancy is found any previous monitor will be cleaned up
+     * and a new monitor will be created.
+     *
+     * This method is idempotent.
+     */
     private void registerPackageMonitorIfNeeded() {
-        if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded");
-        final List<String> providerPackages =
-            mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
+        if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded()");
+        final NetworkScorerAppData appData = mNetworkScorerAppManager.getActiveScorer();
         synchronized (mPackageMonitorLock) {
             // Unregister the current monitor if needed.
-            if (mPackageMonitor != null) {
+            if (mPackageMonitor != null && (appData == null
+                    || !appData.getRecommendationServicePackageName().equals(
+                            mPackageMonitor.mPackageToWatch))) {
                 if (DBG) {
                     Log.d(TAG, "Unregistering package monitor for "
-                            + mPackageMonitor.mPackagesToWatch);
+                            + mPackageMonitor.mPackageToWatch);
                 }
                 mPackageMonitor.unregister();
                 mPackageMonitor = null;
             }
 
-            // Create and register the monitor if there are packages that could be providers.
-            if (!providerPackages.isEmpty()) {
-                mPackageMonitor = new NetworkScorerPackageMonitor(providerPackages);
+            // Create and register the monitor if a scorer is active.
+            if (appData != null && mPackageMonitor == null) {
+                mPackageMonitor = new NetworkScorerPackageMonitor(
+                        appData.getRecommendationServicePackageName());
                 // TODO: Need to update when we support per-user scorers. http://b/23422763
                 mPackageMonitor.register(mContext, null /* thread */, UserHandle.SYSTEM,
                         false /* externalStorage */);
                 if (DBG) {
                     Log.d(TAG, "Registered package monitor for "
-                            + mPackageMonitor.mPackagesToWatch);
+                            + mPackageMonitor.mPackageToWatch);
                 }
             }
         }
@@ -337,6 +337,13 @@
         bindToScoringServiceIfNeeded(scorerData);
     }
 
+    /**
+     * Ensures the service connection is bound to the current active scorer.
+     * If a discrepancy is found any previous connection will be cleaned up
+     * and a new connection will be created.
+     *
+     * This method is idempotent.
+     */
     private void bindToScoringServiceIfNeeded(NetworkScorerAppData appData) {
         if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + appData + ")");
         if (appData != null) {
@@ -365,6 +372,8 @@
         synchronized (mServiceConnectionLock) {
             if (mServiceConnection != null) {
                 mServiceConnection.disconnect(mContext);
+                if (DBG) Log.d(TAG, "Disconnected from: "
+                        + mServiceConnection.mAppData.getRecommendationServiceComponent());
             }
             mServiceConnection = null;
         }
@@ -653,17 +662,13 @@
 
     @Override
     public boolean setActiveScorer(String packageName) {
-        // TODO: For now, since SCORE_NETWORKS requires an app to be privileged, we allow such apps
-        // to directly set the scorer app rather than having to use the consent dialog. The
-        // assumption is that anyone bundling a scorer app with the system is trusted by the OEM to
-        // do the right thing and not enable this feature without explaining it to the user.
-        // In the future, should this API be opened to 3p apps, we will need to lock this down and
-        // figure out another way to streamline the UX.
-
-        mContext.enforceCallingOrSelfPermission(permission.SCORE_NETWORKS, TAG);
-
-        // Scorers (recommendation providers) are selected and no longer set.
-        return false;
+        // Only the system can set the active scorer
+        if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
+            return mNetworkScorerAppManager.setActiveScorer(packageName);
+        } else {
+            throw new SecurityException(
+                    "Caller is neither the system process nor a score requester.");
+        }
     }
 
     /**
@@ -700,7 +705,6 @@
         return null;
     }
 
-
     /**
      * Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
      */
@@ -727,7 +731,13 @@
      */
     @Override
     public List<NetworkScorerAppData> getAllValidScorers() {
-        return mNetworkScorerAppManager.getAllValidScorers();
+        // Only the system can access this data.
+        if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
+            return mNetworkScorerAppManager.getAllValidScorers();
+        } else {
+            throw new SecurityException(
+                    "Caller is neither the system process nor a score requester.");
+        }
     }
 
     @Override
@@ -1159,7 +1169,7 @@
     @VisibleForTesting
     public final class ServiceHandler extends Handler {
         public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT = 1;
-        public static final int MSG_RECOMMENDATIONS_ENABLED_CHANGED = 2;
+        public static final int MSG_RECOMMENDATIONS_PACKAGE_CHANGED = 2;
         public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED = 3;
 
         public ServiceHandler(Looper looper) {
@@ -1181,8 +1191,8 @@
                     sendDefaultRecommendationResponse(request, remoteCallback);
                     break;
 
-                case MSG_RECOMMENDATIONS_ENABLED_CHANGED:
-                    bindToScoringServiceIfNeeded();
+                case MSG_RECOMMENDATIONS_PACKAGE_CHANGED:
+                    refreshBinding();
                     break;
 
                 case MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED:
diff --git a/services/core/java/com/android/server/NetworkScorerAppManager.java b/services/core/java/com/android/server/NetworkScorerAppManager.java
new file mode 100644
index 0000000..2f4485a
--- /dev/null
+++ b/services/core/java/com/android/server/NetworkScorerAppManager.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.Manifest.permission;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Internal class for discovering and managing the network scorer/recommendation application.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class NetworkScorerAppManager {
+    private static final String TAG = "NetworkScorerAppManager";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+    private final Context mContext;
+    private final SettingsFacade mSettingsFacade;
+
+    public NetworkScorerAppManager(Context context) {
+      this(context, new SettingsFacade());
+    }
+
+    @VisibleForTesting
+    public NetworkScorerAppManager(Context context, SettingsFacade settingsFacade) {
+        mContext = context;
+        mSettingsFacade = settingsFacade;
+    }
+
+    /**
+     * Returns the list of available scorer apps. The list will be empty if there are
+     * no valid scorers.
+     */
+    @VisibleForTesting
+    public List<NetworkScorerAppData> getAllValidScorers() {
+        if (VERBOSE) Log.v(TAG, "getAllValidScorers()");
+        final PackageManager pm = mContext.getPackageManager();
+        final Intent serviceIntent = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
+        final List<ResolveInfo> resolveInfos =
+                pm.queryIntentServices(serviceIntent, PackageManager.GET_META_DATA);
+        if (resolveInfos == null || resolveInfos.isEmpty()) {
+            if (DEBUG) Log.d(TAG, "Found 0 Services able to handle " + serviceIntent);
+            return Collections.emptyList();
+        }
+
+        List<NetworkScorerAppData> appDataList = new ArrayList<>();
+        for (int i = 0; i < resolveInfos.size(); i++) {
+            final ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
+            if (hasPermissions(serviceInfo.packageName)) {
+                if (VERBOSE) {
+                    Log.v(TAG, serviceInfo.packageName + " is a valid scorer/recommender.");
+                }
+                final ComponentName serviceComponentName =
+                        new ComponentName(serviceInfo.packageName, serviceInfo.name);
+                final ComponentName useOpenWifiNetworksActivity =
+                        findUseOpenWifiNetworksActivity(serviceInfo);
+                appDataList.add(
+                        new NetworkScorerAppData(serviceInfo.applicationInfo.uid,
+                                serviceComponentName, useOpenWifiNetworksActivity));
+            } else {
+                if (VERBOSE) Log.v(TAG, serviceInfo.packageName
+                        + " is NOT a valid scorer/recommender.");
+            }
+        }
+
+        return appDataList;
+    }
+
+    @Nullable
+    private ComponentName findUseOpenWifiNetworksActivity(ServiceInfo serviceInfo) {
+        if (serviceInfo.metaData == null) {
+            if (DEBUG) {
+                Log.d(TAG, "No metadata found on " + serviceInfo.getComponentName());
+            }
+            return null;
+        }
+        final String useOpenWifiPackage = serviceInfo.metaData
+                .getString(NetworkScoreManager.USE_OPEN_WIFI_PACKAGE_META_DATA);
+        if (TextUtils.isEmpty(useOpenWifiPackage)) {
+            if (DEBUG) {
+                Log.d(TAG, "No use_open_wifi_package metadata found on "
+                        + serviceInfo.getComponentName());
+            }
+            return null;
+        }
+        final Intent enableUseOpenWifiIntent = new Intent(NetworkScoreManager.ACTION_CUSTOM_ENABLE)
+                .setPackage(useOpenWifiPackage);
+        final ResolveInfo resolveActivityInfo = mContext.getPackageManager()
+                .resolveActivity(enableUseOpenWifiIntent, 0 /* flags */);
+        if (VERBOSE) {
+            Log.d(TAG, "Resolved " + enableUseOpenWifiIntent + " to " + resolveActivityInfo);
+        }
+
+        if (resolveActivityInfo != null && resolveActivityInfo.activityInfo != null) {
+            return resolveActivityInfo.activityInfo.getComponentName();
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the application to use for scoring networks.
+     *
+     * @return the scorer app info or null if scoring is disabled (including if no scorer was ever
+     *     selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
+     *     it was disabled or uninstalled).
+     */
+    @Nullable
+    @VisibleForTesting
+    public NetworkScorerAppData getActiveScorer() {
+        return getScorer(getNetworkRecommendationsPackage());
+    }
+
+    private NetworkScorerAppData getScorer(String packageName) {
+        if (TextUtils.isEmpty(packageName)) {
+            return null;
+        }
+
+        // Otherwise return the recommendation provider (which may be null).
+        List<NetworkScorerAppData> apps = getAllValidScorers();
+        for (int i = 0; i < apps.size(); i++) {
+            NetworkScorerAppData app = apps.get(i);
+            if (app.getRecommendationServicePackageName().equals(packageName)) {
+                return app;
+            }
+        }
+
+        return null;
+    }
+
+    private boolean hasPermissions(String packageName) {
+        final PackageManager pm = mContext.getPackageManager();
+        return pm.checkPermission(permission.SCORE_NETWORKS, packageName)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
+     * Set the specified package as the default scorer application.
+     *
+     * <p>The caller must have permission to write to {@link Settings.Global}.
+     *
+     * @param packageName the packageName of the new scorer to use. If null, the scoring app will
+     *                    revert back to the configured default. Otherwise, the scorer will only
+     *                    be set if it is a valid scorer application.
+     * @return true if the scorer was changed, or false if the package is not a valid scorer or
+     *         a valid network recommendation provider exists.
+     */
+    @VisibleForTesting
+    public boolean setActiveScorer(String packageName) {
+        String oldPackageName = getNetworkRecommendationsPackage();
+        if (TextUtils.equals(oldPackageName, packageName)) {
+            // No change.
+            return true;
+        }
+
+        Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);
+
+        if (packageName == null) {
+            // revert to the default setting.
+            setNetworkRecommendationsPackage(getDefaultPackageSetting());
+            return true;
+        } else {
+            // We only make the change if the new package is valid.
+            if (getScorer(packageName) != null) {
+                setNetworkRecommendationsPackage(packageName);
+                return true;
+            } else {
+                Log.w(TAG, "Requested network scorer is not valid: " + packageName);
+                return false;
+            }
+        }
+    }
+
+    /**
+     * If the active scorer is null then revert to the default scorer.
+     */
+    @VisibleForTesting
+    public void revertToDefaultIfNoActive() {
+        if (getActiveScorer() == null) {
+            final String defaultPackage = getDefaultPackageSetting();
+            setNetworkRecommendationsPackage(defaultPackage);
+            Log.i(TAG, "Defaulted the network recommendations app to: " + defaultPackage);
+        }
+    }
+
+    private String getDefaultPackageSetting() {
+        return mContext.getResources().getString(
+                R.string.config_defaultNetworkRecommendationProviderPackage);
+    }
+
+    private String getNetworkRecommendationsPackage() {
+        return mSettingsFacade.getString(mContext, Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE);
+    }
+
+    private void setNetworkRecommendationsPackage(String packageName) {
+        mSettingsFacade.putString(mContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, packageName);
+    }
+
+    /**
+     * Wrapper around Settings to make testing easier.
+     */
+    public static class SettingsFacade {
+        public boolean putString(Context context, String name, String value) {
+            return Settings.Global.putString(context.getContentResolver(), name, value);
+        }
+
+        public String getString(Context context, String name) {
+            return Settings.Global.getString(context.getContentResolver(), name);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index ce3166d..421d5a6 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.IBinder;
 import android.os.ServiceManager;
+import android.os.UserManager;
 
 /**
  * The base class for services running in the system process. Override and implement
@@ -133,9 +134,16 @@
     public void onStartUser(int userHandle) {}
 
     /**
-     * Called when an existing user is unlocked. This means the
-     * credential-encrypted storage for that user is now available, and
-     * encryption-aware component filtering is no longer in effect.
+     * Called when an existing user is in the process of being unlocked. This
+     * means the credential-encrypted storage for that user is now available,
+     * and encryption-aware component filtering is no longer in effect.
+     * <p>
+     * While dispatching this event to services, the user is in the
+     * {@code STATE_RUNNING_UNLOCKING} state, and once dispatching is finished
+     * the user will transition into the {@code STATE_RUNNING_UNLOCKED} state.
+     * Code written inside system services should use
+     * {@link UserManager#isUserUnlockingOrUnlocked(int)} to handle both of
+     * these states.
      *
      * @param userHandle The identifier of the user.
      */
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7524351..d9b6fd7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3023,15 +3023,24 @@
             startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
         } else {
             finishRunningVoiceLocked();
-            IVoiceInteractionSession session;
-            if (mLastResumedActivity != null
-                    && ((session = mLastResumedActivity.task.voiceSession) != null
-                    || (session = mLastResumedActivity.voiceSession) != null)) {
-                // We had been in a voice interaction session, but now focused has
-                // move to something different.  Just finish the session, we can't
-                // return to it and retain the proper state and synchronization with
-                // the voice interaction service.
-                finishVoiceTask(session);
+
+            if (mLastResumedActivity != null) {
+                final IVoiceInteractionSession session;
+
+                if (mLastResumedActivity.task != null
+                    && mLastResumedActivity.task.voiceSession != null) {
+                    session = mLastResumedActivity.task.voiceSession;
+                } else {
+                    session = mLastResumedActivity.voiceSession;
+                }
+
+                if (session != null) {
+                    // We had been in a voice interaction session, but now focused has
+                    // move to something different.  Just finish the session, we can't
+                    // return to it and retain the proper state and synchronization with
+                    // the voice interaction service.
+                    finishVoiceTask(session);
+                }
             }
         }
 
@@ -10636,7 +10645,7 @@
             providers = AppGlobals.getPackageManager()
                     .queryContentProviders(app.processName, app.uid,
                             STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
-                                    | MATCH_DEBUG_TRIAGED_MISSING)
+                                    | MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null)
                     .getList();
         } catch (RemoteException ex) {
         }
@@ -10708,10 +10717,7 @@
         } catch (RemoteException ignored) {
         }
         if (cpi == null) {
-            // TODO: make this an outright failure in a future platform release;
-            // until then anonymous content notifications are unprotected
-            //return "Failed to find provider " + authority + " for user " + userId;
-            return null;
+            return "Failed to find provider " + authority + " for user " + userId;
         }
 
         ProcessRecord r = null;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index aef429e..10055c8 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -802,10 +802,7 @@
 
         // Remove the activity from the old task and add it to the new task
         prevTask.removeActivity(this);
-        // TODO(b/34179495): This should really be set to null in removeActivity() call above,
-        // but really bad things that I can't track down right now happen when I do that.
-        // So, setting it here now and will change later when there is time for investigation.
-        task = null;
+
         newTask.addActivityAtIndex(position, this);
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 1e33bb9..ab1559d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -177,7 +177,6 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -1196,13 +1195,11 @@
     }
 
     ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
-        try {
-            return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
+        synchronized (mService) {
+            return mService.getPackageManagerInternalLocked().resolveIntent(intent, resolvedType,
                     PackageManager.MATCH_INSTANT | PackageManager.MATCH_DEFAULT_ONLY | flags
                     | ActivityManagerService.STOCK_PM_FLAGS, userId);
-        } catch (RemoteException e) {
         }
-        return null;
     }
 
     ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
@@ -4904,7 +4901,7 @@
                 setResizingDuringAnimation(task);
             }
 
-            mService.mActivityStarter.postStartActivityUncheckedProcessing(task.getTopActivity(),
+            mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(),
                     ActivityManager.START_TASK_TO_FRONT,
                     sourceRecord != null ? sourceRecord.task.getStackId() : INVALID_STACK_ID,
                     sourceRecord, task.getStack());
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 83d43db..d8c5533 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import static android.app.Activity.RESULT_CANCELED;
+import static android.app.ActivityManager.START_CANCELED;
 import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
 import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
 import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED;
@@ -88,12 +89,10 @@
 import android.app.AppGlobals;
 import android.app.IActivityContainer;
 import android.app.IApplicationThread;
-import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.ProfilerInfo;
 import android.app.WaitResult;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -509,33 +508,26 @@
 
         doPendingActivityLaunchesLocked(false);
 
-        try {
-            mService.mWindowManager.deferSurfaceLayout();
-            err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
-                    true, options, inTask);
-        } finally {
-            mService.mWindowManager.continueSurfaceLayout();
-        }
-        postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
-        return err;
+        return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
+            options, inTask);
     }
 
     /** Creates a launch intent for the given auxiliary resolution data. */
     private @NonNull Intent createLaunchIntent(@NonNull AuxiliaryResolveInfo auxiliaryResponse,
-            Intent originalIntent, String callingPackage,
-            String resolvedType, int userId) {
+        Intent originalIntent, String callingPackage,
+        String resolvedType, int userId) {
         if (auxiliaryResponse.needsPhaseTwo) {
             // request phase two resolution
             mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
-                    auxiliaryResponse, originalIntent, resolvedType, callingPackage, userId);
+                auxiliaryResponse, originalIntent, resolvedType, callingPackage, userId);
         }
         return EphemeralResolver.buildEphemeralInstallerIntent(originalIntent,
-                callingPackage, resolvedType, userId, auxiliaryResponse.packageName,
-                auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
-                auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
+            callingPackage, resolvedType, userId, auxiliaryResponse.packageName,
+            auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
+            auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
     }
 
-    void postStartActivityUncheckedProcessing(
+    void postStartActivityProcessing(
             ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
             ActivityStack targetStack) {
 
@@ -937,6 +929,32 @@
         }
     }
 
+    private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
+        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+        int result = START_CANCELED;
+        try {
+            mService.mWindowManager.deferSurfaceLayout();
+            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
+                startFlags,
+                doResume, options, inTask);
+        } finally {
+            // If we are not able to proceed, disassociate the activity from the task. Leaving an
+            // activity in an incomplete state can lead to issues, such as performing operations
+            // without a window container.
+            if (result != START_SUCCESS && mStartActivity.task != null) {
+                mStartActivity.task.removeActivity(mStartActivity);
+            }
+            mService.mWindowManager.continueSurfaceLayout();
+        }
+
+        postStartActivityProcessing(r, result, mSupervisor.mFocusedStack.mStackId,
+            mSourceRecord, mTargetStack);
+
+        return result;
+    }
+
+    // Note: This method should only be called from {@link startActivity}.
     private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
@@ -1843,11 +1861,8 @@
             final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
             final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
             try {
-                final int result = startActivityUnchecked(
-                        pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null, null);
-                postStartActivityUncheckedProcessing(
-                        pal.r, result, mSupervisor.mFocusedStack.mStackId, mSourceRecord,
-                        mTargetStack);
+                startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null,
+                    null);
             } catch (Exception e) {
                 Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
                 pal.sendErrorResult(e.getMessage());
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index f8645d6..b051304 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1083,6 +1083,13 @@
 
     /** @return true if this was the last activity in the task */
     boolean removeActivity(ActivityRecord r) {
+        if (r.task != this) {
+            throw new IllegalArgumentException(
+                "Activity=" + r + " does not belong to task=" + this);
+        }
+
+        r.task = null;
+
         if (mActivities.remove(r) && r.fullscreen) {
             // Was previously in list.
             numFullscreen--;
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index e8ff510..d648dd8 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -51,14 +51,36 @@
     private final static boolean DEBUG = false;
     private final static int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
 
-    private ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
+    private final VolumeShaper.Configuration DUCK_VSHAPE =
+            new VolumeShaper.Configuration.Builder()
+                .setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
+                .setCurve(new float[] { 0.f, 1.f } /* times */,
+                    new float[] { 1.f, 0.2f } /* volumes */)
+                .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME)
+                .setDurationMs(MediaFocusControl.getFocusRampTimeMs(
+                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+                    new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
+                            .build()))
+                .build();
+    private final VolumeShaper.Configuration DUCK_ID =
+            new VolumeShaper.Configuration(VOLUME_SHAPER_SYSTEM_DUCK_ID);
+    private final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
+            new VolumeShaper.Operation.Builder(VolumeShaper.Operation.PLAY)
+                    .createIfNeeded()
+                    .build();
+    private final VolumeShaper.Operation TERMINATE =
+            new VolumeShaper.Operation.Builder()
+                    .terminate()
+                    .build();
+
+    private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
     // a public client is one that needs an anonymized version of the playback configurations, we
     // keep track of whether there is at least one to know when we need to create the list of
     // playback configurations that do not contain uid/pid/package name information.
     private boolean mHasPublicClients = false;
 
     private final Object mPlayerLock = new Object();
-    private HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
+    private final HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
             new HashMap<Integer, AudioPlaybackConfiguration>();
 
     PlaybackActivityMonitor() {
@@ -130,12 +152,10 @@
         synchronized(mPlayerLock) {
             final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
             if (checkConfigurationCaller(piid, apc, binderUid)) {
+                apc.getPlayerProxy().applyVolumeShaper(
+                        DUCK_ID,
+                        TERMINATE);
                 mPlayers.remove(new Integer(piid));
-                final VolumeShaper vs = mDuckVolumeShapers.get(new Integer(piid));
-                if (vs != null) {
-                    vs.release();
-                    mDuckVolumeShapers.remove(new Integer(piid));
-                }
             } else {
                 Log.e(TAG, "Error releasing player " + piid);
             }
@@ -252,20 +272,6 @@
     private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
     private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>();
 
-    private final VolumeShaper.Configuration DUCK_VSHAPE =
-            new VolumeShaper.Configuration.Builder()
-                .setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
-                .setCurve(new float[] { 0.f, 1.f } /* times */,
-                    new float[] { 1.f, 0.2f } /* volumes */)
-                .setDurationMs(MediaFocusControl.getFocusRampTimeMs(
-                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
-                    new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
-                            .build()))
-                .build();
-
-    private final HashMap<Integer, VolumeShaper> mDuckVolumeShapers =
-            new HashMap<Integer, VolumeShaper>();
-
     @Override
     public boolean duckPlayers(FocusRequester winner, FocusRequester loser) {
         if (DEBUG) {
@@ -302,17 +308,9 @@
                     } else {
                         try {
                             if (DEBUG) { Log.v(TAG, "ducking player " + piid); }
-                            final VolumeShaper ducker;
-                            if (mDuckVolumeShapers.containsKey(new Integer(piid))) {
-                                ducker = mDuckVolumeShapers.get(new Integer(piid));
-                            } else {
-                                ducker = new VolumeShaper(
-                                        DUCK_VSHAPE,
-                                        apc.getPlayerProxy(),
-                                        true /* keepReference */);
-                                mDuckVolumeShapers.put(new Integer(piid), ducker);
-                            }
-                            ducker.apply(VolumeShaper.Operation.PLAY); // duck
+                            apc.getPlayerProxy().applyVolumeShaper(
+                                    DUCK_VSHAPE,
+                                    PLAY_CREATE_IF_NEEDED);
                             mDuckedPlayers.add(piid);
                         } catch (Exception e) {
                             Log.e(TAG, "Error ducking player " + piid, e);
@@ -341,10 +339,9 @@
                     try {
                         if (DEBUG) { Log.v(TAG, "unducking player" + piid); }
                         mDuckedPlayers.remove(new Integer(piid));
-                        if (mDuckVolumeShapers.containsKey(new Integer(piid))) {
-                            final VolumeShaper ducker = mDuckVolumeShapers.get(new Integer(piid));
-                            ducker.apply(VolumeShaper.Operation.REVERSE); // unduck
-                        }
+                        apc.getPlayerProxy().applyVolumeShaper(
+                                DUCK_ID,
+                                VolumeShaper.Operation.REVERSE);
                     } catch (Exception e) {
                         Log.e(TAG, "Error unducking player " + piid, e);
                     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 63024db..6106093 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -20,6 +20,8 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
 
 import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.LinkProperties;
@@ -72,6 +74,7 @@
 
     private final Context mContext;
     private final StateMachine mTarget;
+    private final Handler mHandler;
     private final int mWhat;
     private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
     private ConnectivityManager mCM;
@@ -84,6 +87,7 @@
     public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
         mContext = ctx;
         mTarget = tgt;
+        mHandler = mTarget.getHandler();
         mWhat = what;
     }
 
@@ -99,10 +103,10 @@
         final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
                 .clearCapabilities().build();
         mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
-        cm().registerNetworkCallback(listenAllRequest, mListenAllCallback);
+        cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
 
         mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
-        cm().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+        cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
     }
 
     public void stop() {
@@ -154,7 +158,7 @@
         // Additionally, we log a message to aid in any subsequent debugging.
         Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
 
-        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType);
+        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
     }
 
     public void releaseMobileNetworkRequest() {
@@ -185,11 +189,13 @@
             case CALLBACK_TRACK_DEFAULT:
                 if (mDefaultNetworkCallback == null) {
                     // The callback was unregistered in the interval between
-                    // ConnectivityService calling onAvailable() and our
-                    // handling of it here on the mTarget.getHandler() thread.
+                    // ConnectivityService enqueueing onAvailable() and our
+                    // handling of it here on the mHandler thread.
+                    //
                     // Clean-up of this network entry is deferred to the
                     // handling of onLost() by other callbacks.
-                    // TODO: change to Log.wtf() after oag/331764 is merged.
+                    //
+                    // These request*() calls can be deleted post oag/339444.
                     return;
                 }
 
@@ -200,11 +206,13 @@
             case CALLBACK_MOBILE_REQUEST:
                 if (mMobileNetworkCallback == null) {
                     // The callback was unregistered in the interval between
-                    // ConnectivityService calling onAvailable() and our
-                    // handling of it here on the mTarget.getHandler() thread.
+                    // ConnectivityService enqueueing onAvailable() and our
+                    // handling of it here on the mHandler thread.
+                    //
                     // Clean-up of this network entry is deferred to the
                     // handling of onLost() by other callbacks.
-                    // TODO: change to Log.wtf() after oag/331764 is merged.
+                    //
+                    // These request*() calls can be deleted post oag/339444.
                     return;
                 }
 
@@ -312,8 +320,9 @@
     }
 
     /**
-     * A NetworkCallback class that relays information of interest to the
-     * tethering master state machine thread for subsequent processing.
+     * A NetworkCallback class that handles information of interest directly
+     * in the thread on which it is invoked. To avoid locking, this MUST be
+     * run on the same thread as the target state machine's handler.
      */
     private class UpstreamNetworkCallback extends NetworkCallback {
         private final int mCallbackType;
@@ -324,22 +333,35 @@
 
         @Override
         public void onAvailable(Network network) {
-            mTarget.getHandler().post(() -> handleAvailable(mCallbackType, network));
+            checkExpectedThread();
+            handleAvailable(mCallbackType, network);
         }
 
         @Override
         public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
-            mTarget.getHandler().post(() -> handleNetCap(network, newNc));
+            checkExpectedThread();
+            handleNetCap(network, newNc);
         }
 
         @Override
         public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
-            mTarget.getHandler().post(() -> handleLinkProp(network, newLp));
+            checkExpectedThread();
+            handleLinkProp(network, newLp);
         }
 
+        // TODO: Handle onNetworkSuspended();
+        // TODO: Handle onNetworkResumed();
+
         @Override
         public void onLost(Network network) {
-            mTarget.getHandler().post(() -> handleLost(mCallbackType, network));
+            checkExpectedThread();
+            handleLost(mCallbackType, network);
+        }
+
+        private void checkExpectedThread() {
+            if (Looper.myLooper() != mHandler.getLooper()) {
+                Log.wtf(TAG, "Handling callback in unexpected thread.");
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 886c97f..4b34eba56 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -43,6 +43,7 @@
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.FactoryTest;
 import android.os.IBinder;
@@ -287,7 +288,7 @@
      */
     @Override
     public void registerContentObserver(Uri uri, boolean notifyForDescendants,
-                                        IContentObserver observer, int userHandle) {
+            IContentObserver observer, int userHandle, int targetSdkVersion) {
         if (observer == null || uri == null) {
             throw new IllegalArgumentException("You must pass a valid uri and observer");
         }
@@ -301,8 +302,17 @@
         final String msg = LocalServices.getService(ActivityManagerInternal.class)
                 .checkContentProviderAccess(uri.getAuthority(), userHandle);
         if (msg != null) {
-            Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
-            return;
+            if (targetSdkVersion >= Build.VERSION_CODES.O) {
+                throw new SecurityException(msg);
+            } else {
+                if (msg.startsWith("Failed to find provider")) {
+                    // Sigh, we need to quietly let apps targeting older API
+                    // levels notify on non-existent providers.
+                } else {
+                    Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
+                    return;
+                }
+            }
         }
 
         synchronized (mRootNode) {
@@ -316,7 +326,7 @@
     public void registerContentObserver(Uri uri, boolean notifyForDescendants,
                                         IContentObserver observer) {
         registerContentObserver(uri, notifyForDescendants, observer,
-                UserHandle.getCallingUserId());
+                UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
     }
 
     @Override
@@ -340,8 +350,8 @@
      */
     @Override
     public void notifyChange(Uri uri, IContentObserver observer,
-                             boolean observerWantsSelfNotifications, int flags,
-                             int userHandle) {
+            boolean observerWantsSelfNotifications, int flags, int userHandle,
+            int targetSdkVersion) {
         if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
                 + " from observer " + observer + ", flags " + Integer.toHexString(flags));
 
@@ -359,8 +369,17 @@
         final String msg = LocalServices.getService(ActivityManagerInternal.class)
                 .checkContentProviderAccess(uri.getAuthority(), userHandle);
         if (msg != null) {
-            Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
-            return;
+            if (targetSdkVersion >= Build.VERSION_CODES.O) {
+                throw new SecurityException(msg);
+            } else {
+                if (msg.startsWith("Failed to find provider")) {
+                    // Sigh, we need to quietly let apps targeting older API
+                    // levels notify on non-existent providers.
+                } else {
+                    Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
+                    return;
+                }
+            }
         }
 
         // This makes it so that future permission checks will be in the context of this
@@ -427,7 +446,7 @@
                              boolean observerWantsSelfNotifications, boolean syncToNetwork) {
         notifyChange(uri, observer, observerWantsSelfNotifications,
                 syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0,
-                UserHandle.getCallingUserId());
+                UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
     }
 
     /**
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index e83b228..0f29942 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -1180,7 +1180,7 @@
 
             // Statistics about secure fingerprint transactions (e.g. to unlock password
             // storage, make secure purchases, etc.)
-            final PerformanceStats crypto = mPerformanceMap.get(userId);
+            final PerformanceStats crypto = mCryptoPerformanceMap.get(userId);
             if (crypto != null) {
                 final long countsToken = proto.start(FingerprintUserStatsProto.CRYPTO);
                 proto.write(FingerprintActionStatsProto.ACCEPT, crypto.accept);
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index 4795fbf..e6edaf1 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -46,7 +46,9 @@
         if (!appCanShowBadge) {
             record.setShowBadge(false);
         } else {
-            record.setShowBadge(record.getChannel().canShowBadge() && appCanShowBadge);
+            record.setShowBadge(mConfig.getNotificationChannel(record.sbn.getPackageName(),
+                    record.sbn.getUid(), record.getChannel().getId(), false).canShowBadge()
+                    && appCanShowBadge);
         }
 
         return null;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8f4ad00..45ff20b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2029,11 +2029,11 @@
          */
         @Override
         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
-                long snoozeUntil) {
+                long duration) {
             long identity = Binder.clearCallingIdentity();
             try {
                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
-                snoozeNotificationInt(key, snoozeUntil, null, info);
+                snoozeNotificationInt(key, duration, null, info);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -3409,7 +3409,7 @@
 
     @VisibleForTesting
     void scheduleTimeoutLocked(NotificationRecord record) {
-        if (record.getNotification().getTimeout() > System.currentTimeMillis()) {
+        if (record.getNotification().getTimeout() > 0) {
             final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
                     REQUEST_CODE_TIMEOUT,
                     new Intent(ACTION_NOTIFICATION_TIMEOUT)
@@ -3418,8 +3418,8 @@
                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                             .putExtra(EXTRA_KEY, record.getKey()),
                     PendingIntent.FLAG_UPDATE_CURRENT);
-            mAlarmManager.setExactAndAllowWhileIdle(
-                    AlarmManager.RTC_WAKEUP, record.getNotification().getTimeout(), pi);
+            mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    SystemClock.elapsedRealtime() + record.getNotification().getTimeout(), pi);
         }
     }
 
@@ -4185,16 +4185,16 @@
         }
     }
 
-    void snoozeNotificationInt(String key, long until, String snoozeCriterionId,
+    void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
             ManagedServiceInfo listener) {
         String listenerName = listener == null ? null : listener.component.toShortString();
-        if (until < System.currentTimeMillis() && snoozeCriterionId == null) {
+        if (duration <= 0 && snoozeCriterionId == null) {
             return;
         }
 
         if (DBG) {
-            Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, until, snoozeCriterionId,
-                    listenerName));
+            Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
+                    snoozeCriterionId, listenerName));
         }
         // Needs to post so that it can cancel notifications not yet enqueued.
         mHandler.post(new Runnable() {
@@ -4215,7 +4215,7 @@
                                     snoozeCriterionId);
                             mSnoozeHelper.snooze(r);
                         } else {
-                            mSnoozeHelper.snooze(r, until);
+                            mSnoozeHelper.snooze(r, duration);
                         }
                         savePolicyFile();
                     }
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 0cd8cea..913f636 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -32,6 +32,7 @@
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
@@ -125,9 +126,9 @@
     /**
      * Snoozes a notification and schedules an alarm to repost at that time.
      */
-    protected void snooze(NotificationRecord record, long until) {
+    protected void snooze(NotificationRecord record, long duration) {
         snooze(record);
-        scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), until);
+        scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), duration);
     }
 
     /**
@@ -291,13 +292,14 @@
                 PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
-    private void scheduleRepost(String pkg, String key, int userId, long time) {
+    private void scheduleRepost(String pkg, String key, int userId, long duration) {
         long identity = Binder.clearCallingIdentity();
         try {
             final PendingIntent pi = createPendingIntent(pkg, key, userId);
             mAm.cancel(pi);
+            long time = SystemClock.elapsedRealtime() + duration;
             if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
-            mAm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pi);
+            mAm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, pi);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c11131a..71bfa64 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -442,8 +442,8 @@
 
         @Override
         public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
-                String packageName, List shortcutIds, ComponentName componentName, int flags,
-                UserHandle targetUser) {
+                String packageName, List shortcutIds, ComponentName componentName, Intent intent,
+                int flags, UserHandle targetUser) {
             ensureShortcutPermission(callingPackage);
             if (!canAccessProfile(callingPackage, targetUser, "Cannot get shortcuts")
                     || !isUserEnabled(targetUser)) {
@@ -454,11 +454,17 @@
                         "To query by shortcut ID, package name must also be set");
             }
 
+            if ((flags & ShortcutQuery.FLAG_MATCH_CHOOSER) == 0
+                    && intent != null) {
+                throw new IllegalArgumentException("Supplied an intent in the query, but did "
+                        + "not request chooser targets");
+            }
+
             // TODO(b/29399275): Eclipse compiler requires explicit List<ShortcutInfo> cast below.
             return new ParceledListSlice<>((List<ShortcutInfo>)
                     mShortcutServiceInternal.getShortcuts(getCallingUserId(),
                             callingPackage, changedSince, packageName, shortcutIds,
-                            componentName, flags, targetUser.getIdentifier()));
+                            componentName, intent, flags, targetUser.getIdentifier()));
         }
 
         @Override
@@ -906,6 +912,7 @@
                                         cookie.packageName,
                                         /* changedSince= */ 0, packageName, /* shortcutIds=*/ null,
                                         /* component= */ null,
+                                        /* intent= */ null,
                                         ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
                                         | ShortcutQuery.FLAG_GET_ALL_KINDS
                                         , userId);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 53765f2..a7a1683 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -607,6 +607,12 @@
                     + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
         }
 
+        if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
+                || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+            throw new IllegalArgumentException(
+                    "New installs into ASEC containers no longer supported");
+        }
+
         // Defensively resize giant app icons
         if (params.appIcon != null) {
             final ActivityManager am = (ActivityManager) mContext.getSystemService(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8591153..116c0a3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -128,7 +128,6 @@
 import android.content.pm.AppsQueryHelper;
 import android.content.pm.ChangedPackages;
 import android.content.pm.ComponentInfo;
-import android.content.pm.InstantAppInfo;
 import android.content.pm.EphemeralRequest;
 import android.content.pm.EphemeralResolveInfo;
 import android.content.pm.AuxiliaryResolveInfo;
@@ -143,6 +142,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstantAppInfo;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
@@ -204,15 +204,16 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.os.storage.IStorageManager;
-import android.os.storage.StorageManagerInternal;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
+import android.os.storage.StorageManagerInternal;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
+import android.service.pm.PackageServiceDumpProto;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.TextUtils;
@@ -235,6 +236,7 @@
 import android.util.SparseIntArray;
 import android.util.Xml;
 import android.util.jar.StrictJarFile;
+import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 
 import com.android.internal.R;
@@ -316,8 +318,8 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
-import java.util.HashSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -4037,8 +4039,17 @@
 
     /**
      * Update given flags when being used to request {@link ResolveInfo}.
+     * <p>Instant apps are resolved specially, depending upon context. Minimally,
+     * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
+     * flag set. However, this flag is only honoured in three circumstances:
+     * <ul>
+     * <li>when called from a system process</li>
+     * <li>when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}</li>
+     * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
+     * action and a {@code android.intent.category.BROWSABLE} category</li>
+     * </ul>
      */
-    int updateFlagsForResolve(int flags, int userId, Object cookie) {
+    int updateFlagsForResolve(int flags, int userId, Intent intent, boolean includeInstantApp) {
         // Safe mode means we shouldn't match any third-party components
         if (mSafeMode) {
             flags |= PackageManager.MATCH_SYSTEM_ONLY;
@@ -4050,15 +4061,24 @@
             flags |= PackageManager.MATCH_INSTANT;
         } else {
             // Otherwise, prevent leaking ephemeral components
+            final boolean isSpecialProcess =
+                    callingUid == Process.SYSTEM_UID
+                    || callingUid == Process.SHELL_UID
+                    || callingUid == 0;
+            final boolean allowMatchInstant =
+                    (includeInstantApp
+                            && Intent.ACTION_VIEW.equals(intent.getAction())
+                            && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
+                            && hasWebURI(intent))
+                    || isSpecialProcess
+                    || mContext.checkCallingOrSelfPermission(
+                            android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED;
             flags &= ~PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
-            if (callingUid != Process.SYSTEM_UID
-                    && callingUid != Process.SHELL_UID
-                    && callingUid != 0) {
-                // Unless called from the system process
+            if (!allowMatchInstant) {
                 flags &= ~PackageManager.MATCH_INSTANT;
             }
         }
-        return updateFlagsForComponent(flags, userId, cookie);
+        return updateFlagsForComponent(flags, userId, intent /*cookie*/);
     }
 
     @Override
@@ -5583,17 +5603,23 @@
     @Override
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
+        return resolveIntentInternal(
+                intent, resolvedType, flags, userId, false /*includeInstantApp*/);
+    }
+
+    private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
+            int flags, int userId, boolean includeInstantApp) {
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
 
             if (!sUserManager.exists(userId)) return null;
-            flags = updateFlagsForResolve(flags, userId, intent);
+            flags = updateFlagsForResolve(flags, userId, intent, includeInstantApp);
             enforceCrossUserPermission(Binder.getCallingUid(), userId,
                     false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
 
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
             final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
-                    flags, userId);
+                    flags, userId, includeInstantApp);
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
             final ResolveInfo bestChoice =
@@ -5615,7 +5641,7 @@
         }
         intent = updateIntentForResolve(intent);
         final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
-        final int flags = updateFlagsForResolve(0, userId, intent);
+        final int flags = updateFlagsForResolve(0, userId, intent, false);
         final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
                 userId);
         synchronized (mPackages) {
@@ -5658,6 +5684,11 @@
                 false, false, false, userId);
     }
 
+    /**
+     * Returns whether or not instant apps have been disabled remotely.
+     * <p><em>IMPORTANT</em> This should not be called with the package manager lock
+     * held. Otherwise we run the risk of deadlock.
+     */
     private boolean isEphemeralDisabled() {
         // ephemeral apps have been disabled across the board
         if (DISABLE_EPHEMERAL_APPS) {
@@ -5678,10 +5709,6 @@
     private boolean isEphemeralAllowed(
             Intent intent, List<ResolveInfo> resolvedActivities, int userId,
             boolean skipPackageCheck) {
-        // Short circuit and return early if possible.
-        if (isEphemeralDisabled()) {
-            return false;
-        }
         final int callingUser = UserHandle.getCallingUserId();
         if (callingUser != UserHandle.USER_SYSTEM) {
             return false;
@@ -5774,6 +5801,13 @@
                 if (ri != null) {
                     return ri;
                 }
+                // If we have an ephemeral app, use it
+                for (int i = 0; i < N; i++) {
+                    ri = query.get(i);
+                    if (ri.activityInfo.applicationInfo.isInstantApp()) {
+                        return ri;
+                    }
+                }
                 ri = new ResolveInfo(mResolveInfo);
                 ri.activityInfo = new ActivityInfo(ri.activityInfo);
                 ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction());
@@ -5892,7 +5926,7 @@
             List<ResolveInfo> query, int priority, boolean always,
             boolean removeMatches, boolean debug, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         intent = updateIntentForResolve(intent);
         // writer
         synchronized (mPackages) {
@@ -6060,7 +6094,7 @@
             // cross-profile app linking works only towards the parent.
             final UserInfo parent = getProfileParent(sourceUserId);
             synchronized(mPackages) {
-                int flags = updateFlagsForResolve(0, parent.id, intent);
+                int flags = updateFlagsForResolve(0, parent.id, intent, false);
                 CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
                         intent, resolvedType, flags, sourceUserId, parent.id);
                 return xpDomainInfo != null;
@@ -6119,9 +6153,14 @@
 
     private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
             String resolvedType, int flags, int userId) {
+        return queryIntentActivitiesInternal(intent, resolvedType, flags, userId, false);
+    }
+
+    private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
+            String resolvedType, int flags, int userId, boolean includeInstantApp) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
         final String instantAppPkgName = getInstantAppPackageName(Binder.getCallingUid());
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, includeInstantApp);
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */,
                 "query intent activities");
@@ -6173,6 +6212,7 @@
         boolean addEphemeral = false;
         List<ResolveInfo> result;
         final String pkgName = intent.getPackage();
+        final boolean ephemeralDisabled = isEphemeralDisabled();
         synchronized (mPackages) {
             if (pkgName == null) {
                 List<CrossProfileIntentFilter> matchingFilters =
@@ -6190,8 +6230,8 @@
                 // Check for results in the current profile.
                 result = filterIfNotSystemUser(mActivities.queryIntent(
                         intent, resolvedType, flags, userId), userId);
-                addEphemeral =
-                        isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
+                addEphemeral = !ephemeralDisabled
+                        && isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
 
                 // Check for cross profile results.
                 boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
@@ -6248,8 +6288,9 @@
                 } else {
                     // the caller wants to resolve for a particular package; however, there
                     // were no installed results, so, try to find an ephemeral result
-                    addEphemeral = isEphemeralAllowed(
-                            intent, null /*result*/, userId, true /*skipPackageCheck*/);
+                    addEphemeral =  !ephemeralDisabled
+                            && isEphemeralAllowed(
+                                    intent, null /*result*/, userId, true /*skipPackageCheck*/);
                     result = new ArrayList<ResolveInfo>();
                 }
             }
@@ -6748,7 +6789,7 @@
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */,
                 "query intent activity options");
@@ -6928,7 +6969,7 @@
     private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -6965,7 +7006,7 @@
     @Override
     public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         List<ResolveInfo> query = queryIntentServicesInternal(intent, resolvedType, flags, userId);
         if (query != null) {
             if (query.size() >= 1) {
@@ -6987,7 +7028,7 @@
     private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -7031,7 +7072,7 @@
     private @NonNull List<ResolveInfo> queryIntentContentProvidersInternal(
             Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -7431,7 +7472,7 @@
 
     @Override
     public @NonNull ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
-            int uid, int flags) {
+            int uid, int flags, String metaDataKey) {
         final int userId = processName != null ? UserHandle.getUserId(uid)
                 : UserHandle.getCallingUserId();
         if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
@@ -7449,6 +7490,14 @@
                                 || (p.info.processName.equals(processName)
                                         && UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
                         && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
+
+                    // See PM.queryContentProviders()'s javadoc for why we have the metaData
+                    // parameter.
+                    if (metaDataKey != null
+                            && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
+                        continue;
+                    }
+
                     if (finalList == null) {
                         finalList = new ArrayList<ProviderInfo>(3);
                     }
@@ -11662,7 +11711,8 @@
             if (!whitelisted) {
                 Slog.w(TAG, "Privileged permission " + perm + " for package "
                         + pkg.packageName + " - not in privapp-permissions whitelist");
-                if (!mSystemReady) {
+                // Only report violations for apps on system image
+                if (!mSystemReady && !pkg.isUpdatedSystemApp()) {
                     if (mPrivappPermissionsViolations == null) {
                         mPrivappPermissionsViolations = new ArraySet<>();
                     }
@@ -13032,6 +13082,12 @@
                     + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
         }
 
+        if ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
+                || (installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+            throw new IllegalArgumentException(
+                    "New installs into ASEC containers no longer supported");
+        }
+
         final File originFile = new File(originPath);
         final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
 
@@ -18666,7 +18722,7 @@
         Slog.w(TAG, "Shame on you for calling a hidden API. Shame!");
         try {
             observer.onGetStatsCompleted(null, false);
-        } catch (RemoteException ignored) {
+        } catch (Throwable ignored) {
         }
     }
 
@@ -20263,6 +20319,9 @@
                 checkin = true;
             } else if ("-f".equals(opt)) {
                 dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
+            } else if ("--proto".equals(opt)) {
+                dumpProto(fd);
+                return;
             } else {
                 pw.println("Unknown argument: " + opt + "; use -h for help");
             }
@@ -20800,6 +20859,98 @@
         }
     }
 
+    private void dumpProto(FileDescriptor fd) {
+        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+        synchronized (mPackages) {
+            final long requiredVerifierPackageToken =
+                    proto.start(PackageServiceDumpProto.REQUIRED_VERIFIER_PACKAGE);
+            proto.write(PackageServiceDumpProto.PackageShortProto.NAME, mRequiredVerifierPackage);
+            proto.write(
+                    PackageServiceDumpProto.PackageShortProto.UID,
+                    getPackageUid(
+                            mRequiredVerifierPackage,
+                            MATCH_DEBUG_TRIAGED_MISSING,
+                            UserHandle.USER_SYSTEM));
+            proto.end(requiredVerifierPackageToken);
+
+            if (mIntentFilterVerifierComponent != null) {
+                String verifierPackageName = mIntentFilterVerifierComponent.getPackageName();
+                final long verifierPackageToken =
+                        proto.start(PackageServiceDumpProto.VERIFIER_PACKAGE);
+                proto.write(PackageServiceDumpProto.PackageShortProto.NAME, verifierPackageName);
+                proto.write(
+                        PackageServiceDumpProto.PackageShortProto.UID,
+                        getPackageUid(
+                                verifierPackageName,
+                                MATCH_DEBUG_TRIAGED_MISSING,
+                                UserHandle.USER_SYSTEM));
+                proto.end(verifierPackageToken);
+            }
+
+            dumpSharedLibrariesProto(proto);
+            dumpFeaturesProto(proto);
+            mSettings.dumpPackagesProto(proto);
+            mSettings.dumpSharedUsersProto(proto);
+            dumpMessagesProto(proto);
+        }
+        proto.flush();
+    }
+
+    private void dumpMessagesProto(ProtoOutputStream proto) {
+        BufferedReader in = null;
+        String line = null;
+        try {
+            in = new BufferedReader(new FileReader(getSettingsProblemFile()));
+            while ((line = in.readLine()) != null) {
+                if (line.contains("ignored: updated version")) continue;
+                proto.write(PackageServiceDumpProto.MESSAGES, line);
+            }
+        } catch (IOException ignored) {
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
+    private void dumpFeaturesProto(ProtoOutputStream proto) {
+        synchronized (mAvailableFeatures) {
+            final int count = mAvailableFeatures.size();
+            for (int i = 0; i < count; i++) {
+                final FeatureInfo feat = mAvailableFeatures.valueAt(i);
+                final long featureToken = proto.start(PackageServiceDumpProto.FEATURES);
+                proto.write(PackageServiceDumpProto.FeatureProto.NAME, feat.name);
+                proto.write(PackageServiceDumpProto.FeatureProto.VERSION, feat.version);
+                proto.end(featureToken);
+            }
+        }
+    }
+
+    private void dumpSharedLibrariesProto(ProtoOutputStream proto) {
+        final int count = mSharedLibraries.size();
+        for (int i = 0; i < count; i++) {
+            final String libName = mSharedLibraries.keyAt(i);
+            SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
+            if (versionedLib == null) {
+                continue;
+            }
+            final int versionCount = versionedLib.size();
+            for (int j = 0; j < versionCount; j++) {
+                final SharedLibraryEntry libEntry = versionedLib.valueAt(j);
+                final long sharedLibraryToken =
+                        proto.start(PackageServiceDumpProto.SHARED_LIBRARIES);
+                proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libEntry.info.getName());
+                final boolean isJar = (libEntry.path != null);
+                proto.write(PackageServiceDumpProto.SharedLibraryProto.IS_JAR, isJar);
+                if (isJar) {
+                    proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH, libEntry.path);
+                } else {
+                    proto.write(PackageServiceDumpProto.SharedLibraryProto.APK, libEntry.apk);
+                }
+                proto.end(sharedLibraryToken);
+            }
+        }
+    }
+
     private void dumpDexoptStateLPr(PrintWriter pw, String packageName) {
         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
         ipw.println();
@@ -22975,7 +23126,6 @@
             return targetPackages;
         }
 
-
         @Override
         public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName,
                 @Nullable List<String> overlayPackageNames) {
@@ -23015,6 +23165,12 @@
                 return true;
             }
         }
+
+        public ResolveInfo resolveIntent(Intent intent, String resolvedType,
+                int flags, int userId) {
+            return resolveIntentInternal(
+                    intent, resolvedType, flags, userId, true /*includeInstantApp*/);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 5f348ab..b4bba88 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -19,6 +19,9 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.content.pm.UserInfo;
+import android.service.pm.PackageProto;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.File;
 import java.util.List;
@@ -128,4 +131,32 @@
         }
         return true;
     }
+
+    public void writeToProto(ProtoOutputStream proto, long fieldId, List<UserInfo> users) {
+        final long packageToken = proto.start(fieldId);
+        proto.write(PackageProto.NAME, (realName != null ? realName : name));
+        proto.write(PackageProto.UID, appId);
+        proto.write(PackageProto.VERSION_CODE, versionCode);
+        proto.write(PackageProto.VERSION_STRING, pkg.mVersionName);
+        proto.write(PackageProto.INSTALL_TIME_MS, firstInstallTime);
+        proto.write(PackageProto.UPDATE_TIME_MS, lastUpdateTime);
+        proto.write(PackageProto.INSTALLER_NAME, installerPackageName);
+
+        if (pkg != null) {
+            long splitToken = proto.start(PackageProto.SPLITS);
+            proto.write(PackageProto.SplitProto.NAME, "base");
+            proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.baseRevisionCode);
+            proto.end(splitToken);
+            if (pkg.splitNames != null) {
+                for (int i = 0; i < pkg.splitNames.length; i++) {
+                    splitToken = proto.start(PackageProto.SPLITS);
+                    proto.write(PackageProto.SplitProto.NAME, pkg.splitNames[i]);
+                    proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.splitRevisionCodes[i]);
+                    proto.end(splitToken);
+                }
+            }
+        }
+        writeUsersInfoToProto(proto, PackageProto.USERS);
+        proto.end(packageToken);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 601377d6..b9c43da 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -25,8 +25,10 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageUserState;
 import android.os.storage.VolumeInfo;
+import android.service.pm.PackageProto;
 import android.util.ArraySet;
 import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -564,4 +566,32 @@
         modifyUserState(userId).domainVerificationStatus =
                 PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
     }
+
+    protected void writeUsersInfoToProto(ProtoOutputStream proto, long fieldId) {
+        int count = userState.size();
+        for (int i = 0; i < count; i++) {
+            final long userToken = proto.start(fieldId);
+            final int userId = userState.keyAt(i);
+            final PackageUserState state = userState.valueAt(i);
+            proto.write(PackageProto.UserInfoProto.ID, userId);
+            final int installType;
+            if (state.instantApp) {
+                installType = PackageProto.UserInfoProto.INSTANT_APP_INSTALL;
+            } else if (state.installed) {
+                installType = PackageProto.UserInfoProto.FULL_APP_INSTALL;
+            } else {
+                installType = PackageProto.UserInfoProto.NOT_INSTALLED_FOR_USER;
+            }
+            proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType);
+            proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden);
+            proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
+            proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.stopped);
+            proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.notLaunched);
+            proto.write(PackageProto.UserInfoProto.ENABLED_STATE, state.enabled);
+            proto.write(
+                    PackageProto.UserInfoProto.LAST_DISABLED_APP_CALLER,
+                    state.lastDisableAppCaller);
+            proto.end(userToken);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a8a5ff0..570b31f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -65,6 +65,7 @@
 import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.service.pm.PackageServiceDumpProto;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -77,6 +78,7 @@
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BackgroundThread;
@@ -887,9 +889,9 @@
         }
         if (p.appId < 0) {
             PackageManagerService.reportSettingsProblem(Log.WARN,
-                    "Package " + p.name + " could not be assigned a valid uid");
+                    "Package " + p.name + " could not be assigned a valid UID");
             throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-                    "Creating application package " + p.name + " failed");
+                    "Package " + p.name + " could not be assigned a valid UID");
         }
     }
 
@@ -3370,7 +3372,7 @@
     private void applyDefaultPreferredActivityLPw(PackageManagerService service,
             Intent intent, int flags, ComponentName cn, String scheme, PatternMatcher ssp,
             IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) {
-        flags = service.updateFlagsForResolve(flags, userId, intent);
+        flags = service.updateFlagsForResolve(flags, userId, intent, false);
         List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
                 intent.getType(), flags, 0);
         if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent
@@ -4876,6 +4878,16 @@
         }
     }
 
+    void dumpPackagesProto(ProtoOutputStream proto) {
+        List<UserInfo> users = getAllUsers(UserManagerService.getInstance());
+
+        final int count = mPackages.size();
+        for (int i = 0; i < count; i++) {
+            final PackageSetting ps = mPackages.valueAt(i);
+            ps.writeToProto(proto, PackageServiceDumpProto.PACKAGES, users);
+        }
+    }
+
     void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
             DumpState dumpState) {
         boolean printedSomething = false;
@@ -4966,6 +4978,17 @@
         }
     }
 
+    void dumpSharedUsersProto(ProtoOutputStream proto) {
+        final int count = mSharedUsers.size();
+        for (int i = 0; i < count; i++) {
+            final SharedUserSetting su = mSharedUsers.valueAt(i);
+            final long sharedUserToken = proto.start(PackageServiceDumpProto.SHARED_USERS);
+            proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, su.userId);
+            proto.write(PackageServiceDumpProto.SharedUserProto.NAME, su.name);
+            proto.end(sharedUserToken);
+        }
+    }
+
     void dumpReadMessagesLPr(PrintWriter pw, DumpState dumpState) {
         pw.println("Settings parse messages:");
         pw.print(mReadMessages.toString());
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 570259b..ac98ab9 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -20,6 +20,7 @@
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
@@ -31,6 +32,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.pm.ShortcutService.ShortcutOperation;
@@ -68,6 +70,9 @@
     private static final String TAG_EXTRAS = "extras";
     private static final String TAG_SHORTCUT = "shortcut";
     private static final String TAG_CATEGORIES = "categories";
+    private static final String TAG_CHOOSER_EXTRAS = "chooser-extras";
+    private static final String TAG_CHOOSER_INTENT_FILTERS = "chooser-intent-filters";
+    private static final String TAG_CHOOSER_COMPONENT_NAMES = "chooser-component-names";
 
     private static final String ATTR_NAME = "name";
     private static final String ATTR_CALL_COUNT = "call-count";
@@ -91,6 +96,7 @@
     private static final String ATTR_ICON_RES_ID = "icon-res";
     private static final String ATTR_ICON_RES_NAME = "icon-resname";
     private static final String ATTR_BITMAP_PATH = "bitmap-path";
+    private static final String ATTR_COMPONENT_NAMES = "component-names";
 
     private static final String NAME_CATEGORIES = "categories";
 
@@ -200,7 +206,7 @@
         if (shortcut != null) {
             mShortcutUser.mService.removeIcon(getPackageUserId(), shortcut);
             shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
-                    | ShortcutInfo.FLAG_MANIFEST);
+                    | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CHOOSER);
         }
         return shortcut;
     }
@@ -226,7 +232,7 @@
         Preconditions.checkArgument(newShortcut.isEnabled(),
                 "add/setDynamicShortcuts() cannot publish disabled shortcuts");
 
-        newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
+        addCorrectDynamicFlags(newShortcut);
 
         final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
 
@@ -250,6 +256,17 @@
         addShortcutInner(newShortcut);
     }
 
+    // TODO: Sample code & JavaDoc for ShortcutManager needs updating to reflect the fact that
+    //       Chooser shortcuts are not always dynamic.
+    public void addCorrectDynamicFlags(@NonNull ShortcutInfo shortcut) {
+        if (shortcut.getIntent() != null) {
+            shortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
+        }
+        if (!ArrayUtils.isEmpty(shortcut.getChooserIntentFilters())) {
+            shortcut.addFlags(ShortcutInfo.FLAG_CHOOSER);
+        }
+    }
+
     /**
      * Remove all shortcuts that aren't pinned nor dynamic.
      */
@@ -282,11 +299,11 @@
         boolean changed = false;
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
-            if (si.isDynamic()) {
+            if (si.isDynamic() || si.isChooser()) {
                 changed = true;
 
                 si.setTimestamp(now);
-                si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+                si.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_CHOOSER);
                 si.setRank(0); // It may still be pinned, so clear the rank.
             }
         }
@@ -355,7 +372,8 @@
         if (oldShortcut.isPinned()) {
 
             oldShortcut.setRank(0);
-            oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
+            oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST
+                    | ShortcutInfo.FLAG_CHOOSER);
             if (disable) {
                 oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
             }
@@ -1116,8 +1134,8 @@
                     // Don't adjust ranks for manifest shortcuts.
                     continue;
                 }
-                // At this point, it must be dynamic.
-                if (!si.isDynamic()) {
+                // At this point, it must be dynamic or a chooser.
+                if (!si.isDynamicOrChooser()) {
                     s.wtf("Non-dynamic shortcut found.");
                     continue;
                 }
@@ -1294,7 +1312,7 @@
             ShortcutService.writeAttr(out, ATTR_FLAGS,
                     si.getFlags() &
                             ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES
-                            | ShortcutInfo.FLAG_DYNAMIC));
+                            | ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_CHOOSER));
         } else {
             // When writing for backup, ranks shouldn't be saved, since shortcuts won't be restored
             // as dynamic.
@@ -1317,15 +1335,36 @@
         }
         final Intent[] intentsNoExtras = si.getIntentsNoExtras();
         final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases();
-        final int numIntents = intentsNoExtras.length;
-        for (int i = 0; i < numIntents; i++) {
-            out.startTag(null, TAG_INTENT);
-            ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]);
-            ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]);
-            out.endTag(null, TAG_INTENT);
+        if (intentsNoExtras != null) {
+            final int numIntents = intentsNoExtras.length;
+            for (int i = 0; i < numIntents; i++) {
+                out.startTag(null, TAG_INTENT);
+                ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]);
+                ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]);
+                out.endTag(null, TAG_INTENT);
+            }
+        }
+        ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
+
+        ShortcutService.writeTagExtra(out, TAG_CHOOSER_EXTRAS, si.getChooserExtras());
+
+        final IntentFilter[] intentFilters = si.getChooserIntentFilters();
+        if (intentFilters != null) {
+            for (int i = 0; i < intentFilters.length; i++) {
+                out.startTag(null, TAG_CHOOSER_INTENT_FILTERS);
+                intentFilters[i].writeToXml(out);
+                out.endTag(null, TAG_CHOOSER_INTENT_FILTERS);
+            }
         }
 
-        ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
+        final ComponentName[] componentNames = si.getChooserComponentNames();
+        if (componentNames != null) {
+            for (int i = 0; i < componentNames.length; i++) {
+                out.startTag(null, TAG_CHOOSER_COMPONENT_NAMES);
+                ShortcutService.writeAttr(out, ATTR_COMPONENT_NAMES, componentNames[i]);
+                out.endTag(null, TAG_CHOOSER_COMPONENT_NAMES);
+            }
+        }
 
         out.endTag(null, TAG_SHORTCUT);
     }
@@ -1398,6 +1437,9 @@
         String iconResName;
         String bitmapPath;
         ArraySet<String> categories = null;
+        PersistableBundle chooserExtras;
+        List<IntentFilter> chooserIntentFilters = new ArrayList<>();
+        List<ComponentName> chooserComponentNames = new ArrayList<>();
 
         id = ShortcutService.parseStringAttribute(parser, ATTR_ID);
         activityComponent = ShortcutService.parseComponentNameAttribute(parser,
@@ -1458,6 +1500,18 @@
                         }
                     }
                     continue;
+                case TAG_CHOOSER_EXTRAS:
+                    chooserExtras = PersistableBundle.restoreFromXml(parser);
+                    continue;
+                case TAG_CHOOSER_COMPONENT_NAMES:
+                    chooserComponentNames.add(ShortcutService.parseComponentNameAttribute(parser,
+                            ATTR_ACTIVITY));
+                    continue;
+                case TAG_CHOOSER_INTENT_FILTERS:
+                    IntentFilter toAdd = new IntentFilter();
+                    toAdd.readFromXml(parser);
+                    chooserIntentFilters.add(toAdd);
+                    continue;
             }
             throw ShortcutService.throwForInvalidTag(depth, tag);
         }
@@ -1551,10 +1605,10 @@
         // Verify each shortcut's status.
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
-            if (!(si.isDeclaredInManifest() || si.isDynamic() || si.isPinned())) {
+            if (!(si.isDeclaredInManifest() || si.isDynamicOrChooser() || si.isPinned())) {
                 failed = true;
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
-                        + " is not manifest, dynamic or pinned.");
+                        + " is not manifest, dynamic, chooser or pinned.");
             }
             if (si.isDeclaredInManifest() && si.isDynamic()) {
                 failed = true;
@@ -1596,6 +1650,11 @@
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
                         + " has a dummy target activity");
             }
+            if (si.getIntent() == null && !si.isChooser()) {
+                failed = true;
+                Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+                        + " has a null intent, but is not a chooser");
+            }
         }
 
         if (failed) {
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index 6eac5e3..b0689b8 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -48,7 +48,7 @@
     /**
      * Internal for {@link android.content.pm.LauncherApps.PinItemRequest} which receives callbacks.
      */
-    private static class PinItemRequestInner extends IPinItemRequest.Stub {
+    private abstract static class PinItemRequestInner extends IPinItemRequest.Stub {
         protected final ShortcutRequestPinProcessor mProcessor;
         private final IntentSender mResultIntent;
         private final int mLauncherUid;
@@ -63,6 +63,14 @@
             mLauncherUid = launcherUid;
         }
 
+        public ShortcutInfo getShortcutInfo() {
+            return null;
+        }
+
+        public AppWidgetProviderInfo getAppWidgetProviderInfo() {
+            return null;
+        }
+
         /**
          * Returns true if the caller is same as the default launcher app when this request
          * object was created.
@@ -126,6 +134,26 @@
     /**
      * Internal for {@link android.content.pm.LauncherApps.PinItemRequest} which receives callbacks.
      */
+    private static class PinAppWidgetRequestInner extends PinItemRequestInner {
+        final AppWidgetProviderInfo mAppWidgetProviderInfo;
+
+        private PinAppWidgetRequestInner(ShortcutRequestPinProcessor processor,
+                IntentSender resultIntent, int launcherUid,
+                AppWidgetProviderInfo appWidgetProviderInfo) {
+            super(processor, resultIntent, launcherUid);
+
+            mAppWidgetProviderInfo = appWidgetProviderInfo;
+        }
+
+        @Override
+        public AppWidgetProviderInfo getAppWidgetProviderInfo() {
+            return mAppWidgetProviderInfo;
+        }
+    }
+
+    /**
+     * Internal for {@link android.content.pm.LauncherApps.PinItemRequest} which receives callbacks.
+     */
     private static class PinShortcutRequestInner extends PinItemRequestInner {
         /** Original shortcut passed by the app. */
         public final ShortcutInfo shortcutOriginal;
@@ -153,6 +181,11 @@
         }
 
         @Override
+        public ShortcutInfo getShortcutInfo() {
+            return shortcutForLauncher;
+        }
+
+        @Override
         protected boolean tryAccept() {
             if (DEBUG) {
                 Slog.d(TAG, "Launcher accepted shortcut. ID=" + shortcutOriginal.getId()
@@ -208,8 +241,9 @@
         } else {
             int launcherUid = mService.injectGetPackageUid(
                     confirmActivity.first.getPackageName(), launcherUserId);
-            request = new PinItemRequest(inAppWidget,
-                    new PinItemRequestInner(this, resultIntent, launcherUid));
+            request = new PinItemRequest(
+                    new PinAppWidgetRequestInner(this, resultIntent, launcherUid, inAppWidget),
+                    PinItemRequest.REQUEST_TYPE_APPWIDGET);
         }
         return startRequestConfirmActivity(confirmActivity.first, launcherUserId, request,
                 requestType);
@@ -319,7 +353,7 @@
                         mService.injectGetPackageUid(launcherPackage, launcherUserId),
                         existsAlready);
 
-        return new PinItemRequest(shortcutForLauncher, inner);
+        return new PinItemRequest(inner, PinItemRequest.REQUEST_TYPE_SHORTCUT);
     }
 
     private void validateExistingShortcut(ShortcutInfo shortcutInfo) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 057e781..74eb340 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -27,6 +27,7 @@
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -64,6 +65,7 @@
 import android.os.Handler;
 import android.os.LocaleList;
 import android.os.Looper;
+import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.os.Process;
@@ -1750,6 +1752,7 @@
             ps.clearAllImplicitRanks();
             assignImplicitRanks(newShortcuts);
 
+            // TODO: Consider removing Chooser fields. If so, the FLAG_CHOOSER should be removed
             for (int i = 0; i < size; i++) {
                 final ShortcutInfo source = newShortcuts.get(i);
                 fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
@@ -1789,6 +1792,13 @@
                 if (replacingIcon || source.hasStringResources()) {
                     fixUpShortcutResourceNamesAndValues(target);
                 }
+
+                // While updating, we keep the dynamic flag as it previously was, but refresh the
+                // chooser flag.
+                // TODO: If we support clearing Chooser fields, we should also remove the flag.
+                if (target.getChooserIntentFilters() != null) {
+                    target.addFlags(ShortcutInfo.FLAG_CHOOSER);
+                }
             }
 
             // Lastly, adjust the ranks.
@@ -1852,6 +1862,7 @@
         return true;
     }
 
+    // TODO: Ensure non-launchable shortcuts can not be pinned
     @Override
     public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut,
             IntentSender resultIntent, int userId) {
@@ -2007,7 +2018,7 @@
 
             return getShortcutsWithQueryLocked(
                     packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
-                    ShortcutInfo::isDynamic);
+                    ShortcutInfo::isDynamicOrChooser);
         }
     }
 
@@ -2200,6 +2211,14 @@
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
+            // For the chooser, we just check is the system is calling.
+            // STOPSHIP: We need to implement a new permission here rather than this terrible check.
+            //           The packageName check is to try to distinguish between when an actual
+            //           launcher is making the call, and when it's the system.
+            if (isCallerSystem() && packageName.equals("android")) {
+                return true;
+            }
+
             final ShortcutUser user = getUserShortcutsLocked(userId);
 
             // Always trust the cached component.
@@ -2372,7 +2391,7 @@
         public List<ShortcutInfo> getShortcuts(int launcherUserId,
                 @NonNull String callingPackage, long changedSince,
                 @Nullable String packageName, @Nullable List<String> shortcutIds,
-                @Nullable ComponentName componentName,
+                @Nullable ComponentName componentName, @Nullable Intent intent,
                 int queryFlags, int userId) {
             final ArrayList<ShortcutInfo> ret = new ArrayList<>();
 
@@ -2394,13 +2413,13 @@
                 if (packageName != null) {
                     getShortcutsInnerLocked(launcherUserId,
                             callingPackage, packageName, shortcutIds, changedSince,
-                            componentName, queryFlags, userId, ret, cloneFlag);
+                            componentName, intent, queryFlags, userId, ret, cloneFlag);
                 } else {
                     final List<String> shortcutIdsF = shortcutIds;
                     getUserShortcutsLocked(userId).forAllPackages(p -> {
                         getShortcutsInnerLocked(launcherUserId,
                                 callingPackage, p.getPackageName(), shortcutIdsF, changedSince,
-                                componentName, queryFlags, userId, ret, cloneFlag);
+                                componentName, intent, queryFlags, userId, ret, cloneFlag);
                     });
                 }
             }
@@ -2409,7 +2428,7 @@
 
         private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
                 @Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince,
-                @Nullable ComponentName componentName, int queryFlags,
+                @Nullable ComponentName componentName, Intent intent, int queryFlags,
                 int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) {
             final ArraySet<String> ids = shortcutIds == null ? null
                     : new ArraySet<>(shortcutIds);
@@ -2434,6 +2453,15 @@
                                 return false;
                             }
                         }
+                        if (intent != null
+                                && !si.hasMatchingFilter(mContext.getContentResolver(), intent)) {
+                            return false;
+                        }
+
+                        if (((queryFlags & ShortcutQuery.FLAG_MATCH_CHOOSER) != 0)
+                                && si.isChooser()) {
+                            return true;
+                        }
                         if (((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0)
                                 && si.isDynamic()) {
                             return true;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index b76a249..d3931fb 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -51,21 +51,23 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
-import android.provider.Settings.Secure;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.dreams.DreamManagerInternal;
+import android.service.power.PowerServiceDumpProto;
+import android.service.power.PowerServiceSettingsAndConfigurationDumpProto;
+import android.service.power.SuspendBlockerProto;
+import android.service.power.WakeLockProto;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
 import android.util.EventLog;
 import android.util.KeyValueListParser;
-import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 import android.view.WindowManagerPolicy;
-
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BackgroundThread;
@@ -78,7 +80,7 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
-import com.android.server.vr.VrManagerService;
+
 import libcore.util.Objects;
 
 import java.io.FileDescriptor;
@@ -575,6 +577,13 @@
             pw.print("    "); pw.print(KEY_NO_CACHED_WAKE_LOCKS); pw.print("=");
             pw.println(NO_CACHED_WAKE_LOCKS);
         }
+
+        void dumpProto(ProtoOutputStream proto) {
+            final long constantsToken = proto.start(PowerServiceDumpProto.CONSTANTS);
+            proto.write(PowerServiceDumpProto.ConstantsProto.IS_NO_CACHED_WAKE_LOCKS,
+                    NO_CACHED_WAKE_LOCKS);
+            proto.end(constantsToken);
+        }
     }
 
     final Constants mConstants;
@@ -3244,6 +3253,354 @@
         }
     }
 
+    private void dumpProto(FileDescriptor fd) {
+        final WirelessChargerDetector wcd;
+        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+        synchronized (mLock) {
+            mConstants.dumpProto(proto);
+            proto.write(PowerServiceDumpProto.DIRTY, mDirty);
+            proto.write(PowerServiceDumpProto.WAKEFULNESS, mWakefulness);
+            proto.write(PowerServiceDumpProto.IS_WAKEFULNESS_CHANGING, mWakefulnessChanging);
+            proto.write(PowerServiceDumpProto.IS_POWERED, mIsPowered);
+            proto.write(PowerServiceDumpProto.PLUG_TYPE, mPlugType);
+            proto.write(PowerServiceDumpProto.BATTERY_LEVEL, mBatteryLevel);
+            proto.write(
+                    PowerServiceDumpProto.BATTERY_LEVEL_WHEN_DREAM_STARTED,
+                    mBatteryLevelWhenDreamStarted);
+            proto.write(PowerServiceDumpProto.DOCK_STATE, mDockState);
+            proto.write(PowerServiceDumpProto.IS_STAY_ON, mStayOn);
+            proto.write(PowerServiceDumpProto.IS_PROXIMITY_POSITIVE, mProximityPositive);
+            proto.write(PowerServiceDumpProto.IS_BOOT_COMPLETED, mBootCompleted);
+            proto.write(PowerServiceDumpProto.IS_SYSTEM_READY, mSystemReady);
+            proto.write(
+                    PowerServiceDumpProto.IS_HAL_AUTO_SUSPEND_MODE_ENABLED,
+                    mHalAutoSuspendModeEnabled);
+            proto.write(
+                    PowerServiceDumpProto.IS_HAL_AUTO_INTERACTIVE_MODE_ENABLED,
+                    mHalInteractiveModeEnabled);
+
+            final long activeWakeLocksToken = proto.start(PowerServiceDumpProto.ACTIVE_WAKE_LOCKS);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_CPU,
+                    (mWakeLockSummary & WAKE_LOCK_CPU) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_SCREEN_BRIGHT,
+                    (mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_SCREEN_DIM,
+                    (mWakeLockSummary & WAKE_LOCK_SCREEN_DIM) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_BUTTON_BRIGHT,
+                    (mWakeLockSummary & WAKE_LOCK_BUTTON_BRIGHT) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_PROXIMITY_SCREEN_OFF,
+                    (mWakeLockSummary & WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_STAY_AWAKE,
+                    (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_DOZE,
+                    (mWakeLockSummary & WAKE_LOCK_DOZE) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_DRAW,
+                    (mWakeLockSummary & WAKE_LOCK_DRAW) != 0);
+            proto.end(activeWakeLocksToken);
+
+            proto.write(PowerServiceDumpProto.NOTIFY_LONG_SCHEDULED_MS, mNotifyLongScheduled);
+            proto.write(PowerServiceDumpProto.NOTIFY_LONG_DISPATCHED_MS, mNotifyLongDispatched);
+            proto.write(PowerServiceDumpProto.NOTIFY_LONG_NEXT_CHECK_MS, mNotifyLongNextCheck);
+
+            final long userActivityToken = proto.start(PowerServiceDumpProto.USER_ACTIVITY);
+            proto.write(
+                    PowerServiceDumpProto.UserActivityProto.IS_SCREEN_BRIGHT,
+                    (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0);
+            proto.write(
+                    PowerServiceDumpProto.UserActivityProto.IS_SCREEN_DIM,
+                    (mUserActivitySummary & USER_ACTIVITY_SCREEN_DIM) != 0);
+            proto.write(
+                    PowerServiceDumpProto.UserActivityProto.IS_SCREEN_DREAM,
+                    (mUserActivitySummary & USER_ACTIVITY_SCREEN_DREAM) != 0);
+            proto.end(userActivityToken);
+
+            proto.write(
+                    PowerServiceDumpProto.IS_REQUEST_WAIT_FOR_NEGATIVE_PROXIMITY,
+                    mRequestWaitForNegativeProximity);
+            proto.write(PowerServiceDumpProto.IS_SANDMAN_SCHEDULED, mSandmanScheduled);
+            proto.write(PowerServiceDumpProto.IS_SANDMAN_SUMMONED, mSandmanSummoned);
+            proto.write(PowerServiceDumpProto.IS_LOW_POWER_MODE_ENABLED, mLowPowerModeEnabled);
+            proto.write(PowerServiceDumpProto.IS_BATTERY_LEVEL_LOW, mBatteryLevelLow);
+            proto.write(PowerServiceDumpProto.IS_LIGHT_DEVICE_IDLE_MODE, mLightDeviceIdleMode);
+            proto.write(PowerServiceDumpProto.IS_DEVICE_IDLE_MODE, mDeviceIdleMode);
+
+            for (int id : mDeviceIdleWhitelist) {
+                proto.write(PowerServiceDumpProto.DEVICE_IDLE_WHITELIST, id);
+            }
+            for (int id : mDeviceIdleTempWhitelist) {
+                proto.write(PowerServiceDumpProto.DEVICE_IDLE_TEMP_WHITELIST, id);
+            }
+
+            proto.write(PowerServiceDumpProto.LAST_WAKE_TIME_MS, mLastWakeTime);
+            proto.write(PowerServiceDumpProto.LAST_SLEEP_TIME_MS, mLastSleepTime);
+            proto.write(PowerServiceDumpProto.LAST_USER_ACTIVITY_TIME_MS, mLastUserActivityTime);
+            proto.write(
+                    PowerServiceDumpProto.LAST_USER_ACTIVITY_TIME_NO_CHANGE_LIGHTS_MS,
+                    mLastUserActivityTimeNoChangeLights);
+            proto.write(
+                    PowerServiceDumpProto.LAST_INTERACTIVE_POWER_HINT_TIME_MS,
+                    mLastInteractivePowerHintTime);
+            proto.write(
+                    PowerServiceDumpProto.LAST_SCREEN_BRIGHTNESS_BOOST_TIME_MS,
+                    mLastScreenBrightnessBoostTime);
+            proto.write(
+                    PowerServiceDumpProto.IS_SCREEN_BRIGHTNESS_BOOST_IN_PROGRESS,
+                    mScreenBrightnessBoostInProgress);
+            proto.write(PowerServiceDumpProto.IS_DISPLAY_READY, mDisplayReady);
+            proto.write(
+                    PowerServiceDumpProto.IS_HOLDING_WAKE_LOCK_SUSPEND_BLOCKER,
+                    mHoldingWakeLockSuspendBlocker);
+            proto.write(
+                    PowerServiceDumpProto.IS_HOLDING_DISPLAY_SUSPEND_BLOCKER,
+                    mHoldingDisplaySuspendBlocker);
+
+            final long settingsAndConfigurationToken =
+                    proto.start(PowerServiceDumpProto.SETTINGS_AND_CONFIGURATION);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_DECOUPLE_HAL_AUTO_SUSPEND_MODE_FROM_DISPLAY_CONFIG,
+                    mDecoupleHalAutoSuspendModeFromDisplayConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_DECOUPLE_HAL_INTERACTIVE_MODE_FROM_DISPLAY_CONFIG,
+                    mDecoupleHalInteractiveModeFromDisplayConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_WAKE_UP_WHEN_PLUGGED_OR_UNPLUGGED_CONFIG,
+                    mWakeUpWhenPluggedOrUnpluggedConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_WAKE_UP_WHEN_PLUGGED_OR_UNPLUGGED_IN_THEATER_MODE_CONFIG,
+                    mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_THEATER_MODE_ENABLED,
+                    mTheaterModeEnabled);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_SUSPEND_WHEN_SCREEN_OFF_DUE_TO_PROXIMITY_CONFIG,
+                    mSuspendWhenScreenOffDueToProximityConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ARE_DREAMS_SUPPORTED_CONFIG,
+                    mDreamsSupportedConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ENABLED_BY_DEFAULT_CONFIG,
+                    mDreamsEnabledByDefaultConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ACTIVATED_ON_SLEEP_BY_DEFAULT_CONFIG,
+                    mDreamsActivatedOnSleepByDefaultConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ACTIVATED_ON_DOCK_BY_DEFAULT_CONFIG,
+                    mDreamsActivatedOnDockByDefaultConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ENABLED_ON_BATTERY_CONFIG,
+                    mDreamsEnabledOnBatteryConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .DREAMS_BATTERY_LEVEL_MINIMUM_WHEN_POWERED_CONFIG,
+                    mDreamsBatteryLevelMinimumWhenPoweredConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .DREAMS_BATTERY_LEVEL_MINIMUM_WHEN_NOT_POWERED_CONFIG,
+                    mDreamsBatteryLevelMinimumWhenNotPoweredConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .DREAMS_BATTERY_LEVEL_DRAIN_CUTOFF_CONFIG,
+                    mDreamsBatteryLevelDrainCutoffConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ARE_DREAMS_ENABLED_SETTING,
+                    mDreamsEnabledSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ACTIVATE_ON_SLEEP_SETTING,
+                    mDreamsActivateOnSleepSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ACTIVATE_ON_DOCK_SETTING,
+                    mDreamsActivateOnDockSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_DOZE_AFTER_SCREEN_OFF_CONFIG,
+                    mDozeAfterScreenOffConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_LOW_POWER_MODE_SETTING,
+                    mLowPowerModeSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_AUTO_LOW_POWER_MODE_CONFIGURED,
+                    mAutoLowPowerModeConfigured);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_AUTO_LOW_POWER_MODE_SNOOZING,
+                    mAutoLowPowerModeSnoozing);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .MINIMUM_SCREEN_OFF_TIMEOUT_CONFIG_MS,
+                    mMinimumScreenOffTimeoutConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .MAXIMUM_SCREEN_DIM_DURATION_CONFIG_MS,
+                    mMaximumScreenDimDurationConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.MAXIMUM_SCREEN_DIM_RATIO_CONFIG,
+                    mMaximumScreenDimRatioConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.SCREEN_OFF_TIMEOUT_SETTING_MS,
+                    mScreenOffTimeoutSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.SLEEP_TIMEOUT_SETTING_MS,
+                    mSleepTimeoutSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .MAXIMUM_SCREEN_OFF_TIMEOUT_FROM_DEVICE_ADMIN_MS,
+                    mMaximumScreenOffTimeoutFromDeviceAdmin);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_MAXIMUM_SCREEN_OFF_TIMEOUT_FROM_DEVICE_ADMIN_ENFORCED_LOCKED,
+                    isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked());
+
+            final long stayOnWhilePluggedInToken =
+                    proto.start(
+                            PowerServiceSettingsAndConfigurationDumpProto.STAY_ON_WHILE_PLUGGED_IN);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
+                            .IS_STAY_ON_WHILE_PLUGGED_IN_AC,
+                    ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_AC) != 0));
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
+                            .IS_STAY_ON_WHILE_PLUGGED_IN_USB,
+                    ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_USB) != 0));
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
+                            .IS_STAY_ON_WHILE_PLUGGED_IN_WIRELESS,
+                    ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_WIRELESS)
+                            != 0));
+            proto.end(stayOnWhilePluggedInToken);
+
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_SETTING,
+                    mScreenBrightnessSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_SETTING,
+                    mScreenAutoBrightnessAdjustmentSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_MODE_SETTING,
+                    mScreenBrightnessModeSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .SCREEN_BRIGHTNESS_OVERRIDE_FROM_WINDOW_MANAGER,
+                    mScreenBrightnessOverrideFromWindowManager);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .USER_ACTIVITY_TIMEOUT_OVERRIDE_FROM_WINDOW_MANAGER_MS,
+                    mUserActivityTimeoutOverrideFromWindowManager);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_USER_INACTIVE_OVERRIDE_FROM_WINDOW_MANAGER,
+                    mUserInactiveOverrideFromWindowManager);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .TEMPORARY_SCREEN_BRIGHTNESS_SETTING_OVERRIDE,
+                    mTemporaryScreenBrightnessSettingOverride);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .TEMPORARY_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_SETTING_OVERRIDE,
+                    mTemporaryScreenAutoBrightnessAdjustmentSettingOverride);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .DOZE_SCREEN_STATE_OVERRIDE_FROM_DREAM_MANAGER,
+                    mDozeScreenStateOverrideFromDreamManager);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .DOZED_SCREEN_BRIGHTNESS_OVERRIDE_FROM_DREAM_MANAGER,
+                    mDozeScreenBrightnessOverrideFromDreamManager);
+
+            final long screenBrightnessSettingLimitsToken =
+                    proto.start(
+                            PowerServiceSettingsAndConfigurationDumpProto
+                                    .SCREEN_BRIGHTNESS_SETTING_LIMITS);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+                            .SETTING_MINIMUM,
+                    mScreenBrightnessSettingMinimum);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+                            .SETTING_MAXIMUM,
+                    mScreenBrightnessSettingMaximum);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+                            .SETTING_DEFAULT,
+                    mScreenBrightnessSettingDefault);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+                            .SETTING_FOR_VR_DEFAULT,
+                    mScreenBrightnessForVrSettingDefault);
+            proto.end(screenBrightnessSettingLimitsToken);
+
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_FOR_VR_SETTING,
+                    mScreenBrightnessForVrSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_DOUBLE_TAP_WAKE_ENABLED,
+                    mDoubleTapWakeEnabled);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_VR_MODE_ENABLED,
+                    mIsVrModeEnabled);
+            proto.end(settingsAndConfigurationToken);
+
+            final int sleepTimeout = getSleepTimeoutLocked();
+            final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
+            final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
+            proto.write(PowerServiceDumpProto.SLEEP_TIMEOUT_MS, sleepTimeout);
+            proto.write(PowerServiceDumpProto.SCREEN_OFF_TIMEOUT_MS, screenOffTimeout);
+            proto.write(PowerServiceDumpProto.SCREEN_DIM_DURATION_MS, screenDimDuration);
+            proto.write(PowerServiceDumpProto.ARE_UIDS_CHANGING, mUidsChanging);
+            proto.write(PowerServiceDumpProto.ARE_UIDS_CHANGED, mUidsChanged);
+
+            for (int i = 0; i < mUidState.size(); i++) {
+                final UidState state = mUidState.valueAt(i);
+                final long uIDToken = proto.start(PowerServiceDumpProto.UIDS);
+                final int uid = mUidState.keyAt(i);
+                proto.write(PowerServiceDumpProto.UidProto.UID, uid);
+                proto.write(PowerServiceDumpProto.UidProto.UID_STRING, UserHandle.formatUid(uid));
+                proto.write(PowerServiceDumpProto.UidProto.IS_ACTIVE, state.mActive);
+                proto.write(PowerServiceDumpProto.UidProto.NUM_WAKE_LOCKS, state.mNumWakeLocks);
+                if (state.mProcState == ActivityManager.PROCESS_STATE_UNKNOWN) {
+                    proto.write(PowerServiceDumpProto.UidProto.IS_PROCESS_STATE_UNKNOWN, true);
+                } else {
+                    proto.write(PowerServiceDumpProto.UidProto.PROCESS_STATE, state.mProcState);
+                }
+                proto.end(uIDToken);
+            }
+
+            mHandler.getLooper().writeToProto(proto, PowerServiceDumpProto.LOOPER);
+
+            for (WakeLock wl : mWakeLocks) {
+                wl.writeToProto(proto, PowerServiceDumpProto.WAKE_LOCKS);
+            }
+
+            for (SuspendBlocker sb : mSuspendBlockers) {
+                sb.writeToProto(proto, PowerServiceDumpProto.SUSPEND_BLOCKERS);
+            }
+            wcd = mWirelessChargerDetector;
+        }
+
+        if (wcd != null) {
+            wcd.writeToProto(proto, PowerServiceDumpProto.WIRELESS_CHARGER_DETECTOR);
+        }
+        proto.flush();
+    }
+
     private SuspendBlocker createSuspendBlockerLocked(String name) {
         SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
         mSuspendBlockers.add(suspendBlocker);
@@ -3471,6 +3828,32 @@
             return sb.toString();
         }
 
+        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long wakeLockToken = proto.start(fieldId);
+            proto.write(WakeLockProto.LOCK_LEVEL, (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK));
+            proto.write(WakeLockProto.TAG, mTag);
+
+            final long wakeLockFlagsToken = proto.start(WakeLockProto.FLAGS);
+            proto.write(WakeLockProto.WakeLockFlagsProto.IS_ACQUIRE_CAUSES_WAKEUP,
+                    (mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP)!=0);
+            proto.write(WakeLockProto.WakeLockFlagsProto.IS_ON_AFTER_RELEASE,
+                    (mFlags & PowerManager.ON_AFTER_RELEASE)!=0);
+            proto.end(wakeLockFlagsToken);
+
+            proto.write(WakeLockProto.IS_DISABLED, mDisabled);
+            if (mNotifiedAcquired) {
+                proto.write(WakeLockProto.ACQ_MS, mAcquireTime);
+            }
+            proto.write(WakeLockProto.IS_NOTIFIED_LONG, mNotifiedLong);
+            proto.write(WakeLockProto.UID, mOwnerUid);
+            proto.write(WakeLockProto.PID, mOwnerPid);
+
+            if (mWorkSource != null) {
+                mWorkSource.writeToProto(proto, WakeLockProto.WORK_SOURCE);
+            }
+            proto.end(wakeLockToken);
+        }
+
         @SuppressWarnings("deprecation")
         private String getLockLevelString() {
             switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
@@ -3568,6 +3951,15 @@
                 return mName + ": ref count=" + mReferenceCount;
             }
         }
+
+        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long sbToken = proto.start(fieldId);
+            synchronized (this) {
+                proto.write(SuspendBlockerProto.NAME, mName);
+                proto.write(SuspendBlockerProto.REFERENCE_COUNT, mReferenceCount);
+            }
+            proto.end(sbToken);
+        }
     }
 
     static final class UidState {
@@ -4055,8 +4447,19 @@
             }
 
             final long ident = Binder.clearCallingIdentity();
+
+            boolean isDumpProto = false;
+            for (String arg : args) {
+                if (arg.equals("--proto")) {
+                    isDumpProto = true;
+                }
+            }
             try {
-                dumpInternal(pw);
+                if (isDumpProto) {
+                    dumpProto(fd);
+                } else {
+                    dumpInternal(pw);
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/power/SuspendBlocker.java b/services/core/java/com/android/server/power/SuspendBlocker.java
index 70b278a..30b35f0 100644
--- a/services/core/java/com/android/server/power/SuspendBlocker.java
+++ b/services/core/java/com/android/server/power/SuspendBlocker.java
@@ -16,6 +16,8 @@
 
 package com.android.server.power;
 
+import android.util.proto.ProtoOutputStream;
+
 /**
  * Low-level suspend blocker mechanism equivalent to holding a partial wake lock.
  *
@@ -40,4 +42,6 @@
      * The system may crash.
      */
     void release();
+
+    void writeToProto(ProtoOutputStream proto, long fieldId);
 }
diff --git a/services/core/java/com/android/server/power/WirelessChargerDetector.java b/services/core/java/com/android/server/power/WirelessChargerDetector.java
index 38f5d77..6ee9dcd 100644
--- a/services/core/java/com/android/server/power/WirelessChargerDetector.java
+++ b/services/core/java/com/android/server/power/WirelessChargerDetector.java
@@ -24,8 +24,10 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
+import android.service.power.WirelessChargerDetectorProto;
 import android.util.Slog;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.PrintWriter;
 
@@ -170,6 +172,44 @@
         }
     }
 
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long wcdToken = proto.start(fieldId);
+        synchronized (mLock) {
+            proto.write(WirelessChargerDetectorProto.IS_POWERED_WIRELESSLY, mPoweredWirelessly);
+            proto.write(WirelessChargerDetectorProto.IS_AT_REST, mAtRest);
+
+            final long restVectorToken = proto.start(WirelessChargerDetectorProto.REST);
+            proto.write(WirelessChargerDetectorProto.VectorProto.X, mRestX);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Y, mRestY);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Z, mRestZ);
+            proto.end(restVectorToken);
+
+            proto.write(
+                    WirelessChargerDetectorProto.IS_DETECTION_IN_PROGRESS, mDetectionInProgress);
+            proto.write(WirelessChargerDetectorProto.DETECTION_START_TIME_MS, mDetectionStartTime);
+            proto.write(
+                    WirelessChargerDetectorProto.IS_MUST_UPDATE_REST_POSITION,
+                    mMustUpdateRestPosition);
+            proto.write(WirelessChargerDetectorProto.TOTAL_SAMPLES, mTotalSamples);
+            proto.write(WirelessChargerDetectorProto.MOVING_SAMPLES, mMovingSamples);
+
+            final long firstSampleVectorToken =
+                    proto.start(WirelessChargerDetectorProto.FIRST_SAMPLE);
+            proto.write(WirelessChargerDetectorProto.VectorProto.X, mFirstSampleX);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Y, mFirstSampleY);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Z, mFirstSampleZ);
+            proto.end(firstSampleVectorToken);
+
+            final long lastSampleVectorToken =
+                    proto.start(WirelessChargerDetectorProto.LAST_SAMPLE);
+            proto.write(WirelessChargerDetectorProto.VectorProto.X, mLastSampleX);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Y, mLastSampleY);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Z, mLastSampleZ);
+            proto.end(lastSampleVectorToken);
+        }
+        proto.end(wcdToken);
+    }
+
     /**
      * Updates the charging state and returns true if docking was detected.
      *
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index d179ea7..3df4d24 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -680,10 +680,10 @@
                 }
             }
 
-            mCurrentVrModeComponent = calling;
             if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
                 sendUpdatedCaller = true;
             }
+            mCurrentVrModeComponent = calling;
 
             if (mCurrentVrModeUser != userId) {
                 mCurrentVrModeUser = userId;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 2b74f84..5041138 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
 
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.GraphicBuffer;
@@ -65,26 +66,22 @@
     }
 
     void onTransitionStarting() {
-        if (!ENABLE_TASK_SNAPSHOTS) {
-            return;
-        }
         handleClosingApps(mService.mClosingApps);
     }
 
-
     /**
      * Called when the visibility of an app changes outside of the regular app transition flow.
      */
     void notifyAppVisibilityChanged(AppWindowToken appWindowToken, boolean visible) {
-        if (!ENABLE_TASK_SNAPSHOTS) {
-            return;
-        }
         if (!visible) {
             handleClosingApps(Sets.newArraySet(appWindowToken));
         }
     }
 
     private void handleClosingApps(ArraySet<AppWindowToken> closingApps) {
+        if (!ENABLE_TASK_SNAPSHOTS || ActivityManager.isLowRamDeviceStatic()) {
+            return;
+        }
 
         // We need to take a snapshot of the task if and only if all activities of the task are
         // either closing or hidden.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 474610b..2f1aab6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5172,7 +5172,7 @@
     // Async Handler
     // -------------------------------------------------------------
 
-    final class H extends Handler {
+    final class H extends android.os.Handler {
         public static final int REPORT_FOCUS_CHANGE = 2;
         public static final int REPORT_LOSING_FOCUS = 3;
         public static final int DO_TRAVERSAL = 4;
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 4c89705..20b70a6 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1036,7 +1036,7 @@
     }
 
     // TODO(b/31632518)
-    gnssHal = IGnss::getService("gnss");
+    gnssHal = IGnss::getService();
     if (gnssHal != nullptr) {
         auto gnssXtra = gnssHal->getExtensionXtra();
         if (!gnssXtra.isOk()) {
diff --git a/services/core/jni/com_android_server_vr_VrManagerService.cpp b/services/core/jni/com_android_server_vr_VrManagerService.cpp
index e06e051..9052697 100644
--- a/services/core/jni/com_android_server_vr_VrManagerService.cpp
+++ b/services/core/jni/com_android_server_vr_VrManagerService.cpp
@@ -38,7 +38,7 @@
         return;
     }
 
-    gVr = IVr::getService("vr");
+    gVr = IVr::getService();
     if (gVr == nullptr) {
         ALOGW("%s: Could not open IVr interface", __FUNCTION__);
         return;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 620d441..17e6bba 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -41,6 +41,7 @@
 import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
 import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
@@ -332,15 +333,6 @@
     }
 
     /**
-     * Keyguard features that when set on a managed profile that doesn't have its own challenge will
-     * affect the profile's parent user. These can also be set on the managed profile's parent DPM
-     * instance.
-     */
-    private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
-            DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
-            | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
-
-    /**
      * Keyguard features that when set on a profile affect the profile content or challenge only.
      * These cannot be set on the managed profile's parent DPM instance
      */
@@ -4859,19 +4851,15 @@
     private void sendPrivateKeyAliasResponse(final String alias, final IBinder responseBinder) {
         final IKeyChainAliasCallback keyChainAliasResponse =
                 IKeyChainAliasCallback.Stub.asInterface(responseBinder);
-        new AsyncTask<Void, Void, Void>() {
-            @Override
-            protected Void doInBackground(Void... unused) {
-                try {
-                    keyChainAliasResponse.alias(alias);
-                } catch (Exception e) {
-                    // Catch everything (not just RemoteException): caller could throw a
-                    // RuntimeException back across processes.
-                    Log.e(LOG_TAG, "error while responding to callback", e);
-                }
-                return null;
-            }
-        }.execute();
+        // Send the response. It's OK to do this from the main thread because IKeyChainAliasCallback
+        // is oneway, which means it won't block if the recipient lives in another process.
+        try {
+            keyChainAliasResponse.alias(alias);
+        } catch (Exception e) {
+            // Caller could throw RuntimeException or RemoteException back across processes. Catch
+            // everything just to be sure.
+            Log.e(LOG_TAG, "error while responding to callback", e);
+        }
     }
 
     /**
diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
index b26bac3..0cf4994 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
@@ -89,6 +89,7 @@
         when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
         NotificationChannel channel =
                 new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
         channel.setShowBadge(false);
 
         NotificationRecord r = getNotificationRecord(channel);
@@ -107,6 +108,7 @@
         NotificationChannel channel =
                 new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_HIGH);
         channel.setShowBadge(true);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
 
         NotificationRecord r = getNotificationRecord(channel);
 
@@ -124,6 +126,7 @@
         NotificationChannel channel =
                 new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
         channel.setShowBadge(true);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
 
         NotificationRecord r = getNotificationRecord(channel);
 
@@ -141,6 +144,7 @@
         NotificationChannel channel =
                 new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
         channel.setShowBadge(false);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
 
         NotificationRecord r = getNotificationRecord(channel);
 
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index 69724f4..c5abba8 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -18,6 +18,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -27,6 +28,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
@@ -71,8 +73,11 @@
     public void testSnoozeForTime() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         mSnoozeHelper.snooze(r, 1000);
+        ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class);
         verify(mAm, times(1)).setExactAndAllowWhileIdle(
-                anyInt(), eq((long) 1000), any(PendingIntent.class));
+                anyInt(), captor.capture(), any(PendingIntent.class));
+        long actualSnoozedUntilDuration = captor.getValue() - SystemClock.elapsedRealtime();
+        assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 2);
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
     }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 665f01f..4141f2f 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -56,8 +56,7 @@
 import android.net.INetworkScoreCache;
 import android.net.NetworkKey;
 import android.net.NetworkScoreManager;
-import android.net.NetworkScorerAppManager;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScorerAppData;
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
@@ -201,10 +200,10 @@
     }
 
     @Test
-    public void testSystemRunning() {
+    public void testOnUserUnlocked() {
         when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
 
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
 
         verify(mContext).bindServiceAsUser(MockUtils.checkIntent(
                 new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
@@ -549,9 +548,9 @@
     }
 
     @Test
-    public void testSetActiveScorer_noScoreNetworksPermission() {
-        doThrow(new SecurityException()).when(mContext)
-                .enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString());
+    public void testSetActiveScorer_noRequestNetworkScoresPermission() {
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
 
         try {
             mNetworkScoreService.setActiveScorer(null);
@@ -630,7 +629,7 @@
 
     @Test
     public void testIsCallerActiveScorer_noBoundService() throws Exception {
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
 
         assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
     }
@@ -651,7 +650,7 @@
 
     @Test
     public void testGetActiveScorerPackage_notActive() throws Exception {
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
 
         assertNull(mNetworkScoreService.getActiveScorerPackage());
     }
@@ -659,7 +658,7 @@
     @Test
     public void testGetActiveScorerPackage_active() throws Exception {
         when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
 
         assertEquals(NEW_SCORER.getRecommendationServicePackageName(),
                 mNetworkScoreService.getActiveScorerPackage());
@@ -960,7 +959,7 @@
                 return true;
             }
         });
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
     }
 
     private void bindToScorer(boolean callerIsScorer) {
@@ -974,7 +973,7 @@
         when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
         when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
                 isA(UserHandle.class))).thenReturn(true);
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
     }
 
     private static class OnResultListener implements RemoteCallback.OnResultListener {
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
similarity index 61%
rename from core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
rename to services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
index 347024d..e9a2d34 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
@@ -14,13 +14,22 @@
  * limitations under the License
  */
 
-package android.net;
+package com.android.server;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.Manifest.permission;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -29,144 +38,84 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.test.InstrumentationTestCase;
+import android.support.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
 import java.util.List;
 
-public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class NetworkScorerAppManagerTest {
     @Mock private Context mMockContext;
     @Mock private PackageManager mMockPm;
     @Mock private Resources mResources;
-    @Mock private ContentResolver mContentResolver;
-    private Context mTargetContext;
+    @Mock private NetworkScorerAppManager.SettingsFacade mSettingsFacade;
     private NetworkScorerAppManager mNetworkScorerAppManager;
+    private List<ResolveInfo> mAvailableServices;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-
-        // Configuration needed to make mockito/dexcache work.
-        mTargetContext = getInstrumentation().getTargetContext();
-        System.setProperty("dexmaker.dexcache", mTargetContext.getCacheDir().getPath());
-        ClassLoader newClassLoader = getInstrumentation().getClass().getClassLoader();
-        Thread.currentThread().setContextClassLoader(newClassLoader);
-
         MockitoAnnotations.initMocks(this);
+        mAvailableServices = new ArrayList<>();
         when(mMockContext.getPackageManager()).thenReturn(mMockPm);
+        when(mMockPm.queryIntentServices(Mockito.argThat(new ArgumentMatcher<Intent>() {
+            @Override
+            public boolean matches(Object object) {
+                Intent intent = (Intent) object;
+                return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS.equals(intent.getAction());
+            }
+        }), eq(PackageManager.GET_META_DATA))).thenReturn(mAvailableServices);
         when(mMockContext.getResources()).thenReturn(mResources);
-        when(mMockContext.getContentResolver()).thenReturn(mTargetContext.getContentResolver());
-        mNetworkScorerAppManager = new NetworkScorerAppManager(mMockContext);
+
+        mNetworkScorerAppManager = new NetworkScorerAppManager(mMockContext, mSettingsFacade);
     }
 
-    public void testGetPotentialRecommendationProviderPackages_emptyConfig() throws Exception {
-        setNetworkRecommendationPackageNames(/*no configured packages*/);
-        assertTrue(mNetworkScorerAppManager.getPotentialRecommendationProviderPackages().isEmpty());
-    }
-
-    public void testGetPotentialRecommendationProviderPackages_permissionNotGranted()
-            throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksDenied("package1");
-
-        assertTrue(mNetworkScorerAppManager.getPotentialRecommendationProviderPackages().isEmpty());
-    }
-
-    public void testGetPotentialRecommendationProviderPackages_permissionGranted()
-            throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksGranted("package1");
-
-        List<String> potentialProviderPackages =
-                mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
-
-        assertFalse(potentialProviderPackages.isEmpty());
-        assertEquals("package1", potentialProviderPackages.get(0));
-    }
-
-    public void testGetPotentialRecommendationProviderPackages_multipleConfigured()
-            throws Exception {
-        setNetworkRecommendationPackageNames("package1", "package2");
-        mockScoreNetworksDenied("package1");
-        mockScoreNetworksGranted("package2");
-
-        List<String> potentialProviderPackages =
-                mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
-
-        assertEquals(1, potentialProviderPackages.size());
-        assertEquals("package2", potentialProviderPackages.get(0));
-    }
-
-    public void testGetNetworkRecommendationProviderData_noPotentialPackages() throws Exception {
-        setNetworkRecommendationPackageNames(/*no configured packages*/);
-        assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
-    }
-
-    public void testGetNetworkRecommendationProviderData_serviceMissing() throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksGranted("package1");
-
-        assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
-    }
-
-    public void testGetNetworkRecommendationProviderData_scoreNetworksNotGranted()
-            throws Exception {
-        final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
-        mockScoreNetworksDenied(recoComponent.getPackageName());
-        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-
-        assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
-    }
-
-    public void testGetNetworkRecommendationProviderData_available() throws Exception {
-        final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
-        mockScoreNetworksGranted(recoComponent.getPackageName());
-        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-
-        NetworkScorerAppData appData =
-                mNetworkScorerAppManager.getNetworkRecommendationProviderData();
-        assertNotNull(appData);
-        assertEquals(recoComponent, appData.getRecommendationServiceComponent());
-        assertEquals(924, appData.packageUid);
-    }
-
+    @Test
     public void testGetActiveScorer_providerAvailable() throws Exception {
         final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        setNetworkRecoPackageSetting(recoComponent.getPackageName());
         mockScoreNetworksGranted(recoComponent.getPackageName());
         mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
 
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNotNull(activeScorer);
         assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
         assertEquals(924, activeScorer.packageUid);
     }
 
+    @Test
+    public void testGetActiveScorer_permissionMissing() throws Exception {
+        final ComponentName recoComponent = new ComponentName("package1", "class1");
+        setNetworkRecoPackageSetting(recoComponent.getPackageName());
+        mockScoreNetworksDenied(recoComponent.getPackageName());
+        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
+
+        final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+        assertNull(activeScorer);
+    }
+
+    @Test
     public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityNotSet()
             throws Exception {
         final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        setNetworkRecoPackageSetting(recoComponent.getPackageName());
         mockScoreNetworksGranted(recoComponent.getPackageName());
         mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
                 null /* enableUseOpenWifiPackageActivityPackage*/);
 
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNotNull(activeScorer);
         assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
@@ -174,17 +123,15 @@
         assertNull(activeScorer.getEnableUseOpenWifiActivity());
     }
 
+    @Test
     public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityNotResolved()
             throws Exception {
         final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        setNetworkRecoPackageSetting(recoComponent.getPackageName());
         mockScoreNetworksGranted(recoComponent.getPackageName());
         mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
                 "package2" /* enableUseOpenWifiPackageActivityPackage*/);
 
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNotNull(activeScorer);
         assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
@@ -192,19 +139,17 @@
         assertNull(activeScorer.getEnableUseOpenWifiActivity());
     }
 
+    @Test
     public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityResolved()
             throws Exception {
         final ComponentName recoComponent = new ComponentName("package1", "class1");
         final ComponentName enableUseOpenWifiComponent = new ComponentName("package2", "class2");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        setNetworkRecoPackageSetting(recoComponent.getPackageName());
         mockScoreNetworksGranted(recoComponent.getPackageName());
         mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
                 enableUseOpenWifiComponent.getPackageName());
         mockEnableUseOpenWifiActivity(enableUseOpenWifiComponent);
 
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNotNull(activeScorer);
         assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
@@ -212,33 +157,105 @@
         assertEquals(enableUseOpenWifiComponent, activeScorer.getEnableUseOpenWifiActivity());
     }
 
-    public void testGetActiveScorer_providerNotAvailable()
+    @Test
+    public void testGetActiveScorer_packageSettingIsNull()
             throws Exception {
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
+        // NETWORK_RECOMMENDATIONS_PACKAGE is null
 
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNull(activeScorer);
     }
 
-    public void testGetActiveScorer_recommendationsDisabled() throws Exception {
+    @Test
+    public void testGetActiveScorer_packageSettingIsInvalid() throws Exception {
         final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        setDefaultNetworkRecommendationPackage(recoComponent.getPackageName());
         mockScoreNetworksGranted(recoComponent.getPackageName());
-        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0);
+        // NETWORK_RECOMMENDATIONS_PACKAGE is set to a package that isn't a recommender.
 
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNull(activeScorer);
     }
 
-    private void setNetworkRecommendationPackageNames(String... names) {
-        if (names == null) {
-            names = new String[0];
-        }
-        when(mResources.getStringArray(R.array.config_networkRecommendationPackageNames))
-                .thenReturn(names);
+    @Test
+    public void testSetActiveScorer_noChange() throws Exception {
+        String packageName = "package";
+        setNetworkRecoPackageSetting(packageName);
+
+        assertTrue(mNetworkScorerAppManager.setActiveScorer(packageName));
+        verify(mSettingsFacade, never()).putString(any(), any(), any());
+    }
+
+    @Test
+    public void testSetActiveScorer_nullPackage() throws Exception {
+        String packageName = "package";
+        String defaultPackage = "defaultPackage";
+        setNetworkRecoPackageSetting(packageName);
+        setDefaultNetworkRecommendationPackage(defaultPackage);
+
+        assertTrue(mNetworkScorerAppManager.setActiveScorer(null));
+        verify(mSettingsFacade).putString(mMockContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
+    }
+
+    @Test
+    public void testSetActiveScorer_validPackage() throws Exception {
+        String packageName = "package";
+        String newPackage = "newPackage";
+        setNetworkRecoPackageSetting(packageName);
+        final ComponentName recoComponent = new ComponentName(newPackage, "class1");
+        mockScoreNetworksGranted(recoComponent.getPackageName());
+        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);
+
+        assertTrue(mNetworkScorerAppManager.setActiveScorer(newPackage));
+        verify(mSettingsFacade).putString(mMockContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, newPackage);
+    }
+
+    @Test
+    public void testSetActiveScorer_invalidPackage() throws Exception {
+        String packageName = "package";
+        String newPackage = "newPackage";
+        setNetworkRecoPackageSetting(packageName);
+        // newPackage doesn't resolve to a valid recommender
+
+        assertFalse(mNetworkScorerAppManager.setActiveScorer(newPackage));
+        verify(mSettingsFacade, never()).putString(any(), any(), any());
+    }
+
+
+    @Test
+    public void testRevertToDefaultIfNoActive_notActive() throws Exception {
+        String defaultPackage = "defaultPackage";
+        setDefaultNetworkRecommendationPackage(defaultPackage);
+
+        mNetworkScorerAppManager.revertToDefaultIfNoActive();
+
+        verify(mSettingsFacade).putString(mMockContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
+    }
+
+    @Test
+    public void testRevertToDefaultIfNoActive_active() throws Exception {
+        String packageName = "package";
+        setNetworkRecoPackageSetting(packageName);
+        final ComponentName recoComponent = new ComponentName(packageName, "class1");
+        mockScoreNetworksGranted(recoComponent.getPackageName());
+        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);
+
+        mNetworkScorerAppManager.revertToDefaultIfNoActive();
+
+        verify(mSettingsFacade, never()).putString(any(), any(), any());
+    }
+
+    private void setNetworkRecoPackageSetting(String packageName) {
+        when(mSettingsFacade.getString(mMockContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE)).thenReturn(packageName);
+    }
+
+    private void setDefaultNetworkRecommendationPackage(String name) {
+        when(mResources.getString(R.string.config_defaultNetworkRecommendationProviderPackage))
+                .thenReturn(name);
     }
 
     private void mockScoreNetworksGranted(String packageName) {
@@ -281,6 +298,8 @@
                                 && compName.getPackageName().equals(intent.getPackage());
                     }
                 }), Mockito.eq(flags))).thenReturn(serviceInfo);
+
+        mAvailableServices.add(serviceInfo);
     }
 
     private void mockEnableUseOpenWifiActivity(final ComponentName useOpenWifiComp) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 100338e..1b59d72 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -34,6 +34,7 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -1324,20 +1325,23 @@
     protected ShortcutInfo makeShortcut(String id) {
         return makeShortcut(
                 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
     }
 
     @Deprecated // Title was renamed to short label.
     protected ShortcutInfo makeShortcutWithTitle(String id, String title) {
         return makeShortcut(
                 id, title, /* activity =*/ null, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
     }
 
     protected ShortcutInfo makeShortcutWithShortLabel(String id, String shortLabel) {
         return makeShortcut(
                 id, shortLabel, /* activity =*/ null, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
     }
 
     /**
@@ -1346,7 +1350,8 @@
     protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) {
         final ShortcutInfo s = makeShortcut(
                 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
         s.setTimestamp(timestamp);
         return s;
     }
@@ -1358,7 +1363,8 @@
             ComponentName activity) {
         final ShortcutInfo s = makeShortcut(
                 id, "Title-" + id, activity, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
         s.setTimestamp(timestamp);
         return s;
     }
@@ -1369,7 +1375,27 @@
     protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
         return makeShortcut(
                 id, "Title-" + id, /* activity =*/ null, icon,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
+    }
+
+    protected ShortcutInfo makeChooserShortcut(String id, int i, boolean includeIntent) {
+        List<IntentFilter> filters = new ArrayList<>();
+        List<ComponentName> componentNames = new ArrayList<>();
+        for(int j = 0; j < i; j++) {
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction("view");
+            filters.add(filter);
+
+            componentNames.add(new ComponentName("xxxx", "yy" + i));
+        }
+        Intent intent = null;
+        if (includeIntent) {
+            intent = makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class);
+        }
+        return makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, /* icon */ null,
+                intent, /* rank =*/ 0, filters, componentNames);
     }
 
     protected ShortcutInfo makePackageShortcut(String packageName, String id) {
@@ -1378,7 +1404,8 @@
         setCaller(packageName);
         ShortcutInfo s = makeShortcut(
                 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
         setCaller(origCaller); // restore the caller
 
         return s;
@@ -1402,39 +1429,52 @@
     protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) {
         return makeShortcut(
                 id, "Title-" + id, activity, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* chooserFilters =*/ null, /* chooserComponentNames =*/ null);
     }
 
     protected ShortcutInfo makeShortcutWithIntent(String id, Intent intent) {
         return makeShortcut(
                 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
-                intent, /* rank =*/ 0);
+                intent, /* rank =*/ 0, /* chooserFilters =*/ null,
+                /* chooserComponentNames =*/ null);
+
     }
 
     protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity,
             String title) {
         return makeShortcut(
                 id, title, activity, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* chooserFilters =*/ null, /* chooserComponentNames =*/ null);
     }
 
     protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity,
             int rank) {
         return makeShortcut(
                 id, "Title-" + id, activity, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank,
+                /* chooserFilters =*/ null, /* chooserComponentNames =*/ null);
     }
 
     /**
      * Make a shortcut with details.
      */
     protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
-            Icon icon, Intent intent, int rank) {
+            Icon icon, Intent intent, int rank, @Nullable List<IntentFilter> chooserFilters,
+            @Nullable List<ComponentName> chooserComponentNames) {
         final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
                 .setActivity(new ComponentName(mClientContext.getPackageName(), "main"))
                 .setShortLabel(title)
-                .setRank(rank)
-                .setIntent(intent);
+                .setRank(rank);
+        if (intent != null) {
+            b.setIntent(intent);
+        }
+        if (chooserFilters != null) {
+            for (int i = 0; i < chooserFilters.size(); i++) {
+                b.addChooserIntentFilter(chooserFilters.get(i), chooserComponentNames.get(i));
+            }
+        }
         if (icon != null) {
             b.setIcon(icon);
         }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 28596f7..d8db331 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -413,9 +413,7 @@
         assertTrue(Arrays.equals(a.sharedLibraryFiles, that.sharedLibraryFiles));
         assertEquals(a.dataDir, that.dataDir);
         assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir);
-        assertEquals(a.deviceEncryptedDataDir, that.deviceEncryptedDataDir);
         assertEquals(a.credentialProtectedDataDir, that.credentialProtectedDataDir);
-        assertEquals(a.credentialEncryptedDataDir, that.credentialEncryptedDataDir);
         assertEquals(a.nativeLibraryDir, that.nativeLibraryDir);
         assertEquals(a.secondaryNativeLibraryDir, that.secondaryNativeLibraryDir);
         assertEquals(a.nativeLibraryRootDir, that.nativeLibraryRootDir);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index e4d92ba..94ff07f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.pm;
 
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllChooser;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDisabled;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamic;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamicOrPinned;
@@ -256,7 +257,9 @@
                 icon1,
                 makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
                         "key1", "val1", "nest", makeBundle("key", 123)),
-                /* weight */ 10);
+                /* weight */ 10,
+                /* chooserFilter=*/ null,
+                /* chooserComponentNames=*/ null);
 
         final ShortcutInfo si2 = makeShortcut(
                 "shortcut2",
@@ -264,14 +267,18 @@
                 /* activity */ null,
                 icon2,
                 makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
-                /* weight */ 12);
+                /* weight */ 12,
+                /* chooserFilter=*/ null,
+                /* chooserComponentNames=*/ null);
         final ShortcutInfo si3 = makeShortcut(
                 "shortcut3",
                 "Title 3",
                 /* activity */ null,
                 icon3,
                 makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
-                /* weight */ 13);
+                /* weight */ 13,
+                /* chooserFilter=*/ null,
+                /* chooserComponentNames=*/ null);
 
         assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
         assertShortcutIds(assertAllNotKeyFieldsOnly(
@@ -982,8 +989,10 @@
                     makeShortcut("s2"),
                     makeShortcut("s3"),
                     makeShortcut("s4"),
-                    makeShortcut("s5")
-            )));
+                    makeShortcut("s5"),
+                    makeChooserShortcut("s6", 2, true),
+                    makeChooserShortcut("s7", 2, true),
+                    makeChooserShortcut("s8", 1, true))));
         });
         runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
             assertTrue(mManager.setDynamicShortcuts(list(
@@ -991,11 +1000,13 @@
                     makeShortcut("s2"),
                     makeShortcut("s3"),
                     makeShortcut("s4"),
-                    makeShortcut("s5")
-            )));
+                    makeShortcut("s5"),
+                    makeChooserShortcut("s6", 2, true),
+                    makeChooserShortcut("s7", 2, true),
+                    makeChooserShortcut("s8", 1, true))));
         });
         runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> {
-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"),
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3", "s6"),
                     getCallingUser());
             mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s4", "s5"),
                     getCallingUser());
@@ -1008,19 +1019,20 @@
             mManager.removeDynamicShortcuts(list("s1"));
             mManager.removeDynamicShortcuts(list("s3"));
             mManager.removeDynamicShortcuts(list("s5"));
+            mManager.removeDynamicShortcuts(list("s7"));
         });
         runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
             assertShortcutIds(assertAllDynamic(
                     mManager.getDynamicShortcuts()),
-                    "s3", "s4", "s5");
+                    "s3", "s4", "s5", "s6", "s7", "s8");
             assertShortcutIds(assertAllPinned(
                     mManager.getPinnedShortcuts()),
-                    "s2", "s3");
+                    "s2", "s3", "s6");
         });
         runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
             assertShortcutIds(assertAllDynamic(
                     mManager.getDynamicShortcuts()),
-                    "s2", "s4");
+                    "s2", "s4", "s6", "s8");
             assertShortcutIds(assertAllPinned(
                     mManager.getPinnedShortcuts()),
                     "s4", "s5");
@@ -1057,10 +1069,10 @@
         runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
             assertShortcutIds(assertAllDynamic(
                     mManager.getDynamicShortcuts()),
-                    "s3", "s4", "s5");
+                    "s3", "s4", "s5", "s6", "s7", "s8");
             assertShortcutIds(assertAllPinned(
                     mManager.getPinnedShortcuts()),
-                    "s2", "s3");
+                    "s2", "s3", "s6");
 
             ShortcutInfo s = getCallerShortcut("s2");
             assertTrue(s.hasIconResource());
@@ -1076,7 +1088,7 @@
         runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
             assertShortcutIds(assertAllDynamic(
                     mManager.getDynamicShortcuts()),
-                    "s2", "s4");
+                    "s2", "s4", "s6", "s8");
             assertShortcutIds(assertAllPinned(
                     mManager.getPinnedShortcuts()),
                     "s4", "s5");
@@ -1173,7 +1185,46 @@
         });
     }
 
-    // === Test for launcher side APIs ===
+    public void testUpdateShortcuts_chooser() {
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"),
+                    makeChooserShortcut("s2", 2, false),
+                    makeChooserShortcut("s3", 2, false)
+            )));
+
+            assertFalse(getCallerShortcut("s1").isChooser());
+            assertTrue(getCallerShortcut("s2").isChooser());
+            assertTrue(getCallerShortcut("s3").isChooser());
+
+            ShortcutInfo s = getCallerShortcut("s1");
+            assertNull(s.getChooserIntentFilters());
+            assertNull(s.getChooserComponentNames());
+
+            assertTrue(getCallerShortcut("s1").isDynamic());
+            assertFalse(getCallerShortcut("s2").isDynamic());
+            assertFalse(getCallerShortcut("s3").isDynamic());
+
+
+            // Replace 2 with a chooser shortcut
+            mManager.updateShortcuts(list(makeChooserShortcut("s1", 2, true)));
+
+            s = getCallerShortcut("s1");
+            assertEquals(2, s.getChooserIntentFilters().length);
+            assertEquals(2, s.getChooserComponentNames().length);
+
+            assertShortcutIds(assertAllChooser(
+                    mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+
+            assertTrue(getCallerShortcut("s1").isDynamic());
+            assertFalse(getCallerShortcut("s2").isDynamic());
+            assertFalse(getCallerShortcut("s3").isDynamic());
+        });
+    }
+
+
+            // === Test for launcher side APIs ===
 
     public void testGetShortcuts() {
 
@@ -1484,15 +1535,17 @@
                 /* icon =*/ null,
                 makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
                         "key1", "val1", "nest", makeBundle("key", 123)),
-                /* weight */ 10);
+                        /* weight */ 10, /* chooserFilter=*/ null,
+                        /* chooserComponentNames=*/ null);
 
         final ShortcutInfo s1_2 = makeShortcut(
-                "s2",
-                "Title 2",
+                "s2", "Title 2",
                 /* activity */ null,
                 /* icon =*/ null,
                 makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
-                /* weight */ 12);
+                /* weight */ 12,
+                /* chooserFilter=*/ null,
+                /* chooserComponentNames=*/ null);
 
         assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
         dumpsysOnLogcat();
@@ -1505,7 +1558,9 @@
                 /* icon =*/ null,
                 makeIntent(Intent.ACTION_ANSWER, ShortcutActivity2.class,
                         "key1", "val1", "nest", makeBundle("key", 123)),
-                /* weight */ 10);
+                /* weight */ 10,
+                /* chooserFilter=*/ null,
+                /* chooserComponentNames=*/ null);
         assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
         dumpsysOnLogcat();
 
@@ -2674,10 +2729,12 @@
             final ShortcutInfo s1_2 = makeShortcut(
                     "s2",
                     "Title 2",
-            /* activity */ null,
-            /* icon =*/ null,
+                    /* activity */ null,
+                    /* icon =*/ null,
                     makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
-            /* rank */ 12);
+                    /* rank */ 12,
+                    /* chooserFilter=*/ null,
+                    /* chooserComponentNames=*/ null);
 
             final ShortcutInfo s1_3 = makeShortcut("s3");
 
@@ -2692,7 +2749,9 @@
                     /* icon =*/ null,
                     makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
                             "key1", "val1", "nest", makeBundle("key", 123)),
-                    /* weight */ 10);
+                    /* weight */ 10,
+                    /* chooserFilter=*/ null,
+                    /* chooserComponentNames=*/ null);
             assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
         });
 
@@ -3110,7 +3169,9 @@
                     icon1,
                     makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
                             "key1", "val1", "nest", makeBundle("key", 123)),
-                        /* weight */ 10);
+                        /* weight */ 10,
+                    /* chooserFilter=*/ null,
+                    /* chooserComponentNames=*/ null);
 
             final ShortcutInfo si2 = makeShortcut(
                     "s2",
@@ -3118,7 +3179,9 @@
                         /* activity */ null,
                     icon2,
                     makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
-                        /* weight */ 12);
+                        /* weight */ 12,
+                    /* chooserFilter=*/ null,
+                    /* chooserComponentNames=*/ null);
 
             assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
 
@@ -3136,8 +3199,8 @@
                     makeComponent(ShortcutActivity.class),
                     icon1,
                     makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
-                            "key1", "val1", "nest", makeBundle("key", 123)),
-                        /* weight */ 10);
+                            "key1", "val1", "nest", makeBundle("key", 123)), /* weight */ 10,
+                            /* chooserFilter=*/ null, /* chooserComponentNames=*/ null);
 
             final ShortcutInfo si2 = makeShortcut(
                     "s2",
@@ -3145,7 +3208,8 @@
                         /* activity */ null,
                     icon2,
                     makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
-                        /* weight */ 12);
+                        /* weight */ 12, /* chooserFilter=*/ null,
+                        /* chooserComponentNames=*/ null);
 
             assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
 
@@ -3167,7 +3231,8 @@
                     icon1,
                     makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
                             "key1", "val1", "nest", makeBundle("key", 123)),
-                        /* weight */ 10);
+                            /* weight */ 10, /* chooserFilter=*/ null,
+                            /* chooserComponentNames=*/ null);
 
             final ShortcutInfo si2 = makeShortcut(
                     "s2",
@@ -3175,7 +3240,8 @@
                         /* activity */ null,
                     icon2,
                     makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
-                        /* weight */ 12);
+                            /* weight */ 12, /* chooserFilter=*/ null,
+                            /* chooserComponentNames=*/ null);
 
             assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
 
@@ -6800,10 +6866,12 @@
             mManager.setDynamicShortcuts(list(
                     makeShortcut("ms1", "title1",
                             new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
-                    /* icon */ null, new Intent("action1"), /* rank */ 0),
+                            /* icon */ null, new Intent("action1"), /* rank */ 0,
+                            /* chooserFilter=*/ null, /* chooserComponentNames=*/ null),
                     makeShortcut("ms2", "title2",
                             new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
-                    /* icon */ null, new Intent("action1"), /* rank */ 0)));
+                            /* icon */ null, new Intent("action1"), /* rank */ 0, /* chooserFilter=*/ null,
+                            /* chooserComponentNames=*/ null)));
         });
 
         runWithCaller(LAUNCHER_1, USER_0, () -> {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 28ec4fd..c54fa02 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -34,6 +34,7 @@
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
 import android.graphics.BitmapFactory;
@@ -93,11 +94,6 @@
 
         assertExpectException(
                 RuntimeException.class,
-                "intents cannot contain null",
-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(null));
-
-        assertExpectException(
-                RuntimeException.class,
                 "action must be set",
                 () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
 
@@ -142,6 +138,19 @@
                 "disabledMessage cannot be empty",
                 () -> new ShortcutInfo.Builder(getTestContext(), "id").setDisabledMessage(""));
 
+
+        assertExpectException(
+                RuntimeException.class,
+                "component name cannot be null",
+                () -> new ShortcutInfo.Builder(getTestContext(), "id")
+                        .addChooserIntentFilter(new IntentFilter(Intent.ACTION_SEND), null));
+
+        assertExpectException(
+                RuntimeException.class,
+                "intent filter cannot be null",
+                () -> new ShortcutInfo.Builder(getTestContext(), "id")
+                        .addChooserIntentFilter(null, new ComponentName("xxx", "s")));
+
         assertExpectException(NullPointerException.class, "action must be set",
                 () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
 
@@ -240,6 +249,10 @@
 
         PersistableBundle pb = new PersistableBundle();
         pb.putInt("k", 1);
+        IntentFilter chooserFilter = new IntentFilter();
+        chooserFilter.addAction(Intent.ACTION_VIEW);
+        PersistableBundle pb2 = new PersistableBundle();
+        pb2.putInt("l", 1);
 
         si = new ShortcutInfo.Builder(getTestContext())
                 .setId("id")
@@ -252,6 +265,8 @@
                 .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                 .setRank(123)
                 .setExtras(pb)
+                .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b"))
+                .setChooserExtras(pb2)
                 .build();
         si.addFlags(ShortcutInfo.FLAG_PINNED);
         si.setBitmapPath("abc");
@@ -282,6 +297,12 @@
         assertEquals(null, si.getTextResName());
         assertEquals(0, si.getDisabledMessageResourceId());
         assertEquals(null, si.getDisabledMessageResName());
+
+        assertEquals(1, si.getChooserIntentFilters().length);
+        assertEquals(Intent.ACTION_VIEW, si.getChooserIntentFilters()[0].getAction(0));
+        assertEquals(1, si.getChooserComponentNames().length);
+        assertEquals(new ComponentName("a", "b"), si.getChooserComponentNames()[0]);
+        assertEquals(1, si.getChooserExtras().getInt("l"));
     }
 
     public void testShortcutInfoParcel_resId() {
@@ -290,6 +311,10 @@
 
         PersistableBundle pb = new PersistableBundle();
         pb.putInt("k", 1);
+        IntentFilter chooserFilter = new IntentFilter();
+        chooserFilter.addAction(Intent.ACTION_VIEW);
+        PersistableBundle pb2 = new PersistableBundle();
+        pb2.putInt("l", 1);
 
         si = new ShortcutInfo.Builder(getTestContext())
                 .setId("id")
@@ -302,6 +327,8 @@
                 .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                 .setRank(123)
                 .setExtras(pb)
+                .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b"))
+                .setChooserExtras(pb2)
                 .build();
         si.addFlags(ShortcutInfo.FLAG_PINNED);
         si.setBitmapPath("abc");
@@ -338,6 +365,11 @@
 
         PersistableBundle pb = new PersistableBundle();
         pb.putInt("k", 1);
+        IntentFilter chooserFilter = new IntentFilter();
+        chooserFilter.addAction(Intent.ACTION_VIEW);
+        PersistableBundle pb2 = new PersistableBundle();
+        pb2.putInt("l", 1);
+
         ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
                 .setId("id")
                 .setActivity(new ComponentName("a", "b"))
@@ -349,6 +381,8 @@
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                 .setRank(123)
                 .setExtras(pb)
+                .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b"))
+                .setChooserExtras(pb2)
                 .build();
         sorig.addFlags(ShortcutInfo.FLAG_PINNED);
         sorig.setBitmapPath("abc");
@@ -378,6 +412,12 @@
         assertEquals(456, si.getIconResourceId());
         assertEquals("string/r456", si.getIconResName());
 
+        assertEquals(1, si.getChooserIntentFilters().length);
+        assertEquals(Intent.ACTION_VIEW, si.getChooserIntentFilters()[0].getAction(0));
+        assertEquals(1, si.getChooserComponentNames().length);
+        assertEquals(new ComponentName("a", "b"), si.getChooserComponentNames()[0]);
+        assertEquals(1, si.getChooserExtras().getInt("l"));
+
         si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
 
         assertEquals(mClientContext.getPackageName(), si.getPackage());
@@ -445,6 +485,10 @@
 
         PersistableBundle pb = new PersistableBundle();
         pb.putInt("k", 1);
+        IntentFilter chooserFilter = new IntentFilter();
+        chooserFilter.addAction(Intent.ACTION_VIEW);
+        PersistableBundle pb2 = new PersistableBundle();
+        pb2.putInt("l", 1);
         ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
                 .setId("id")
                 .setActivity(new ComponentName("a", "b"))
@@ -456,6 +500,8 @@
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                 .setRank(123)
                 .setExtras(pb)
+                .addChooserIntentFilter(chooserFilter, new ComponentName("a", "b"))
+                .setChooserExtras(pb2)
                 .build();
         sorig.addFlags(ShortcutInfo.FLAG_PINNED);
         sorig.setBitmapPath("abc");
@@ -488,6 +534,12 @@
         assertEquals(456, si.getIconResourceId());
         assertEquals("string/r456", si.getIconResName());
 
+        assertEquals(1, si.getChooserIntentFilters().length);
+        assertEquals(Intent.ACTION_VIEW, si.getChooserIntentFilters()[0].getAction(0));
+        assertEquals(1, si.getChooserComponentNames().length);
+        assertEquals(new ComponentName("a", "b"), si.getChooserComponentNames()[0]);
+        assertEquals(1, si.getChooserExtras().getInt("l"));
+
         si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
 
         assertEquals(mClientContext.getPackageName(), si.getPackage());
@@ -603,6 +655,10 @@
     public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
         PersistableBundle pb = new PersistableBundle();
         pb.putInt("k", 1);
+        IntentFilter chooserFilter = new IntentFilter();
+        chooserFilter.addAction(Intent.ACTION_VIEW);
+        PersistableBundle pb2 = new PersistableBundle();
+        pb2.putInt("l", 1);
         ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
                 .setId("id")
                 .setActivity(new ComponentName("a", "b"))
@@ -714,12 +770,12 @@
         assertEquals(999, si.getRank());
 
 
-        PersistableBundle pb2 = new PersistableBundle();
-        pb2.putInt("x", 99);
+        PersistableBundle pb3 = new PersistableBundle();
+        pb3.putInt("x", 99);
 
         si = sorig.clone(/* flags=*/ 0);
         si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
-                .setExtras(pb2).build());
+                .setExtras(pb3).build());
         assertEquals("text", si.getText());
         assertEquals(99, si.getExtras().getInt("x"));
     }
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
index 0bd014c..42ddedf 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
@@ -45,12 +45,12 @@
         final int userId = 0;
         AppIdleHistory aih = new AppIdleHistory(mStorageDir, 0);
 
-        aih.updateDisplayLocked(true, /* elapsedRealtime= */ 1000);
-        aih.updateDisplayLocked(false, /* elapsedRealtime= */ 2000);
+        aih.updateDisplay(true, /* elapsedRealtime= */ 1000);
+        aih.updateDisplay(false, /* elapsedRealtime= */ 2000);
         // Screen On time file should be written right away
         assertTrue(aih.getScreenOnTimeFile().exists());
 
-        aih.writeAppIdleTimesLocked(userId);
+        aih.writeAppIdleTimes(userId);
         // stats file should be written now
         assertTrue(new File(new File(mStorageDir, "users/" + userId),
                 AppIdleHistory.APP_IDLE_FILENAME).exists());
@@ -58,43 +58,43 @@
 
     public void testScreenOnTime() {
         AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
-        aih.updateDisplayLocked(false, 2000);
-        assertEquals(aih.getScreenOnTimeLocked(2000), 0);
-        aih.updateDisplayLocked(true, 3000);
-        assertEquals(aih.getScreenOnTimeLocked(4000), 1000);
-        assertEquals(aih.getScreenOnTimeLocked(5000), 2000);
-        aih.updateDisplayLocked(false, 6000);
+        aih.updateDisplay(false, 2000);
+        assertEquals(aih.getScreenOnTime(2000), 0);
+        aih.updateDisplay(true, 3000);
+        assertEquals(aih.getScreenOnTime(4000), 1000);
+        assertEquals(aih.getScreenOnTime(5000), 2000);
+        aih.updateDisplay(false, 6000);
         // Screen on time should not keep progressing with screen is off
-        assertEquals(aih.getScreenOnTimeLocked(7000), 3000);
-        assertEquals(aih.getScreenOnTimeLocked(8000), 3000);
-        aih.writeAppIdleDurationsLocked();
+        assertEquals(aih.getScreenOnTime(7000), 3000);
+        assertEquals(aih.getScreenOnTime(8000), 3000);
+        aih.writeAppIdleDurations();
 
         // Check if the screen on time is persisted across instantiations
         AppIdleHistory aih2 = new AppIdleHistory(mStorageDir, 0);
-        assertEquals(aih2.getScreenOnTimeLocked(11000), 3000);
-        aih2.updateDisplayLocked(true, 4000);
-        aih2.updateDisplayLocked(false, 5000);
-        assertEquals(aih2.getScreenOnTimeLocked(13000), 4000);
+        assertEquals(aih2.getScreenOnTime(11000), 3000);
+        aih2.updateDisplay(true, 4000);
+        aih2.updateDisplay(false, 5000);
+        assertEquals(aih2.getScreenOnTime(13000), 4000);
     }
 
     public void testPackageEvents() {
         AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
         aih.setThresholds(4000, 1000);
-        aih.updateDisplayLocked(true, 1000);
+        aih.updateDisplay(true, 1000);
         // App is not-idle by default
-        assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 1500));
+        assertFalse(aih.isIdle(PACKAGE_1, 0, 1500));
         // Still not idle
-        assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 3000));
+        assertFalse(aih.isIdle(PACKAGE_1, 0, 3000));
         // Idle now
-        assertTrue(aih.isIdleLocked(PACKAGE_1, 0, 8000));
+        assertTrue(aih.isIdle(PACKAGE_1, 0, 8000));
         // Not idle
-        assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 9000));
+        assertFalse(aih.isIdle(PACKAGE_2, 0, 9000));
 
         // Screen off
-        aih.updateDisplayLocked(false, 9100);
+        aih.updateDisplay(false, 9100);
         // Still idle after 10 seconds because screen hasn't been on long enough
-        assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 20000));
-        aih.updateDisplayLocked(true, 21000);
-        assertTrue(aih.isIdleLocked(PACKAGE_2, 0, 23000));
+        assertFalse(aih.isIdle(PACKAGE_2, 0, 20000));
+        aih.updateDisplay(true, 21000);
+        assertTrue(aih.isIdle(PACKAGE_2, 0, 23000));
     }
 }
\ No newline at end of file
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index ea45bd1..fd335c3 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -508,6 +508,13 @@
         return actualShortcuts;
     }
 
+    public static List<ShortcutInfo> assertAllChooser(List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.isChooser());
+        }
+        return actualShortcuts;
+    }
+
     public static List<ShortcutInfo> assertAllPinned(List<ShortcutInfo> actualShortcuts) {
         for (ShortcutInfo s : actualShortcuts) {
             assertTrue("ID " + s.getId(), s.isPinned());
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index f69dae4..f298559 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -18,7 +18,6 @@
 
 import android.os.Environment;
 import android.os.SystemClock;
-import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Slog;
@@ -101,7 +100,7 @@
         mElapsedSnapshot = elapsedRealtime;
         mScreenOnSnapshot = elapsedRealtime;
         mStorageDir = storageDir;
-        readScreenOnTimeLocked();
+        readScreenOnTime();
     }
 
     public void setThresholds(long elapsedTimeThreshold, long screenOnTimeThreshold) {
@@ -109,7 +108,7 @@
         mScreenOnTimeThreshold = screenOnTimeThreshold;
     }
 
-    public void updateDisplayLocked(boolean screenOn, long elapsedRealtime) {
+    public void updateDisplay(boolean screenOn, long elapsedRealtime) {
         if (screenOn == mScreenOn) return;
 
         mScreenOn = screenOn;
@@ -122,7 +121,7 @@
         }
     }
 
-    public long getScreenOnTimeLocked(long elapsedRealtime) {
+    public long getScreenOnTime(long elapsedRealtime) {
         long screenOnTime = mScreenOnDuration;
         if (mScreenOn) {
             screenOnTime += elapsedRealtime - mScreenOnSnapshot;
@@ -135,7 +134,7 @@
         return new File(mStorageDir, "screen_on_time");
     }
 
-    private void readScreenOnTimeLocked() {
+    private void readScreenOnTime() {
         File screenOnTimeFile = getScreenOnTimeFile();
         if (screenOnTimeFile.exists()) {
             try {
@@ -146,11 +145,11 @@
             } catch (IOException | NumberFormatException e) {
             }
         } else {
-            writeScreenOnTimeLocked();
+            writeScreenOnTime();
         }
     }
 
-    private void writeScreenOnTimeLocked() {
+    private void writeScreenOnTime() {
         AtomicFile screenOnTimeFile = new AtomicFile(getScreenOnTimeFile());
         FileOutputStream fos = null;
         try {
@@ -166,30 +165,30 @@
     /**
      * To be called periodically to keep track of elapsed time when app idle times are written
      */
-    public void writeAppIdleDurationsLocked() {
+    public void writeAppIdleDurations() {
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         // Only bump up and snapshot the elapsed time. Don't change screen on duration.
         mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
         mElapsedSnapshot = elapsedRealtime;
-        writeScreenOnTimeLocked();
+        writeScreenOnTime();
     }
 
-    public void reportUsageLocked(String packageName, int userId, long elapsedRealtime) {
-        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
-        PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
+    public void reportUsage(String packageName, int userId, long elapsedRealtime) {
+        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
+        PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
                 elapsedRealtime);
 
         shiftHistoryToNow(userHistory, elapsedRealtime);
 
         packageHistory.lastUsedElapsedTime = mElapsedDuration
                 + (elapsedRealtime - mElapsedSnapshot);
-        packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime);
+        packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
         packageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
     }
 
     public void setIdle(String packageName, int userId, long elapsedRealtime) {
-        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
-        PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
+        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
+        PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
                 elapsedRealtime);
 
         shiftHistoryToNow(userHistory, elapsedRealtime);
@@ -222,23 +221,23 @@
         mLastPeriod = thisPeriod;
     }
 
-    private ArrayMap<String, PackageHistory> getUserHistoryLocked(int userId) {
+    private ArrayMap<String, PackageHistory> getUserHistory(int userId) {
         ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
         if (userHistory == null) {
             userHistory = new ArrayMap<>();
             mIdleHistory.put(userId, userHistory);
-            readAppIdleTimesLocked(userId, userHistory);
+            readAppIdleTimes(userId, userHistory);
         }
         return userHistory;
     }
 
-    private PackageHistory getPackageHistoryLocked(ArrayMap<String, PackageHistory> userHistory,
+    private PackageHistory getPackageHistory(ArrayMap<String, PackageHistory> userHistory,
             String packageName, long elapsedRealtime) {
         PackageHistory packageHistory = userHistory.get(packageName);
         if (packageHistory == null) {
             packageHistory = new PackageHistory();
-            packageHistory.lastUsedElapsedTime = getElapsedTimeLocked(elapsedRealtime);
-            packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime);
+            packageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
+            packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
             userHistory.put(packageName, packageHistory);
         }
         return packageHistory;
@@ -248,41 +247,41 @@
         mIdleHistory.remove(userId);
     }
 
-    public boolean isIdleLocked(String packageName, int userId, long elapsedRealtime) {
-        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
+    public boolean isIdle(String packageName, int userId, long elapsedRealtime) {
+        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
         PackageHistory packageHistory =
-                getPackageHistoryLocked(userHistory, packageName, elapsedRealtime);
+                getPackageHistory(userHistory, packageName, elapsedRealtime);
         if (packageHistory == null) {
             return false; // Default to not idle
         } else {
-            return hasPassedThresholdsLocked(packageHistory, elapsedRealtime);
+            return hasPassedThresholds(packageHistory, elapsedRealtime);
         }
     }
 
-    private long getElapsedTimeLocked(long elapsedRealtime) {
+    private long getElapsedTime(long elapsedRealtime) {
         return (elapsedRealtime - mElapsedSnapshot + mElapsedDuration);
     }
 
-    public void setIdleLocked(String packageName, int userId, boolean idle, long elapsedRealtime) {
-        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
-        PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
+    public void setIdle(String packageName, int userId, boolean idle, long elapsedRealtime) {
+        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
+        PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
                 elapsedRealtime);
-        packageHistory.lastUsedElapsedTime = getElapsedTimeLocked(elapsedRealtime)
+        packageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime)
                 - mElapsedTimeThreshold;
-        packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime)
+        packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime)
                 - (idle ? mScreenOnTimeThreshold : 0) - 1000 /* just a second more */;
     }
 
-    public void clearUsageLocked(String packageName, int userId) {
-        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
+    public void clearUsage(String packageName, int userId) {
+        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
         userHistory.remove(packageName);
     }
 
-    private boolean hasPassedThresholdsLocked(PackageHistory packageHistory, long elapsedRealtime) {
+    private boolean hasPassedThresholds(PackageHistory packageHistory, long elapsedRealtime) {
         return (packageHistory.lastUsedScreenTime
-                    <= getScreenOnTimeLocked(elapsedRealtime) - mScreenOnTimeThreshold)
+                    <= getScreenOnTime(elapsedRealtime) - mScreenOnTimeThreshold)
                 && (packageHistory.lastUsedElapsedTime
-                        <= getElapsedTimeLocked(elapsedRealtime) - mElapsedTimeThreshold);
+                        <= getElapsedTime(elapsedRealtime) - mElapsedTimeThreshold);
     }
 
     private File getUserFile(int userId) {
@@ -290,7 +289,7 @@
                 Integer.toString(userId)), APP_IDLE_FILENAME);
     }
 
-    private void readAppIdleTimesLocked(int userId, ArrayMap<String, PackageHistory> userHistory) {
+    private void readAppIdleTimes(int userId, ArrayMap<String, PackageHistory> userHistory) {
         FileInputStream fis = null;
         try {
             AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
@@ -332,7 +331,7 @@
         }
     }
 
-    public void writeAppIdleTimesLocked(int userId) {
+    public void writeAppIdleTimes(int userId) {
         FileOutputStream fos = null;
         AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
         try {
@@ -346,7 +345,7 @@
 
             xml.startTag(null, TAG_PACKAGES);
 
-            ArrayMap<String,PackageHistory> userHistory = getUserHistoryLocked(userId);
+            ArrayMap<String,PackageHistory> userHistory = getUserHistory(userId);
             final int N = userHistory.size();
             for (int i = 0; i < N; i++) {
                 String packageName = userHistory.keyAt(i);
@@ -374,8 +373,8 @@
         idpw.increaseIndent();
         ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
         final long elapsedRealtime = SystemClock.elapsedRealtime();
-        final long totalElapsedTime = getElapsedTimeLocked(elapsedRealtime);
-        final long screenOnTime = getScreenOnTimeLocked(elapsedRealtime);
+        final long totalElapsedTime = getElapsedTime(elapsedRealtime);
+        final long screenOnTime = getScreenOnTime(elapsedRealtime);
         if (userHistory == null) return;
         final int P = userHistory.size();
         for (int p = 0; p < P; p++) {
@@ -386,15 +385,15 @@
             TimeUtils.formatDuration(totalElapsedTime - packageHistory.lastUsedElapsedTime, idpw);
             idpw.print(" lastUsedScreenOn=");
             TimeUtils.formatDuration(screenOnTime - packageHistory.lastUsedScreenTime, idpw);
-            idpw.print(" idle=" + (isIdleLocked(packageName, userId, elapsedRealtime) ? "y" : "n"));
+            idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
             idpw.println();
         }
         idpw.println();
         idpw.print("totalElapsedTime=");
-        TimeUtils.formatDuration(getElapsedTimeLocked(elapsedRealtime), idpw);
+        TimeUtils.formatDuration(getElapsedTime(elapsedRealtime), idpw);
         idpw.println();
         idpw.print("totalScreenOnTime=");
-        TimeUtils.formatDuration(getScreenOnTimeLocked(elapsedRealtime), idpw);
+        TimeUtils.formatDuration(getScreenOnTime(elapsedRealtime), idpw);
         idpw.println();
         idpw.decreaseIndent();
     }
@@ -410,7 +409,7 @@
             for (int i = 0; i < HISTORY_SIZE; i++) {
                 idpw.print(history[i] == 0 ? '.' : 'A');
             }
-            idpw.print(" idle=" + (isIdleLocked(packageName, userId, elapsedRealtime) ? "y" : "n"));
+            idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
             idpw.print("  " + packageName);
             idpw.println();
         }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 3c743b5..469a8f1 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -153,13 +153,17 @@
     private volatile boolean mPendingOneTimeCheckIdleStates;
     private boolean mSystemServicesReady = false;
 
-    @GuardedBy("mLock")
+    private final Object mAppIdleLock = new Object();
+    @GuardedBy("mAppIdleLock")
     private AppIdleHistory mAppIdleHistory;
 
+    @GuardedBy("mAppIdleLock")
     private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
             mPackageAccessListeners = new ArrayList<>();
 
+    @GuardedBy("mAppIdleLock")
     private boolean mHaveCarrierPrivilegedApps;
+    @GuardedBy("mAppIdleLock")
     private List<String> mCarrierPrivilegedApps;
 
     public UsageStatsService(Context context) {
@@ -206,6 +210,8 @@
 
         synchronized (mLock) {
             cleanUpRemovedUsersLocked();
+        }
+        synchronized (mAppIdleLock) {
             mAppIdleHistory = new AppIdleHistory(SystemClock.elapsedRealtime());
         }
 
@@ -234,8 +240,8 @@
             mPowerManager = getContext().getSystemService(PowerManager.class);
 
             mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
-            synchronized (mLock) {
-                mAppIdleHistory.updateDisplayLocked(isDisplayOn(), SystemClock.elapsedRealtime());
+            synchronized (mAppIdleLock) {
+                mAppIdleHistory.updateDisplay(isDisplayOn(), SystemClock.elapsedRealtime());
             }
 
             if (mPendingOneTimeCheckIdleStates) {
@@ -324,8 +330,8 @@
         @Override public void onDisplayChanged(int displayId) {
             if (displayId == Display.DEFAULT_DISPLAY) {
                 final boolean displayOn = isDisplayOn();
-                synchronized (UsageStatsService.this.mLock) {
-                    mAppIdleHistory.updateDisplayLocked(displayOn, SystemClock.elapsedRealtime());
+                synchronized (UsageStatsService.this.mAppIdleLock) {
+                    mAppIdleHistory.updateDisplay(displayOn, SystemClock.elapsedRealtime());
                 }
             }
         }
@@ -386,18 +392,20 @@
                 PackageManager.MATCH_DISABLED_COMPONENTS,
                 userId);
         final int packageCount = packages.size();
-        for (int i = 0; i < packageCount; i++) {
-            final PackageInfo pi = packages.get(i);
-            String packageName = pi.packageName;
-            if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
-                mAppIdleHistory.reportUsageLocked(packageName, userId, elapsedRealtime);
+        synchronized (mAppIdleLock) {
+            for (int i = 0; i < packageCount; i++) {
+                final PackageInfo pi = packages.get(i);
+                String packageName = pi.packageName;
+                if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
+                    mAppIdleHistory.reportUsage(packageName, userId, elapsedRealtime);
+                }
             }
         }
     }
 
     void clearAppIdleForPackage(String packageName, int userId) {
-        synchronized (mLock) {
-            mAppIdleHistory.clearUsageLocked(packageName, userId);
+        synchronized (mAppIdleLock) {
+            mAppIdleHistory.clearUsage(packageName, userId);
         }
     }
 
@@ -429,7 +437,7 @@
     }
 
     void setChargingState(boolean charging) {
-        synchronized (mLock) {
+        synchronized (mAppIdleLock) {
             if (mCharging != charging) {
                 mCharging = charging;
                 postParoleStateChanged();
@@ -439,15 +447,16 @@
 
     /** Paroled here means temporary pardon from being inactive */
     void setAppIdleParoled(boolean paroled) {
-        synchronized (mLock) {
+        synchronized (mAppIdleLock) {
+            final long now = System.currentTimeMillis();
             if (mAppIdleTempParoled != paroled) {
                 mAppIdleTempParoled = paroled;
                 if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled);
                 if (paroled) {
                     postParoleEndTimeout();
                 } else {
-                    mLastAppIdleParoledTime = checkAndGetTimeLocked();
-                    postNextParoleTimeout();
+                    mLastAppIdleParoledTime = now;
+                    postNextParoleTimeout(now);
                 }
                 postParoleStateChanged();
             }
@@ -455,19 +464,18 @@
     }
 
     boolean isParoledOrCharging() {
-        synchronized (mLock) {
+        synchronized (mAppIdleLock) {
             return mAppIdleTempParoled || mCharging;
         }
     }
 
-    private void postNextParoleTimeout() {
+    private void postNextParoleTimeout(long now) {
         if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
         mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
         // Compute when the next parole needs to happen. We check more frequently than necessary
         // since the message handler delays are based on elapsedRealTime and not wallclock time.
         // The comparison is done in wallclock time.
-        long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis)
-                - checkAndGetTimeLocked();
+        long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis) - now;
         if (timeLeft < 0) {
             timeLeft = 0;
         }
@@ -546,7 +554,7 @@
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
                         userId, isIdle ? 1 : 0, packageName));
                 if (isIdle) {
-                    synchronized (mLock) {
+                    synchronized (mAppIdleLock) {
                         mAppIdleHistory.setIdle(packageName, userId, elapsedRealtime);
                     }
                 }
@@ -561,18 +569,23 @@
 
     /** Check if it's been a while since last parole and let idle apps do some work */
     void checkParoleTimeout() {
-        synchronized (mLock) {
+        boolean setParoled = false;
+        synchronized (mAppIdleLock) {
+            final long now = System.currentTimeMillis();
             if (!mAppIdleTempParoled) {
-                final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
+                final long timeSinceLastParole = now - mLastAppIdleParoledTime;
                 if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
                     if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
-                    setAppIdleParoled(true);
+                    setParoled = true;
                 } else {
                     if (DEBUG) Slog.d(TAG, "Not long enough to go to parole");
-                    postNextParoleTimeout();
+                    postNextParoleTimeout(now);
                 }
             }
         }
+        if (setParoled) {
+            setAppIdleParoled(true);
+        }
     }
 
     private void notifyBatteryStats(String packageName, int userId, boolean idle) {
@@ -593,17 +606,23 @@
     void onDeviceIdleModeChanged() {
         final boolean deviceIdle = mPowerManager.isDeviceIdleMode();
         if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
-        synchronized (mLock) {
-            final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
+        boolean paroled = false;
+        synchronized (mAppIdleLock) {
+            final long timeSinceLastParole = System.currentTimeMillis() - mLastAppIdleParoledTime;
             if (!deviceIdle
                     && timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
-                if (DEBUG) Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
-                setAppIdleParoled(true);
+                if (DEBUG) {
+                    Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
+                }
+                paroled = true;
             } else if (deviceIdle) {
                 if (DEBUG) Slog.i(TAG, "Device idle, back to prison");
-                setAppIdleParoled(false);
+                paroled = false;
+            } else {
+                return;
             }
         }
+        setAppIdleParoled(paroled);
     }
 
     private static void deleteRecursively(File f) {
@@ -682,21 +701,24 @@
 
             final UserUsageStatsService service =
                     getUserDataAndInitializeIfNeededLocked(userId, timeNow);
-            // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
-            // about apps that are on some kind of whitelist anyway.
-            final boolean previouslyIdle = mAppIdleHistory.isIdleLocked(
-                    event.mPackage, userId, elapsedRealtime);
             service.reportEvent(event);
-            // Inform listeners if necessary
-            if ((event.mEventType == Event.MOVE_TO_FOREGROUND
-                    || event.mEventType == Event.MOVE_TO_BACKGROUND
-                    || event.mEventType == Event.SYSTEM_INTERACTION
-                    || event.mEventType == Event.USER_INTERACTION)) {
-                mAppIdleHistory.reportUsageLocked(event.mPackage, userId, elapsedRealtime);
-                if (previouslyIdle) {
-                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
-                            /* idle = */ 0, event.mPackage));
-                    notifyBatteryStats(event.mPackage, userId, false);
+
+            synchronized (mAppIdleLock) {
+                // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
+                // about apps that are on some kind of whitelist anyway.
+                final boolean previouslyIdle = mAppIdleHistory.isIdle(
+                        event.mPackage, userId, elapsedRealtime);
+                // Inform listeners if necessary
+                if ((event.mEventType == Event.MOVE_TO_FOREGROUND
+                        || event.mEventType == Event.MOVE_TO_BACKGROUND
+                        || event.mEventType == Event.SYSTEM_INTERACTION
+                        || event.mEventType == Event.USER_INTERACTION)) {
+                    mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime);
+                    if (previouslyIdle) {
+                        mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
+                                /* idle = */ 0, event.mPackage));
+                        notifyBatteryStats(event.mPackage, userId, false);
+                    }
                 }
             }
         }
@@ -716,7 +738,7 @@
                     continue;
                 }
                 if (!packageName.equals(providerPkgName)) {
-                    forceIdleState(packageName, userId, false);
+                    setAppIdleAsync(packageName, false, userId);
                 }
             } catch (NameNotFoundException e) {
                 // Shouldn't happen
@@ -728,25 +750,28 @@
      * Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle,
      * then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind
      * the threshold for idle.
+     *
+     * This method is always called from the handler thread, so not much synchronization is
+     * required.
      */
     void forceIdleState(String packageName, int userId, boolean idle) {
         final int appId = getAppId(packageName);
         if (appId < 0) return;
-        synchronized (mLock) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
 
-            final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
-                    userId, elapsedRealtime);
-            mAppIdleHistory.setIdleLocked(packageName, userId, idle, elapsedRealtime);
-            final boolean stillIdle = isAppIdleFiltered(packageName, appId,
-                    userId, elapsedRealtime);
-            // Inform listeners if necessary
-            if (previouslyIdle != stillIdle) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
-                        /* idle = */ stillIdle ? 1 : 0, packageName));
-                if (!stillIdle) {
-                    notifyBatteryStats(packageName, userId, idle);
-                }
+        final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
+                userId, elapsedRealtime);
+        synchronized (mAppIdleLock) {
+            mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime);
+        }
+        final boolean stillIdle = isAppIdleFiltered(packageName, appId,
+                userId, elapsedRealtime);
+        // Inform listeners if necessary
+        if (previouslyIdle != stillIdle) {
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
+                    /* idle = */ stillIdle ? 1 : 0, packageName));
+            if (!stillIdle) {
+                notifyBatteryStats(packageName, userId, idle);
             }
         }
     }
@@ -767,7 +792,9 @@
         synchronized (mLock) {
             Slog.i(TAG, "Removing user " + userId + " and all data.");
             mUserState.remove(userId);
-            mAppIdleHistory.onUserRemoved(userId);
+            synchronized (mAppIdleLock) {
+                mAppIdleHistory.onUserRemoved(userId);
+            }
             cleanUpRemovedUsersLocked();
         }
     }
@@ -822,13 +849,13 @@
     }
 
     private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
-        synchronized (mLock) {
-            return mAppIdleHistory.isIdleLocked(packageName, userId, elapsedRealtime);
+        synchronized (mAppIdleLock) {
+            return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
         }
     }
 
     void addListener(AppIdleStateChangeListener listener) {
-        synchronized (mLock) {
+        synchronized (mAppIdleLock) {
             if (!mPackageAccessListeners.contains(listener)) {
                 mPackageAccessListeners.add(listener);
             }
@@ -836,7 +863,7 @@
     }
 
     void removeListener(AppIdleStateChangeListener listener) {
-        synchronized (mLock) {
+        synchronized (mAppIdleLock) {
             mPackageAccessListeners.remove(listener);
         }
     }
@@ -988,7 +1015,7 @@
         return res;
     }
 
-    void setAppIdle(String packageName, boolean idle, int userId) {
+    void setAppIdleAsync(String packageName, boolean idle, int userId) {
         if (packageName == null) return;
 
         mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
@@ -1012,9 +1039,9 @@
     }
 
     private boolean isCarrierApp(String packageName) {
-        synchronized (mLock) {
+        synchronized (mAppIdleLock) {
             if (!mHaveCarrierPrivilegedApps) {
-                fetchCarrierPrivilegedAppsLocked();
+                fetchCarrierPrivilegedAppsLA();
             }
             if (mCarrierPrivilegedApps != null) {
                 return mCarrierPrivilegedApps.contains(packageName);
@@ -1027,13 +1054,14 @@
         if (DEBUG) {
             Slog.i(TAG, "Clearing carrier privileged apps list");
         }
-        synchronized (mLock) {
+        synchronized (mAppIdleLock) {
             mHaveCarrierPrivilegedApps = false;
             mCarrierPrivilegedApps = null; // Need to be refetched.
         }
     }
 
-    private void fetchCarrierPrivilegedAppsLocked() {
+    @GuardedBy("mAppIdleLock")
+    private void fetchCarrierPrivilegedAppsLA() {
         TelephonyManager telephonyManager =
                 getContext().getSystemService(TelephonyManager.class);
         mCarrierPrivilegedApps = telephonyManager.getPackagesWithCarrierPrivileges();
@@ -1071,11 +1099,15 @@
         for (int i = 0; i < userCount; i++) {
             UserUsageStatsService service = mUserState.valueAt(i);
             service.persistActiveStats();
-            mAppIdleHistory.writeAppIdleTimesLocked(mUserState.keyAt(i));
+            synchronized (mAppIdleLock) {
+                mAppIdleHistory.writeAppIdleTimes(mUserState.keyAt(i));
+            }
         }
         // Persist elapsed and screen on time. If this fails for whatever reason, the apps will be
         // considered not-idle, which is the safest outcome in such an event.
-        mAppIdleHistory.writeAppIdleDurationsLocked();
+        synchronized (mAppIdleLock) {
+            mAppIdleHistory.writeAppIdleDurations();
+        }
         mHandler.removeMessages(MSG_FLUSH_TO_DISK);
     }
 
@@ -1100,20 +1132,26 @@
                     idpw.println();
                     if (args.length > 0) {
                         if ("history".equals(args[0])) {
-                            mAppIdleHistory.dumpHistory(idpw, mUserState.keyAt(i));
+                            synchronized (mAppIdleLock) {
+                                mAppIdleHistory.dumpHistory(idpw, mUserState.keyAt(i));
+                            }
                         } else if ("flush".equals(args[0])) {
                             UsageStatsService.this.flushToDiskLocked();
                             pw.println("Flushed stats to disk");
                         }
                     }
                 }
-                mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
+                synchronized (mAppIdleLock) {
+                    mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
+                }
                 idpw.decreaseIndent();
             }
 
             pw.println();
-            pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
-                    + "): " + mCarrierPrivilegedApps);
+            synchronized (mAppIdleLock) {
+                pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
+                        + "): " + mCarrierPrivilegedApps);
+            }
 
             pw.println();
             pw.println("Settings:");
@@ -1252,7 +1290,7 @@
         }
 
         void updateSettings() {
-            synchronized (mLock) {
+            synchronized (mAppIdleLock) {
                 // Look at global settings for this.
                 // TODO: Maybe apply different thresholds for different users.
                 try {
@@ -1384,7 +1422,7 @@
             try {
                 userId = ActivityManager.getService().handleIncomingUser(
                         Binder.getCallingPid(), callingUid, userId, false, true,
-                        "setAppIdle", null);
+                        "setAppInactive", null);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
@@ -1394,7 +1432,7 @@
             try {
                 final int appId = getAppId(packageName);
                 if (appId < 0) return;
-                UsageStatsService.this.setAppIdle(packageName, idle, userId);
+                UsageStatsService.this.setAppIdleAsync(packageName, idle, userId);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1586,21 +1624,25 @@
         @Override
         public byte[] getBackupPayload(int user, String key) {
             // Check to ensure that only user 0's data is b/r for now
-            if (user == UserHandle.USER_SYSTEM) {
-                final UserUsageStatsService userStats =
-                        getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
-                return userStats.getBackupPayload(key);
-            } else {
-                return null;
+            synchronized (UsageStatsService.this.mLock) {
+                if (user == UserHandle.USER_SYSTEM) {
+                    final UserUsageStatsService userStats =
+                            getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
+                    return userStats.getBackupPayload(key);
+                } else {
+                    return null;
+                }
             }
         }
 
         @Override
         public void applyRestoredPayload(int user, String key, byte[] payload) {
-            if (user == UserHandle.USER_SYSTEM) {
-                final UserUsageStatsService userStats =
-                        getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
-                userStats.applyRestoredPayload(key, payload);
+            synchronized (UsageStatsService.this.mLock) {
+                if (user == UserHandle.USER_SYSTEM) {
+                    final UserUsageStatsService userStats =
+                            getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
+                    userStats.applyRestoredPayload(key, payload);
+                }
             }
         }
 
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index d9f352c..8d335a5 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -529,7 +529,6 @@
         pw.decreaseIndent();
 
         pw.println();
-        pw.increaseIndent();
         pw.println("ChooserCounts");
         pw.increaseIndent();
         for (UsageStats usageStats : pkgStats.values()) {
@@ -553,6 +552,7 @@
             }
             pw.println();
         }
+        pw.decreaseIndent();
 
         pw.println("configurations");
         pw.increaseIndent();
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index 216603c..e0e3a08 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -235,7 +235,7 @@
         StringBuilder sb = new StringBuilder();
         sb.append("Audio");
 
-        if (isAudioOnly(videoState)) {
+        if (videoState == STATE_AUDIO_ONLY) {
             sb.append(" Only");
         } else {
             if (isTransmissionEnabled(videoState)) {
@@ -256,6 +256,9 @@
 
     /**
      * Indicates whether the video state is audio only.
+     * <p>
+     * Note: Considers only whether either both the {@link #STATE_RX_ENABLED} or
+     * {@link #STATE_TX_ENABLED} bits are off, but not {@link #STATE_PAUSED}.
      *
      * @param videoState The video state.
      * @return {@code True} if the video state is audio only, {@code false} otherwise.
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 70df69c..7bb58dd4 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -942,7 +942,7 @@
 
     /**
      * Defines carrier-specific actions which act upon
-     * android.intent.action.CARRIER_SIGNAL_REDIRECTED, used for customization of the
+     * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED, used for customization of the
      * default carrier app
      * Format: "CARRIER_ACTION_IDX, ..."
      * Where {@code CARRIER_ACTION_IDX} is an integer defined in
@@ -957,7 +957,7 @@
 
     /**
      * Defines carrier-specific actions which act upon
-     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+     * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
      * and configured signal args:
      * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_APN_TYPE_KEY apnType},
      * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_ERROR_CODE_KEY errorCode}
@@ -998,11 +998,11 @@
      * @see com.android.internal.telephony.TelephonyIntents
      * Example:
      * <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
-     * android.intent.action.CARRIER_SIGNAL_REDIRECTED,
-     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+     * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED,
+     * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
      * </item>
      * <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
-     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+     * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
      * </item>
      * @hide
      */
@@ -1017,11 +1017,11 @@
      * @see com.android.internal.telephony.TelephonyIntents
      * Example:
      * <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
-     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
-     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+     * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
+     * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
      * </item>
      * <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
-     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+     * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
      * </item>
      * @hide
      */
@@ -1493,7 +1493,7 @@
         sDefaults.putStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
                 new String[]{
                         "com.android.carrierdefaultapp/.CarrierDefaultBroadcastReceiver:" +
-                                "android.intent.action.CARRIER_SIGNAL_REDIRECTED"
+                                "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"
                 });
         sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
 
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 6f51c6e..cc21b5e 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1140,6 +1140,8 @@
 
     private static final String KOREA_ISO_COUNTRY_CODE = "KR";
 
+    private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
+
     /**
      * Breaks the given number down and formats it according to the rules
      * for the country the number is from.
@@ -1460,15 +1462,25 @@
         String result = null;
         try {
             PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
-            /**
-             * Need to reformat any local Korean phone numbers (when the user is in Korea) with
-             * country code to corresponding national format which would replace the leading
-             * +82 with 0.
-             */
-            if (KOREA_ISO_COUNTRY_CODE.equals(defaultCountryIso) &&
+
+            if (KOREA_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
                     (pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE)) &&
                     (pn.getCountryCodeSource() ==
                             PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
+                /**
+                 * Need to reformat any local Korean phone numbers (when the user is in Korea) with
+                 * country code to corresponding national format which would replace the leading
+                 * +82 with 0.
+                 */
+                result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
+            } else if (JAPAN_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
+                    pn.getCountryCode() == util.getCountryCodeForRegion(JAPAN_ISO_COUNTRY_CODE) &&
+                    (pn.getCountryCodeSource() ==
+                            PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
+                /**
+                 * Need to reformat Japanese phone numbers (when user is in Japan) with the national
+                 * dialing format.
+                 */
                 result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
             } else {
                 result = util.formatInOriginalFormat(pn, defaultCountryIso);
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index dd03305..afff6d5 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -208,7 +208,9 @@
      *
      * @see #onOemHookRawEvent
      * @hide
+     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
      */
+    @Deprecated
     public static final int LISTEN_OEM_HOOK_RAW_EVENT                       = 0x00008000;
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a4235d7..f5974cd 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5229,7 +5229,9 @@
      *         0 request was handled succesfully, but no response data
      *         positive value success, data length of response
      * @hide
+     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
      */
+    @Deprecated
     public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
         try {
             ITelephony telephony = getITelephony();
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 0e60d7e..bcaac6e 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -264,15 +264,6 @@
             = "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
 
     /**
-     * Activity Action: Start this activity to invoke the carrier setup app.
-     * The carrier app must be signed using a certificate that matches the UICC access rules.
-     *
-     * <p class="note">Callers of this should hold the android.permission.INVOKE_CARRIER_SETUP
-     * permission.</p>
-     */
-    public static final String ACTION_CARRIER_SETUP = "android.intent.action.ACTION_CARRIER_SETUP";
-
-    /**
      * <p>Broadcast Action: Indicates that the action is forbidden by network.
      * <p class="note">
      * This is for the OEM applications to understand about possible provisioning issues.
diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml
index 0fd8b12..2c6c8d7 100644
--- a/tests/SoundTriggerTestApp/res/layout/main.xml
+++ b/tests/SoundTriggerTestApp/res/layout/main.xml
@@ -87,6 +87,7 @@
             android:text="@string/capture"
             android:id="@+id/caputre_check_box"
             android:layout_gravity="center_horizontal"
+            android:onClick="onCaptureAudioCheckboxClicked"
             android:padding="20dp" />
 
         <Button
@@ -94,6 +95,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/play_capture"
+            android:onClick="onPlayCapturedAudioButtonClicked"
             android:padding="20dp"
             android:enabled="false" />
     </LinearLayout>
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 56aad23..9b1a9f2 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -297,6 +297,7 @@
                     Notification n = new Notification.Builder(NotificationTestList.this)
                             .setSmallIcon(R.drawable.icon2)
                             .setContentTitle("Low priority")
+                            .setTimeout(60000)
                             .setLights(0xff0000ff, 1, 0)
                             .setPriority(Notification.PRIORITY_LOW)
                             .build();
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 3ed56df..c72efb0 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -32,6 +32,8 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.IConnectivityManager;
@@ -42,6 +44,10 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import org.junit.After;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import org.junit.Test;
@@ -49,6 +55,7 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -63,6 +70,7 @@
     @Mock private Context mContext;
     @Mock private IConnectivityManager mCS;
 
+    private TestStateMachine mSM;
     private TestConnectivityManager mCM;
     private UpstreamNetworkMonitor mUNM;
 
@@ -72,7 +80,15 @@
         reset(mCS);
 
         mCM = spy(new TestConnectivityManager(mContext, mCS));
-        mUNM = new UpstreamNetworkMonitor(null, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+        mSM = new TestStateMachine();
+        mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+    }
+
+    @After public void tearDown() throws Exception {
+        if (mSM != null) {
+            mSM.quit();
+            mSM = null;
+        }
     }
 
     @Test
@@ -139,15 +155,17 @@
 
         mUNM.start();
         verify(mCM, Mockito.times(1)).registerNetworkCallback(
-                any(NetworkRequest.class), any(NetworkCallback.class));
-        verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(any(NetworkCallback.class));
+                any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
+        verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(
+                any(NetworkCallback.class), any(Handler.class));
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
         mUNM.updateMobileRequiresDun(true);
         mUNM.registerMobileNetworkRequest();
         verify(mCM, Mockito.times(1)).requestNetwork(
-                any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt());
+                any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(),
+                any(Handler.class));
 
         assertTrue(mUNM.mobileNetworkRequested());
         assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
@@ -224,6 +242,7 @@
     }
 
     public static class TestConnectivityManager extends ConnectivityManager {
+        public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
         public Set<NetworkCallback> trackingDefault = new HashSet<>();
         public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
         public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
@@ -234,7 +253,8 @@
         }
 
         boolean hasNoCallbacks() {
-            return trackingDefault.isEmpty() &&
+            return allCallbacks.isEmpty() &&
+                   trackingDefault.isEmpty() &&
                    listening.isEmpty() &&
                    requested.isEmpty() &&
                    legacyTypeMap.isEmpty();
@@ -262,14 +282,23 @@
         }
 
         @Override
-        public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+        public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
+            assertFalse(allCallbacks.containsKey(cb));
+            allCallbacks.put(cb, h);
             assertFalse(requested.containsKey(cb));
             requested.put(cb, req);
         }
 
         @Override
+        public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+            fail("Should never be called.");
+        }
+
+        @Override
         public void requestNetwork(NetworkRequest req, NetworkCallback cb,
-                int timeoutMs, int legacyType) {
+                int timeoutMs, int legacyType, Handler h) {
+            assertFalse(allCallbacks.containsKey(cb));
+            allCallbacks.put(cb, h);
             assertFalse(requested.containsKey(cb));
             requested.put(cb, req);
             assertFalse(legacyTypeMap.containsKey(cb));
@@ -279,18 +308,32 @@
         }
 
         @Override
-        public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+        public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb, Handler h) {
+            assertFalse(allCallbacks.containsKey(cb));
+            allCallbacks.put(cb, h);
             assertFalse(listening.containsKey(cb));
             listening.put(cb, req);
         }
 
         @Override
-        public void registerDefaultNetworkCallback(NetworkCallback cb) {
+        public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+            fail("Should never be called.");
+        }
+
+        @Override
+        public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) {
+            assertFalse(allCallbacks.containsKey(cb));
+            allCallbacks.put(cb, h);
             assertFalse(trackingDefault.contains(cb));
             trackingDefault.add(cb);
         }
 
         @Override
+        public void registerDefaultNetworkCallback(NetworkCallback cb) {
+            fail("Should never be called.");
+        }
+
+        @Override
         public void unregisterNetworkCallback(NetworkCallback cb) {
             if (trackingDefault.contains(cb)) {
                 trackingDefault.remove(cb);
@@ -302,10 +345,35 @@
             } else {
                 fail("Unexpected callback removed");
             }
+            allCallbacks.remove(cb);
 
+            assertFalse(allCallbacks.containsKey(cb));
             assertFalse(trackingDefault.contains(cb));
             assertFalse(listening.containsKey(cb));
             assertFalse(requested.containsKey(cb));
         }
     }
+
+    public static class TestStateMachine extends StateMachine {
+        public final ArrayList<Message> messages = new ArrayList<>();
+        private final State mLoggingState = new LoggingState();
+
+        class LoggingState extends State {
+            @Override public void enter() { messages.clear(); }
+
+            @Override public void exit() { messages.clear(); }
+
+            @Override public boolean processMessage(Message msg) {
+                messages.add(msg);
+                return true;
+            }
+        }
+
+        public TestStateMachine() {
+            super("UpstreamNetworkMonitor.TestStateMachine");
+            addState(mLoggingState);
+            setInitialState(mLoggingState);
+            super.start();
+        }
+    }
 }
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index f193ea4..eb8a1cc 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -14,7 +14,9 @@
 
 LANG_TO_SCRIPT = {
     'as': 'Beng',
+    'bg': 'Cyrl',
     'bn': 'Beng',
+    'cu': 'Cyrl',
     'cy': 'Latn',
     'da': 'Latn',
     'de': 'Latn',
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
index 174bbcf..cc7631a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -571,6 +571,8 @@
         @NonNull
         public Consumer<Float> getFloatPropertySetter(int propertyIdx) {
             switch (propertyIdx) {
+                case STROKE_WIDTH_INDEX:
+                    return this::setStrokeWidth;
                 case STROKE_ALPHA_INDEX:
                     return this::setStrokeAlpha;
                 case FILL_ALPHA_INDEX:
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
index a53dcba..f15d669 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml
index 05a3665..456b5f6 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml
@@ -263,7 +263,8 @@
             android:id="@id/radioButton2"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:text="New RadioButton" />
+            android:text="New RadioButton"
+            android:checked="true" />
 
     </RadioGroup>
 
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index adf189b..57b98e9 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -31,8 +31,7 @@
  * {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
  * class provides functionality common to both publish and subscribe discovery sessions:
  * <ul>
- *     <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} or
- *     {@link #sendMessage(PeerHandle, int, byte[], int)} methods.
+ *     <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])}.
  *     <li>Creating a network-specifier when requesting a Aware connection:
  *     {@link #createNetworkSpecifier(PeerHandle, byte[])}.
  * </ul>
@@ -62,6 +61,8 @@
      * {@link #sendMessage(PeerHandle, int, byte[], int)}.
      *
      * @return Maximum retry count when sending messages.
+     *
+     * @hide
      */
     public static int getMaxSendRetryCount() {
         return MAX_SEND_RETRY_COUNT;
@@ -163,6 +164,8 @@
      *            or MAC level) retries should be attempted if there is no ACK from the receiver
      *            (note: no retransmissions are attempted in other failure cases). A value of 0
      *            indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
+     *
+     * @hide
      */
     public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
             @Nullable byte[] message, int retryCount) {
@@ -195,8 +198,6 @@
      * The peer will get a callback indicating a message was received using
      * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])}.
-     * Equivalent to {@link #sendMessage(PeerHandle, int, byte[], int)}
-     * with a {@code retryCount} of 0.
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
index 33da182..9645b1d 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -124,10 +124,9 @@
     }
 
     /**
-     * Called when message transmission fails - when no ACK is received from the peer.
-     * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
-     * the {@link DiscoverySession#sendMessage(PeerHandle, int,
-     * byte[], int)} method) - this event is received after all retries are exhausted.
+     * Called when message transmission initiated with
+     * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} fails. E.g. when no ACK is
+     * received from the peer.
      * <p>
      * Note that either this callback or
      * {@link DiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
@@ -141,9 +140,7 @@
 
     /**
      * Called when a message is received from a discovery session peer - in response to the
-     * peer's {@link DiscoverySession#sendMessage(PeerHandle, int,
-     * byte[])} or {@link DiscoverySession#sendMessage(PeerHandle,
-     * int, byte[], int)}.
+     * peer's {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}.
      *
      * @param peerHandle An opaque handle to the peer matching our discovery operation.
      * @param message A byte array containing the message.