Merge "Allow location provider to deep link into permissions UI"
diff --git a/Android.bp b/Android.bp
index 10b92f3..93e6963 100644
--- a/Android.bp
+++ b/Android.bp
@@ -766,6 +766,16 @@
     ],
 }
 
+// A host library containing the inspector annotations for inspector-annotation-processor.
+java_library_host {
+    name: "inspector-annotation",
+    srcs: [
+        "core/java/android/view/inspector/InspectableChildren.java",
+        "core/java/android/view/inspector/InspectableNodeName.java",
+        "core/java/android/view/inspector/InspectableProperty.java",
+    ],
+}
+
 // A host library including just UnsupportedAppUsage.java so that the annotation
 // processor can also use this annotation.
 java_library_host {
diff --git a/api/current.txt b/api/current.txt
index 673309d..a5724fe 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -769,6 +769,7 @@
     field public static final int insetRight = 16843192; // 0x10101b8
     field public static final int insetTop = 16843193; // 0x10101b9
     field public static final int installLocation = 16843447; // 0x10102b7
+    field public static final int interactiveUiTimeout = 16844181; // 0x1010595
     field public static final int interpolator = 16843073; // 0x1010141
     field public static final int isAlwaysSyncable = 16843571; // 0x1010333
     field public static final int isAsciiCapable = 16843753; // 0x10103e9
@@ -941,7 +942,6 @@
     field public static final int minSdkVersion = 16843276; // 0x101020c
     field public static final int minWidth = 16843071; // 0x101013f
     field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
-    field public static final int minimumUiTimeout = 16844175; // 0x101058f
     field public static final int minimumVerticalAngle = 16843902; // 0x101047e
     field public static final int mipMap = 16843725; // 0x10103cd
     field public static final int mirrorForRtl = 16843726; // 0x10103ce
@@ -965,6 +965,7 @@
     field public static final int nextFocusRight = 16842978; // 0x10100e2
     field public static final int nextFocusUp = 16842979; // 0x10100e3
     field public static final int noHistory = 16843309; // 0x101022d
+    field public static final int nonInteractiveUiTimeout = 16844175; // 0x101058f
     field public static final int normalScreens = 16843397; // 0x1010285
     field public static final int notificationTimeout = 16843651; // 0x1010383
     field public static final int numColumns = 16843032; // 0x1010118
@@ -2886,12 +2887,14 @@
     method public int getCapabilities();
     method public deprecated java.lang.String getDescription();
     method public java.lang.String getId();
-    method public int getMinimumUiTimeoutMillis();
+    method public int getInteractiveUiTimeoutMillis();
+    method public int getNonInteractiveUiTimeoutMillis();
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public java.lang.String getSettingsActivityName();
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadSummary(android.content.pm.PackageManager);
-    method public void setMinimumUiTimeoutMillis(int);
+    method public void setInteractiveUiTimeoutMillis(int);
+    method public void setNonInteractiveUiTimeoutMillis(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
     field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
@@ -11176,12 +11179,17 @@
 
   public static class PackageInstaller.Session implements java.io.Closeable {
     method public void abandon();
+    method public void addChildSessionId(int);
     method public void close();
     method public void commit(android.content.IntentSender);
     method public void fsync(java.io.OutputStream) throws java.io.IOException;
+    method public int[] getChildSessionIds();
     method public java.lang.String[] getNames() throws java.io.IOException;
+    method public int getParentSessionId();
+    method public boolean isMultiPackage();
     method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
     method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
+    method public void removeChildSessionId(int);
     method public void removeSplit(java.lang.String) throws java.io.IOException;
     method public void setStagingProgress(float);
     method public void transfer(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11202,20 +11210,24 @@
     method public android.graphics.Bitmap getAppIcon();
     method public java.lang.CharSequence getAppLabel();
     method public java.lang.String getAppPackageName();
+    method public int[] getChildSessionIds();
     method public int getInstallLocation();
     method public int getInstallReason();
     method public java.lang.String getInstallerPackageName();
     method public int getMode();
     method public int getOriginatingUid();
     method public android.net.Uri getOriginatingUri();
+    method public int getParentSessionId();
     method public float getProgress();
     method public android.net.Uri getReferrerUri();
     method public int getSessionId();
     method public long getSize();
     method public boolean isActive();
+    method public boolean isMultiPackage();
     method public boolean isSealed();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
+    field public static final int INVALID_ID = -1; // 0xffffffff
   }
 
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
@@ -11226,6 +11238,7 @@
     method public void setAppPackageName(java.lang.String);
     method public void setInstallLocation(int);
     method public void setInstallReason(int);
+    method public void setMultiPackage();
     method public void setOriginatingUid(int);
     method public void setOriginatingUri(android.net.Uri);
     method public void setReferrerUri(android.net.Uri);
@@ -14980,7 +14993,7 @@
     method public final int getLevel();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
-    method public abstract int getOpacity();
+    method public abstract deprecated int getOpacity();
     method public android.graphics.Insets getOpticalInsets();
     method public void getOutline(android.graphics.Outline);
     method public boolean getPadding(android.graphics.Rect);
@@ -35681,6 +35694,15 @@
     method public static java.lang.String getLastOutgoingCall(android.content.Context);
     field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
     field public static final int BLOCKED_TYPE = 6; // 0x6
+    field public static final java.lang.String BLOCK_REASON = "block_reason";
+    field public static final int BLOCK_REASON_BLOCKED_NUMBER = 3; // 0x3
+    field public static final int BLOCK_REASON_CALL_SCREENING_SERVICE = 1; // 0x1
+    field public static final int BLOCK_REASON_DIRECT_TO_VOICEMAIL = 2; // 0x2
+    field public static final int BLOCK_REASON_NOT_BLOCKED = 0; // 0x0
+    field public static final int BLOCK_REASON_NOT_IN_CONTACTS = 7; // 0x7
+    field public static final int BLOCK_REASON_PAY_PHONE = 6; // 0x6
+    field public static final int BLOCK_REASON_RESTRICTED_NUMBER = 5; // 0x5
+    field public static final int BLOCK_REASON_UNKNOWN_NUMBER = 4; // 0x4
     field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
     field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
     field public static final java.lang.String CACHED_MATCHED_NUMBER = "matched_number";
@@ -35690,6 +35712,8 @@
     field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
     field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
     field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri";
+    field public static final java.lang.String CALL_SCREENING_APP_NAME = "call_screening_app_name";
+    field public static final java.lang.String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name";
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
@@ -40342,6 +40366,7 @@
 
   public static class NotificationListenerService.Ranking {
     ctor public NotificationListenerService.Ranking();
+    method public boolean audiblyAlerted();
     method public boolean canShowBadge();
     method public android.app.NotificationChannel getChannel();
     method public int getImportance();
@@ -42874,6 +42899,16 @@
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityLte> CREATOR;
   }
 
+  public final class CellIdentityNr extends android.telephony.CellIdentity {
+    method public int getChannelNumber();
+    method public java.lang.String getMccString();
+    method public java.lang.String getMncString();
+    method public int getPci();
+    method public int getTac();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityNr> CREATOR;
+  }
+
   public final class CellIdentityTdscdma extends android.telephony.CellIdentity {
     method public int getCid();
     method public int getCpid();
@@ -42933,6 +42968,13 @@
     field public static final android.os.Parcelable.Creator<android.telephony.CellInfoLte> CREATOR;
   }
 
+  public final class CellInfoNr extends android.telephony.CellInfo {
+    method public android.telephony.CellIdentity getCellIdentity();
+    method public android.telephony.CellSignalStrength getCellSignalStrength();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.CellInfoNr> CREATOR;
+  }
+
   public final class CellInfoWcdma extends android.telephony.CellInfo implements android.os.Parcelable {
     method public android.telephony.CellIdentityWcdma getCellIdentity();
     method public android.telephony.CellSignalStrengthWcdma getCellSignalStrength();
@@ -42999,6 +43041,21 @@
     field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthLte> CREATOR;
   }
 
+  public final class CellSignalStrengthNr extends android.telephony.CellSignalStrength implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getAsuLevel();
+    method public int getCsiRsrp();
+    method public int getCsiRsrq();
+    method public int getCsiSinr();
+    method public int getDbm();
+    method public int getLevel();
+    method public int getSsRsrp();
+    method public int getSsRsrq();
+    method public int getSsSinr();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthNr> CREATOR;
+  }
+
   public final class CellSignalStrengthWcdma extends android.telephony.CellSignalStrength implements android.os.Parcelable {
     method public int describeContents();
     method public int getAsuLevel();
@@ -50464,7 +50521,7 @@
     method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
-    method public int getMinimumUiTimeoutMillis();
+    method public int getRecommendedTimeoutMillis(int, int);
     method public void interrupt();
     method public static boolean isAccessibilityButtonSupported();
     method public boolean isEnabled();
@@ -50473,6 +50530,9 @@
     method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
     method public boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
     method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    field public static final int FLAG_CONTENT_CONTROLS = 4; // 0x4
+    field public static final int FLAG_CONTENT_ICONS = 1; // 0x1
+    field public static final int FLAG_CONTENT_TEXT = 2; // 0x2
   }
 
   public static abstract interface AccessibilityManager.AccessibilityStateChangeListener {
diff --git a/api/system-current.txt b/api/system-current.txt
index 6bb6d50..237d4c4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3834,6 +3834,14 @@
 
 }
 
+package android.net.wifi.p2p {
+
+  public class WifiP2pManager {
+    method public void factoryReset(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+  }
+
+}
+
 package android.net.wifi.rtt {
 
   public static final class RangingRequest.Builder {
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index ff436f1..e5764f0 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -24213,7 +24213,90 @@
 HSPLandroid/icu/util/CharsTrie;->next(I)Landroid/icu/util/BytesTrie$Result;
 HSPLandroid/icu/util/CharsTrie;->nextImpl(II)Landroid/icu/util/BytesTrie$Result;
 HSPLandroid/icu/util/CharsTrie;->readValue(Ljava/lang/CharSequence;II)I
-HSPLandroid/icu/util/Currency$1;-><init>()V
+HSPLandroid/icu/util/CodePointTrie$Small8;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small8;
+HSPLandroid/icu/util/CodePointTrie$Small32;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small32;
+HSPLandroid/icu/util/CodePointTrie$Small16;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small16;
+HSPLandroid/icu/util/CodePointTrie$Fast8;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast8;
+HSPLandroid/icu/util/CodePointTrie$Fast8;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast8;->get(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast8;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast32;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast32;
+HSPLandroid/icu/util/CodePointTrie$Fast32;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast32;->get(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast32;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast16;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast16;
+HSPLandroid/icu/util/CodePointTrie$Fast16;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast16;->get(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast16;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Small;->fromBinary(Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small;
+HSPLandroid/icu/util/CodePointTrie$Small;->cpIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Small;->getType()Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie$Small;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;
+HSPLandroid/icu/util/CodePointTrie$Fast;->fromBinary(Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast;
+HSPLandroid/icu/util/CodePointTrie$Fast;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast;->cpIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast;->getType()Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie$Fast;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;
+HSPLandroid/icu/util/CodePointTrie$Fast;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Data8;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data8;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data8;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data8;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$Data32;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data32;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data32;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data32;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$Data16;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data16;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data16;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data16;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$Data;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$ValueWidth;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$ValueWidth;->values()[Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Type;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie$Type;->values()[Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie;->fromBinary(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie;
+HSPLandroid/icu/util/CodePointTrie;->internalSmallIndex(Landroid/icu/util/CodePointTrie$Type;I)I
+HSPLandroid/icu/util/CodePointTrie;->maybeFilterValue(IIILandroid/icu/util/CodePointMap$ValueFilter;)I
+HSPLandroid/icu/util/CodePointTrie;->asciiGet(I)I
+HSPLandroid/icu/util/CodePointTrie;->cpIndex(I)I
+HSPLandroid/icu/util/CodePointTrie;->fastIndex(I)I
+HSPLandroid/icu/util/CodePointTrie;->get(I)I
+HSPLandroid/icu/util/CodePointTrie;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/CodePointTrie;->getType()Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie;->smallIndex(Landroid/icu/util/CodePointTrie$Type;I)I
+HSPLandroid/icu/util/CodePointTrie;->toBinary(Ljava/io/OutputStream;)I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->getCodePoint()I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->getIndex()I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->getValue()I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->next()Z
+HSPLandroid/icu/util/CodePointMap$StringIterator;->previous()Z
+HSPLandroid/icu/util/CodePointMap$StringIterator;->reset(Ljava/lang/CharSequence;I)V
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->hasNext()Z
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->next()Landroid/icu/util/CodePointMap$Range;
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->next()Ljava/lang/Object;
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->remove()V
+HSPLandroid/icu/util/CodePointMap$Range;->access$000(Landroid/icu/util/CodePointMap$Range;)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$002(Landroid/icu/util/CodePointMap$Range;I)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$100(Landroid/icu/util/CodePointMap$Range;)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$102(Landroid/icu/util/CodePointMap$Range;I)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$202(Landroid/icu/util/CodePointMap$Range;I)I
+HSPLandroid/icu/util/CodePointMap$Range;->getEnd()I
+HSPLandroid/icu/util/CodePointMap$Range;->getStart()I
+HSPLandroid/icu/util/CodePointMap$Range;->getValue()I
+HSPLandroid/icu/util/CodePointMap$Range;->set(III)V
+HSPLandroid/icu/util/CodePointMap$ValueFilter;->apply(I)I
+HSPLandroid/icu/util/CodePointMap$RangeOption;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointMap$RangeOption;
+HSPLandroid/icu/util/CodePointMap$RangeOption;->values()[Landroid/icu/util/CodePointMap$RangeOption;
+HSPLandroid/icu/util/CodePointMap;->get(I)I
+HSPLandroid/icu/util/CodePointMap;->getRange(ILandroid/icu/util/CodePointMap$RangeOption;ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/CodePointMap;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/CodePointMap;->iterator()Ljava/util/Iterator;
+HSPLandroid/icu/util/CodePointMap;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;HSPLandroid/icu/util/Currency$1;-><init>()V
 HSPLandroid/icu/util/Currency$1;->createInstance(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 HSPLandroid/icu/util/Currency$1;->createInstance(Ljava/lang/String;Ljava/lang/Void;)Landroid/icu/util/Currency;
 HSPLandroid/icu/util/Currency$CurrencyUsage;-><init>(Ljava/lang/String;I)V
@@ -24259,6 +24342,61 @@
 HSPLandroid/icu/util/MeasureUnit;->equals(Ljava/lang/Object;)Z
 HSPLandroid/icu/util/MeasureUnit;->hashCode()I
 HSPLandroid/icu/util/MeasureUnit;->internalGetInstance(Ljava/lang/String;Ljava/lang/String;)Landroid/icu/util/MeasureUnit;
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->addEntry([I[CIII)V
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findEntry([III)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findEntry([I[C[I[CII)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode(I)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode([CI)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode([II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->modulo(II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->nextIndex(II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->extend([CIII)V
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->extend([IIII)V
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findAllSameBlock([II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([C[CI)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([C[II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([I[II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->init(II)V
+HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->add(III)V
+HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->findMostUsed()I
+HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->findOrAdd(III)I
+HSPLandroid/icu/util/MutableCodePointTrie;->access$000([II[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->access$100([CI[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->access$200([CI[CII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->access$300([IIII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->allValuesSameAs([IIII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->allocDataBlock(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->build(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;)Landroid/icu/util/CodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->clear()V
+HSPLandroid/icu/util/MutableCodePointTrie;->compactData(I[IILandroid/icu/util/MutableCodePointTrie$MixedBlocks;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->compactIndex(ILandroid/icu/util/MutableCodePointTrie$MixedBlocks;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->compactTrie(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->compactWholeDataBlocks(ILandroid/icu/util/MutableCodePointTrie$AllSameBlocks;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->ensureHighStart(I)V
+HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([CI[CII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([CI[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([II[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->fillBlock(IIII)V
+HSPLandroid/icu/util/MutableCodePointTrie;->findAllSameBlock([IIIII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->findHighStart()I
+HSPLandroid/icu/util/MutableCodePointTrie;->findSameBlock([CII[CII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->fromCodePointMap(Landroid/icu/util/CodePointMap;)Landroid/icu/util/MutableCodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->getAllSameOverlap([IIII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getDataBlock(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([CI[CII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([CI[III)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([II[III)I
+HSPLandroid/icu/util/MutableCodePointTrie;->isStartOfSomeFastBlock(I[II)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->maskValues(I)V
+HSPLandroid/icu/util/MutableCodePointTrie;->maybeFilterValue(IIILandroid/icu/util/CodePointMap$ValueFilter;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->writeBlock(II)V
+HSPLandroid/icu/util/MutableCodePointTrie;->buildImmutable(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;)Landroid/icu/util/CodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->clone()Landroid/icu/util/MutableCodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->clone()Ljava/lang/Object;
+HSPLandroid/icu/util/MutableCodePointTrie;->get(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->set(II)V
+HSPLandroid/icu/util/MutableCodePointTrie;->setRange(III)V
 HSPLandroid/icu/util/SimpleTimeZone;-><init>(ILjava/lang/String;IIIIIIIIIII)V
 HSPLandroid/icu/util/SimpleTimeZone;->clone()Ljava/lang/Object;
 HSPLandroid/icu/util/SimpleTimeZone;->cloneAsThawed()Landroid/icu/util/TimeZone;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index d7cca15..997ed25 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -76,7 +76,8 @@
  * @attr ref android.R.styleable#AccessibilityService_notificationTimeout
  * @attr ref android.R.styleable#AccessibilityService_packageNames
  * @attr ref android.R.styleable#AccessibilityService_settingsActivity
- * @attr ref android.R.styleable#AccessibilityService_minimumUiTimeout
+ * @attr ref android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
+ * @attr ref android.R.styleable#AccessibilityService_interactiveUiTimeout
  * @see AccessibilityService
  * @see android.view.accessibility.AccessibilityEvent
  * @see android.view.accessibility.AccessibilityManager
@@ -434,11 +435,14 @@
     public boolean crashed;
 
     /**
-     * The minimum timeout in milliseconds that UI controls need to remain on the screen.
-     *
-     * @see #setMinimumUiTimeoutMillis
+     * A recommended timeout in milliseconds for non-interactive controls.
      */
-    private int mMinimumUiTimeout;
+    private int mNonInteractiveUiTimeout;
+
+    /**
+     * A recommended timeout in milliseconds for interactive controls.
+     */
+    private int mInteractiveUiTimeout;
 
     /**
      * The component name the accessibility service.
@@ -544,8 +548,11 @@
             notificationTimeout = asAttributes.getInt(
                     com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
                     0);
-            mMinimumUiTimeout = asAttributes.getInt(
-                    com.android.internal.R.styleable.AccessibilityService_minimumUiTimeout,
+            mNonInteractiveUiTimeout = asAttributes.getInt(
+                    com.android.internal.R.styleable.AccessibilityService_nonInteractiveUiTimeout,
+                    0);
+            mInteractiveUiTimeout = asAttributes.getInt(
+                    com.android.internal.R.styleable.AccessibilityService_interactiveUiTimeout,
                     0);
             flags = asAttributes.getInt(
                     com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
@@ -616,7 +623,8 @@
         packageNames = other.packageNames;
         feedbackType = other.feedbackType;
         notificationTimeout = other.notificationTimeout;
-        mMinimumUiTimeout = other.mMinimumUiTimeout;
+        mNonInteractiveUiTimeout = other.mNonInteractiveUiTimeout;
+        mInteractiveUiTimeout = other.mInteractiveUiTimeout;
         flags = other.flags;
     }
 
@@ -775,26 +783,57 @@
     }
 
     /**
-     * Set the minimum time that controls need to remain on the screen to support the user.
+     * Set the recommended time that non-interactive controls need to remain on the screen to
+     * support the user.
      * <p>
-     *    <strong>This value can be dynamically set at runtime by
-     *    {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
+     *     <strong>This value can be dynamically set at runtime by
+     *     {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
      * </p>
      *
      * @param timeout The timeout in milliseconds.
+     *
+     * @see android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
      */
-    public void setMinimumUiTimeoutMillis(int timeout) {
-        mMinimumUiTimeout = timeout;
+    public void setNonInteractiveUiTimeoutMillis(int timeout) {
+        mNonInteractiveUiTimeout = timeout;
     }
 
     /**
-     * Get the minimum ui timeout.
+     * Get the recommended timeout for non-interactive controls.
      *
-     * @see #setMinimumUiTimeoutMillis
      * @return The timeout in milliseconds.
+     *
+     * @see #setNonInteractiveUiTimeoutMillis(int)
      */
-    public int getMinimumUiTimeoutMillis() {
-        return mMinimumUiTimeout;
+    public int getNonInteractiveUiTimeoutMillis() {
+        return mNonInteractiveUiTimeout;
+    }
+
+    /**
+     * Set the recommended time that interactive controls need to remain on the screen to
+     * support the user.
+     * <p>
+     *     <strong>This value can be dynamically set at runtime by
+     *     {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
+     * </p>
+     *
+     * @param timeout The timeout in milliseconds.
+     *
+     * @see android.R.styleable#AccessibilityService_interactiveUiTimeout
+     */
+    public void setInteractiveUiTimeoutMillis(int timeout) {
+        mInteractiveUiTimeout = timeout;
+    }
+
+    /**
+     * Get the recommended timeout for interactive controls.
+     *
+     * @return The timeout in milliseconds.
+     *
+     * @see #setInteractiveUiTimeoutMillis(int)
+     */
+    public int getInteractiveUiTimeoutMillis() {
+        return mInteractiveUiTimeout;
     }
 
     /** {@hide} */
@@ -815,7 +854,8 @@
         parcel.writeStringArray(packageNames);
         parcel.writeInt(feedbackType);
         parcel.writeLong(notificationTimeout);
-        parcel.writeInt(mMinimumUiTimeout);
+        parcel.writeInt(mNonInteractiveUiTimeout);
+        parcel.writeInt(mInteractiveUiTimeout);
         parcel.writeInt(flags);
         parcel.writeInt(crashed ? 1 : 0);
         parcel.writeParcelable(mComponentName, flagz);
@@ -833,7 +873,8 @@
         packageNames = parcel.readStringArray();
         feedbackType = parcel.readInt();
         notificationTimeout = parcel.readLong();
-        mMinimumUiTimeout = parcel.readInt();
+        mNonInteractiveUiTimeout = parcel.readInt();
+        mInteractiveUiTimeout = parcel.readInt();
         flags = parcel.readInt();
         crashed = parcel.readInt() != 0;
         mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
@@ -884,7 +925,9 @@
         stringBuilder.append(", ");
         stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
         stringBuilder.append(", ");
-        stringBuilder.append("minimumUiTimeout: ").append(mMinimumUiTimeout);
+        stringBuilder.append("nonInteractiveUiTimeout: ").append(mNonInteractiveUiTimeout);
+        stringBuilder.append(", ");
+        stringBuilder.append("interactiveUiTimeout: ").append(mInteractiveUiTimeout);
         stringBuilder.append(", ");
         appendFlags(stringBuilder, flags);
         stringBuilder.append(", ");
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index f5d5e6e..7fe21b2 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.NonNull;
 import android.util.SparseIntArray;
 
 import com.android.internal.util.function.QuadFunction;
@@ -73,4 +74,21 @@
      * access to app ops for their user.
      */
     public abstract void setDeviceAndProfileOwners(SparseIntArray owners);
+
+    /**
+     * Sets the app-ops mode for a certain app-op and uid.
+     *
+     * <p>Similar as {@link AppOpsManager#setMode} but does not require the package manager to be
+     * working. Hence this can be used very early during boot.
+     *
+     * <p>Only for internal callers. Does <u>not</u> verify that package name belongs to uid.
+     *
+     * @param code The op code to set.
+     * @param uid The UID for which to set.
+     * @param packageName The package for which to set.
+     * @param mode The new mode to set.
+     * @param isPrivileged If the package is privileged
+     */
+    public abstract void setMode(int code, int uid, @NonNull String packageName, int mode,
+            boolean isPrivileged);
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6d464fb..4f4df5d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4457,6 +4457,7 @@
             contentView.setViewVisibility(R.id.time, View.GONE);
             contentView.setImageViewIcon(R.id.profile_badge, null);
             contentView.setViewVisibility(R.id.profile_badge, View.GONE);
+            contentView.setViewVisibility(R.id.alerted_icon, View.GONE);
             mN.mUsesStandardHeader = false;
         }
 
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e95f9ab..713f752 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -857,11 +857,17 @@
                     @Override
                     public BiometricManager createService(ContextImpl ctx)
                             throws ServiceNotFoundException {
-                        final IBinder binder =
-                                ServiceManager.getServiceOrThrow(Context.BIOMETRIC_SERVICE);
-                        final IBiometricService service =
-                                IBiometricService.Stub.asInterface(binder);
-                        return new BiometricManager(ctx.getOuterContext(), service);
+                        if (BiometricManager.hasBiometrics(ctx)) {
+                            final IBinder binder =
+                                    ServiceManager.getServiceOrThrow(Context.BIOMETRIC_SERVICE);
+                            final IBiometricService service =
+                                    IBiometricService.Stub.asInterface(binder);
+                            return new BiometricManager(ctx.getOuterContext(), service);
+                        } else {
+                            // Allow access to the manager when service is null. This saves memory
+                            // on devices without biometric hardware.
+                            return new BiometricManager(ctx.getOuterContext(), null);
+                        }
                     }
                 });
 
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 8fddb99..cef21f6 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -38,4 +38,9 @@
     void commit(in IntentSender statusReceiver, boolean forTransferred);
     void transfer(in String packageName);
     void abandon();
+    boolean isMultiPackage();
+    int[] getChildSessionIds();
+    void addChildSessionId(in int sessionId);
+    void removeChildSessionId(in int sessionId);
+    int getParentSessionId();
 }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index e9cfa78..8f90199 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -365,12 +365,14 @@
      */
     public @NonNull Session openSession(int sessionId) throws IOException {
         try {
-            return new Session(mInstaller.openSession(sessionId));
+            try {
+                return new Session(mInstaller.openSession(sessionId));
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         } catch (RuntimeException e) {
             ExceptionUtils.maybeUnwrapIOException(e);
             throw e;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -769,9 +771,18 @@
      * If an APK included in this session is already defined by the existing
      * installation (for example, the same split name), the APK in this session
      * will replace the existing APK.
+     * <p>
+     * In such a case that multiple packages need to be commited simultaneously,
+     * multiple sessions can be referenced by a single multi-package session.
+     * This session is created with no package name and calling
+     * {@link SessionParams#setMultiPackage()} with {@code true}. The
+     * individual session IDs can be added with {@link #addChildSessionId(int)}
+     * and commit of the multi-package session will result in all child sessions
+     * being committed atomically.
      */
     public static class Session implements Closeable {
-        private IPackageInstallerSession mSession;
+        /** {@hide} */
+        protected final IPackageInstallerSession mSession;
 
         /** {@hide} */
         public Session(IPackageInstallerSession session) {
@@ -1080,6 +1091,71 @@
                 throw e.rethrowFromSystemServer();
             }
         }
+
+        /**
+         * @return {@code true} if this session will commit more than one package when it is
+         * committed.
+         */
+        public boolean isMultiPackage() {
+            try {
+                return mSession.isMultiPackage();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * @return the session ID of the multi-package session that this belongs to or
+         * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session.
+         */
+        public int getParentSessionId() {
+            try {
+                return mSession.getParentSessionId();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * @return the set of session IDs that will be committed atomically when this session is
+         * committed if this is a multi-package session or null if none exist.
+         */
+        @NonNull
+        public int[] getChildSessionIds() {
+            try {
+                return mSession.getChildSessionIds();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Adds a session ID to the set of sessions that will be committed atomically
+         * when this session is committed.
+         *
+         * @param sessionId the session ID to add to this multi-package session.
+         */
+        public void addChildSessionId(int sessionId) {
+            try {
+                mSession.addChildSessionId(sessionId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Removes a session ID from the set of sessions that will be committed
+         * atomically when this session is committed.
+         *
+         * @param sessionId the session ID to remove from this multi-package session.
+         */
+        public void removeChildSessionId(int sessionId) {
+            try {
+                mSession.removeChildSessionId(sessionId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
     }
 
     /**
@@ -1149,6 +1225,8 @@
         public String[] grantedRuntimePermissions;
         /** {@hide} */
         public String installerPackageName;
+        /** {@hide} */
+        public boolean isMultiPackage;
 
         /**
          * Construct parameters for a new package install session.
@@ -1178,6 +1256,7 @@
             volumeUuid = source.readString();
             grantedRuntimePermissions = source.readStringArray();
             installerPackageName = source.readString();
+            isMultiPackage = source.readBoolean();
         }
 
         /**
@@ -1392,6 +1471,18 @@
             this.installerPackageName = installerPackageName;
         }
 
+        /**
+         * Set this session to be the parent of a multi-package install.
+         *
+         * A multi-package install session contains no APKs and only references other install
+         * sessions via ID. When a multi-package session is committed, all of its children
+         * are committed to the system in an atomic manner. If any children fail to install,
+         * all of them do, including the multi-package session.
+         */
+        public void setMultiPackage() {
+            this.isMultiPackage = true;
+        }
+
         /** {@hide} */
         public void dump(IndentingPrintWriter pw) {
             pw.printPair("mode", mode);
@@ -1408,6 +1499,7 @@
             pw.printPair("volumeUuid", volumeUuid);
             pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions);
             pw.printPair("installerPackageName", installerPackageName);
+            pw.printPair("isMultiPackage", isMultiPackage);
             pw.println();
         }
 
@@ -1433,6 +1525,7 @@
             dest.writeString(volumeUuid);
             dest.writeStringArray(grantedRuntimePermissions);
             dest.writeString(installerPackageName);
+            dest.writeBoolean(isMultiPackage);
         }
 
         public static final Parcelable.Creator<SessionParams>
@@ -1454,6 +1547,12 @@
      */
     public static class SessionInfo implements Parcelable {
 
+        /**
+         * A session ID that does not exist or is invalid.
+         */
+        public static final int INVALID_ID = -1;
+        /** {@hide} */
+        private static final int[] NO_SESSIONS = {};
         /** {@hide} */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int sessionId;
@@ -1503,6 +1602,12 @@
         public String[] grantedRuntimePermissions;
         /** {@hide} */
         public int installFlags;
+        /** {@hide} */
+        public boolean isMultiPackage;
+        /** {@hide} */
+        public int parentSessionId = INVALID_ID;
+        /** {@hide} */
+        public int[] childSessionIds = NO_SESSIONS;
 
         /** {@hide} */
         @UnsupportedAppUsage
@@ -1531,6 +1636,12 @@
             referrerUri = source.readParcelable(null);
             grantedRuntimePermissions = source.readStringArray();
             installFlags = source.readInt();
+            isMultiPackage = source.readBoolean();
+            parentSessionId = source.readInt();
+            childSessionIds = source.createIntArray();
+            if (childSessionIds == null) {
+                childSessionIds = NO_SESSIONS;
+            }
         }
 
         /**
@@ -1784,6 +1895,30 @@
             return createDetailsIntent();
         }
 
+        /**
+         * Returns true if this session is a multi-package session containing references to other
+         * sessions.
+         */
+        public boolean isMultiPackage() {
+            return isMultiPackage;
+        }
+
+        /**
+         * Returns the parent multi-package session ID if this session belongs to one,
+         * {@link #INVALID_ID} otherwise.
+         */
+        public int getParentSessionId() {
+            return parentSessionId;
+        }
+
+        /**
+         * Returns the set of session IDs that will be committed when this session is commited if
+         * this session is a multi-package session.
+         */
+        public int[] getChildSessionIds() {
+            return childSessionIds;
+        }
+
         @Override
         public int describeContents() {
             return 0;
@@ -1811,6 +1946,9 @@
             dest.writeParcelable(referrerUri, flags);
             dest.writeStringArray(grantedRuntimePermissions);
             dest.writeInt(installFlags);
+            dest.writeBoolean(isMultiPackage);
+            dest.writeInt(parentSessionId);
+            dest.writeIntArray(childSessionIds);
         }
 
         public static final Parcelable.Creator<SessionInfo>
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 67b86c0..c1ac061 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -915,6 +915,11 @@
     public static final int INSTALL_REASON_USER = 4;
 
     /**
+     * @hide
+     */
+    public static final int INSTALL_UNKNOWN = 0;
+
+    /**
      * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
      * on success.
      *
@@ -2943,6 +2948,15 @@
     public static final int FLAG_PERMISSION_REVIEW_REQUIRED =  1 << 6;
 
     /**
+     * Permission flag: The permission has not been explicitly requested by
+     * the app but has been added automatically by the system. Revoke once
+     * the app does explicitly request it.
+     *
+     * @hide
+     */
+    public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED =  1 << 7;
+
+    /**
      * Mask for all permission flags.
      *
      * @hide
@@ -3593,7 +3607,10 @@
             FLAG_PERMISSION_POLICY_FIXED,
             FLAG_PERMISSION_REVOKE_ON_UPGRADE,
             FLAG_PERMISSION_SYSTEM_FIXED,
-            FLAG_PERMISSION_GRANTED_BY_DEFAULT
+            FLAG_PERMISSION_GRANTED_BY_DEFAULT,
+            /*
+            FLAG_PERMISSION_REVOKE_WHEN_REQUESED
+            */
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PermissionFlags {}
@@ -6133,6 +6150,7 @@
             case FLAG_PERMISSION_REVOKE_ON_UPGRADE: return "REVOKE_ON_UPGRADE";
             case FLAG_PERMISSION_USER_FIXED: return "USER_FIXED";
             case FLAG_PERMISSION_REVIEW_REQUIRED: return "REVIEW_REQUIRED";
+            case FLAG_PERMISSION_REVOKE_WHEN_REQUESTED: return "REVOKE_WHEN_REQUESTED";
             default: return Integer.toString(flag);
         }
     }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index dc33bde..7ef5264 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2435,7 +2435,7 @@
         }
 
         final int NP = PackageParser.NEW_PERMISSIONS.length;
-        StringBuilder implicitPerms = null;
+        StringBuilder newPermsMsg = null;
         for (int ip=0; ip<NP; ip++) {
             final PackageParser.NewPermissionInfo npi
                     = PackageParser.NEW_PERMISSIONS[ip];
@@ -2443,19 +2443,20 @@
                 break;
             }
             if (!pkg.requestedPermissions.contains(npi.name)) {
-                if (implicitPerms == null) {
-                    implicitPerms = new StringBuilder(128);
-                    implicitPerms.append(pkg.packageName);
-                    implicitPerms.append(": compat added ");
+                if (newPermsMsg == null) {
+                    newPermsMsg = new StringBuilder(128);
+                    newPermsMsg.append(pkg.packageName);
+                    newPermsMsg.append(": compat added ");
                 } else {
-                    implicitPerms.append(' ');
+                    newPermsMsg.append(' ');
                 }
-                implicitPerms.append(npi.name);
+                newPermsMsg.append(npi.name);
                 pkg.requestedPermissions.add(npi.name);
+                pkg.implicitPermissions.add(npi.name);
             }
         }
-        if (implicitPerms != null) {
-            Slog.i(TAG, implicitPerms.toString());
+        if (newPermsMsg != null) {
+            Slog.i(TAG, newPermsMsg.toString());
         }
 
 
@@ -2472,6 +2473,7 @@
                 final String perm = newPerms.get(in);
                 if (!pkg.requestedPermissions.contains(perm)) {
                     pkg.requestedPermissions.add(perm);
+                    pkg.implicitPermissions.add(perm);
                 }
             }
         }
@@ -6394,6 +6396,9 @@
         @UnsupportedAppUsage
         public final ArrayList<String> requestedPermissions = new ArrayList<String>();
 
+        /** Permissions requested but not in the manifest. */
+        public final ArrayList<String> implicitPermissions = new ArrayList<>();
+
         @UnsupportedAppUsage
         public ArrayList<String> protectedBroadcasts;
 
@@ -6923,6 +6928,8 @@
 
             dest.readStringList(requestedPermissions);
             internStringArrayList(requestedPermissions);
+            dest.readStringList(implicitPermissions);
+            internStringArrayList(implicitPermissions);
             protectedBroadcasts = dest.createStringArrayList();
             internStringArrayList(protectedBroadcasts);
 
@@ -7087,6 +7094,7 @@
             dest.writeParcelableList(instrumentation, flags);
 
             dest.writeStringList(requestedPermissions);
+            dest.writeStringList(implicitPermissions);
             dest.writeStringList(protectedBroadcasts);
 
             // TODO: This doesn't work: b/64295061
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index fe00604..ff58c75 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -22,6 +22,7 @@
 import android.annotation.IntDef;
 import android.annotation.RequiresPermission;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.RemoteException;
 import android.util.Slog;
 
@@ -64,6 +65,19 @@
 
     private final Context mContext;
     private final IBiometricService mService;
+    private final boolean mHasHardware;
+
+    /**
+     * @param context
+     * @return
+     * @hide
+     */
+    public static boolean hasBiometrics(Context context) {
+        final PackageManager pm = context.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
+                || pm.hasSystemFeature(PackageManager.FEATURE_IRIS)
+                || pm.hasSystemFeature(PackageManager.FEATURE_FACE);
+    }
 
     /**
      * @hide
@@ -73,6 +87,8 @@
     public BiometricManager(Context context, IBiometricService service) {
         mContext = context;
         mService = service;
+
+        mHasHardware = hasBiometrics(context);
     }
 
     /**
@@ -93,8 +109,12 @@
                 throw e.rethrowFromSystemServer();
             }
         } else {
-            Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
-            return BIOMETRIC_ERROR_UNAVAILABLE;
+            if (!mHasHardware) {
+                return BIOMETRIC_ERROR_NO_HARDWARE;
+            } else {
+                Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
+                return BIOMETRIC_ERROR_UNAVAILABLE;
+            }
         }
     }
 
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index fc30eed..2ea7066 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -67,15 +67,14 @@
      * such an old app asks for a location permission (i.e. the
      * {@link SplitPermissionInfo#getSplitPermission()}), then the
      * {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside
-     * {@{@link SplitPermissionInfo#getNewPermissions}) is added.
+     * {@link SplitPermissionInfo#getNewPermissions}) is added.
      *
      * <p>Note: Regular apps do not have to worry about this. The platform and permission controller
      * automatically add the new permissions where needed.
      *
      * @return All permissions that are split.
      */
-    public @NonNull
-    List<SplitPermissionInfo> getSplitPermissions() {
+    public @NonNull List<SplitPermissionInfo> getSplitPermissions() {
         return SPLIT_PERMISSIONS;
     }
 
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index c0fa1de..3d93afd 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -509,6 +509,100 @@
         private static final int MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS = 1000 * 10;
 
         /**
+         * Value for {@link CallLog.Calls#BLOCK_REASON}, set as the default value when a call was
+         * not blocked by a CallScreeningService or any other system call blocking method.
+         */
+        public static final int BLOCK_REASON_NOT_BLOCKED = 0;
+
+        /**
+         * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+         * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked by a
+         * CallScreeningService. The {@link CallLog.Calls#CALL_SCREENING_COMPONENT_NAME} and
+         * {@link CallLog.Calls#CALL_SCREENING_APP_NAME} columns will indicate which call screening
+         * service was responsible for blocking the call.
+         */
+        public static final int BLOCK_REASON_CALL_SCREENING_SERVICE = 1;
+
+        /**
+         * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+         * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+         * configured a contact to be sent directly to voicemail.
+         */
+        public static final int BLOCK_REASON_DIRECT_TO_VOICEMAIL = 2;
+
+        /**
+         * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+         * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because it is
+         * in the BlockedNumbers provider.
+         */
+        public static final int BLOCK_REASON_BLOCKED_NUMBER = 3;
+
+        /**
+         * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+         * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+         * has chosen to block all calls from unknown numbers.
+         */
+        public static final int BLOCK_REASON_UNKNOWN_NUMBER = 4;
+
+        /**
+         * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+         * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+         * has chosen to block all calls from restricted numbers.
+         */
+        public static final int BLOCK_REASON_RESTRICTED_NUMBER = 5;
+
+        /**
+         * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+         * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+         * has chosen to block all calls from pay phones.
+         */
+        public static final int BLOCK_REASON_PAY_PHONE = 6;
+
+        /**
+         * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+         * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+         * has chosen to block all calls from numbers not in their contacts.
+         */
+        public static final int BLOCK_REASON_NOT_IN_CONTACTS = 7;
+
+        /**
+         * The ComponentName of the CallScreeningService which blocked this call. Will be
+         * populated when the {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE}.
+         * <P>Type: TEXT</P>
+         */
+        public static final String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name";
+
+        /**
+         * The name of the app which blocked a call. Will be populated when the
+         * {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE}. Provided as a
+         * convenience so that the call log can still indicate which app blocked a call, even if
+         * that app is no longer installed.
+         * <P>Type: TEXT</P>
+         */
+        public static final String CALL_SCREENING_APP_NAME = "call_screening_app_name";
+
+        /**
+         * Where the {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE},
+         * indicates the reason why a call is blocked.
+         * <P>Type: INTEGER</P>
+         *
+         * <p>
+         * Allowed values:
+         * <ul>
+         * <li>{@link CallLog.Calls#BLOCK_REASON_NOT_BLOCKED}</li>
+         * <li>{@link CallLog.Calls#BLOCK_REASON_CALL_SCREENING_SERVICE}</li>
+         * <li>{@link CallLog.Calls#BLOCK_REASON_DIRECT_TO_VOICEMAIL}</li>
+         * <li>{@link CallLog.Calls#BLOCK_REASON_BLOCKED_NUMBER}</li>
+         * <li>{@link CallLog.Calls#BLOCK_REASON_UNKNOWN_NUMBER}</li>
+         * <li>{@link CallLog.Calls#BLOCK_REASON_RESTRICTED_NUMBER}</li>
+         * <li>{@link CallLog.Calls#BLOCK_REASON_PAY_PHONE}</li>
+         * <li>{@link CallLog.Calls#BLOCK_REASON_NOT_IN_CONTACTS}</li>
+         * </ul>
+         * </p>
+         */
+        public static final String BLOCK_REASON = "block_reason";
+
+        /**
          * Adds a call to the call log.
          *
          * @param ci the CallerInfo object to get the target contact from.  Can be null
@@ -530,12 +624,14 @@
          * {@hide}
          */
         public static Uri addCall(CallerInfo ci, Context context, String number,
-                int presentation, int callType, int features, PhoneAccountHandle accountHandle,
+                int presentation, int callType, int features,
+                PhoneAccountHandle accountHandle,
                 long start, int duration, Long dataUsage) {
-            return addCall(ci, context, number, /* postDialDigits =*/ "", /* viaNumber =*/ "",
-                    presentation, callType, features, accountHandle, start, duration,
-                    dataUsage, /* addForAllUsers =*/ false, /* userToBeInsertedTo =*/ null,
-                    /* is_read =*/ false);
+            return addCall(ci, context, number, "" /* postDialDigits */, "" /* viaNumber */,
+                presentation, callType, features, accountHandle, start, duration,
+                dataUsage, false /* addForAllUsers */, null /* userToBeInsertedTo */,
+                false /* isRead */, Calls.BLOCK_REASON_NOT_BLOCKED /* callBlockReason */,
+                null /* callScreeningAppName */, null /* callScreeningComponentName */);
         }
 
 
@@ -572,8 +668,10 @@
                 int features, PhoneAccountHandle accountHandle, long start, int duration,
                 Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo) {
             return addCall(ci, context, number, postDialDigits, viaNumber, presentation, callType,
-                    features, accountHandle, start, duration, dataUsage, addForAllUsers,
-                    userToBeInsertedTo, /* is_read =*/ false);
+                features, accountHandle, start, duration, dataUsage, addForAllUsers,
+                userToBeInsertedTo, false /* isRead */ , Calls.BLOCK_REASON_NOT_BLOCKED
+                /* callBlockReason */, null /* callScreeningAppName */,
+                null /* callScreeningComponentName */);
         }
 
         /**
@@ -602,8 +700,11 @@
          * @param userToBeInsertedTo {@link UserHandle} of user that the call is going to be
          *                           inserted to. null if it is inserted to the current user. The
          *                           value is ignored if @{link addForAllUsers} is true.
-         * @param is_read Flag to show if the missed call log has been read by the user or not.
+         * @param isRead Flag to show if the missed call log has been read by the user or not.
          *                Used for call log restore of missed calls.
+         * @param callBlockReason The reason why the call is blocked.
+         * @param callScreeningAppName The call screening application name which block the call.
+         * @param callScreeningComponentName The call screening component name which block the call.
          *
          * @result The URI of the call log entry belonging to the user that made or received this
          *        call.  This could be of the shadow provider.  Do not return it to non-system apps,
@@ -615,7 +716,8 @@
                 String postDialDigits, String viaNumber, int presentation, int callType,
                 int features, PhoneAccountHandle accountHandle, long start, int duration,
                 Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
-                boolean is_read) {
+                boolean isRead, int callBlockReason, String callScreeningAppName,
+                String callScreeningComponentName) {
             if (VERBOSE_LOG) {
                 Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
                         number, userToBeInsertedTo, addForAllUsers));
@@ -690,9 +792,13 @@
             values.put(ADD_FOR_ALL_USERS, addForAllUsers ? 1 : 0);
 
             if (callType == MISSED_TYPE) {
-                values.put(IS_READ, Integer.valueOf(is_read ? 1 : 0));
+                values.put(IS_READ, Integer.valueOf(isRead ? 1 : 0));
             }
 
+            values.put(BLOCK_REASON, callBlockReason);
+            values.put(CALL_SCREENING_APP_NAME, callScreeningAppName);
+            values.put(CALL_SCREENING_COMPONENT_NAME, callScreeningComponentName);
+
             if ((ci != null) && (ci.contactIdOrZero > 0)) {
                 // Update usage information for the number associated with the contact ID.
                 // We need to use both the number and the ID for obtaining a data ID since other
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3b5dca9..8e4de9f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4895,6 +4895,7 @@
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET);
             MOVED_TO_GLOBAL.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
             MOVED_TO_GLOBAL.add(Settings.Global.PACKAGE_VERIFIER_ENABLE);
             MOVED_TO_GLOBAL.add(Settings.Global.PACKAGE_VERIFIER_TIMEOUT);
@@ -6567,23 +6568,22 @@
         public static final String MULTI_PRESS_TIMEOUT = "multi_press_timeout";
 
         /**
-         * Whether the user specifies a minimum ui timeout to override minimum ui timeout of
-         * accessibility service
+         * Setting that specifies recommended timeout in milliseconds for controls
+         * which don't need user's interactions.
          *
-         * Type: int (0 for false, 1 for true)
          * @hide
          */
-        public static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED =
-                "accessibility_minimum_ui_timeout_enabled";
+        public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS =
+                "accessibility_non_interactive_ui_timeout_ms";
 
         /**
-         * Setting that specifies ui minimum timeout in milliseconds.
+         * Setting that specifies recommended timeout in milliseconds for controls
+         * which need user's interactions.
          *
-         * @see #ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED
          * @hide
          */
-        public static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS =
-                "accessibility_minimum_ui_timeout_ms";
+        public static final String ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS =
+                "accessibility_interactive_ui_timeout_ms";
 
         /**
          * List of the enabled print services.
@@ -8201,6 +8201,12 @@
                 "packages_to_clear_data_before_full_restore";
 
         /**
+         * Setting to determine whether to use the new notification priority handling features.
+         * @hide
+         */
+        public static final String NOTIFICATION_NEW_INTERRUPTION_MODEL = "new_interruption_model";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -8312,8 +8318,9 @@
             ZEN_SETTINGS_SUGGESTION_VIEWED,
             CHARGING_SOUNDS_ENABLED,
             CHARGING_VIBRATION_ENABLED,
-            ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
-            ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
+            ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+            ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
+            NOTIFICATION_NEW_INTERRUPTION_MODEL,
         };
 
         /**
@@ -8469,10 +8476,12 @@
             VALIDATORS.put(ZEN_SETTINGS_SUGGESTION_VIEWED, BOOLEAN_VALIDATOR);
             VALIDATORS.put(CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
             VALIDATORS.put(CHARGING_VIBRATION_ENABLED, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
+            VALIDATORS.put(ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+                    NON_NEGATIVE_INTEGER_VALIDATOR);
+            VALIDATORS.put(ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
             VALIDATORS.put(USER_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
+            VALIDATORS.put(NOTIFICATION_NEW_INTERRUPTION_MODEL, BOOLEAN_VALIDATOR);
         }
 
         /**
@@ -9987,6 +9996,15 @@
                 "wifi_rtt_background_exec_gap_ms";
 
         /**
+         * Indicate whether factory reset request is pending.
+         *
+         * Type: int (0 for false, 1 for true)
+         * @hide
+         */
+        public static final String WIFI_P2P_PENDING_FACTORY_RESET =
+                "wifi_p2p_pending_factory_reset";
+
+        /**
          * Whether soft AP will shut down after a timeout period when no devices are connected.
          *
          * Type: int (0 for false, 1 for true)
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index b8e0387..56e6aea 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1461,6 +1461,7 @@
         private boolean mShowBadge;
         private @UserSentiment int mUserSentiment = USER_SENTIMENT_NEUTRAL;
         private boolean mHidden;
+        private boolean mAudiblyAlerted;
         private ArrayList<Notification.Action> mSmartActions;
         private ArrayList<CharSequence> mSmartReplies;
 
@@ -1627,6 +1628,15 @@
         }
 
         /**
+         * Returns whether this notification alerted the user via sound or vibration.
+         *
+         * @return true if the notification alerted the user, false otherwise.
+         */
+        public boolean audiblyAlerted() {
+            return mAudiblyAlerted;
+        }
+
+        /**
          * @hide
          */
         @VisibleForTesting
@@ -1635,8 +1645,8 @@
                 CharSequence explanation, String overrideGroupKey,
                 NotificationChannel channel, ArrayList<String> overridePeople,
                 ArrayList<SnoozeCriterion> snoozeCriteria, boolean showBadge,
-                int userSentiment, boolean hidden, ArrayList<Notification.Action> smartActions,
-                ArrayList<CharSequence> smartReplies) {
+                int userSentiment, boolean hidden, boolean audiblyAlerted,
+                ArrayList<Notification.Action> smartActions, ArrayList<CharSequence> smartReplies) {
             mKey = key;
             mRank = rank;
             mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
@@ -1652,6 +1662,7 @@
             mShowBadge = showBadge;
             mUserSentiment = userSentiment;
             mHidden = hidden;
+            mAudiblyAlerted = audiblyAlerted;
             mSmartActions = smartActions;
             mSmartReplies = smartReplies;
         }
@@ -1703,6 +1714,7 @@
         private ArrayMap<String, Boolean> mShowBadge;
         private ArrayMap<String, Integer> mUserSentiment;
         private ArrayMap<String, Boolean> mHidden;
+        private ArrayMap<String, Boolean> mAudiblyAlerted;
         private ArrayMap<String, ArrayList<Notification.Action>> mSmartActions;
         private ArrayMap<String, ArrayList<CharSequence>> mSmartReplies;
 
@@ -1733,8 +1745,8 @@
                     getVisibilityOverride(key), getSuppressedVisualEffects(key),
                     getImportance(key), getImportanceExplanation(key), getOverrideGroupKey(key),
                     getChannel(key), getOverridePeople(key), getSnoozeCriteria(key),
-                    getShowBadge(key), getUserSentiment(key), getHidden(key), getSmartActions(key),
-                    getSmartReplies(key));
+                    getShowBadge(key), getUserSentiment(key), getHidden(key),
+                    getAudiblyAlerted(key), getSmartActions(key), getSmartReplies(key));
             return rank >= 0;
         }
 
@@ -1872,6 +1884,16 @@
             return hidden == null ? false : hidden.booleanValue();
         }
 
+        private boolean getAudiblyAlerted(String key) {
+            synchronized (this) {
+                if (mAudiblyAlerted == null) {
+                    buildAudiblyAlertedLocked();
+                }
+            }
+            Boolean audiblyAlerted = mAudiblyAlerted.get(key);
+            return audiblyAlerted == null ? false : audiblyAlerted.booleanValue();
+        }
+
         private ArrayList<Notification.Action> getSmartActions(String key) {
             synchronized (this) {
                 if (mSmartActions == null) {
@@ -2007,6 +2029,11 @@
         }
 
         // Locked by 'this'
+        private void buildAudiblyAlertedLocked() {
+            mAudiblyAlerted = buildBooleanMapFromBundle(mRankingUpdate.getAudiblyAlerted());
+        }
+
+        // Locked by 'this'
         private void buildSmartActions() {
             Bundle smartActions = mRankingUpdate.getSmartActions();
             mSmartActions = new ArrayMap<>(smartActions.size());
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index c67fad0..b561bfd 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -39,13 +39,14 @@
     private final Bundle mHidden;
     private final Bundle mSmartActions;
     private final Bundle mSmartReplies;
+    private final Bundle mAudiblyAlerted;
 
     public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
             Bundle visibilityOverrides, Bundle suppressedVisualEffects,
             int[] importance, Bundle explanation, Bundle overrideGroupKeys,
             Bundle channels, Bundle overridePeople, Bundle snoozeCriteria,
             Bundle showBadge, Bundle userSentiment, Bundle hidden, Bundle smartActions,
-            Bundle smartReplies) {
+            Bundle smartReplies, Bundle audiblyAlerted) {
         mKeys = keys;
         mInterceptedKeys = interceptedKeys;
         mVisibilityOverrides = visibilityOverrides;
@@ -61,6 +62,7 @@
         mHidden = hidden;
         mSmartActions = smartActions;
         mSmartReplies = smartReplies;
+        mAudiblyAlerted = audiblyAlerted;
     }
 
     public NotificationRankingUpdate(Parcel in) {
@@ -80,6 +82,7 @@
         mHidden = in.readBundle();
         mSmartActions = in.readBundle();
         mSmartReplies = in.readBundle();
+        mAudiblyAlerted = in.readBundle();
     }
 
     @Override
@@ -104,6 +107,7 @@
         out.writeBundle(mHidden);
         out.writeBundle(mSmartActions);
         out.writeBundle(mSmartReplies);
+        out.writeBundle(mAudiblyAlerted);
     }
 
     public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -176,4 +180,8 @@
     public Bundle getSmartReplies() {
         return mSmartReplies;
     }
+
+    public Bundle getAudiblyAlerted() {
+        return mAudiblyAlerted;
+    }
 }
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 769dd1b..b047ef7 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -42,7 +42,6 @@
     private static final Map<String, String> DEFAULT_FLAGS;
     static {
         DEFAULT_FLAGS = new HashMap<>();
-        DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
         DEFAULT_FLAGS.put("settings_dynamic_homepage", "false");
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 81da76d..fa30221 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -61,6 +61,7 @@
     private View mCameraIcon;
     private View mMicIcon;
     private View mAppOps;
+    private View mAudiblyAlertedIcon;
     private int mIconColor;
     private int mOriginalNotificationColor;
     private boolean mExpanded;
@@ -121,6 +122,7 @@
         mMicIcon = findViewById(com.android.internal.R.id.mic);
         mOverlayIcon = findViewById(com.android.internal.R.id.overlay);
         mAppOps = findViewById(com.android.internal.R.id.app_ops);
+        mAudiblyAlertedIcon = findViewById(com.android.internal.R.id.alerted_icon);
     }
 
     @Override
@@ -216,6 +218,11 @@
                 layoutRight = end - paddingEnd;
                 end = layoutLeft = layoutRight - child.getMeasuredWidth();
             }
+            if (child == mAudiblyAlertedIcon) {
+                int paddingEnd = mContentEndMargin;
+                layoutRight = end - paddingEnd;
+                end = layoutLeft = layoutRight - child.getMeasuredWidth();
+            }
             if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
                 int ltrLeft = layoutLeft;
                 layoutLeft = getWidth() - layoutRight;
@@ -337,6 +344,11 @@
                 ? View.VISIBLE : View.GONE);
     }
 
+    /** Updates icon visibility based on the noisiness of the notification. */
+    public void setAudiblyAlerted(boolean audiblyAlerted) {
+        mAudiblyAlertedIcon.setVisibility(audiblyAlerted ? View.VISIBLE : View.GONE);
+    }
+
     private void updateExpandButton() {
         int drawableId;
         int contentDescriptionId;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index a7d0cfb..88b9c80 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -21,6 +21,7 @@
 import android.Manifest;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -54,6 +55,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IntPair;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -117,6 +120,39 @@
     public static final String ACTION_CHOOSE_ACCESSIBILITY_BUTTON =
             "com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON";
 
+    /**
+     * Annotations for content flag of UI.
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "FLAG_CONTENT_" }, value = {
+            FLAG_CONTENT_ICONS,
+            FLAG_CONTENT_TEXT,
+            FLAG_CONTENT_CONTROLS
+    })
+    public @interface ContentFlag {}
+
+    /**
+     * Use this flag to indicate the content of a UI that times out contains icons.
+     *
+     * @see #getRecommendedTimeoutMillis(int, int)
+     */
+    public static final int FLAG_CONTENT_ICONS = 1;
+
+    /**
+     * Use this flag to indicate the content of a UI that times out contains text.
+     *
+     * @see #getRecommendedTimeoutMillis(int, int)
+     */
+    public static final int FLAG_CONTENT_TEXT = 2;
+
+    /**
+     * Use this flag to indicate the content of a UI that times out contains interactive controls.
+     *
+     * @see #getRecommendedTimeoutMillis(int, int)
+     */
+    public static final int FLAG_CONTENT_CONTROLS = 4;
+
     @UnsupportedAppUsage
     static final Object sInstanceSync = new Object();
 
@@ -142,7 +178,8 @@
 
     int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
 
-    int mMinimumUiTimeout;
+    int mInteractiveUiTimeout;
+    int mNonInteractiveUiTimeout;
 
     boolean mIsTouchExplorationEnabled;
 
@@ -304,7 +341,9 @@
         }
 
         @Override
-        public void notifyServicesStateChanged() {
+        public void notifyServicesStateChanged(long updatedUiTimeout) {
+            updateUiTimeout(updatedUiTimeout);
+
             final ArrayMap<AccessibilityServicesStateChangeListener, Handler> listeners;
             synchronized (mLock) {
                 if (mServicesStateChangeListeners.isEmpty()) {
@@ -326,11 +365,6 @@
         public void setRelevantEventTypes(int eventTypes) {
             mRelevantEventTypes = eventTypes;
         }
-
-        @Override
-        public void setMinimumUiTimeout(int uiTimeout) {
-            mMinimumUiTimeout = uiTimeout;
-        }
     };
 
     /**
@@ -840,16 +874,35 @@
     }
 
     /**
-     * Get the minimum timeout for changes to the UI needed by this user. Controls should remain
+     * Get the recommended timeout for changes to the UI needed by this user. Controls should remain
      * on the screen for at least this long to give users time to react. Some users may need
      * extra time to review the controls, or to reach them, or to activate assistive technology
      * to activate the controls automatically.
+     * <p>
+     * Use the combination of content flags to indicate contents of UI. For example, use
+     * {@code FLAG_CONTENT_ICONS | FLAG_CONTENT_TEXT} for message notification which contains
+     * icons and text, or use {@code FLAG_CONTENT_TEXT | FLAG_CONTENT_CONTROLS} for button dialog
+     * which contains text and button controls.
+     * <p/>
      *
-     * @return The minimum ui timeout for the current user in milliseconds.
-     * {@link Integer#MAX_VALUE} if timeout is infinite.
+     * @param originalTimeout The timeout appropriate for users with no accessibility needs.
+     * @param uiContentFlags The combination of flags {@link #FLAG_CONTENT_ICONS},
+     *                       {@link #FLAG_CONTENT_TEXT} or {@link #FLAG_CONTENT_CONTROLS} to
+     *                       indicate the contents of UI.
+     * @return The recommended UI timeout for the current user in milliseconds.
      */
-    public int getMinimumUiTimeoutMillis() {
-        return mMinimumUiTimeout;
+    public int getRecommendedTimeoutMillis(int originalTimeout, @ContentFlag int uiContentFlags) {
+        boolean hasControls = (uiContentFlags & FLAG_CONTENT_CONTROLS) != 0;
+        boolean hasIconsOrText = (uiContentFlags & FLAG_CONTENT_ICONS) != 0
+                || (uiContentFlags & FLAG_CONTENT_TEXT) != 0;
+        int recommendedTimeout = originalTimeout;
+        if (hasControls) {
+            recommendedTimeout = Math.max(recommendedTimeout, mInteractiveUiTimeout);
+        }
+        if (hasIconsOrText) {
+            recommendedTimeout = Math.max(recommendedTimeout, mNonInteractiveUiTimeout);
+        }
+        return recommendedTimeout;
     }
 
     /**
@@ -1192,7 +1245,7 @@
             final long userStateAndRelevantEvents = service.addClient(mClient, mUserId);
             setStateLocked(IntPair.first(userStateAndRelevantEvents));
             mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
-            mMinimumUiTimeout = service.getMinimumUiTimeout();
+            updateUiTimeout(service.getRecommendedTimeoutMillis());
             mService = service;
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
@@ -1266,6 +1319,17 @@
     }
 
     /**
+     * Update interactive and non-interactive UI timeout.
+     *
+     * @param uiTimeout A pair of {@code int}s. First integer for interactive one, and second
+     *                  integer for non-interactive one.
+     */
+    private void updateUiTimeout(long uiTimeout) {
+        mInteractiveUiTimeout = IntPair.first(uiTimeout);
+        mNonInteractiveUiTimeout = IntPair.second(uiTimeout);
+    }
+
+    /**
      * Determines if the accessibility button within the system navigation area is supported.
      *
      * @return {@code true} if the accessibility button is supported on this device,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 61a8a1da..2767a82 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -76,5 +76,5 @@
     // System process only
     boolean sendFingerprintGesture(int gestureKeyCode);
 
-    int getMinimumUiTimeout();
+    long getRecommendedTimeoutMillis();
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index d2ddca3..94b9ad1 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -26,9 +26,7 @@
 
     void setState(int stateFlags);
 
-    void notifyServicesStateChanged();
+    void notifyServicesStateChanged(long updatedUiTimeout);
 
     void setRelevantEventTypes(int eventTypes);
-
-    void setMinimumUiTimeout(int uiTimeout);
 }
diff --git a/core/java/android/view/inspector/InspectableChildren.java b/core/java/android/view/inspector/InspectableChildren.java
new file mode 100644
index 0000000..de8fa29
--- /dev/null
+++ b/core/java/android/view/inspector/InspectableChildren.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 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.view.inspector;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a getter for an inspectable node's inspectable children.
+ *
+ * This annotation can be applied to any getter that returns a collection of objects, either an
+ * array, an {@link Iterable} or a {@link java.util.Iterator}. The getter may return null, which
+ * will be treated as an empty collection. Additionally, the inspector will discard any null
+ * entries in the collection.
+ *
+ * By default, this annotation is inherited. At runtime, the inspector introspects on the class
+ * hierachy and uses the annotated getter from the bottommost class, if different from any
+ * annoated getters of the parent class. If a class inherits from a parent class with an annotated
+ * getter, but does not include this annotation, the child class will be traversed using the
+ * getter annotated on the parent. This holds true even if the child class overrides the getter.
+ *
+ * @see InspectionHelper#traverseChildren(Object, ChildTraverser)
+ * @see InspectionHelper#hasChildTraversal()
+ * @hide
+ */
+@Target({METHOD})
+@Retention(SOURCE)
+public @interface InspectableChildren {
+}
diff --git a/core/java/android/view/inspector/InspectableNodeName.java b/core/java/android/view/inspector/InspectableNodeName.java
new file mode 100644
index 0000000..716409c
--- /dev/null
+++ b/core/java/android/view/inspector/InspectableNodeName.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 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.view.inspector;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Marks the node name to display to a developer in the inspection tree.
+ *
+ * This annotation is optional to marking a class as inspectable. If it is omitted, the node name
+ * will be inferred using the semantics of {@link Class#getSimpleName()}. The fully qualified class
+ * name is always available in the tree, this is for display purposes only. If a class is inflated
+ * from XML and the tag it inflates from does not match its simple name, this annotation should be
+ * used to inform the inspector to display the XML tag name in the inspection tree view.
+ *
+ * This annotation does not inherit. If a class extends an annotated parent class, but does not
+ * annotate itself, its node name will be inferred from its Java name.
+ *
+ * @see InspectionHelper#getNodeName()
+ * @hide
+ */
+@Target({TYPE})
+@Retention(SOURCE)
+public @interface InspectableNodeName {
+    /**
+     * The display name for nodes of this type.
+     *
+     * @return The name for nodes of this type
+     */
+    String value();
+}
diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java
new file mode 100644
index 0000000..b0fd503
--- /dev/null
+++ b/core/java/android/view/inspector/InspectableProperty.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.view.inspector;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a getter of a property on an inspectable node.
+ *
+ * This annotation is inherited by default. If a child class doesn't add it to a getter, but a
+ * parent class does, the property will be inspected, even if the child overrides the definition
+ * of the getter. If a child class defines a property of the same name of a property on the parent
+ * but on a different getter, the inspector will use the child's getter when inspecting instances
+ * of the child, and the parent's otherwise.
+ *
+ * @see InspectionHelper#mapProperties(PropertyMapper)
+ * @see InspectionHelper#readProperties(Object, PropertyReader)
+ * @hide
+ */
+@Target({METHOD})
+@Retention(SOURCE)
+public @interface InspectableProperty {
+    /**
+     * The name of the property.
+     *
+     * If left empty (the default), the property name will be inferred from the name of the getter
+     * method.
+     *
+     * @return The name of the property.
+     */
+    String value() default "";
+}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f96f088..5b1544b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3928,6 +3928,7 @@
                 SelectionModifierCursorController selectionController = getSelectionController();
                 if (selectionController.mStartHandle == null) {
                     // As these are for initializing selectionController, hide() must be called.
+                    loadHandleDrawables(false /* overwrite */);
                     selectionController.initHandles();
                     selectionController.hide();
                 }
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 5433393..3a908dc 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -64,5 +64,8 @@
 
     // OPEN: Biometric Enrollment (android.settings.BIOMETRIC_ENROLL action intent)
     BIOMETRIC_ENROLL_ACTIVITY = 1586;
+
+    // OPEN: Settings > Privacy
+    TOP_LEVEL_PRIVACY = 1587;
 }
 
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 3ead633..f8acc33 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -72,8 +72,10 @@
         // List of the accessibility services to which the user has granted
         // permission to put the device into touch exploration mode.
         optional SettingProto touch_exploration_granted_accessibility_services = 31;
-        optional SettingProto minimum_ui_timeout_enabled = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
-        optional SettingProto minimum_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        reserved 32; // minimum_ui_timeout_enabled
+        reserved 33; // minimum_ui_timeout_ms
+        optional SettingProto non_interactive_ui_timeout_ms = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto interactive_ui_timeout_ms = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     }
     optional Accessibility accessibility = 2;
diff --git a/core/res/res/drawable/ic_notifications_alerted.xml b/core/res/res/drawable/ic_notifications_alerted.xml
new file mode 100644
index 0000000..4bfac37
--- /dev/null
+++ b/core/res/res/drawable/ic_notifications_alerted.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2018 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M7.58 4.08L6.15 2.65C3.75 4.48 2.17 7.3 2.03 10.5h2c.15-2.65 1.51-4.97 3.55-6.42zm12.39 6.42h2c-.15-3.2-1.73-6.02-4.12-7.85l-1.42 1.43c2.02 1.45 3.39 3.77 3.54 6.42zM18 11c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2v-5zm-6 11c.14 0 .27-.01.4-.04.65-.14 1.18-.58 1.44-1.18.1-.24.15-.5.15-.78h-4c.01 1.1.9 2 2.01 2z"
+        android:fillColor="#FF000000" />
+</vector>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 8b1f28b..4ee9731 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -126,6 +126,19 @@
         android:visibility="gone"
         android:contentDescription="@string/notification_work_profile_content_description"
         />
+    <ImageView
+        android:id="@+id/alerted_icon"
+        android:layout_width="@dimen/notification_alerted_size"
+        android:layout_height="@dimen/notification_alerted_size"
+        android:layout_gravity="center"
+        android:layout_marginStart="4dp"
+        android:paddingTop="1dp"
+        android:scaleType="fitCenter"
+        android:visibility="gone"
+        android:contentDescription="@string/notification_alerted_content_description"
+        android:src="@drawable/ic_notifications_alerted"
+        android:tint="@color/notification_secondary_text_color_light"
+        />
     <LinearLayout
         android:id="@+id/app_ops"
         android:layout_height="match_parent"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a25c998..68ec342 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3587,11 +3587,22 @@
              {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
              android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
         <attr name="notificationTimeout" format="integer" />
-        <!-- The minimum timeout in milliseconds that UI controls need to remain on the screen.
+        <!-- A recommended timeout in milliseconds used in
+             {@link android.view.accessibility.AccessibilityManager#getRecommendedTimeoutMillis(int, int)
+             android.view.accessibility.AccessibilityManager.getRecommendedTimeoutMillis(int, int)}
+             to return a suitable value for UIs that do not include interactive controls.
              This setting can be changed at runtime by calling
              {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
              android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
-        <attr name="minimumUiTimeout" format="integer" />
+        <attr name="nonInteractiveUiTimeout" format="integer" />
+        <!-- A recommended timeout in milliseconds used in
+             {@link android.view.accessibility.AccessibilityManager#getRecommendedTimeoutMillis(int, int)
+             android.view.accessibility.AccessibilityManager.getRecommendedTimeoutMillis(int, int)}
+             to return a suitable value for interactive controls.
+             This setting can be changed at runtime by calling
+             {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
+             android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
+        <attr name="interactiveUiTimeout" format="integer" />
         <!-- Additional flags as specified in
              {@link android.accessibilityservice.AccessibilityServiceInfo}.
              This setting can be changed at runtime by calling
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a8c78a6..bca72f4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2793,7 +2793,7 @@
         <item>LPP_PROFILE=0</item>
         <item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
         <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
-        <item>GPS_LOCK=0</item>
+        <item>GPS_LOCK=3</item>
     </string-array>
 
     <!-- Sprint need a 70 ms delay for 3way call -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index ba483fb..b65c0fd 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -426,6 +426,9 @@
     <!-- Size of the profile badge for notifications -->
     <dimen name="notification_badge_size">12dp</dimen>
 
+    <!-- Size of the alerted icon for notifications -->
+    <dimen name="notification_alerted_size">18dp</dimen>
+
     <!-- Keyguard dimensions -->
     <!-- TEMP -->
     <dimen name="kg_security_panel_height">600dp</dimen>
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index a0c02ed..c1ca33e 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -44,9 +44,10 @@
     <dimen name="car_headline3_size">24sp</dimen>
     <dimen name="car_headline4_size">20sp</dimen>
     <dimen name="car_body1_size">32sp</dimen>
-    <dimen name="car_body2_size">26sp</dimen>
-    <dimen name="car_body3_size">16sp</dimen>
-    <dimen name="car_body4_size">14sp</dimen>
+    <dimen name="car_body2_size">28sp</dimen>
+    <dimen name="car_body3_size">26sp</dimen>
+    <dimen name="car_body4_size">24sp</dimen>
+    <!-- car_body5_size is deprecated -->
     <dimen name="car_body5_size">18sp</dimen>
     <dimen name="car_label1_size">26sp</dimen>
     <dimen name="car_label2_size">64sp</dimen>
@@ -85,6 +86,7 @@
     <dimen name="car_borderless_button_horizontal_padding">0dp</dimen>
     <dimen name="car_button_radius">@dimen/car_radius_1</dimen>
     <dimen name="car_pill_button_size">56dp</dimen>
+    <dimen name="car_touch_target_size">76dp</dimen>
 
     <!-- Seekbar -->
     <dimen name="car_seekbar_height">6dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e1c5df3..15f29ce 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2912,12 +2912,13 @@
         <public name="supportsAmbientMode" />
         <!-- @hide For use by platform and tools only. Developers should not specify this value. -->
         <public name="usesNonSdkApi" />
-        <public name="minimumUiTimeout" />
+        <public name="nonInteractiveUiTimeout" />
         <public name="isLightTheme" />
         <public name="isSplitRequired" />
         <public name="textLocale" />
         <public name="settingsSliceUri" />
         <public name="shell" />
+        <public name="interactiveUiTimeout" />
     </public-group>
 
     <public-group type="drawable" first-id="0x010800b4">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8b7cafb..8d3992d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4820,6 +4820,9 @@
     <!-- Content description of the work profile icon in the notification. -->
     <string name="notification_work_profile_content_description">Work profile</string>
 
+    <!-- Content description of the alerting icon in the notification. [CHAR_LIMIT=NONE] -->
+    <string name="notification_alerted_content_description">Alerted</string>
+
     <!-- Content description of the expand button icon in the notification when collaped.-->
     <string name="expand_button_content_description_collapsed">Expand</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 670a4a2..5418e03 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -215,6 +215,7 @@
   <java-symbol type="id" name="pin_error_message" />
   <java-symbol type="id" name="timePickerLayout" />
   <java-symbol type="id" name="profile_badge" />
+  <java-symbol type="id" name="alerted_icon" />
   <java-symbol type="id" name="transitionPosition" />
   <java-symbol type="id" name="selection_start_handle" />
   <java-symbol type="id" name="selection_end_handle" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index d5dc903..3342266 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -497,6 +497,7 @@
                     Settings.Global.WIFI_NUM_OPEN_NETWORKS_KEPT,
                     Settings.Global.WIFI_ON,
                     Settings.Global.WIFI_P2P_DEVICE_NAME,
+                    Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET,
                     Settings.Global.WIFI_REENABLE_DELAY_MS,
                     Settings.Global.WIFI_RTT_BACKGROUND_EXEC_GAP_MS,
                     Settings.Global.WIFI_SAVED_STATE,
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 18b41fa..3c44916 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -149,9 +149,13 @@
     }
 
     /**
-     * Returns the alpha value of this drawable's color.
+     * Returns the alpha value of this drawable's color. Note this may not be the same alpha value
+     * provided in {@link Drawable#setAlpha(int)}. Instead this will return the alpha of the color
+     * combined with the alpha provided by setAlpha
      *
      * @return A value between 0 and 255.
+     *
+     * @see ColorDrawable#setAlpha(int)
      */
     @Override
     public int getAlpha() {
@@ -159,7 +163,9 @@
     }
 
     /**
-     * Sets the color's alpha value.
+     * Applies the given alpha to the underlying color. Note if the color already has
+     * an alpha applied to it, this will apply this alpha to the existing value instead of
+     * overwriting it.
      *
      * @param alpha The alpha value to set, between 0 and 255.
      */
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index e1f7263..caf610b 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -934,11 +934,13 @@
      * do account for the value of {@link #setAlpha}, but the general behavior is dependent
      * upon the implementation of the subclass.
      *
+     * @deprecated This method is no longer used in graphics optimizations
+     *
      * @return int The opacity class of the Drawable.
      *
      * @see android.graphics.PixelFormat
      */
-    public abstract @PixelFormat.Opacity int getOpacity();
+    @Deprecated public abstract @PixelFormat.Opacity int getOpacity();
 
     /**
      * Return the appropriate opacity value for two source opacities.  If
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index a028515..59abad4 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1709,13 +1709,13 @@
 
     struct resource_name
     {
-        const char16_t* package;
+        const char16_t* package = NULL;
         size_t packageLen;
-        const char16_t* type;
-        const char* type8;
+        const char16_t* type = NULL;
+        const char* type8 = NULL;
         size_t typeLen;
-        const char16_t* name;
-        const char* name8;
+        const char16_t* name = NULL;
+        const char* name8 = NULL;
         size_t nameLen;
     };
 
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index 9eb4a13..26d2896 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -94,15 +94,15 @@
             target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
 
   ResTable::resource_name res_name;
-  ASSERT_TRUE(target_table_.getResourceName(R::array::integerArray1, false, &res_name));
+  ASSERT_TRUE(target_table_.getResourceName(R::array::integerArray1, true, &res_name));
 
   ASSERT_TRUE(res_name.package != NULL);
   ASSERT_TRUE(res_name.type != NULL);
-  ASSERT_TRUE(res_name.name != NULL);
+  ASSERT_TRUE(res_name.name8 != NULL);
 
   EXPECT_EQ(String16("com.android.basic"), String16(res_name.package, res_name.packageLen));
   EXPECT_EQ(String16("array"), String16(res_name.type, res_name.typeLen));
-  EXPECT_EQ(String16("integerArray1"), String16(res_name.name, res_name.nameLen));
+  EXPECT_EQ(String8("integerArray1"), String8(res_name.name8, res_name.nameLen));
 }
 
 constexpr const uint32_t kNonOverlaidResourceId = 0x7fff0000u;
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 05dc340..c58bcb3 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -139,7 +139,7 @@
 
 uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
     uint32_t flags = paint->getFlags();
-    SkFontHinting hinting = (SkFontHinting)paint->getHinting();
+    unsigned hinting = static_cast<unsigned>(paint->getHinting());
     // select only flags that might affect text layout
     flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag |
               SkPaint::kSubpixelText_Flag | SkPaint::kEmbeddedBitmapText_Flag |
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 2b5dea1..47ab7fa 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -34,7 +34,6 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
-import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
 import android.view.Surface;
@@ -835,46 +834,29 @@
         return null;
     }
 
-    // Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
-    @GuardedBy("mRoutingChangeListeners")
-    private void enableNativeRoutingCallbacksLocked(boolean enabled) {
-        if (mRoutingChangeListeners.size() == 0) {
-            native_enableDeviceCallback(enabled);
-        }
-    }
-
-    // The list of AudioRouting.OnRoutingChangedListener interfaces added with
-    // addOnRoutingChangedListener by an app to receive (re)routing notifications.
-    @GuardedBy("mRoutingChangeListeners")
-    private ArrayMap<AudioRouting.OnRoutingChangedListener,
-            NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
-
     @Override
     public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
             Handler handler) {
-        synchronized (mRoutingChangeListeners) {
-            if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
-                enableNativeRoutingCallbacksLocked(true);
-                mRoutingChangeListeners.put(
-                        listener, new NativeRoutingEventHandlerDelegate(this, listener,
-                                handler != null ? handler : mTaskHandler));
-            }
+        if (listener == null) {
+            throw new IllegalArgumentException("addOnRoutingChangedListener: listener is NULL");
         }
+        RoutingDelegate routingDelegate = new RoutingDelegate(this, listener, handler);
+        native_addDeviceCallback(routingDelegate);
     }
 
     @Override
     public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
-        synchronized (mRoutingChangeListeners) {
-            if (mRoutingChangeListeners.containsKey(listener)) {
-                mRoutingChangeListeners.remove(listener);
-                enableNativeRoutingCallbacksLocked(false);
-            }
+        if (listener == null) {
+            throw new IllegalArgumentException("removeOnRoutingChangedListener: listener is NULL");
         }
+        native_removeDeviceCallback(listener);
     }
 
     private native final boolean native_setOutputDevice(int deviceId);
     private native final int native_getRoutedDeviceId();
-    private native final void native_enableDeviceCallback(boolean enabled);
+    private native void native_addDeviceCallback(RoutingDelegate rd);
+    private native void native_removeDeviceCallback(
+            AudioRouting.OnRoutingChangedListener listener);
 
     @Override
     public Object setWakeMode(Context context, int mode) {
@@ -1614,7 +1596,6 @@
     private static final int MEDIA_SUBTITLE_DATA = 201;
     private static final int MEDIA_META_DATA = 202;
     private static final int MEDIA_DRM_INFO = 210;
-    private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
 
     private class TaskHandler extends Handler {
         private MediaPlayer2Impl mMediaPlayer;
@@ -1946,18 +1927,6 @@
                     break;
                 }
 
-                case MEDIA_AUDIO_ROUTING_CHANGED:
-                {
-                    AudioManager.resetAudioPortGeneration();
-                    synchronized (mRoutingChangeListeners) {
-                        for (NativeRoutingEventHandlerDelegate delegate
-                                : mRoutingChangeListeners.values()) {
-                            delegate.notifyClient();
-                        }
-                    }
-                    return;
-                }
-
                 default:
                 {
                     Log.e(TAG, "Unknown message type " + msg.what);
diff --git a/media/java/android/media/RoutingDelegate.java b/media/java/android/media/RoutingDelegate.java
new file mode 100644
index 0000000..2359813
--- /dev/null
+++ b/media/java/android/media/RoutingDelegate.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.os.Handler;
+
+class RoutingDelegate implements AudioRouting.OnRoutingChangedListener {
+    private AudioRouting mAudioRouting;
+    private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
+    private Handler mHandler;
+
+    RoutingDelegate(final AudioRouting audioRouting,
+                    final AudioRouting.OnRoutingChangedListener listener,
+                    Handler handler) {
+        mAudioRouting = audioRouting;
+        mOnRoutingChangedListener = listener;
+        mHandler = handler;
+    }
+
+    public AudioRouting.OnRoutingChangedListener getListener() {
+        return mOnRoutingChangedListener;
+    }
+
+    public Handler getHandler() {
+        return mHandler;
+    }
+
+    @Override
+    public void onRoutingChanged(AudioRouting router) {
+        if (mOnRoutingChangedListener != null) {
+            mOnRoutingChangedListener.onRoutingChanged(mAudioRouting);
+        }
+    }
+}
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index aa9e3d2..67005be 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -1324,15 +1324,30 @@
     return mp->getRoutedDeviceId();
 }
 
-static void android_media_MediaPlayer2_enableDeviceCallback(
-        JNIEnv* env, jobject thiz, jboolean enabled)
+static void android_media_MediaPlayer2_addDeviceCallback(
+        JNIEnv* env, jobject thiz, jobject routingDelegate)
 {
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
     if (mp == NULL) {
         return;
     }
 
-    status_t status = mp->enableAudioDeviceCallback(enabled);
+    status_t status = mp->addAudioDeviceCallback(routingDelegate);
+    if (status != NO_ERROR) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        ALOGE("enable device callback failed: %d", status);
+    }
+}
+
+static void android_media_MediaPlayer2_removeDeviceCallback(
+        JNIEnv* env, jobject thiz, jobject listener)
+{
+    sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL) {
+        return;
+    }
+
+    status_t status = mp->removeAudioDeviceCallback(listener);
     if (status != NO_ERROR) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         ALOGE("enable device callback failed: %d", status);
@@ -1457,7 +1472,9 @@
     // AudioRouting
     {"native_setOutputDevice", "(I)Z",                          (void *)android_media_MediaPlayer2_setOutputDevice},
     {"native_getRoutedDeviceId", "()I",                         (void *)android_media_MediaPlayer2_getRoutedDeviceId},
-    {"native_enableDeviceCallback", "(Z)V",                     (void *)android_media_MediaPlayer2_enableDeviceCallback},
+    {"native_addDeviceCallback", "(Landroid/media/RoutingDelegate;)V", (void *)android_media_MediaPlayer2_addDeviceCallback},
+    {"native_removeDeviceCallback", "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V",
+            (void *)android_media_MediaPlayer2_removeDeviceCallback},
 
     // StreamEventCallback for JAudioTrack
     {"native_stream_event_onTearDown",                "(JJ)V",  (void *)android_media_MediaPlayer2_native_on_tear_down},
diff --git a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
index 8fee822..6f437bd5 100644
--- a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
+++ b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
@@ -15,6 +15,7 @@
  */
 package android.ext.services.notification;
 
+import static android.app.Notification.CATEGORY_MESSAGE;
 import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
@@ -148,6 +149,18 @@
         return Objects.equals(getNotification().category, category);
     }
 
+    /**
+     * Similar to {@link #isCategory(String)}, but checking the public version of the notification,
+     * if available.
+     */
+    public boolean isPublicVersionCategory(String category) {
+        Notification publicVersion = getNotification().publicVersion;
+        if (publicVersion == null) {
+            return false;
+        }
+        return Objects.equals(publicVersion.category, category);
+    }
+
     public boolean isAudioAttributesUsage(int usage) {
         return mAttributes != null && mAttributes.getUsage() == usage;
     }
@@ -175,9 +188,9 @@
     }
 
     protected boolean isMessaging() {
-        return isCategory(Notification.CATEGORY_MESSAGE)
-                || hasStyle(Notification.MessagingStyle.class)
-                || hasInlineReply();
+        return isCategory(CATEGORY_MESSAGE)
+                || isPublicVersionCategory(CATEGORY_MESSAGE)
+                || hasStyle(Notification.MessagingStyle.class);
     }
 
     public boolean hasInlineReply() {
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index 37a98fd..b2fc417 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -19,23 +19,22 @@
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.RemoteAction;
-import android.app.RemoteInput;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.Process;
-import android.os.SystemProperties;
-import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.view.textclassifier.ConversationActions;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextLinks;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
 
 public class SmartActionsHelper {
     private static final ArrayList<Notification.Action> EMPTY_ACTION_LIST = new ArrayList<>();
@@ -50,12 +49,18 @@
     private static final int MAX_ACTION_EXTRACTION_TEXT_LENGTH = 400;
     private static final int MAX_ACTIONS_PER_LINK = 1;
     private static final int MAX_SMART_ACTIONS = Notification.MAX_ACTION_BUTTONS;
-    // Allow us to test out smart reply with dumb suggestions, it is disabled by default.
-    // TODO: Removed this once we have the model.
-    private static final String SYS_PROP_SMART_REPLIES_EXPERIMENT =
-            "persist.sys.smart_replies_experiment";
+    private static final int MAX_SUGGESTED_REPLIES = 3;
 
-    SmartActionsHelper() {}
+    private static final ConversationActions.TypeConfig TYPE_CONFIG =
+            new ConversationActions.TypeConfig.Builder().setIncludedTypes(
+                    Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+                    .includeTypesFromTextClassifier(false)
+                    .build();
+    private static final List<String> HINTS =
+            Collections.singletonList(ConversationActions.HINT_FOR_NOTIFICATION);
+
+    SmartActionsHelper() {
+    }
 
     /**
      * Adds action adjustments based on the notification contents.
@@ -92,8 +97,31 @@
         if (context == null) {
             return EMPTY_REPLY_LIST;
         }
-        // TODO: replaced this with our model when it is ready.
-        return new ArrayList<>(Arrays.asList("Yes, please", "No, thanks"));
+        TextClassificationManager tcm = context.getSystemService(TextClassificationManager.class);
+        if (tcm == null) {
+            return EMPTY_REPLY_LIST;
+        }
+        CharSequence text = getMostSalientActionText(entry.getNotification());
+        ConversationActions.Message message =
+                new ConversationActions.Message.Builder()
+                        .setText(text)
+                        .build();
+
+        ConversationActions.Request request =
+                new ConversationActions.Request.Builder(Collections.singletonList(message))
+                        .setMaxSuggestions(MAX_SUGGESTED_REPLIES)
+                        .setHints(HINTS)
+                        .setTypeConfig(TYPE_CONFIG)
+                        .build();
+
+        TextClassifier textClassifier = tcm.getTextClassifier();
+        List<ConversationActions.ConversationAction> conversationActions =
+                textClassifier.suggestConversationActions(request).getConversationActions();
+
+        return conversationActions.stream()
+                .map(conversationAction -> conversationAction.getTextReply())
+                .filter(textReply -> !TextUtils.isEmpty(textReply))
+                .collect(Collectors.toCollection(ArrayList::new));
     }
 
     /**
@@ -124,20 +152,30 @@
     }
 
     private boolean isEligibleForReplyAdjustment(@NonNull NotificationEntry entry) {
-        if (!SystemProperties.getBoolean(SYS_PROP_SMART_REPLIES_EXPERIMENT, false)) {
+        if (!Process.myUserHandle().equals(entry.getSbn().getUser())) {
             return false;
         }
-        Notification notification = entry.getNotification();
-        if (notification.actions == null) {
+        String pkg = entry.getSbn().getPackageName();
+        if (TextUtils.isEmpty(pkg) || pkg.equals("android")) {
             return false;
         }
-        return entry.hasInlineReply();
+        // For now, we are only interested in messages.
+        if (!entry.isMessaging()) {
+            return false;
+        }
+        // Does not make sense to provide suggested replies if it is not something that can be
+        // replied.
+        if (!entry.hasInlineReply()) {
+            return false;
+        }
+        return true;
     }
 
     /** Returns the text most salient for action extraction in a notification. */
     @Nullable
     private CharSequence getMostSalientActionText(@NonNull Notification notification) {
         /* If it's messaging style, use the most recent message. */
+        // TODO: Use the last few X messages instead and take the Person object into consideration.
         Parcelable[] messages = notification.extras.getParcelableArray(Notification.EXTRA_MESSAGES);
         if (messages != null && messages.length != 0) {
             Bundle lastMessage = (Bundle) messages[messages.length - 1];
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 508adbd..e2a34f4 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -21,35 +21,47 @@
     <!-- Toast message when Wi-Fi cannot scan for networks -->
     <string name="wifi_fail_to_scan">Can\'t scan for networks</string>
     <!-- Do not translate.  Concise terminology for wifi with WEP security -->
-    <string name="wifi_security_short_wep">WEP</string>
+    <string name="wifi_security_short_wep" translatable="false">WEP</string>
     <!-- Do not translate.  Concise terminology for wifi with WPA security -->
-    <string name="wifi_security_short_wpa">WPA</string>
+    <string name="wifi_security_short_wpa" translatable="false">WPA</string>
     <!-- Do not translate.  Concise terminology for wifi with WPA2 security -->
-    <string name="wifi_security_short_wpa2">WPA2</string>
+    <string name="wifi_security_short_wpa2" translatable="false">WPA2</string>
     <!-- Do not translate.  Concise terminology for wifi with both WPA/WPA2 security -->
-    <string name="wifi_security_short_wpa_wpa2">WPA/WPA2</string>
+    <string name="wifi_security_short_wpa_wpa2" translatable="false">WPA/WPA2</string>
     <!-- Do not translate.  Concise terminology for wifi with unknown PSK type -->
-    <string name="wifi_security_short_psk_generic">@string/wifi_security_short_wpa_wpa2</string>
+    <string name="wifi_security_short_psk_generic" translatable="false">@string/wifi_security_short_wpa_wpa2</string>
     <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP security -->
-    <string name="wifi_security_short_eap">802.1x</string>
+    <string name="wifi_security_short_eap" translatable="false">802.1x</string>
+    <!-- Do not translate.  Concise terminology for wifi with WPA3 security -->
+    <string name="wifi_security_short_sae" translatable="false">WPA3</string>
+    <!-- Do not translate.  Concise terminology for wifi with OWE security -->
+    <string name="wifi_security_short_owe" translatable="false">OWE</string>
+    <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP Suite-B security -->
+    <string name="wifi_security_short_eap_suiteb" translatable="false">Suite-B</string>
 
     <!-- Used in Wi-Fi settings dialogs when Wi-Fi does not have any security. -->
-    <string name="wifi_security_none">None</string>
+    <string name="wifi_security_none" translatable="false">None</string>
 
     <!-- Do not translate.  Terminology for wifi with WEP security -->
-    <string name="wifi_security_wep">WEP</string>
+    <string name="wifi_security_wep" translatable="false">WEP</string>
     <!-- Do not translate.  Terminology for wifi with WPA security -->
-    <string name="wifi_security_wpa">WPA PSK</string>
+    <string name="wifi_security_wpa" translatable="false">WPA-Personal</string>
     <!-- Do not translate.  Terminology for wifi with WPA2 security -->
-    <string name="wifi_security_wpa2">WPA2 PSK</string>
+    <string name="wifi_security_wpa2" translatable="false">WPA2-Personal</string>
     <!-- Do not translate.  Terminology for wifi with both WPA/WPA2 security, or unknown -->
-    <string name="wifi_security_wpa_wpa2">WPA/WPA2 PSK</string>
+    <string name="wifi_security_wpa_wpa2" translatable="false">WPA/WPA2-Personal</string>
     <!-- Do not translate.  Terminology for wifi with unknown PSK type -->
-    <string name="wifi_security_psk_generic">@string/wifi_security_wpa_wpa2</string>
+    <string name="wifi_security_psk_generic" translatable="false">@string/wifi_security_wpa_wpa2</string>
     <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP security -->
-    <string name="wifi_security_eap">802.1x EAP</string>
+    <string name="wifi_security_eap" translatable="false">WPA/WPA2-Enterprise</string>
     <!-- Do not translate.  Concise terminology for Passpoint network -->
-    <string name="wifi_security_passpoint">Passpoint</string>
+    <string name="wifi_security_passpoint" translatable="false">Passpoint</string>
+    <!-- Do not translate.  Terminology for wifi with WPA3 security -->
+    <string name="wifi_security_sae" translatable="false">WPA3-Personal</string>
+    <!-- Do not translate.  Terminology for wifi with OWE security -->
+    <string name="wifi_security_owe" translatable="false">Enhanced Open</string>
+    <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP Suite-B security -->
+    <string name="wifi_security_eap_suiteb" translatable="false">WPA3-Enterprise</string>
 
     <!-- Summary for the remembered network. -->
     <string name="wifi_remembered">Saved</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index dd8bfda..92fd868 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -51,6 +51,8 @@
     public static final String CATEGORY_GESTURES = "com.android.settings.category.ia.gestures";
     public static final String CATEGORY_NIGHT_DISPLAY =
             "com.android.settings.category.ia.night_display";
+    public static final String CATEGORY_PRIVACY =
+            "com.android.settings.category.ia.privacy";
 
     public static final Map<String, String> KEY_COMPAT_MAP;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index e950e8e..523361d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -158,9 +158,12 @@
      * These values are matched in string arrays -- changes must be kept in sync
      */
     public static final int SECURITY_NONE = 0;
-    public static final int SECURITY_WEP = 1;
-    public static final int SECURITY_PSK = 2;
-    public static final int SECURITY_EAP = 3;
+    public static final int SECURITY_OWE = 1;
+    public static final int SECURITY_WEP = 2;
+    public static final int SECURITY_PSK = 3;
+    public static final int SECURITY_SAE = 4;
+    public static final int SECURITY_EAP = 5;
+    public static final int SECURITY_EAP_SUITE_B = 6;
 
     private static final int PSK_UNKNOWN = 0;
     private static final int PSK_WPA = 1;
@@ -433,7 +436,7 @@
         if (isConnectable()) {
             builder.append(',').append("connectable");
         }
-        if (security != SECURITY_NONE) {
+        if ((security != SECURITY_NONE) && (security != SECURITY_OWE)) {
             builder.append(',').append(securityToString(security, pskType));
         }
         builder.append(",level=").append(getLevel());
@@ -720,6 +723,9 @@
             case SECURITY_EAP:
                 return concise ? context.getString(R.string.wifi_security_short_eap) :
                     context.getString(R.string.wifi_security_eap);
+            case SECURITY_EAP_SUITE_B:
+                return concise ? context.getString(R.string.wifi_security_short_eap_suiteb) :
+                        context.getString(R.string.wifi_security_eap_suiteb);
             case SECURITY_PSK:
                 switch (pskType) {
                     case PSK_WPA:
@@ -739,6 +745,12 @@
             case SECURITY_WEP:
                 return concise ? context.getString(R.string.wifi_security_short_wep) :
                     context.getString(R.string.wifi_security_wep);
+            case SECURITY_SAE:
+                return concise ? context.getString(R.string.wifi_security_short_sae) :
+                    context.getString(R.string.wifi_security_sae);
+            case SECURITY_OWE:
+                return concise ? context.getString(R.string.wifi_security_short_owe) :
+                    context.getString(R.string.wifi_security_owe);
             case SECURITY_NONE:
             default:
                 return concise ? "" : context.getString(R.string.wifi_security_none);
@@ -980,13 +992,20 @@
      * Can only be called for unsecured networks.
      */
     public void generateOpenNetworkConfig() {
-        if (security != SECURITY_NONE)
+        if ((security != SECURITY_NONE) && (security != SECURITY_OWE)) {
             throw new IllegalStateException();
+        }
         if (mConfig != null)
             return;
         mConfig = new WifiConfiguration();
         mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
-        mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+
+        if (security == SECURITY_NONE) {
+            mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+        } else {
+            mConfig.allowedKeyManagement.set(KeyMgmt.OWE);
+            mConfig.requirePMF = true;
+        }
     }
 
     public void saveWifiState(Bundle savedState) {
@@ -1288,22 +1307,38 @@
     private static int getSecurity(ScanResult result) {
         if (result.capabilities.contains("WEP")) {
             return SECURITY_WEP;
+        } else if (result.capabilities.contains("SAE")) {
+            return SECURITY_SAE;
         } else if (result.capabilities.contains("PSK")) {
             return SECURITY_PSK;
+        } else if (result.capabilities.contains("EAP_SUITE_B_192")) {
+            return SECURITY_EAP_SUITE_B;
         } else if (result.capabilities.contains("EAP")) {
             return SECURITY_EAP;
+        } else if (result.capabilities.contains("OWE")) {
+            return SECURITY_OWE;
         }
+
         return SECURITY_NONE;
     }
 
     static int getSecurity(WifiConfiguration config) {
+        if (config.allowedKeyManagement.get(KeyMgmt.SAE)) {
+            return SECURITY_SAE;
+        }
         if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
             return SECURITY_PSK;
         }
+        if (config.allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+            return SECURITY_EAP_SUITE_B;
+        }
         if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
                 config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
             return SECURITY_EAP;
         }
+        if (config.allowedKeyManagement.get(KeyMgmt.OWE)) {
+            return SECURITY_OWE;
+        }
         return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
     }
 
@@ -1321,6 +1356,12 @@
             return "PSK";
         } else if (security == SECURITY_EAP) {
             return "EAP";
+        } else if (security == SECURITY_SAE) {
+            return "SAE";
+        } else if (security == SECURITY_EAP_SUITE_B) {
+            return "SUITE_B";
+        } else if (security == SECURITY_OWE) {
+            return "OWE";
         }
         return "NONE";
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index f3c43cc..db364a3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -200,7 +200,8 @@
         if (frictionImageView == null || mFrictionSld == null) {
             return;
         }
-        if (mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
+        if ((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
+                && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
             mFrictionSld.setState(STATE_SECURED);
         } else if (mAccessPoint.isMetered()) {
             mFrictionSld.setState(STATE_METERED);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index b46c288..ca0267c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1643,11 +1643,11 @@
                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
                 SecureSettingsProto.Accessibility.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
         dumpSetting(s, p,
-                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
-                SecureSettingsProto.Accessibility.MINIMUM_UI_TIMEOUT_ENABLED);
+                Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+                SecureSettingsProto.Accessibility.NON_INTERACTIVE_UI_TIMEOUT_MS);
         dumpSetting(s, p,
-                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
-                SecureSettingsProto.Accessibility.MINIMUM_UI_TIMEOUT_MS);
+                Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
+                SecureSettingsProto.Accessibility.INTERACTIVE_UI_TIMEOUT_MS);
         p.end(accessibilityToken);
 
         dumpSetting(s, p,
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index b4fc820..887ea59 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -13,11 +13,11 @@
  */
 package com.android.systemui.plugins;
 
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
 import android.graphics.Paint.Style;
 import android.view.View;
 
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
 /**
  * This plugin is used to replace main clock in keyguard.
  */
@@ -44,4 +44,9 @@
      * @param color A color value.
      */
     void setTextColor(int color);
+
+    /**
+     * Notifies that time tick alarm from doze service fired.
+     */
+    default void dozeTimeTick() { }
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingPlugin.java
new file mode 100644
index 0000000..dce02e1
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingPlugin.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 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.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Used to capture Falsing data (related to unlocking the screen).
+ *
+ * The intent is that the data can later be analyzed to validate the quality of the
+ * {@link com.android.systemui.classifier.FalsingManager}.
+ */
+@ProvidesInterface(action = FalsingPlugin.ACTION, version = FalsingPlugin.VERSION)
+public interface FalsingPlugin extends Plugin {
+    String ACTION = "com.android.systemui.action.FALSING_PLUGIN";
+    int VERSION = 1;
+
+    /**
+     * Called when there is data to be recorded.
+     *
+     * @param success Indicates whether the action is considered a success.
+     * @param data The raw data to be recorded for analysis.
+     */
+    void dataCollected(boolean success, byte[] data);
+}
diff --git a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
index d4dfdee..d041556 100644
--- a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
@@ -21,6 +21,6 @@
     <corners android:radius="1dp"
         android:topLeftRadius="@dimen/biometric_dialog_corner_size"
         android:topRightRadius="@dimen/biometric_dialog_corner_size"
-        android:bottomLeftRadius="0dp"
-        android:bottomRightRadius="0dp"/>
+        android:bottomLeftRadius="@dimen/biometric_dialog_corner_size"
+        android:bottomRightRadius="@dimen/biometric_dialog_corner_size"/>
 </shape>
diff --git a/packages/SystemUI/res/layout/biometric_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
index ec25e31..67c0adf 100644
--- a/packages/SystemUI/res/layout/biometric_dialog.xml
+++ b/packages/SystemUI/res/layout/biometric_dialog.xml
@@ -31,7 +31,8 @@
 
     <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="wrap_content">
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
 
         <!-- This is not a Space since Spaces cannot be clicked. The width of this changes depending
          on horizontal/portrait orientation -->
@@ -43,11 +44,13 @@
 
         <LinearLayout
             android:id="@+id/dialog"
-            android:layout_width="0dp"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="vertical"
-            android:elevation="2dp"
-            android:background="@drawable/biometric_dialog_bg">
+            android:background="@drawable/biometric_dialog_bg"
+            android:layout_marginBottom="@dimen/biometric_dialog_border_padding"
+            android:layout_marginLeft="@dimen/biometric_dialog_border_padding"
+            android:layout_marginRight="@dimen/biometric_dialog_border_padding">
 
             <TextView
                 android:id="@+id/title"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 525421a..3050e79 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -889,6 +889,7 @@
     <dimen name="biometric_dialog_biometric_icon_size">64dp</dimen>
     <dimen name="biometric_dialog_corner_size">4dp</dimen>
     <dimen name="biometric_dialog_animation_translation_offset">350dp</dimen>
+    <dimen name="biometric_dialog_border_padding">4dp</dimen>
 
     <!-- Wireless Charging Animation values -->
     <dimen name="wireless_charging_dots_radius_start">0dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 013745a..8881f8a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -143,6 +143,15 @@
     }
 
     /**
+     * Notifies that time tick alarm from doze service fired.
+     */
+    public void dozeTimeTick() {
+        if (mClockPlugin != null) {
+            mClockPlugin.dozeTimeTick();
+        }
+    }
+
+    /**
      * When plugin changes, set all kept parameters into newer plugin.
      */
     private void initPluginParams() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index a403b75..f701e22 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -47,7 +47,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
 
 import com.google.android.collect.Sets;
 
@@ -276,6 +275,7 @@
     public void dozeTimeTick() {
         refreshTime();
         mKeyguardSlice.refresh();
+        mClockView.dozeTimeTick();
     }
 
     private void refreshTime() {
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
index 4010c43..46e004c 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
@@ -35,6 +35,11 @@
 import android.view.MotionEvent;
 import android.widget.Toast;
 
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.FalsingPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.shared.plugins.PluginManager;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -75,6 +80,8 @@
 
     private static DataCollector sInstance = null;
 
+    private FalsingPlugin mFalsingPlugin = null;
+
     protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
         @Override
         public void onChange(boolean selfChange) {
@@ -82,6 +89,16 @@
         }
     };
 
+    private final PluginListener mPluginListener = new PluginListener<FalsingPlugin>() {
+        public void onPluginConnected(FalsingPlugin plugin, Context context) {
+            mFalsingPlugin = plugin;
+        }
+
+        public void onPluginDisconnected(FalsingPlugin plugin) {
+            mFalsingPlugin = null;
+        }
+    };
+
     private DataCollector(Context context) {
         mContext = context;
 
@@ -106,6 +123,8 @@
                 UserHandle.USER_ALL);
 
         updateConfiguration();
+
+        Dependency.get(PluginManager.class).addPluginListener(mPluginListener, FalsingPlugin.class);
     }
 
     public static DataCollector getInstance(Context context) {
@@ -191,24 +210,28 @@
             @Override
             public void run() {
                 byte[] b = Session.toByteArray(currentSession.toProto());
-                String dir = mContext.getFilesDir().getAbsolutePath();
-                if (currentSession.getResult() != Session.SUCCESS) {
-                    if (!mDisableUnlocking && !mCollectBadTouches) {
-                        return;
+
+                if (mFalsingPlugin != null) {
+                    mFalsingPlugin.dataCollected(currentSession.getResult() == Session.SUCCESS, b);
+                } else {
+                    String dir = mContext.getFilesDir().getAbsolutePath();
+                    if (currentSession.getResult() != Session.SUCCESS) {
+                        if (!mDisableUnlocking && !mCollectBadTouches) {
+                            return;
+                        }
+                        dir += "/bad_touches";
+                    } else if (!mDisableUnlocking) {
+                        dir += "/good_touches";
                     }
-                    dir += "/bad_touches";
-                } else if (!mDisableUnlocking) {
-                    dir += "/good_touches";
-                }
 
-                File file = new File(dir);
-                file.mkdir();
-                File touch = new File(file, "trace_" + System.currentTimeMillis());
-
-                try {
-                    new FileOutputStream(touch).write(b);
-                } catch (IOException e) {
-                    throw new RuntimeException(e);
+                    File file = new File(dir);
+                    file.mkdir();
+                    File touch = new File(file, "trace_" + System.currentTimeMillis());
+                    try {
+                        new FileOutputStream(touch).write(b);
+                    } catch (IOException e) {
+                        throw new RuntimeException(e);
+                    }
                 }
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index 7935115..1faae9d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -42,6 +42,7 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.util.leak.RotationUtils;
 
 /**
  * Abstract base class. Shows a dialog for BiometricPrompt.
@@ -199,7 +200,10 @@
         final Button negative = mLayout.findViewById(R.id.button2);
         final Button positive = mLayout.findViewById(R.id.button1);
 
-        mDialog.getLayoutParams().width = (int) mDialogWidth;
+        if (RotationUtils.getRotation(mContext) != RotationUtils.ROTATION_NONE) {
+            mDialog.getLayoutParams().width = (int) mDialogWidth;
+        }
+
         mLastState = STATE_NONE;
         updateState(STATE_AUTHENTICATING);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 8994568..bc662e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -15,7 +15,6 @@
 package com.android.systemui.statusbar;
 
 import android.content.pm.UserInfo;
-import android.os.SystemProperties;
 import android.service.notification.StatusBarNotification;
 import android.util.SparseArray;
 
@@ -26,8 +25,6 @@
     String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
             = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
 
-    boolean AUTO_DEMOTE_NOTIFICATIONS = SystemProperties.getBoolean("debug.demote_notifs", false);
-
     boolean shouldAllowLockscreenRemoteInput();
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 0108469..e3bc5b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -49,6 +49,7 @@
 import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
@@ -293,7 +294,7 @@
             return false;
         }
         boolean exceedsPriorityThreshold;
-        if (AUTO_DEMOTE_NOTIFICATIONS) {
+        if (NotificationUtils.useNewInterruptionModel(mContext)) {
             exceedsPriorityThreshold =
                     getEntryManager().getNotificationData().getImportance(sbn.getKey())
                             >= IMPORTANCE_DEFAULT;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 92765bb..7581d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -24,7 +24,6 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.Dependency;
-import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -380,6 +379,7 @@
             }
 
             row.showAppOpsIcons(entry.mActiveAppOps);
+            row.setAudiblyAlerted(entry.audiblyAlerted);
         }
 
         Trace.beginSection("NotificationPresenter#onUpdateRowStates");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index 3539fff..b84b77c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -51,13 +51,14 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.InitController;
 import com.android.systemui.statusbar.InflationTask;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -75,8 +76,6 @@
 import java.util.List;
 import java.util.Objects;
 
-import androidx.annotation.Nullable;
-
 /**
  * The list of currently displaying notifications.
  */
@@ -102,6 +101,7 @@
         public String key;
         public StatusBarNotification notification;
         public NotificationChannel channel;
+        public boolean audiblyAlerted;
         public StatusBarIconView icon;
         public StatusBarIconView expandedIcon;
         public ExpandableNotificationRow row; // the outer expanded view
@@ -154,6 +154,7 @@
 
         public void populateFromRanking(@NonNull Ranking ranking) {
             channel = ranking.getChannel();
+            audiblyAlerted = ranking.audiblyAlerted();
             snoozeCriteria = ranking.getSnoozeCriteria();
             userSentiment = ranking.getUserSentiment();
             smartActions = ranking.getSmartActions() == null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 66ba9e9..1f48c15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -16,8 +16,11 @@
 
 package com.android.systemui.statusbar.notification;
 
+import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
+
 import android.content.Context;
 import android.graphics.Color;
+import android.provider.Settings;
 import android.view.View;
 import android.widget.ImageView;
 
@@ -68,4 +71,10 @@
                 context.getResources().getDisplayMetrics().density);
         return (int) (dimensionPixelSize * factor);
     }
+
+    /** Returns the value of the new interruption model setting. */
+    public static boolean useNewInterruptionModel(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                NOTIFICATION_NEW_INTERRUPTION_MODEL, 0) != 0;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 965fb13..5166e06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -16,14 +16,22 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback;
+import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator
+        .ExpandAnimationParameters;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView
+        .VISIBLE_TYPE_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView
+        .VISIBLE_TYPE_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView
+        .VISIBLE_TYPE_HEADSUP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+        .FLAG_CONTENT_VIEW_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+        .FLAG_CONTENT_VIEW_HEADS_UP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+        .FLAG_CONTENT_VIEW_PUBLIC;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+        .InflationCallback;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -1658,6 +1666,17 @@
         mPublicLayout.showAppOpsIcons(activeOps);
     }
 
+    /** Sets whether the notification being displayed audibly alerted the user. */
+    public void setAudiblyAlerted(boolean audiblyAlerted) {
+        if (NotificationUtils.useNewInterruptionModel(mContext)) {
+            if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
+                mChildrenContainer.getHeaderView().setAudiblyAlerted(audiblyAlerted);
+            }
+            mPrivateLayout.setAudiblyAlerted(audiblyAlerted);
+            mPublicLayout.setAudiblyAlerted(audiblyAlerted);
+        }
+    }
+
     public View.OnClickListener getAppOpsOnClickListener() {
         return mOnAppOpsClickListener;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 11cf8e0..fa3fa5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1551,6 +1551,19 @@
         }
     }
 
+    /** Sets whether the notification being displayed audibly alerted the user. */
+    public void setAudiblyAlerted(boolean audiblyAlerted) {
+        if (mContractedChild != null && mContractedWrapper.getNotificationHeader() != null) {
+            mContractedWrapper.getNotificationHeader().setAudiblyAlerted(audiblyAlerted);
+        }
+        if (mExpandedChild != null && mExpandedWrapper.getNotificationHeader() != null) {
+            mExpandedWrapper.getNotificationHeader().setAudiblyAlerted(audiblyAlerted);
+        }
+        if (mHeadsUpChild != null && mHeadsUpWrapper.getNotificationHeader() != null) {
+            mHeadsUpWrapper.getNotificationHeader().setAudiblyAlerted(audiblyAlerted);
+        }
+    }
+
     public NotificationHeaderView getContractedNotificationHeader() {
         if (mContractedChild != null) {
             return mContractedWrapper.getNotificationHeader();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index 7e60c4b..674c8ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -16,17 +16,8 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import java.util.ArrayList;
-
 import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION;
 
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.AlphaOptimizedImageView;
-import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -45,6 +36,15 @@
 import android.widget.FrameLayout.LayoutParams;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
+import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+
+import java.util.ArrayList;
+import java.util.List;
 
 public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnClickListener,
         ExpandableNotificationRow.LayoutListener {
@@ -70,7 +70,8 @@
     private MenuItem mInfoItem;
     private MenuItem mAppOpsItem;
     private MenuItem mSnoozeItem;
-    private ArrayList<MenuItem> mMenuItems;
+    private ArrayList<MenuItem> mLeftMenuItems;
+    private ArrayList<MenuItem> mRightMenuItems;
     private OnMenuEventListener mMenuListener;
 
     private ValueAnimator mFadeAnimator;
@@ -107,12 +108,13 @@
         mContext = context;
         mShouldShowMenu = context.getResources().getBoolean(R.bool.config_showNotificationGear);
         mHandler = new Handler(Looper.getMainLooper());
-        mMenuItems = new ArrayList<>();
+        mLeftMenuItems = new ArrayList<>();
+        mRightMenuItems = new ArrayList<>();
     }
 
     @Override
     public ArrayList<MenuItem> getMenuItems(Context context) {
-        return mMenuItems;
+        return mOnLeft ? mLeftMenuItems : mRightMenuItems;
     }
 
     @Override
@@ -231,7 +233,8 @@
         final Resources res = mContext.getResources();
         mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
         mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
-        mMenuItems.clear();
+        mLeftMenuItems.clear();
+        mRightMenuItems.clear();
         // Construct the menu items based on the notification
         if (mParent != null && mParent.getStatusBarNotification() != null) {
             int flags = mParent.getStatusBarNotification().getNotification().flags;
@@ -239,24 +242,19 @@
             if (!isForeground) {
                 // Only show snooze for non-foreground notifications
                 mSnoozeItem = createSnoozeItem(mContext);
-                mMenuItems.add(mSnoozeItem);
+                mLeftMenuItems.add(mSnoozeItem);
+                mRightMenuItems.add(mSnoozeItem);
             }
         }
         mInfoItem = createInfoItem(mContext);
-        mMenuItems.add(mInfoItem);
+        mLeftMenuItems.add(mInfoItem);
+        mRightMenuItems.add(mInfoItem);
 
         mAppOpsItem = createAppOpsItem(mContext);
-        mMenuItems.add(mAppOpsItem);
+        mLeftMenuItems.add(mAppOpsItem);
+        mRightMenuItems.add(mAppOpsItem);
 
-        // Construct the menu views
-        if (mMenuContainer != null) {
-            mMenuContainer.removeAllViews();
-        } else {
-            mMenuContainer = new FrameLayout(mContext);
-        }
-        for (int i = 0; i < mMenuItems.size(); i++) {
-            addMenuView(mMenuItems.get(i), mMenuContainer);
-        }
+        populateMenuViews();
         if (resetState) {
             resetState(false /* notify */);
         } else {
@@ -268,6 +266,18 @@
         }
     }
 
+    private void populateMenuViews() {
+        if (mMenuContainer != null) {
+            mMenuContainer.removeAllViews();
+        } else {
+            mMenuContainer = new FrameLayout(mContext);
+        }
+        List<MenuItem> menuItems = mOnLeft ? mLeftMenuItems : mRightMenuItems;
+        for (int i = 0; i < menuItems.size(); i++) {
+            addMenuView(menuItems.get(i), mMenuContainer);
+        }
+    }
+
     private void resetState(boolean notify) {
         setMenuAlpha(0f);
         mIconsPlaced = false;
@@ -386,10 +396,16 @@
         if (appName == null) {
             return;
         }
+        setAppName(appName, mLeftMenuItems);
+        setAppName(appName, mRightMenuItems);
+    }
+
+    private void setAppName(String appName,
+            ArrayList<MenuItem> menuItems) {
         Resources res = mContext.getResources();
-        final int count = mMenuItems.size();
+        final int count = menuItems.size();
         for (int i = 0; i < count; i++) {
-            MenuItem item = mMenuItems.get(i);
+            MenuItem item = menuItems.get(i);
             String description = String.format(
                     res.getString(R.string.notification_menu_accessibility),
                     appName, item.getContentDescription());
@@ -402,7 +418,9 @@
 
     @Override
     public void onParentHeightUpdate() {
-        if (mParent == null || mMenuItems.size() == 0 || mMenuContainer == null) {
+        if (mParent == null
+                || (mLeftMenuItems.isEmpty() && mRightMenuItems.isEmpty())
+                || mMenuContainer == null) {
             return;
         }
         int parentHeight = mParent.getActualHeight();
@@ -443,13 +461,14 @@
         }
         v.getLocationOnScreen(mIconLocation);
         mParent.getLocationOnScreen(mParentLocation);
-        final int centerX = (int) (mHorizSpaceForIcon / 2);
+        final int centerX = mHorizSpaceForIcon / 2;
         final int centerY = v.getHeight() / 2;
         final int x = mIconLocation[0] - mParentLocation[0] + centerX;
         final int y = mIconLocation[1] - mParentLocation[1] + centerY;
         final int index = mMenuContainer.indexOfChild(v);
         if (mMenuListener != null) {
-            mMenuListener.onMenuClicked(mParent, x, y, mMenuItems.get(index));
+            mMenuListener.onMenuClicked(mParent, x, y,
+                    (mOnLeft ? mLeftMenuItems : mRightMenuItems).get(index));
         }
     }
 
@@ -469,6 +488,11 @@
             // Do nothing
             return;
         }
+        boolean wasOnLeft = mOnLeft;
+        mOnLeft = showOnLeft;
+        if (wasOnLeft != showOnLeft) {
+            populateMenuViews();
+        }
         final int count = mMenuContainer.getChildCount();
         for (int i = 0; i < count; i++) {
             final View v = mMenuContainer.getChildAt(i);
@@ -476,7 +500,6 @@
             final float right = mParent.getWidth() - (mHorizSpaceForIcon * (i + 1));
             v.setX(showOnLeft ? left : right);
         }
-        mOnLeft = showOnLeft;
         mIconsPlaced = true;
     }
 
@@ -603,6 +626,7 @@
     private void addMenuView(MenuItem item, ViewGroup parent) {
         View menuView = item.getMenuView();
         if (menuView != null) {
+            menuView.setAlpha(mAlpha);
             parent.addView(menuView);
             menuView.setOnClickListener(this);
             FrameLayout.LayoutParams lp = (LayoutParams) menuView.getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index f50e9a2..8e90f98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -20,7 +20,6 @@
 import com.android.internal.widget.ViewClippingUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.NotificationData;
@@ -50,7 +49,7 @@
         public void onTuningChanged(String key, String newValue) {
             if (key.equals(LOW_PRIORITY)) {
                 mShowLowPriority = "1".equals(newValue)
-                        || !NotificationLockscreenUserManager.AUTO_DEMOTE_NOTIFICATIONS;
+                        || !NotificationUtils.useNewInterruptionModel(mContext);
                 if (mNotificationScrollLayout != null) {
                     updateStatusBarIcons();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 3744105..9077b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -539,9 +539,9 @@
       if (value != volumeItem.progress) {
         volumeItem.listItem.setProgress(value);
         volumeItem.progress = value;
-        if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
-          show(Events.SHOW_REASON_VOLUME_CHANGED);
-        }
+      }
+      if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
+        show(Events.SHOW_REASON_VOLUME_CHANGED);
       }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
index 459dc5d..0251f64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
@@ -437,21 +437,23 @@
                         outRanking.getImportance(), outRanking.getImportanceExplanation(),
                         outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
                         outRanking.canShowBadge(), outRanking.getUserSentiment(), true,
-                        null, null);
+                        false, null, null);
             } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
                 outRanking.populate(key, outRanking.getRank(),
                         outRanking.matchesInterruptionFilter(),
                         outRanking.getVisibilityOverride(), 255,
                         outRanking.getImportance(), outRanking.getImportanceExplanation(),
                         outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
-                        outRanking.canShowBadge(), outRanking.getUserSentiment(), true, null, null);
+                        outRanking.canShowBadge(), outRanking.getUserSentiment(), true, false, null,
+                        null);
             } else {
                 outRanking.populate(key, outRanking.getRank(),
                         outRanking.matchesInterruptionFilter(),
                         outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
                         outRanking.getImportance(), outRanking.getImportanceExplanation(),
                         outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null,
-                        outRanking.canShowBadge(), outRanking.getUserSentiment(), false, null,
+                        outRanking.canShowBadge(), outRanking.getUserSentiment(), false, false,
+                        null,
                         null);
             }
             return true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index fb4ecd1..9c68e7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -19,7 +19,6 @@
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.assertFalse;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
@@ -168,7 +167,7 @@
                     0,
                     NotificationManager.IMPORTANCE_DEFAULT,
                     null, null,
-                    null, null, null, true, sentiment, false, null, null);
+                    null, null, null, true, sentiment, false, false, null, null);
             return true;
         }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
     }
@@ -186,7 +185,7 @@
                     NotificationManager.IMPORTANCE_DEFAULT,
                     null, null,
                     null, null, null, true,
-                    NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false,
+                    NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false, false,
                     smartActions, null);
             return true;
         }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index ddd0c2c..a947ea1 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -2832,7 +2832,7 @@
     // ACTION: Logs the end to end time taken by all provisioning tasks.
     PROVISIONING_TOTAL_TASK_TIME_MS = 627;
 
-    // OPEN: Settings > Privacy
+    // OPEN: Settings > Security
     // CATEGORY: SETTINGS
     // OS: O
     ENTERPRISE_PRIVACY_SETTINGS = 628;
@@ -6579,6 +6579,11 @@
     // OS: Q
     BIOMETRIC_ENROLL_ACTIVITY = 1586;
 
+    // OPEN: Settings > Privacy
+    // CATEGORY: SETTINGS
+    // OS: Q
+    TOP_LEVEL_PRIVACY = 1587;
+
     // ---- End Q Constants, all Q constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e89b951..5c189ce 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1672,22 +1672,23 @@
                 client -> client.setState(clientState)));
     }
 
-    private void scheduleNotifyClientsOfServicesStateChange(UserState userState) {
+    private void scheduleNotifyClientsOfServicesStateChangeLocked(UserState userState) {
+        updateRecommendedUiTimeoutLocked(userState);
         mMainHandler.sendMessage(obtainMessage(
                 AccessibilityManagerService::sendServicesStateChanged,
-                this, userState.mUserClients));
+                this, userState.mUserClients, getRecommendedTimeoutMillisLocked(userState)));
     }
 
     private void sendServicesStateChanged(
-            RemoteCallbackList<IAccessibilityManagerClient> userClients) {
-        notifyClientsOfServicesStateChange(mGlobalClients);
-        notifyClientsOfServicesStateChange(userClients);
+            RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout) {
+        notifyClientsOfServicesStateChange(mGlobalClients, uiTimeout);
+        notifyClientsOfServicesStateChange(userClients, uiTimeout);
     }
 
     private void notifyClientsOfServicesStateChange(
-            RemoteCallbackList<IAccessibilityManagerClient> clients) {
+            RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout) {
         clients.broadcast(ignoreRemoteException(
-                client -> client.notifyServicesStateChanged()));
+                client -> client.notifyServicesStateChanged(uiTimeout)));
     }
 
     private void scheduleUpdateInputFilter(UserState userState) {
@@ -1701,24 +1702,6 @@
                 this, userState));
     }
 
-    private void scheduleSetAllClientsMinimumUiTimeout(UserState userState) {
-        mMainHandler.sendMessage(obtainMessage(
-                AccessibilityManagerService::sendMinimumUiTimeoutChanged,
-                this, userState.mUserClients, userState.mMinimumUiTimeout));
-    }
-
-    private void sendMinimumUiTimeoutChanged(
-            RemoteCallbackList<IAccessibilityManagerClient> userClients, int uiTimeout) {
-        notifyClientsOfServicesMinimumUiTimeoutChange(mGlobalClients, uiTimeout);
-        notifyClientsOfServicesMinimumUiTimeoutChange(userClients, uiTimeout);
-    }
-
-    private void notifyClientsOfServicesMinimumUiTimeoutChange(
-            RemoteCallbackList<IAccessibilityManagerClient> clients, int uiTimeout) {
-        clients.broadcast(ignoreRemoteException(
-                client -> client.setMinimumUiTimeout(uiTimeout)));
-    }
-
     private void updateInputFilter(UserState userState) {
         if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) return;
 
@@ -1852,7 +1835,6 @@
         scheduleUpdateClientsIfNeededLocked(userState);
         updateRelevantEventsLocked(userState);
         updateAccessibilityButtonTargetsLocked(userState);
-        updateMinimumUiTimeoutLocked(userState);
     }
 
     private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
@@ -1971,7 +1953,7 @@
         somethingChanged |= readAutoclickEnabledSettingLocked(userState);
         somethingChanged |= readAccessibilityShortcutSettingLocked(userState);
         somethingChanged |= readAccessibilityButtonSettingsLocked(userState);
-        somethingChanged |= readUserMinimumUiTimeoutSettingsLocked(userState);
+        somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
         return somethingChanged;
     }
 
@@ -2083,7 +2065,7 @@
         }
 
         userState.mServiceToEnableWithShortcut = componentNameToEnable;
-        scheduleNotifyClientsOfServicesStateChange(userState);
+        scheduleNotifyClientsOfServicesStateChangeLocked(userState);
         return true;
     }
 
@@ -2118,17 +2100,20 @@
         return true;
     }
 
-    private boolean readUserMinimumUiTimeoutSettingsLocked(UserState userState) {
-        final boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, 0,
-                userState.mUserId) == 1;
-        final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, 0,
+    private boolean readUserRecommendedUiTimeoutSettingsLocked(UserState userState) {
+        final int nonInteractiveUiTimeout = Settings.Secure.getIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, 0,
                 userState.mUserId);
-        if (enabled != userState.mUserMinimumUiTimeoutEnabled
-                || timeout != userState.mUserMinimumUiTimeout) {
-            userState.mUserMinimumUiTimeoutEnabled = enabled;
-            userState.mUserMinimumUiTimeout = timeout;
+        final int interactiveUiTimeout = Settings.Secure.getIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, 0,
+                userState.mUserId);
+        if (nonInteractiveUiTimeout != userState.mUserNonInteractiveUiTimeout
+                || interactiveUiTimeout != userState.mUserInteractiveUiTimeout) {
+            userState.mUserNonInteractiveUiTimeout = nonInteractiveUiTimeout;
+            userState.mUserInteractiveUiTimeout = interactiveUiTimeout;
+            scheduleNotifyClientsOfServicesStateChangeLocked(userState);
             return true;
         }
         return false;
@@ -2300,25 +2285,33 @@
         }
     }
 
-    private void updateMinimumUiTimeoutLocked(UserState userState) {
-        int newUiTimeout = 0;
-        if (userState.mUserMinimumUiTimeoutEnabled) {
-            newUiTimeout = userState.mUserMinimumUiTimeout;
-        } else {
+    private void updateRecommendedUiTimeoutLocked(UserState userState) {
+        int newNonInteractiveUiTimeout = userState.mUserNonInteractiveUiTimeout;
+        int newInteractiveUiTimeout = userState.mUserInteractiveUiTimeout;
+        // read from a11y services if user does not specify value
+        if (newNonInteractiveUiTimeout == 0 || newInteractiveUiTimeout == 0) {
+            int serviceNonInteractiveUiTimeout = 0;
+            int serviceInteractiveUiTimeout = 0;
             final List<AccessibilityServiceConnection> services = userState.mBoundServices;
-            final int numServices = services.size();
-            for (int i = 0; i < numServices; i++) {
-                final int serviceUiTimeout = services.get(i).getServiceInfo()
-                        .getMinimumUiTimeoutMillis();
-                if (newUiTimeout < serviceUiTimeout) {
-                    newUiTimeout = serviceUiTimeout;
+            for (int i = 0; i < services.size(); i++) {
+                int timeout = services.get(i).getServiceInfo().getInteractiveUiTimeoutMillis();
+                if (serviceInteractiveUiTimeout < timeout) {
+                    serviceInteractiveUiTimeout = timeout;
+                }
+                timeout = services.get(i).getServiceInfo().getNonInteractiveUiTimeoutMillis();
+                if (serviceNonInteractiveUiTimeout < timeout) {
+                    serviceNonInteractiveUiTimeout = timeout;
                 }
             }
+            if (newNonInteractiveUiTimeout == 0) {
+                newNonInteractiveUiTimeout = serviceNonInteractiveUiTimeout;
+            }
+            if (newInteractiveUiTimeout == 0) {
+                newInteractiveUiTimeout = serviceInteractiveUiTimeout;
+            }
         }
-        if (newUiTimeout != userState.mMinimumUiTimeout) {
-            userState.mMinimumUiTimeout = newUiTimeout;
-            scheduleSetAllClientsMinimumUiTimeout(userState);
-        }
+        userState.mNonInteractiveUiTimeout = newNonInteractiveUiTimeout;
+        userState.mInteractiveUiTimeout = newInteractiveUiTimeout;
     }
 
     @GuardedBy("mLock")
@@ -2473,19 +2466,24 @@
     }
 
     /**
-     * Get the minimum timeout for changes to the UI needed by this user. Controls should remain
-     * on the screen for at least this long to give users time to react.
+     * Get the recommended timeout of interactive controls and non-interactive controls.
      *
-     * @return The minimum timeout for the current user in milliseconds.
+     * @return A long for pair of {@code int}s. First integer for interactive one, and second
+     * integer for non-interactive one.
      */
     @Override
-    public int getMinimumUiTimeout() {
+    public long getRecommendedTimeoutMillis() {
         synchronized(mLock) {
             final UserState userState = getCurrentUserStateLocked();
-            return userState.mMinimumUiTimeout;
+            return getRecommendedTimeoutMillisLocked(userState);
         }
     }
 
+    private long getRecommendedTimeoutMillisLocked(UserState userState) {
+        return IntPair.of(userState.mInteractiveUiTimeout,
+                userState.mNonInteractiveUiTimeout);
+    }
+
     @Override
     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
@@ -2503,7 +2501,8 @@
                 pw.append(", navBarMagnificationEnabled="
                         + userState.mIsNavBarMagnificationEnabled);
                 pw.append(", autoclickEnabled=" + userState.mIsAutoclickEnabled);
-                pw.append(", minimumUiTimeout=" + userState.mMinimumUiTimeout);
+                pw.append(", nonInteractiveUiTimeout=" + userState.mNonInteractiveUiTimeout);
+                pw.append(", interactiveUiTimeout=" + userState.mInteractiveUiTimeout);
                 if (mUiAutomationManager.isUiAutomationRunningLocked()) {
                     pw.append(", ");
                     mUiAutomationManager.dumpUiAutomationService(fd, pw, args);
@@ -2819,7 +2818,7 @@
         AccessibilityManagerService.UserState userState = getUserStateLocked(mCurrentUserId);
         onUserStateChangedLocked(userState);
         if (serviceInfoChanged) {
-            scheduleNotifyClientsOfServicesStateChange(userState);
+            scheduleNotifyClientsOfServicesStateChangeLocked(userState);
         }
     }
 
@@ -3794,7 +3793,8 @@
         public ComponentName mServiceToEnableWithShortcut;
 
         public int mLastSentClientState = -1;
-        public int mMinimumUiTimeout = 0;
+        public int mNonInteractiveUiTimeout = 0;
+        public int mInteractiveUiTimeout = 0;
 
         private int mSoftKeyboardShowMode = 0;
 
@@ -3809,8 +3809,8 @@
         public boolean mIsPerformGesturesEnabled;
         public boolean mIsFilterKeyEventsEnabled;
         public boolean mAccessibilityFocusOnlyInActiveWindow;
-        public boolean mUserMinimumUiTimeoutEnabled;
-        public int mUserMinimumUiTimeout;
+        public int mUserNonInteractiveUiTimeout;
+        public int mUserInteractiveUiTimeout;
 
         private boolean mBindInstantServiceAllowed;
 
@@ -3850,8 +3850,9 @@
             // Clear event management state.
             mLastSentClientState = -1;
 
-            // clear minimum ui timeout
-            mMinimumUiTimeout = 0;
+            // clear UI timeout
+            mNonInteractiveUiTimeout = 0;
+            mInteractiveUiTimeout = 0;
 
             // Clear state persisted in settings.
             mEnabledServices.clear();
@@ -3862,8 +3863,8 @@
             mServiceAssignedToAccessibilityButton = null;
             mIsNavBarMagnificationAssignedToAccessibilityButton = false;
             mIsAutoclickEnabled = false;
-            mUserMinimumUiTimeoutEnabled = false;
-            mUserMinimumUiTimeout = 0;
+            mUserNonInteractiveUiTimeout = 0;
+            mUserInteractiveUiTimeout = 0;
         }
 
         public void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -3871,7 +3872,7 @@
                 serviceConnection.onAdded();
                 mBoundServices.add(serviceConnection);
                 mComponentNameToServiceMap.put(serviceConnection.mComponentName, serviceConnection);
-                scheduleNotifyClientsOfServicesStateChange(this);
+                scheduleNotifyClientsOfServicesStateChangeLocked(this);
             }
         }
 
@@ -3897,7 +3898,7 @@
                 AccessibilityServiceConnection boundClient = mBoundServices.get(i);
                 mComponentNameToServiceMap.put(boundClient.mComponentName, boundClient);
             }
-            scheduleNotifyClientsOfServicesStateChange(this);
+            scheduleNotifyClientsOfServicesStateChangeLocked(this);
         }
 
         /**
@@ -4108,11 +4109,11 @@
         private final Uri mAccessibilityButtonComponentIdUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT);
 
-        private final Uri mUserMinimumUiTimeoutEnabledUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED);
+        private final Uri mUserNonInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);
 
-        private final Uri mUserMinimumUiTimeoutUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS);
+        private final Uri mUserInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS);
 
         public AccessibilityContentObserver(Handler handler) {
             super(handler);
@@ -4149,9 +4150,9 @@
             contentResolver.registerContentObserver(
                     mAccessibilityButtonComponentIdUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
-                    mUserMinimumUiTimeoutEnabledUri, false, this, UserHandle.USER_ALL);
+                    mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
-                    mUserMinimumUiTimeoutUri, false, this, UserHandle.USER_ALL);
+                    mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -4202,11 +4203,9 @@
                     if (readAccessibilityButtonSettingsLocked(userState)) {
                         onUserStateChangedLocked(userState);
                     }
-                } else if (mUserMinimumUiTimeoutEnabledUri.equals(uri)
-                        || mUserMinimumUiTimeoutUri.equals(uri)) {
-                    if (readUserMinimumUiTimeoutSettingsLocked(userState)) {
-                        updateMinimumUiTimeoutLocked(userState);
-                    }
+                } else if (mUserNonInteractiveUiTimeoutUri.equals(uri)
+                        || mUserInteractiveUiTimeoutUri.equals(uri)) {
+                    readUserRecommendedUiTimeoutSettingsLocked(userState);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index cd98263..32667b8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1210,13 +1210,29 @@
 
     @Override
     public void setMode(int code, int uid, String packageName, int mode) {
+        setMode(code, uid, packageName, mode, true, false);
+    }
+
+    /**
+     * Sets the mode for a certain op and uid.
+     *
+     * @param code The op code to set
+     * @param uid The UID for which to set
+     * @param packageName The package for which to set
+     * @param mode The new mode to set
+     * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
+     * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
+     *                     false})
+     */
+    private void setMode(int code, int uid, @NonNull String packageName, int mode,
+            boolean verifyUid, boolean isPrivileged) {
         enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
         verifyIncomingOp(code);
         ArraySet<ModeCallback> repCbs = null;
         code = AppOpsManager.opToSwitch(code);
         synchronized (this) {
             UidState uidState = getUidStateLocked(uid, false);
-            Op op = getOpLocked(code, uid, packageName, true);
+            Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
             if (op != null) {
                 if (op.mode != mode) {
                     op.mode = mode;
@@ -1575,7 +1591,7 @@
                     && uidState.opModes.indexOfKey(code) >= 0) {
                 return uidState.opModes.get(code);
             }
-            Op op = getOpLocked(code, uid, resolvedPackageName, false);
+            Op op = getOpLocked(code, uid, resolvedPackageName, false, true, false);
             if (op == null) {
                 return AppOpsManager.opToDefaultMode(code);
             }
@@ -1918,7 +1934,7 @@
         }
         ClientState client = (ClientState) token;
         synchronized (this) {
-            Op op = getOpLocked(code, uid, resolvedPackageName, true);
+            Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
             if (op == null) {
                 return;
             }
@@ -2172,6 +2188,43 @@
         return ops;
     }
 
+    /**
+     * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
+     *
+     * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
+     *
+     * @param uid The uid the of the package
+     * @param packageName The package name for which to get the state for
+     * @param edit Iff {@code true} create the {@link Ops} object if not yet created
+     * @param isPrivileged Whether the package is privileged or not
+     *
+     * @return The {@link Ops state} of all ops for the package
+     */
+    private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
+            boolean edit, boolean isPrivileged) {
+        UidState uidState = getUidStateLocked(uid, edit);
+        if (uidState == null) {
+            return null;
+        }
+
+        if (uidState.pkgOps == null) {
+            if (!edit) {
+                return null;
+            }
+            uidState.pkgOps = new ArrayMap<>();
+        }
+
+        Ops ops = uidState.pkgOps.get(packageName);
+        if (ops == null) {
+            if (!edit) {
+                return null;
+            }
+            ops = new Ops(packageName, uidState, isPrivileged);
+            uidState.pkgOps.put(packageName, ops);
+        }
+        return ops;
+    }
+
     private void scheduleWriteLocked() {
         if (!mWriteScheduled) {
             mWriteScheduled = true;
@@ -2188,9 +2241,29 @@
         }
     }
 
-    private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
-        Ops ops = getOpsRawLocked(uid, packageName, edit,
-                false /* uidMismatchExpected */);
+    /**
+     * Get the state of an op for a uid.
+     *
+     * @param code The code of the op
+     * @param uid The uid the of the package
+     * @param packageName The package name for which to get the state for
+     * @param edit Iff {@code true} create the {@link Op} object if not yet created
+     * @param verifyUid Iff {@code true} check that the package belongs to the uid
+     * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
+     *                     == false})
+     *
+     * @return The {@link Op state} of the op
+     */
+    private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
+            boolean verifyUid, boolean isPrivileged) {
+        Ops ops;
+
+        if (verifyUid) {
+            ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
+        }  else {
+            ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
+        }
+
         if (ops == null) {
             return null;
         }
@@ -3948,5 +4021,11 @@
                 mProfileOwners = owners;
             }
         }
+
+        @Override
+        public void setMode(int code, int uid, @NonNull String packageName, int mode,
+                boolean isPrivileged) {
+            AppOpsService.this.setMode(code, uid, packageName, mode, false, isPrivileged);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 924b075..f87a5f7 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4756,6 +4756,10 @@
                     applyZenModeLocked(r);
                     mRankingHelper.sort(mNotificationList);
 
+                    if (!r.isHidden()) {
+                        buzzBeepBlinkLocked(r);
+                    }
+
                     if (notification.getSmallIcon() != null) {
                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
                         mListeners.notifyPostedLocked(r, old);
@@ -4788,9 +4792,6 @@
                                 + n.getPackageName());
                     }
 
-                    if (!r.isHidden()) {
-                        buzzBeepBlinkLocked(r);
-                    }
                     maybeRecordInterruptionLocked(r);
                 } finally {
                     int N = mEnqueuedNotifications.size();
@@ -5157,6 +5158,7 @@
                     .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
             EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
         }
+        record.setAudiblyAlerted(buzz || beep);
     }
 
     @GuardedBy("mNotificationLock")
@@ -6561,6 +6563,7 @@
         Bundle hidden = new Bundle();
         Bundle smartActions = new Bundle();
         Bundle smartReplies = new Bundle();
+        Bundle audiblyAlerted = new Bundle();
         for (int i = 0; i < N; i++) {
             NotificationRecord record = mNotificationList.get(i);
             if (!isVisibleToListener(record.sbn, info)) {
@@ -6590,6 +6593,7 @@
             hidden.putBoolean(key, record.isHidden());
             smartActions.putParcelableArrayList(key, record.getSmartActions());
             smartReplies.putCharSequenceArrayList(key, record.getSmartReplies());
+            audiblyAlerted.putBoolean(key, record.getAudiblyAlerted());
         }
         final int M = keys.size();
         String[] keysAr = keys.toArray(new String[M]);
@@ -6601,7 +6605,7 @@
         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
                 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden,
-                smartActions, smartReplies);
+                smartActions, smartReplies, audiblyAlerted);
     }
 
     boolean hasCompanionDevice(ManagedServiceInfo info) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index e9f2718..84d0c01 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -170,6 +170,7 @@
     private final NotificationStats mStats;
     private int mUserSentiment;
     private boolean mIsInterruptive;
+    private boolean mAudiblyAlerted;
     private boolean mTextChanged;
     private boolean mRecordedInterruption;
     private int mNumberOfSmartRepliesAdded;
@@ -1023,6 +1024,10 @@
         }
     }
 
+    public void setAudiblyAlerted(boolean audiblyAlerted) {
+        mAudiblyAlerted = audiblyAlerted;
+    }
+
     public void setTextChanged(boolean textChanged) {
         mTextChanged = textChanged;
     }
@@ -1039,6 +1044,11 @@
         return mIsInterruptive;
     }
 
+    /** Returns true if the notification audibly alerted the user. */
+    public boolean getAudiblyAlerted() {
+        return mAudiblyAlerted;
+    }
+
     protected void setPeopleOverride(ArrayList<String> people) {
         mPeopleOverride = people;
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 6ccd040..1a5b86c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -107,7 +107,9 @@
 import java.util.Objects;
 import java.util.Random;
 
-public class PackageInstallerService extends IPackageInstaller.Stub {
+/** The service responsible for installing packages. */
+public class PackageInstallerService extends IPackageInstaller.Stub implements
+        PackageSessionProvider {
     private static final String TAG = "PackageInstaller";
     private static final boolean LOGD = false;
 
@@ -296,6 +298,7 @@
             in.setInput(fis, StandardCharsets.UTF_8.name());
 
             int type;
+            PackageInstallerSession currentSession = null;
             while ((type = in.next()) != END_DOCUMENT) {
                 if (type == START_TAG) {
                     final String tag = in.getName();
@@ -303,8 +306,10 @@
                         final PackageInstallerSession session;
                         try {
                             session = PackageInstallerSession.readFromXml(in, mInternalCallback,
-                                    mContext, mPm, mInstallThread.getLooper(), mSessionsDir);
+                                    mContext, mPm, mInstallThread.getLooper(), mSessionsDir, this);
+                            currentSession = session;
                         } catch (Exception e) {
+                            currentSession = null;
                             Slog.e(TAG, "Could not read session", e);
                             continue;
                         }
@@ -329,6 +334,10 @@
                             addHistoricalSessionLocked(session);
                         }
                         mAllocatedSessions.put(session.sessionId, true);
+                    } else if (currentSession != null
+                            && PackageInstallerSession.TAG_CHILD_SESSION.equals(tag)) {
+                        currentSession.addChildSessionIdInternal(
+                                PackageInstallerSession.readChildSessionIdFromXml(in));
                     }
                 }
             }
@@ -436,70 +445,72 @@
             }
         }
 
-        // Only system components can circumvent runtime permissions when installing.
-        if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
-                && mContext.checkCallingOrSelfPermission(Manifest.permission
-                .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
-            throw new SecurityException("You need the "
-                    + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
-                    + "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(
-                    Context.ACTIVITY_SERVICE);
-            final int iconSize = am.getLauncherLargeIconSize();
-            if ((params.appIcon.getWidth() > iconSize * 2)
-                    || (params.appIcon.getHeight() > iconSize * 2)) {
-                params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
-                        true);
-            }
-        }
-
-        switch (params.mode) {
-            case SessionParams.MODE_FULL_INSTALL:
-            case SessionParams.MODE_INHERIT_EXISTING:
-                break;
-            default:
-                throw new IllegalArgumentException("Invalid install mode: " + params.mode);
-        }
-
-        // If caller requested explicit location, sanity check it, otherwise
-        // resolve the best internal or adopted location.
-        if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
-            if (!PackageHelper.fitsOnInternal(mContext, params)) {
-                throw new IOException("No suitable internal storage available");
+        if (!params.isMultiPackage) {
+            // Only system components can circumvent runtime permissions when installing.
+            if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
+                    && mContext.checkCallingOrSelfPermission(Manifest.permission
+                    .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
+                throw new SecurityException("You need the "
+                        + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
+                        + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
             }
 
-        } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
-            if (!PackageHelper.fitsOnExternal(mContext, params)) {
-                throw new IOException("No suitable external storage available");
+            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");
             }
 
-        } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
-            // For now, installs to adopted media are treated as internal from
-            // an install flag point-of-view.
-            params.setInstallFlagsInternal();
+            // Defensively resize giant app icons
+            if (params.appIcon != null) {
+                final ActivityManager am = (ActivityManager) mContext.getSystemService(
+                        Context.ACTIVITY_SERVICE);
+                final int iconSize = am.getLauncherLargeIconSize();
+                if ((params.appIcon.getWidth() > iconSize * 2)
+                        || (params.appIcon.getHeight() > iconSize * 2)) {
+                    params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
+                            true);
+                }
+            }
 
-        } else {
-            // For now, installs to adopted media are treated as internal from
-            // an install flag point-of-view.
-            params.setInstallFlagsInternal();
+            switch (params.mode) {
+                case SessionParams.MODE_FULL_INSTALL:
+                case SessionParams.MODE_INHERIT_EXISTING:
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid install mode: " + params.mode);
+            }
 
-            // Resolve best location for install, based on combination of
-            // requested install flags, delta size, and manifest settings.
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
+            // If caller requested explicit location, sanity check it, otherwise
+            // resolve the best internal or adopted location.
+            if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+                if (!PackageHelper.fitsOnInternal(mContext, params)) {
+                    throw new IOException("No suitable internal storage available");
+                }
+
+            } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+                if (!PackageHelper.fitsOnExternal(mContext, params)) {
+                    throw new IOException("No suitable external storage available");
+                }
+
+            } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
+                // For now, installs to adopted media are treated as internal from
+                // an install flag point-of-view.
+                params.setInstallFlagsInternal();
+
+            } else {
+                // For now, installs to adopted media are treated as internal from
+                // an install flag point-of-view.
+                params.setInstallFlagsInternal();
+
+                // Resolve best location for install, based on combination of
+                // requested install flags, delta size, and manifest settings.
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             }
         }
 
@@ -525,17 +536,19 @@
         // We're staging to exactly one location
         File stageDir = null;
         String stageCid = null;
-        if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
-            final boolean isInstant =
-                    (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
-            stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
-        } else {
-            stageCid = buildExternalStageCid(sessionId);
+        if (!params.isMultiPackage) {
+            if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+                final boolean isInstant =
+                        (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+                stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
+            } else {
+                stageCid = buildExternalStageCid(sessionId);
+            }
         }
-
-        session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
-                mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
-                params, createdMillis, stageDir, stageCid, false, false);
+        session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
+                mInstallThread.getLooper(), sessionId, userId, installerPackageName,
+                callingUid, params, createdMillis, stageDir, stageCid, false, false, null,
+                SessionInfo.INVALID_ID);
 
         synchronized (mSessions) {
             mSessions.put(sessionId, session);
@@ -678,7 +691,7 @@
         synchronized (mSessions) {
             for (int i = 0; i < mSessions.size(); i++) {
                 final PackageInstallerSession session = mSessions.valueAt(i);
-                if (session.userId == userId) {
+                if (session.userId == userId && !session.hasParentSessionId()) {
                     result.add(session.generateInfo(false));
                 }
             }
@@ -699,7 +712,7 @@
 
                 SessionInfo info = session.generateInfo(false);
                 if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
-                        && session.userId == userId) {
+                        && session.userId == userId && !session.hasParentSessionId()) {
                     result.add(info);
                 }
             }
@@ -781,6 +794,13 @@
         mCallbacks.unregister(callback);
     }
 
+    @Override
+    public PackageInstallerSession getSession(int sessionId) {
+        synchronized (mSessions) {
+            return mSessions.get(sessionId);
+        }
+    }
+
     private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
             int installerUid) {
         int count = 0;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 249edab..26f6e96 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -47,6 +47,8 @@
 import android.app.admin.DeviceAdminInfo;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
@@ -69,6 +71,7 @@
 import android.os.FileBridge;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
@@ -90,6 +93,7 @@
 import android.util.ExceptionUtils;
 import android.util.MathUtils;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.util.apk.ApkSignatureVerifier;
 
 import com.android.internal.annotations.GuardedBy;
@@ -130,6 +134,7 @@
 
     /** XML constants used for persisting a session */
     static final String TAG_SESSION = "session";
+    static final String TAG_CHILD_SESSION = "childSession";
     private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
     private static final String ATTR_SESSION_ID = "sessionId";
     private static final String ATTR_USER_ID = "userId";
@@ -140,6 +145,8 @@
     private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
     private static final String ATTR_PREPARED = "prepared";
     private static final String ATTR_SEALED = "sealed";
+    private static final String ATTR_MULTI_PACKAGE = "multiPackage";
+    private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
     private static final String ATTR_MODE = "mode";
     private static final String ATTR_INSTALL_FLAGS = "installFlags";
     private static final String ATTR_INSTALL_LOCATION = "installLocation";
@@ -157,6 +164,7 @@
     private static final String ATTR_INSTALL_REASON = "installRason";
 
     private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
+    private static final int[] EMPTY_CHILD_SESSION_ARRAY = {};
 
     // TODO: enforce INSTALL_ALLOW_TEST
     // TODO: enforce INSTALL_ALLOW_DOWNGRADE
@@ -165,6 +173,7 @@
     private final Context mContext;
     private final PackageManagerService mPm;
     private final Handler mHandler;
+    private final PackageSessionProvider mSessionProvider;
 
     final int sessionId;
     final int userId;
@@ -236,6 +245,10 @@
     private long mVersionCode;
     @GuardedBy("mLock")
     private PackageParser.SigningDetails mSigningDetails;
+    @GuardedBy("mLock")
+    private SparseIntArray mChildSessionIds = new SparseIntArray();
+    @GuardedBy("mLock")
+    private int mParentSessionId;
 
     /**
      * Path to the validated base APK for this session, which may point at an
@@ -372,12 +385,16 @@
     }
 
     public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
-            Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
+            Context context, PackageManagerService pm,
+            PackageSessionProvider sessionProvider, Looper looper,
+            int sessionId, int userId,
             String installerPackageName, int installerUid, SessionParams params, long createdMillis,
-            File stageDir, String stageCid, boolean prepared, boolean sealed) {
+            File stageDir, String stageCid, boolean prepared, boolean sealed,
+            @Nullable int[] childSessionIds, int parentSessionId) {
         mCallback = callback;
         mContext = context;
         mPm = pm;
+        mSessionProvider = sessionProvider;
         mHandler = new Handler(looper, mHandlerCallback);
 
         this.sessionId = sessionId;
@@ -389,8 +406,14 @@
         this.createdMillis = createdMillis;
         this.stageDir = stageDir;
         this.stageCid = stageCid;
+        if (childSessionIds != null) {
+            for (int childSessionId : childSessionIds) {
+                mChildSessionIds.put(childSessionId, 0);
+            }
+        }
+        this.mParentSessionId = parentSessionId;
 
-        if ((stageDir == null) == (stageCid == null)) {
+        if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
             throw new IllegalArgumentException(
                     "Exactly one of stageDir or stageCid stage must be set");
         }
@@ -439,6 +462,12 @@
             info.referrerUri = params.referrerUri;
             info.grantedRuntimePermissions = params.grantedRuntimePermissions;
             info.installFlags = params.installFlags;
+            info.isMultiPackage = params.isMultiPackage;
+            info.parentSessionId = mParentSessionId;
+            info.childSessionIds = mChildSessionIds.copyKeys();
+            if (info.childSessionIds == null) {
+                info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
+            }
         }
         return info;
     }
@@ -762,6 +791,92 @@
 
     @Override
     public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
+        if (!markAsCommitted(statusReceiver, forTransfer  /* enforce */)) {
+            return;
+        }
+        if (isMultiPackage()) {
+
+            final SparseIntArray remainingSessions = mChildSessionIds.clone();
+            final ChildStatusIntentReceiver localIntentReceiver =
+                    new ChildStatusIntentReceiver(remainingSessions, statusReceiver);
+            for (int childSessionId : getChildSessionIds()) {
+                mSessionProvider.getSession(childSessionId)
+                        .markAsCommitted(localIntentReceiver.getIntentSender(), forTransfer);
+            }
+        }
+        mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
+    }
+
+    private class ChildStatusIntentReceiver {
+        private final SparseIntArray mChildSessionsRemaining;
+        private final IntentSender mStatusReceiver;
+        private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+            @Override
+            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
+                statusUpdate(intent);
+            }
+        };
+
+        private ChildStatusIntentReceiver(SparseIntArray remainingSessions,
+                IntentSender statusReceiver) {
+            this.mChildSessionsRemaining = remainingSessions;
+            this.mStatusReceiver = statusReceiver;
+        }
+
+        public IntentSender getIntentSender() {
+            return new IntentSender((IIntentSender) mLocalSender);
+        }
+
+        public void statusUpdate(Intent intent) {
+            mHandler.post(() -> {
+                if (mChildSessionsRemaining.size() == 0) {
+                    return;
+                }
+                final int sessionId = intent.getIntExtra(
+                        PackageInstaller.EXTRA_SESSION_ID, 0);
+                final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                        PackageInstaller.STATUS_FAILURE);
+                final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
+                if (PackageInstaller.STATUS_SUCCESS == status) {
+                    mChildSessionsRemaining.removeAt(sessionIndex);
+                    if (mChildSessionsRemaining.size() == 0) {
+                        try {
+                            intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
+                                    PackageInstallerSession.this.sessionId);
+                            mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+                        } catch (IntentSender.SendIntentException ignore) {
+                        }
+                    }
+                } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
+                    try {
+                        mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+                    } catch (IntentSender.SendIntentException ignore) {
+                    }
+                } else {
+                    intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
+                            PackageInstallerSession.this.sessionId);
+                    mChildSessionsRemaining.clear(); // we're done. Don't send any more.
+                    try {
+                        mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+                    } catch (IntentSender.SendIntentException ignore) {
+                    }
+                }
+            });
+        }
+    }
+
+
+    /**
+     * Do everything but actually commit the session. If this was not already called, the session
+     * will be sealed and marked as committed. The caller of this method is responsible for
+     * subsequently submitting this session for processing.
+     *
+     * This method may be called multiple times to update the status receiver validate caller
+     * permissions.
+     */
+    public boolean markAsCommitted(
+            @NonNull IntentSender statusReceiver, boolean forTransfer) {
         Preconditions.checkNotNull(statusReceiver);
 
         final boolean wasSealed;
@@ -786,6 +901,12 @@
                 }
             }
 
+            // After validations and updating the observer, we can skip re-sealing, etc. because we
+            // have already marked ourselves as committed.
+            if (mCommitted) {
+                return true;
+            }
+
             wasSealed = mSealed;
             if (!mSealed) {
                 try {
@@ -796,7 +917,7 @@
                     // Do now throw an exception here to stay compatible with O and older
                     destroyInternal();
                     dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
-                    return;
+                    return false;
                 }
             }
 
@@ -809,7 +930,6 @@
             mActiveCount.incrementAndGet();
 
             mCommitted = true;
-            mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
         }
 
         if (!wasSealed) {
@@ -818,6 +938,7 @@
             // the session lock, since otherwise it's a lock inversion.
             mCallback.onSessionSealedBlocking(this);
         }
+        return true;
     }
 
     /**
@@ -833,32 +954,37 @@
         assertNoWriteFileTransfersOpenLocked();
         assertPreparedAndNotDestroyedLocked("sealing of session");
 
-        final PackageInfo pkgInfo = mPm.getPackageInfo(
-                params.appPackageName, PackageManager.GET_SIGNATURES
-                        | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
-
-        resolveStageDirLocked();
-
         mSealed = true;
-        try {
-            if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
-                validateApexInstallLocked(pkgInfo);
-            } else {
-                // Verify that stage looks sane with respect to existing application.
-                // This currently only ensures packageName, versionCode, and certificate
-                // consistency.
-                validateApkInstallLocked(pkgInfo);
-            }
-        } catch (PackageManagerException e) {
-            throw e;
-        } catch (Throwable e) {
-            // Convert all exceptions into package manager exceptions as only those are handled
-            // in the code above
-            throw new PackageManagerException(e);
-        }
 
         // Read transfers from the original owner stay open, but as the session's data
         // cannot be modified anymore, there is no leak of information.
+        if (!params.isMultiPackage) {
+            final PackageInfo pkgInfo = mPm.getPackageInfo(
+                    params.appPackageName, PackageManager.GET_SIGNATURES
+                            | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
+
+            resolveStageDirLocked();
+
+            // Verify that stage looks sane with respect to existing application.
+            // This currently only ensures packageName, versionCode, and certificate
+            // consistency.
+            try {
+                if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+                    validateApexInstallLocked(pkgInfo);
+                } else {
+                    // Verify that stage looks sane with respect to existing application.
+                    // This currently only ensures packageName, versionCode, and certificate
+                    // consistency.
+                    validateApkInstallLocked(pkgInfo);
+                }
+            } catch (PackageManagerException e) {
+                throw e;
+            } catch (Throwable e) {
+                // Convert all exceptions into package manager exceptions as only those are handled
+                // in the code above
+                throw new PackageManagerException(e);
+            }
+        }
     }
 
     @Override
@@ -916,25 +1042,52 @@
     @GuardedBy("mLock")
     private void commitLocked()
             throws PackageManagerException {
-        if (mRelinquished) {
-            Slog.d(TAG, "Ignoring commit after previous commit relinquished control");
+        final PackageManagerService.ActiveInstallSession committingSession =
+                makeSessionActiveLocked();
+        if (committingSession == null) {
             return;
         }
-        if (mDestroyed) {
-            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
-        }
-        if (!mSealed) {
-            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
-        }
-
-        Preconditions.checkNotNull(mPackageName);
-        Preconditions.checkNotNull(mSigningDetails);
-        Preconditions.checkNotNull(mResolvedBaseFile);
-
-        if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
-            commitApexLocked();
+        if (isMultiPackage()) {
+            final int[] childSessionIds = getChildSessionIds();
+            List<PackageManagerService.ActiveInstallSession> childSessions =
+                    new ArrayList<>(childSessionIds.length);
+            boolean success = true;
+            PackageManagerException failure = null;
+            for (int childSessionId : getChildSessionIds()) {
+                final PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
+                try {
+                    final PackageManagerService.ActiveInstallSession activeSession =
+                            session.makeSessionActiveLocked();
+                    if (activeSession != null) {
+                        if ((activeSession.getSessionParams().installFlags
+                                & PackageManager.INSTALL_APEX) != 0) {
+                            // TODO(b/118865310): Add exception to this case for staged installs
+                            throw new PackageManagerException(
+                                    PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+                                    "Atomic install is not supported for APEX packages.");
+                        }
+                        childSessions.add(activeSession);
+                    }
+                } catch (PackageManagerException e) {
+                    failure = e;
+                    success = false;
+                }
+            }
+            if (!success) {
+                try {
+                    mRemoteObserver.onPackageInstalled(
+                            null, failure.error, failure.getLocalizedMessage(), null);
+                } catch (RemoteException ignored) {
+                }
+                return;
+            }
+            mPm.installStage(childSessions);
         } else {
-            commitApkLocked();
+            if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+                commitApexLocked();
+            } else {
+                mPm.installStage(committingSession);
+            }
         }
     }
 
@@ -954,81 +1107,105 @@
         }
     }
 
+    /**
+     * Stages this session for install and returns a
+     * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
+     * in case permissions need to be requested before install can proceed.
+     */
     @GuardedBy("mLock")
-    private void commitApkLocked() throws PackageManagerException {
-        if (needToAskForPermissionsLocked()) {
-            // User needs to confirm installation; give installer an intent they can use to involve
-            // user.
-            final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
-            intent.setPackage(mPm.getPackageInstallerPackageName());
-            intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
-            try {
-                mRemoteObserver.onUserActionRequired(intent);
-            } catch (RemoteException ignored) {
-            }
-
-            // Commit was keeping session marked as active until now; release
-            // that extra refcount so session appears idle.
-            closeInternal(false);
-            return;
+    private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
+            throws PackageManagerException {
+        if (mRelinquished) {
+            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                    "Session relinquished");
+        }
+        if (mDestroyed) {
+            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
+        }
+        if (!mSealed) {
+            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
         }
 
-        // Inherit any packages and native libraries from existing install that
-        // haven't been overridden.
-        if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
-            try {
-                final List<File> fromFiles = mResolvedInheritedFiles;
-                final File toDir = resolveStageDirLocked();
+        if (!params.isMultiPackage) {
+            Preconditions.checkNotNull(mPackageName);
+            Preconditions.checkNotNull(mSigningDetails);
+            Preconditions.checkNotNull(mResolvedBaseFile);
 
-                if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
-                if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
-                    throw new IllegalStateException("mInheritedFilesBase == null");
+            if (needToAskForPermissionsLocked()) {
+                // User needs to confirm installation;
+                // give installer an intent they can use to involve
+                // user.
+                final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
+                intent.setPackage(mPm.getPackageInstallerPackageName());
+                intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
+                try {
+                    mRemoteObserver.onUserActionRequired(intent);
+                } catch (RemoteException ignored) {
                 }
 
-                if (isLinkPossible(fromFiles, toDir)) {
-                    if (!mResolvedInstructionSets.isEmpty()) {
-                        final File oatDir = new File(toDir, "oat");
-                        createOatDirs(mResolvedInstructionSets, oatDir);
+                // Commit was keeping session marked as active until now; release
+                // that extra refcount so session appears idle.
+                closeInternal(false);
+                return null;
+            }
+
+            // Inherit any packages and native libraries from existing install that
+            // haven't been overridden.
+            if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
+                try {
+                    final List<File> fromFiles = mResolvedInheritedFiles;
+                    final File toDir = resolveStageDirLocked();
+
+                    if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
+                    if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
+                        throw new IllegalStateException("mInheritedFilesBase == null");
                     }
-                    // pre-create lib dirs for linking if necessary
-                    if (!mResolvedNativeLibPaths.isEmpty()) {
-                        for (String libPath : mResolvedNativeLibPaths) {
-                            // "/lib/arm64" -> ["lib", "arm64"]
-                            final int splitIndex = libPath.lastIndexOf('/');
-                            if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
-                                Slog.e(TAG, "Skipping native library creation for linking due to "
-                                        + "invalid path: " + libPath);
-                                continue;
-                            }
-                            final String libDirPath = libPath.substring(1, splitIndex);
-                            final File libDir = new File(toDir, libDirPath);
-                            if (!libDir.exists()) {
-                                NativeLibraryHelper.createNativeLibrarySubdir(libDir);
-                            }
-                            final String archDirPath = libPath.substring(splitIndex + 1);
-                            NativeLibraryHelper.createNativeLibrarySubdir(
-                                    new File(libDir, archDirPath));
+
+                    if (isLinkPossible(fromFiles, toDir)) {
+                        if (!mResolvedInstructionSets.isEmpty()) {
+                            final File oatDir = new File(toDir, "oat");
+                            createOatDirs(mResolvedInstructionSets, oatDir);
                         }
+                        // pre-create lib dirs for linking if necessary
+                        if (!mResolvedNativeLibPaths.isEmpty()) {
+                            for (String libPath : mResolvedNativeLibPaths) {
+                                // "/lib/arm64" -> ["lib", "arm64"]
+                                final int splitIndex = libPath.lastIndexOf('/');
+                                if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
+                                    Slog.e(TAG,
+                                            "Skipping native library creation for linking due to "
+                                                    + "invalid path: " + libPath);
+                                    continue;
+                                }
+                                final String libDirPath = libPath.substring(1, splitIndex);
+                                final File libDir = new File(toDir, libDirPath);
+                                if (!libDir.exists()) {
+                                    NativeLibraryHelper.createNativeLibrarySubdir(libDir);
+                                }
+                                final String archDirPath = libPath.substring(splitIndex + 1);
+                                NativeLibraryHelper.createNativeLibrarySubdir(
+                                        new File(libDir, archDirPath));
+                            }
+                        }
+                        linkFiles(fromFiles, toDir, mInheritedFilesBase);
+                    } else {
+                        // TODO: this should delegate to DCS so the system process
+                        // avoids holding open FDs into containers.
+                        copyFiles(fromFiles, toDir);
                     }
-                    linkFiles(fromFiles, toDir, mInheritedFilesBase);
-                } else {
-                    // TODO: this should delegate to DCS so the system process
-                    // avoids holding open FDs into containers.
-                    copyFiles(fromFiles, toDir);
+                } catch (IOException e) {
+                    throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
+                            "Failed to inherit existing install", e);
                 }
-            } catch (IOException e) {
-                throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-                        "Failed to inherit existing install", e);
             }
+
+            // TODO: surface more granular state from dexopt
+            mInternalProgress = 0.5f;
+            computeProgressLocked(true);
+
+            // Unpack native libraries
+            extractNativeLibraries(mResolvedStageDir, params.abiOverride, mayInheritNativeLibs());
         }
-
-        // TODO: surface more granular state from dexopt
-        mInternalProgress = 0.5f;
-        computeProgressLocked(true);
-
-        // Unpack native libraries
-        extractNativeLibraries(mResolvedStageDir, params.abiOverride, mayInheritNativeLibs());
-
         // We've reached point of no return; call into PMS to install the stage.
         // Regardless of success or failure we always destroy session.
         final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@@ -1053,8 +1230,11 @@
         }
 
         mRelinquished = true;
-        mPm.installStage(mPackageName, stageDir, localObserver, params,
-                mInstallerPackageName, mInstallerUid, user, mSigningDetails);
+        final PackageManagerService.ActiveInstallSession activeInstallSession =
+                new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
+                        localObserver, params, mInstallerPackageName, mInstallerUid, user,
+                        mSigningDetails);
+        return activeInstallSession;
     }
 
     private static void maybeRenameFile(File from, File to) throws PackageManagerException {
@@ -1556,6 +1736,14 @@
         }
     }
 
+    /**
+     * Adds a child session ID without any safety / sanity checks. This should only be used to
+     * build a session from XML or similar.
+     */
+    void addChildSessionIdInternal(int sessionId) {
+        mChildSessionIds.put(sessionId, 0);
+    }
+
     public void open() throws IOException {
         if (mActiveCount.getAndIncrement() == 0) {
             mCallback.onSessionActiveChanged(this, true);
@@ -1567,6 +1755,8 @@
             if (!mPrepared) {
                 if (stageDir != null) {
                     prepareStageDir(stageDir);
+                } else if (params.isMultiPackage) {
+                    // it's all ok
                 } else {
                     throw new IllegalArgumentException("stageDir must be set");
                 }
@@ -1615,6 +1805,81 @@
         dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
     }
 
+    @Override
+    public boolean isMultiPackage() {
+        return params.isMultiPackage;
+    }
+
+    @Override
+    public int[] getChildSessionIds() {
+        final int[] childSessionIds = mChildSessionIds.copyKeys();
+        if (childSessionIds != null) {
+            return childSessionIds;
+        }
+        return EMPTY_CHILD_SESSION_ARRAY;
+    }
+
+    @Override
+    public void addChildSessionId(int sessionId) {
+        final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
+        if (session == null) {
+            throw new RemoteException("Unable to add child.",
+                    new PackageManagerException("Child session " + sessionId + " does not exist"),
+                    false, true).rethrowAsRuntimeException();
+        }
+        synchronized (mLock) {
+            final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+            if (indexOfSession >= 0) {
+                return;
+            }
+            session.setParentSessionId(this.sessionId);
+            addChildSessionIdInternal(sessionId);
+        }
+    }
+
+    @Override
+    public void removeChildSessionId(int sessionId) {
+        final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
+        synchronized (mLock) {
+            final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+            if (session != null) {
+                session.setParentSessionId(SessionInfo.INVALID_ID);
+            }
+            if (indexOfSession < 0) {
+                // not added in the first place; no-op
+                return;
+            }
+            mChildSessionIds.removeAt(indexOfSession);
+        }
+    }
+
+    /**
+     * Sets the parent session ID if not already set.
+     * If {@link SessionInfo#INVALID_ID} is passed, it will be unset.
+     */
+    void setParentSessionId(int parentSessionId) {
+        synchronized (mLock) {
+            if (parentSessionId != SessionInfo.INVALID_ID
+                    && mParentSessionId != SessionInfo.INVALID_ID) {
+                throw new RemoteException("Unable to set parent session.",
+                        new PackageManagerException(
+                                "The parent of " + sessionId + " is" + " already set to "
+                                        + mParentSessionId), false,
+                        true).rethrowAsRuntimeException();
+            }
+            this.mParentSessionId = parentSessionId;
+        }
+    }
+
+    boolean hasParentSessionId() {
+        return mParentSessionId != SessionInfo.INVALID_ID;
+    }
+
+    @Override
+    public int getParentSessionId() {
+        return mParentSessionId;
+    }
+
     private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
         final IPackageInstallObserver2 observer;
         final String packageName;
@@ -1704,6 +1969,7 @@
         pw.printPair("mBridges", mBridges.size());
         pw.printPair("mFinalStatus", mFinalStatus);
         pw.printPair("mFinalMessage", mFinalMessage);
+        pw.printPair("params.isMultiPackage", params.isMultiPackage);
         pw.println();
 
         pw.decreaseIndent();
@@ -1754,6 +2020,10 @@
             writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
             writeBooleanAttribute(out, ATTR_SEALED, isSealed());
 
+            writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
+            // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
+            //                       we've read all sessions.
+            writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
             writeIntAttribute(out, ATTR_MODE, params.mode);
             writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
             writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
@@ -1788,6 +2058,12 @@
 
                 params.appIconLastModified = appIconFile.lastModified();
             }
+            final int[] childSessionIds = getChildSessionIds();
+            for (int childSessionId : childSessionIds) {
+                out.startTag(null, TAG_CHILD_SESSION);
+                writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
+                out.endTag(null, TAG_CHILD_SESSION);
+            }
         }
 
         out.endTag(null, TAG_SESSION);
@@ -1832,11 +2108,15 @@
      * @param installerThread Thread to be used for callbacks of this session
      * @param sessionsDir The directory the sessions are stored in
      *
+     * @param sessionProvider
      * @return The newly created session
      */
+    // TODO(patb,109941548): modify readFromXml to consume to the next tag session tag so we
+    //                       can have a complete session for the constructor
     public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
             @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
-            @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir)
+            @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir,
+            @NonNull PackageSessionProvider sessionProvider)
             throws IOException, XmlPullParserException {
         final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
         final int userId = readIntAttribute(in, ATTR_USER_ID);
@@ -1849,9 +2129,12 @@
         final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
         final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
         final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
+        final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
+                SessionInfo.INVALID_ID);
 
         final SessionParams params = new SessionParams(
                 SessionParams.MODE_INVALID);
+        params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false);
         params.mode = readIntAttribute(in, ATTR_MODE);
         params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
         params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
@@ -1874,9 +2157,16 @@
             params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
             params.appIconLastModified = appIconFile.lastModified();
         }
-
-        return new PackageInstallerSession(callback, context, pm,
+        return new PackageInstallerSession(callback, context, pm, sessionProvider,
                 installerThread, sessionId, userId, installerPackageName, installerUid,
-                params, createdMillis, stageDir, stageCid, prepared, sealed);
+                params, createdMillis, stageDir, stageCid, prepared, sealed,
+                EMPTY_CHILD_SESSION_ARRAY, parentSessionId);
+    }
+
+    /**
+     * Reads the session ID from a child session tag stored in the provided {@link XmlPullParser}
+     */
+    static int readChildSessionIdFromXml(@NonNull XmlPullParser in) {
+        return readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID);
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ed3e857..ed5b33b6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -60,6 +60,7 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
 import static android.content.pm.PackageManager.INSTALL_INTERNAL;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
@@ -239,7 +240,6 @@
 import android.os.storage.StorageManagerInternal;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
-import android.permission.PermissionManager;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.security.KeyStore;
@@ -2930,60 +2930,6 @@
 
             checkDefaultBrowser();
 
-            // If a granted permission is split, all new permissions should be granted too
-            if (mIsUpgrade) {
-                final int callingUid = getCallingUid();
-
-                final List<PermissionManager.SplitPermissionInfo> splitPermissions =
-                        mContext.getSystemService(PermissionManager.class).getSplitPermissions();
-                final int numSplitPerms = splitPermissions.size();
-                for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
-                    final PermissionManager.SplitPermissionInfo splitPerm =
-                            splitPermissions.get(splitPermNum);
-                    final String rootPerm = splitPerm.getSplitPermission();
-
-                    if (preUpgradeSdkVersion >= splitPerm.getTargetSdk()) {
-                        continue;
-                    }
-
-                    final int numPackages = mPackages.size();
-                    for (int packageNum = 0; packageNum < numPackages; packageNum++) {
-                        final PackageParser.Package pkg = mPackages.valueAt(packageNum);
-
-                        if (pkg.applicationInfo.targetSdkVersion >= splitPerm.getTargetSdk()
-                                || !pkg.requestedPermissions.contains(rootPerm)) {
-                            continue;
-                        }
-
-                        final int userId = UserHandle.getUserId(pkg.applicationInfo.uid);
-                        final String pkgName = pkg.packageName;
-
-                        if (checkPermission(rootPerm, pkgName, userId) == PERMISSION_DENIED) {
-                            continue;
-                        }
-
-                        final List<String> newPerms = splitPerm.getNewPermissions();
-
-                        final int numNewPerms = newPerms.size();
-                        for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
-                            final String newPerm = newPerms.get(newPermNum);
-                            if (checkPermission(newPerm, pkgName, userId) == PERMISSION_GRANTED) {
-                                continue;
-                            }
-
-                            if (DEBUG_PERMISSIONS) {
-                                Slog.v(TAG, "Granting " + newPerm + " to " + pkgName
-                                        + " as the root permission " + rootPerm
-                                        + " is already granted");
-                            }
-
-                            mPermissionManager.grantRuntimePermission(newPerm, pkgName, true,
-                                    callingUid, userId, null);
-                        }
-                    }
-                }
-            }
-
             // clear only after permissions and other defaults have been updated
             mExistingSystemPackages.clear();
             mPromoteSystemApps = false;
@@ -12357,28 +12303,15 @@
         return installReason;
     }
 
-    void installStage(String packageName, File stagedDir,
-            IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
-            String installerPackageName, int installerUid, UserHandle user,
-            PackageParser.SigningDetails signingDetails) {
+    void installStage(ActiveInstallSession activeInstallSession) {
         if (DEBUG_INSTANT) {
-            if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
-                Slog.d(TAG, "Ephemeral install of " + packageName);
+            if ((activeInstallSession.getSessionParams().installFlags
+                    & PackageManager.INSTALL_INSTANT_APP) != 0) {
+                Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
             }
         }
-        final VerificationInfo verificationInfo = new VerificationInfo(
-                sessionParams.originatingUri, sessionParams.referrerUri,
-                sessionParams.originatingUid, installerUid);
-
-        final OriginInfo origin = OriginInfo.fromStagedFile(stagedDir);
-
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        final int installReason = fixUpInstallReason(installerPackageName, installerUid,
-                sessionParams.installReason);
-        final InstallParams params = new InstallParams(origin, null, observer,
-                sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
-                verificationInfo, user, sessionParams.abiOverride,
-                sessionParams.grantedRuntimePermissions, signingDetails, installReason);
+        final InstallParams params = new InstallParams(activeInstallSession);
         params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -12390,6 +12323,22 @@
         mHandler.sendMessage(msg);
     }
 
+    void installStage(List<ActiveInstallSession> children)
+            throws PackageManagerException {
+        final Message msg = mHandler.obtainMessage(INIT_COPY);
+        final MultiPackageInstallParams params =
+                new MultiPackageInstallParams(UserHandle.ALL, children);
+        params.setTraceMethod("installStageMultiPackage")
+                .setTraceCookie(System.identityHashCode(params));
+        msg.obj = params;
+
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
+                System.identityHashCode(msg.obj));
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+                System.identityHashCode(msg.obj));
+        mHandler.sendMessage(msg);
+    }
+
     private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
             int userId) {
         final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
@@ -13567,88 +13516,113 @@
     }
 
     private void processPendingInstall(final InstallArgs args, final int currentStatus) {
-        // Queue up an async operation since the package installation may take a little while.
-        mHandler.post(new Runnable() {
-            public void run() {
-                mHandler.removeCallbacks(this);
-                 // Result object to be returned
-                PackageInstalledInfo res = new PackageInstalledInfo();
-                res.setReturnCode(currentStatus);
-                res.uid = -1;
-                res.pkg = null;
-                res.removedInfo = null;
-                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                    args.doPreInstall(res.returnCode);
-                    synchronized (mInstallLock) {
-                        installPackageTracedLI(args, res);
-                    }
-                    args.doPostInstall(res.returnCode, res.uid);
+        if (args.mMultiPackageInstallParams != null) {
+            args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
+        } else {
+            PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
+            processInstallRequestsAsync(
+                    res.returnCode == PackageManager.INSTALL_SUCCEEDED,
+                    Collections.singletonList(new InstallRequest(args, res)));
+        }
+    }
+
+    // Queue up an async operation since the package installation may take a little while.
+    private void processInstallRequestsAsync(boolean success,
+            List<InstallRequest> installRequests) {
+        mHandler.post(() -> {
+            if (success) {
+                for (InstallRequest request : installRequests) {
+                    request.args.doPreInstall(request.installResult.returnCode);
                 }
-
-                // A restore should be performed at this point if (a) the install
-                // succeeded, (b) the operation is not an update, and (c) the new
-                // package has not opted out of backup participation.
-                final boolean update = res.removedInfo != null
-                        && res.removedInfo.removedPackage != null;
-                final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
-                boolean doRestore = !update
-                        && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
-
-                // Set up the post-install work request bookkeeping.  This will be used
-                // and cleaned up by the post-install event handling regardless of whether
-                // there's a restore pass performed.  Token values are >= 1.
-                int token;
-                if (mNextInstallToken < 0) mNextInstallToken = 1;
-                token = mNextInstallToken++;
-
-                PostInstallData data = new PostInstallData(args, res);
-                mRunningInstalls.put(token, data);
-                if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
-
-                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
-                    // Pass responsibility to the Backup Manager.  It will perform a
-                    // restore if appropriate, then pass responsibility back to the
-                    // Package Manager to run the post-install observer callbacks
-                    // and broadcasts.
-                    IBackupManager bm = IBackupManager.Stub.asInterface(
-                            ServiceManager.getService(Context.BACKUP_SERVICE));
-                    if (bm != null) {
-                        if (DEBUG_INSTALL) Log.v(TAG, "token " + token
-                                + " to BM for possible restore");
-                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
-                        try {
-                            // TODO: http://b/22388012
-                            if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
-                                bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
-                            } else {
-                                doRestore = false;
-                            }
-                        } catch (RemoteException e) {
-                            // can't happen; the backup manager is local
-                        } catch (Exception e) {
-                            Slog.e(TAG, "Exception trying to enqueue restore", e);
-                            doRestore = false;
-                        }
-                    } else {
-                        Slog.e(TAG, "Backup Manager not found!");
-                        doRestore = false;
-                    }
+                synchronized (mInstallLock) {
+                    installPackagesTracedLI(installRequests);
                 }
-
-                if (!doRestore) {
-                    // No restore possible, or the Backup Manager was mysteriously not
-                    // available -- just fire the post-install work request directly.
-                    if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
-
-                    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
-
-                    Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
-                    mHandler.sendMessage(msg);
+                for (InstallRequest request : installRequests) {
+                    request.args.doPostInstall(
+                            request.installResult.returnCode, request.installResult.uid);
                 }
             }
+            for (InstallRequest request : installRequests) {
+                resolvePackageInstalledInfo(request.args,
+                        request.installResult);
+            }
         });
     }
 
+    private PackageInstalledInfo createPackageInstalledInfo(
+            int currentStatus) {
+        PackageInstalledInfo res = new PackageInstalledInfo();
+        res.setReturnCode(currentStatus);
+        res.uid = -1;
+        res.pkg = null;
+        res.removedInfo = null;
+        return res;
+    }
+
+    private void resolvePackageInstalledInfo(InstallArgs args, PackageInstalledInfo res) {
+        // A restore should be performed at this point if (a) the install
+        // succeeded, (b) the operation is not an update, and (c) the new
+        // package has not opted out of backup participation.
+        final boolean update = res.removedInfo != null
+                && res.removedInfo.removedPackage != null;
+        final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
+        boolean doRestore = !update
+                && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
+
+        // Set up the post-install work request bookkeeping.  This will be used
+        // and cleaned up by the post-install event handling regardless of whether
+        // there's a restore pass performed.  Token values are >= 1.
+        int token;
+        if (mNextInstallToken < 0) mNextInstallToken = 1;
+        token = mNextInstallToken++;
+
+        PostInstallData data = new PostInstallData(args, res);
+        mRunningInstalls.put(token, data);
+        if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
+
+        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
+            // Pass responsibility to the Backup Manager.  It will perform a
+            // restore if appropriate, then pass responsibility back to the
+            // Package Manager to run the post-install observer callbacks
+            // and broadcasts.
+            IBackupManager bm = IBackupManager.Stub.asInterface(
+                    ServiceManager.getService(Context.BACKUP_SERVICE));
+            if (bm != null) {
+                if (DEBUG_INSTALL) {
+                    Log.v(TAG, "token " + token + " to BM for possible restore");
+                }
+                Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
+                try {
+                    // TODO: http://b/22388012
+                    if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
+                        bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
+                    } else {
+                        doRestore = false;
+                    }
+                } catch (RemoteException e) {
+                    // can't happen; the backup manager is local
+                } catch (Exception e) {
+                    Slog.e(TAG, "Exception trying to enqueue restore", e);
+                    doRestore = false;
+                }
+            } else {
+                Slog.e(TAG, "Backup Manager not found!");
+                doRestore = false;
+            }
+        }
+
+        if (!doRestore) {
+            // No restore possible, or the Backup Manager was mysteriously not
+            // available -- just fire the post-install work request directly.
+            if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
+
+            Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
+
+            Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
+            mHandler.sendMessage(msg);
+        }
+    }
+
     /**
      * Callback from PackageSettings whenever an app is first transitioned out of the
      * 'stopped' state.  Normally we just issue the broadcast, but we can't do that if
@@ -13836,7 +13810,83 @@
         }
     }
 
+    /**
+     * Container for a multi-package install which refers to all install sessions and args being
+     * committed together.
+     */
+    class MultiPackageInstallParams extends HandlerParams {
+
+        private int mRet = INSTALL_SUCCEEDED;
+        @NonNull
+        private final ArrayList<InstallParams> mChildParams;
+        @NonNull
+        private final Map<InstallArgs, Integer> mVerifiedState;
+
+        MultiPackageInstallParams(
+                @NonNull UserHandle user,
+                @NonNull List<ActiveInstallSession> activeInstallSessions)
+                throws PackageManagerException {
+            super(user);
+            if (activeInstallSessions.size() == 0) {
+                throw new PackageManagerException("No child sessions found!");
+            }
+            mChildParams = new ArrayList<>(activeInstallSessions.size());
+            for (int i = 0; i < activeInstallSessions.size(); i++) {
+                final InstallParams childParams = new InstallParams(activeInstallSessions.get(i));
+                childParams.mParentInstallParams = this;
+                this.mChildParams.add(childParams);
+            }
+            this.mVerifiedState = new ArrayMap<>(mChildParams.size());
+        }
+
+        @Override
+        void handleStartCopy() {
+            for (InstallParams params : mChildParams) {
+                params.handleStartCopy();
+                if (params.mRet != INSTALL_SUCCEEDED) {
+                    mRet = params.mRet;
+                    break;
+                }
+            }
+        }
+
+        @Override
+        void handleReturnCode() {
+            for (InstallParams params : mChildParams) {
+                params.handleReturnCode();
+                if (params.mRet != INSTALL_SUCCEEDED) {
+                    mRet = params.mRet;
+                    break;
+                }
+            }
+        }
+
+        void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
+            mVerifiedState.put(args, currentStatus);
+            boolean success = true;
+            if (mVerifiedState.size() != mChildParams.size()) {
+                return;
+            }
+            for (Integer status : mVerifiedState.values()) {
+                if (status == PackageManager.INSTALL_UNKNOWN) {
+                    return;
+                } else if (status != PackageManager.INSTALL_SUCCEEDED) {
+                    success = false;
+                    break;
+                }
+            }
+            final List<InstallRequest> installRequests = new ArrayList<>(mVerifiedState.size());
+            for (Map.Entry<InstallArgs, Integer> entry : mVerifiedState.entrySet()) {
+                installRequests.add(new InstallRequest(entry.getKey(),
+                        createPackageInstalledInfo(entry.getValue())));
+            }
+            processInstallRequestsAsync(success, installRequests);
+        }
+    }
+
     class InstallParams extends HandlerParams {
+        // TODO: see if we can collapse this into ActiveInstallSession
+
         final OriginInfo origin;
         final MoveInfo move;
         final IPackageInstallObserver2 observer;
@@ -13844,17 +13894,20 @@
         final String installerPackageName;
         final String volumeUuid;
         private InstallArgs mArgs;
-        private int mRet;
+        int mRet;
         final String packageAbiOverride;
         final String[] grantedRuntimePermissions;
         final VerificationInfo verificationInfo;
         final PackageParser.SigningDetails signingDetails;
         final int installReason;
+        @Nullable
+        MultiPackageInstallParams mParentInstallParams;
 
         InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, String installerPackageName, String volumeUuid,
                 VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
-                String[] grantedPermissions, PackageParser.SigningDetails signingDetails, int installReason) {
+                String[] grantedPermissions, PackageParser.SigningDetails signingDetails,
+                int installReason) {
             super(user);
             this.origin = origin;
             this.move = move;
@@ -13869,6 +13922,34 @@
             this.installReason = installReason;
         }
 
+        InstallParams(ActiveInstallSession activeInstallSession) {
+            super(activeInstallSession.getUser());
+            if (DEBUG_INSTANT) {
+                if ((activeInstallSession.getSessionParams().installFlags
+                        & PackageManager.INSTALL_INSTANT_APP) != 0) {
+                    Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
+                }
+            }
+            verificationInfo = new VerificationInfo(
+                    activeInstallSession.getSessionParams().originatingUri,
+                    activeInstallSession.getSessionParams().referrerUri,
+                    activeInstallSession.getSessionParams().originatingUid,
+                    activeInstallSession.getInstallerUid());
+            origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
+            move = null;
+            installReason = fixUpInstallReason(activeInstallSession.getInstallerPackageName(),
+                    activeInstallSession.getInstallerUid(),
+                    activeInstallSession.getSessionParams().installReason);
+            observer = activeInstallSession.getObserver();
+            installFlags = activeInstallSession.getSessionParams().installFlags;
+            installerPackageName = activeInstallSession.getInstallerPackageName();
+            volumeUuid = activeInstallSession.getSessionParams().volumeUuid;
+            packageAbiOverride = activeInstallSession.getSessionParams().abiOverride;
+            grantedRuntimePermissions =
+                    activeInstallSession.getSessionParams().grantedRuntimePermissions;
+            signingDetails = activeInstallSession.getSigningDetails();
+        }
+
         @Override
         public String toString() {
             return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
@@ -14290,6 +14371,7 @@
         final int traceCookie;
         final PackageParser.SigningDetails signingDetails;
         final int installReason;
+        @Nullable final MultiPackageInstallParams mMultiPackageInstallParams;
 
         // The list of instruction sets supported by this app. This is currently
         // only used during the rmdex() phase to clean up resources. We can get rid of this
@@ -14300,8 +14382,9 @@
                 int installFlags, String installerPackageName, String volumeUuid,
                 UserHandle user, String[] instructionSets,
                 String abiOverride, String[] installGrantPermissions,
-                String traceMethod, int traceCookie, PackageParser.SigningDetails signingDetails,
-                int installReason) {
+                String traceMethod, int traceCookie, SigningDetails signingDetails,
+                int installReason,
+                MultiPackageInstallParams multiPackageInstallParams) {
             this.origin = origin;
             this.move = move;
             this.installFlags = installFlags;
@@ -14316,6 +14399,7 @@
             this.traceCookie = traceCookie;
             this.signingDetails = signingDetails;
             this.installReason = installReason;
+            this.mMultiPackageInstallParams = multiPackageInstallParams;
         }
 
         abstract int copyApk();
@@ -14411,7 +14495,7 @@
                     params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
                     params.grantedRuntimePermissions,
                     params.traceMethod, params.traceCookie, params.signingDetails,
-                    params.installReason);
+                    params.installReason, params.mParentInstallParams);
             if (isFwdLocked()) {
                 throw new IllegalArgumentException("Forward locking only supported in ASEC");
             }
@@ -14421,7 +14505,7 @@
         FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
             super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
                     null, null, null, 0, PackageParser.SigningDetails.UNKNOWN,
-                    PackageManager.INSTALL_REASON_UNKNOWN);
+                    PackageManager.INSTALL_REASON_UNKNOWN, null /* parent */);
             this.codeFile = (codePath != null) ? new File(codePath) : null;
             this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
         }
@@ -14613,7 +14697,7 @@
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
                     params.grantedRuntimePermissions,
                     params.traceMethod, params.traceCookie, params.signingDetails,
-                    params.installReason);
+                    params.installReason, params.mParentInstallParams);
         }
 
         int copyApk() {
@@ -15018,10 +15102,10 @@
     }
 
     @GuardedBy({"mInstallLock", "mPackages"})
-    private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo installResult) {
+    private void installPackagesTracedLI(List<InstallRequest> requests) {
         try {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
-            installPackagesLI(Collections.singletonList(new InstallRequest(args, installResult)));
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
+            installPackagesLI(requests);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -15361,7 +15445,7 @@
                             request.installResult.setError(
                                     PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
                                     "Duplicate package " + result.pkgSetting.pkg.packageName
-                                            + " in atomic install request.");
+                                            + " in multi-package install request.");
                             return;
                         }
                     }
@@ -23433,6 +23517,62 @@
 
         return mProtectedPackages.isPackageStateProtected(userId, packageName);
     }
+
+    static class ActiveInstallSession {
+        private final String mPackageName;
+        private final File mStagedDir;
+        private final IPackageInstallObserver2 mObserver;
+        private final PackageInstaller.SessionParams mSessionParams;
+        private final String mInstallerPackageName;
+        private final int mInstallerUid;
+        private final UserHandle mUser;
+        private final SigningDetails mSigningDetails;
+
+        ActiveInstallSession(String packageName, File stagedDir, IPackageInstallObserver2 observer,
+                PackageInstaller.SessionParams sessionParams, String installerPackageName,
+                int installerUid, UserHandle user, SigningDetails signingDetails) {
+            mPackageName = packageName;
+            mStagedDir = stagedDir;
+            mObserver = observer;
+            mSessionParams = sessionParams;
+            mInstallerPackageName = installerPackageName;
+            mInstallerUid = installerUid;
+            mUser = user;
+            mSigningDetails = signingDetails;
+        }
+
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        public File getStagedDir() {
+            return mStagedDir;
+        }
+
+        public IPackageInstallObserver2 getObserver() {
+            return mObserver;
+        }
+
+        public PackageInstaller.SessionParams getSessionParams() {
+            return mSessionParams;
+        }
+
+        public String getInstallerPackageName() {
+            return mInstallerPackageName;
+        }
+
+        public int getInstallerUid() {
+            return mInstallerUid;
+        }
+
+        public UserHandle getUser() {
+            return mUser;
+        }
+
+        public SigningDetails getSigningDetails() {
+            return mSigningDetails;
+        }
+    }
 }
 
 interface PackageSender {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 38bd172..31711e5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -173,6 +173,8 @@
                     return runSetInstallLocation();
                 case "get-install-location":
                     return runGetInstallLocation();
+                case "install-add-session":
+                    return runInstallAddSession();
                 case "move-package":
                     return runMovePackage();
                 case "move-primary-storage":
@@ -983,6 +985,23 @@
         return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
     }
 
+    private int runInstallAddSession() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        final int parentSessionId = Integer.parseInt(getNextArg());
+
+        List<Integer> otherSessionIds = new ArrayList<>();
+        String opt;
+        while ((opt = getNextArg()) != null) {
+            otherSessionIds.add(Integer.parseInt(opt));
+        }
+        if (otherSessionIds.size() == 0) {
+            pw.println("Error: At least two sessions are required.");
+            return 1;
+        }
+        return doInstallAddSession(parentSessionId, ArrayUtils.convertToIntArray(otherSessionIds),
+                true /*logSuccess*/);
+    }
+
     private int runInstallRemove() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
 
@@ -2268,6 +2287,9 @@
                 case "--apex":
                     sessionParams.installFlags |= PackageManager.INSTALL_APEX;
                     break;
+                case "--multi-package":
+                    sessionParams.setMultiPackage();
+                    break;
                 default:
                     throw new IllegalArgumentException("Unknown option " + opt);
             }
@@ -2500,6 +2522,30 @@
         }
     }
 
+    private int doInstallAddSession(int parentId, int[] sessionIds, boolean logSuccess)
+            throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        PackageInstaller.Session session = null;
+        try {
+            session = new PackageInstaller.Session(
+                    mInterface.getPackageInstaller().openSession(parentId));
+            if (!session.isMultiPackage()) {
+                getErrPrintWriter().println(
+                        "Error: parent session ID is not a multi-package session");
+                return 1;
+            }
+            for (int i = 0; i < sessionIds.length; i++) {
+                session.addChildSessionId(sessionIds[i]);
+            }
+            if (logSuccess) {
+                pw.println("Success");
+            }
+            return 0;
+        } finally {
+            IoUtils.closeQuietly(session);
+        }
+    }
+
     private int doRemoveSplit(int sessionId, String splitName, boolean logSuccess)
             throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
@@ -2521,24 +2567,26 @@
         }
     }
 
-    private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
+    private int doCommitSession(int sessionId, boolean logSuccess)
+            throws RemoteException {
+
         final PrintWriter pw = getOutPrintWriter();
         PackageInstaller.Session session = null;
         try {
             session = new PackageInstaller.Session(
                     mInterface.getPackageInstaller().openSession(sessionId));
-
-            // Sanity check that all .dm files match an apk.
-            // (The installer does not support standalone .dm files and will not process them.)
-            try {
-                DexMetadataHelper.validateDexPaths(session.getNames());
-            } catch (IllegalStateException | IOException e) {
-                pw.println("Warning [Could not validate the dex paths: " + e.getMessage() + "]");
+            if (!session.isMultiPackage()) {
+                // Sanity check that all .dm files match an apk.
+                // (The installer does not support standalone .dm files and will not process them.)
+                try {
+                    DexMetadataHelper.validateDexPaths(session.getNames());
+                } catch (IllegalStateException | IOException e) {
+                    pw.println(
+                            "Warning [Could not validate the dex paths: " + e.getMessage() + "]");
+                }
             }
-
             final LocalIntentReceiver receiver = new LocalIntentReceiver();
             session.commit(receiver.getIntentSender());
-
             final Intent result = receiver.getResult();
             final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                     PackageInstaller.STATUS_FAILURE);
@@ -2809,6 +2857,7 @@
         pw.println("       [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
         pw.println("       [--preload] [--instantapp] [--full] [--dont-kill]");
         pw.println("       [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
+        pw.println("       [--multi-package]");
         pw.println("    Like \"install\", but starts an install session.  Use \"install-write\"");
         pw.println("    to push data into the session, and \"install-commit\" to finish.");
         pw.println("");
@@ -2817,6 +2866,9 @@
         pw.println("    will be read from stdin.  Options are:");
         pw.println("      -S: size in bytes of package, required for stdin");
         pw.println("");
+        pw.println("  install-add-session MULTI_PACKAGE_SESSION_ID CHILD_SESSION_IDs");
+        pw.println("    Add one or more session IDs to a multi-package session.");
+        pw.println("");
         pw.println("  install-commit SESSION_ID");
         pw.println("    Commit the given active install session, installing the app.");
         pw.println("");
diff --git a/services/core/java/com/android/server/pm/PackageSessionProvider.java b/services/core/java/com/android/server/pm/PackageSessionProvider.java
new file mode 100644
index 0000000..af11e77
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageSessionProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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.pm;
+
+/** Provides access to individual sessions managed by the install service */
+public interface PackageSessionProvider {
+
+    /**
+     * Get the sessions for the provided session IDs. Null will be returned for session IDs that
+     * do not exist.
+     */
+    PackageInstallerSession getSession(int sessionId);
+
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e2818b7..13bb817 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -20,6 +20,7 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -256,6 +257,7 @@
     private static final String ATTR_USER_SET = "set";
     private static final String ATTR_USER_FIXED = "fixed";
     private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
+    private static final String ATTR_REVOKE_WHEN_REQUESTED = "rwr";
 
     // Flag mask of restored permission grants that are applied at install time
     private static final int USER_RUNTIME_GRANT_MASK =
@@ -2775,13 +2777,13 @@
                 // dataPath   - path to package's data path
                 // seinfo     - seinfo label for the app (assigned at install time)
                 // gids       - supplementary gids this app launches with
+                // profileableFromShellFlag  - 0 or 1 if the package is profileable from shell.
                 //
                 // NOTE: We prefer not to expose all ApplicationInfo flags for now.
                 //
                 // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
                 // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
-                //   frameworks/base/libs/packagelistparser
-                //   system/core/run-as/run-as.c
+                //   system/core/libpackagelistparser
                 //
                 sb.setLength(0);
                 sb.append(ai.packageName);
@@ -2801,6 +2803,8 @@
                 } else {
                     sb.append("none");
                 }
+                sb.append(" ");
+                sb.append(ai.isProfileableByShell() ? "1" : "0");
                 sb.append("\n");
                 writer.append(sb);
             }
@@ -5011,6 +5015,9 @@
                                 if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
                                     pw.print(" revoke_on_upgrade");
                                 }
+                                if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+                                    pw.print(" revoke_when_requested");
+                                }
                                 pw.println();
                             }
                         }
@@ -5326,6 +5333,11 @@
                                     if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
                                         serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
                                     }
+                                    if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)
+                                            != 0) {
+                                        serializer.attribute(null, ATTR_REVOKE_WHEN_REQUESTED,
+                                                "true");
+                                    }
                                     serializer.endTag(null, TAG_PERMISSION_ENTRY);
                                 }
                                 serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
@@ -5512,6 +5524,10 @@
                         if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
                             permBits |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
                         }
+                        if ("true".equals(parser.getAttributeValue(null,
+                                ATTR_REVOKE_WHEN_REQUESTED))) {
+                            permBits |= FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+                        }
 
                         if (isGranted || permBits != 0) {
                             rememberRestoredUserGrantLPr(pkgName, permName, isGranted, permBits, userId);
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 9d1a301..32b2bf0 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.AppOpsManager;
 import android.app.DownloadManager;
 import android.app.SearchManager;
 import android.app.admin.DevicePolicyManager;
@@ -1009,6 +1010,41 @@
         }
     }
 
+    /**
+     * Check if a permission is already fixed or is set by the user.
+     *
+     * <p>A permission should not be set by the default policy if the user or other policies already
+     * set the permission.
+     *
+     * @param flags The flags of the permission
+     *
+     * @return {@code true} iff the permission can be set without violating a policy of the users
+     *         intention
+     */
+    private boolean isFixedOrUserSet(int flags) {
+        return (flags & (PackageManager.FLAG_PERMISSION_USER_SET
+                | PackageManager.FLAG_PERMISSION_USER_FIXED
+                | PackageManager.FLAG_PERMISSION_POLICY_FIXED
+                | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0;
+    }
+
+    /**
+     * Return the background permission for a permission.
+     *
+     * @param permission The name of the foreground permission
+     *
+     * @return The name of the background permission or {@code null} if the permission has no
+     *         background permission
+     */
+    private @Nullable String getBackgroundPermission(@NonNull String permission) {
+        try {
+            return mContext.getPackageManager().getPermissionInfo(permission,
+                    0).backgroundPermission;
+        } catch (NameNotFoundException e) {
+            return null;
+        }
+    }
+
     private void grantRuntimePermissions(PackageInfo pkg,
             Set<String> permissionsWithoutSplits, boolean systemFixed, boolean ignoreSystemPackage,
             int userId) {
@@ -1021,9 +1057,15 @@
             return;
         }
 
+        PackageManager pm = mContext.getPackageManager();
         final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits);
         ApplicationInfo applicationInfo = pkg.applicationInfo;
 
+        int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+        if (systemFixed) {
+            newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+        }
+
         // Automatically attempt to grant split permissions to older APKs
         final List<PermissionManager.SplitPermissionInfo> splitPermissions =
                 mContext.getSystemService(PermissionManager.class).getSplitPermissions();
@@ -1063,9 +1105,28 @@
             }
         }
 
-        final int grantablePermissionCount = requestedPermissions.length;
-        for (int i = 0; i < grantablePermissionCount; i++) {
+        final int numRequestedPermissions = requestedPermissions.length;
+
+        // Sort requested permissions so that all permissions that are a foreground permission (i.e.
+        // permisions that have background permission) are before their background permissions.
+        final String[] sortedRequestedPermissions = new String[numRequestedPermissions];
+        int numForeground = 0;
+        int numOther = 0;
+        for (int i = 0; i < numRequestedPermissions; i++) {
             String permission = requestedPermissions[i];
+            if (getBackgroundPermission(permission) != null) {
+                sortedRequestedPermissions[numForeground] = permission;
+                numForeground++;
+            } else {
+                sortedRequestedPermissions[numRequestedPermissions - 1 - numOther] =
+                        permission;
+                numOther++;
+            }
+        }
+
+        for (int requestedPermissionNum = 0; requestedPermissionNum < numRequestedPermissions;
+                requestedPermissionNum++) {
+            String permission = requestedPermissions[requestedPermissionNum];
 
             // If there is a disabled system app it may request a permission the updated
             // version ot the data partition doesn't, In this case skip the permission.
@@ -1078,13 +1139,14 @@
                 final int flags = mContext.getPackageManager().getPermissionFlags(
                         permission, pkg.packageName, user);
 
-                // If any flags are set to the permission, then it is either set in
-                // its current state by the system or device/profile owner or the user.
-                // In all these cases we do not want to clobber the current state.
+                // Certain flags imply that the permission's current state by the system or
+                // device/profile owner or the user. In these cases we do not want to clobber the
+                // current state.
+                //
                 // Unless the caller wants to override user choices. The override is
                 // to make sure we can grant the needed permission to the default
                 // sms and phone apps after the user chooses this in the UI.
-                if (flags == 0 || ignoreSystemPackage) {
+                if (!isFixedOrUserSet(flags) || ignoreSystemPackage) {
                     // Never clobber policy fixed permissions.
                     // We must allow the grant of a system-fixed permission because
                     // system-fixed is sticky, but the permission itself may be revoked.
@@ -1092,20 +1154,58 @@
                         continue;
                     }
 
+                    int uid = UserHandle.getUid(userId,
+                            UserHandle.getAppId(pkg.applicationInfo.uid));
+                    String op = AppOpsManager.permissionToOp(permission);
+
                     mContext.getPackageManager()
                             .grantRuntimePermission(pkg.packageName, permission, user);
+
+                    mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+                            newFlags, newFlags, user);
+
+                    List<String> fgPerms = mPermissionManager.getBackgroundPermissions()
+                            .get(permission);
+                    if (fgPerms != null) {
+                        int numFgPerms = fgPerms.size();
+                        for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
+                            String fgPerm = fgPerms.get(fgPermNum);
+
+                            if (pm.checkPermission(fgPerm, pkg.packageName)
+                                    == PackageManager.PERMISSION_GRANTED) {
+                                // Upgrade the app-op state of the fg permission to allow bg access
+                                mContext.getSystemService(AppOpsManager.class).setMode(
+                                        AppOpsManager.permissionToOp(fgPerm), uid,
+                                        pkg.packageName, AppOpsManager.MODE_ALLOWED);
+
+                                break;
+                            }
+                        }
+                    }
+
+                    String bgPerm = getBackgroundPermission(permission);
+                    if (bgPerm == null) {
+                        if (op != null) {
+                            mContext.getSystemService(AppOpsManager.class).setMode(op, uid,
+                                    pkg.packageName, AppOpsManager.MODE_ALLOWED);
+                        }
+                    } else {
+                        int mode;
+                        if (pm.checkPermission(bgPerm, pkg.packageName)
+                                == PackageManager.PERMISSION_GRANTED) {
+                            mode = AppOpsManager.MODE_ALLOWED;
+                        } else {
+                            mode = AppOpsManager.MODE_FOREGROUND;
+                        }
+
+                        mContext.getSystemService(AppOpsManager.class).setMode(op, uid,
+                                pkg.packageName, mode);
+                    }
+
                     if (DEBUG) {
                         Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
                                 + permission + " to default handler " + pkg);
                     }
-
-                    int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
-                    if (systemFixed) {
-                        newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
-                    }
-
-                    mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
-                            newFlags, newFlags, user);
                 }
 
                 // If a component gets a permission for being the default handler A
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 18c6a3d..b788935 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -16,10 +16,28 @@
 
 package com.android.server.pm.permission;
 
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.MODE_ERRORED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.permissionToOp;
+import static android.app.AppOpsManager.permissionToOpCode;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.UserHandle.getAppId;
+import static android.os.UserHandle.getUid;
 
 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
@@ -30,6 +48,9 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppOpsManager;
+import android.app.AppOpsManagerInternal;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
@@ -49,6 +70,7 @@
 import android.os.UserManagerInternal;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
+import android.permission.PermissionManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -152,6 +174,13 @@
     @GuardedBy("mLock")
     private boolean mSystemReady;
 
+    /**
+     * For each foreground/background permission the mapping:
+     * Background permission -> foreground permissions
+     */
+    @GuardedBy("mLock")
+    private ArrayMap<String, List<String>> mBackgroundPermissions;
+
     PermissionManagerService(Context context,
             @Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
             @NonNull Object externalLock) {
@@ -680,8 +709,24 @@
         }
     }
 
-    private void grantPermissions(PackageParser.Package pkg, boolean replace,
-            String packageOfInterest, PermissionCallback callback) {
+    /**
+     * Restore the permission state for a package.
+     *
+     * <ul>
+     *     <li>During boot the state gets restored from the disk</li>
+     *     <li>During app update the state gets restored from the last version of the app</li>
+     * </ul>
+     *
+     * <p>This restores the permission state for all users.
+     *
+     * @param pkg the package the permissions belong to
+     * @param replace if the package is getting replaced (this might change the requested
+     *                permissions of this package)
+     * @param packageOfInterest If this is the name of {@code pkg} add extra logging
+     * @param callback Result call back
+     */
+    private void restorePermissionState(@NonNull PackageParser.Package pkg, boolean replace,
+            @Nullable String packageOfInterest, @Nullable PermissionCallback callback) {
         // IMPORTANT: There are two types of permissions: install and runtime.
         // Install time permissions are granted when the app is installed to
         // all device users and users added in the future. Runtime permissions
@@ -809,7 +854,8 @@
                 }
 
                 if (DEBUG_PERMISSIONS) {
-                    Slog.i(TAG, "Granting permission " + perm + " to package " + pkg.packageName);
+                    Slog.i(TAG, "Considering granting permission " + perm + " to package "
+                            + pkg.packageName);
                 }
 
                 if (grant != GRANT_DENIED) {
@@ -998,6 +1044,11 @@
                 // changed.
                 ps.setInstallPermissionsFixed(true);
             }
+
+            updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg,
+                    updatedUserIds);
+            updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
+                    permissionsState, pkg, updatedUserIds);
         }
 
         // Persist the runtime permissions state for users with changes. If permissions
@@ -1008,6 +1059,317 @@
         }
     }
 
+    /**
+     * Set app op for a app-op related to a permission.
+     *
+     * @param permission The permission the app-op belongs to
+     * @param pkg The package the permission belongs to
+     * @param userId The user to be changed
+     * @param mode The new mode to set
+     */
+    private void setAppOpMode(@NonNull String permission, @NonNull PackageParser.Package pkg,
+            @UserIdInt int userId, int mode) {
+        AppOpsManagerInternal appOpsInternal = LocalServices.getService(
+                AppOpsManagerInternal.class);
+
+        appOpsInternal.setMode(permissionToOpCode(permission),
+                getUid(userId, getAppId(pkg.applicationInfo.uid)), pkg.packageName, mode,
+                (pkg.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0);
+    }
+
+    /**
+     * Revoke permissions that are not implicit anymore and that have
+     * {@link PackageManager#FLAG_PERMISSION_REVOKE_WHEN_REQUESTED} set.
+     *
+     * @param ps The state of the permissions of the package
+     * @param pkg The package that is currently looked at
+     * @param updatedUserIds a list of user ids that needs to be amended if the permission state
+     *                       for a user is changed.
+     *
+     * @return The updated value of the {@code updatedUserIds} parameter
+     */
+    private @NonNull int[] revokePermissionsNoLongerImplicitLocked(
+            @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+            @NonNull int[] updatedUserIds) {
+        AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+
+        String pkgName = pkg.packageName;
+
+        int[] users = UserManagerService.getInstance().getUserIds();
+        int numUsers = users.length;
+        for (int i = 0; i < numUsers; i++) {
+            int userId = users[i];
+
+            for (String permission : ps.getPermissions(userId)) {
+                if (!pkg.implicitPermissions.contains(permission)) {
+                    if (!ps.hasInstallPermission(permission)) {
+                        int flags = ps.getRuntimePermissionState(permission, userId).getFlags();
+
+                        if ((flags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+                            BasePermission bp = mSettings.getPermissionLocked(permission);
+
+                            ps.updatePermissionFlags(bp, userId,
+                                    FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
+                                            | FLAG_PERMISSION_USER_FIXED | FLAG_PERMISSION_USER_SET,
+                                    0);
+                            updatedUserIds = ArrayUtils.appendInt(updatedUserIds,
+                                    userId);
+
+                            if ((flags & (FLAG_PERMISSION_GRANTED_BY_DEFAULT
+                                    | FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED))
+                                    == 0) {
+                                if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+                                    if (permissionToOpCode(permission) != OP_NONE) {
+                                        setAppOpMode(permission, pkg, userId, MODE_IGNORED);
+
+                                        if (DEBUG_PERMISSIONS) {
+                                            Slog.i(TAG, "Revoking app-op "
+                                                    + permissionToOp(permission) + " for " + pkgName
+                                                    + " as it is now requested");
+                                        }
+                                    }
+                                } else {
+                                    int revokeResult = ps.revokeRuntimePermission(bp, userId);
+                                    if (revokeResult
+                                            != PermissionsState.PERMISSION_OPERATION_FAILURE) {
+
+                                        if (DEBUG_PERMISSIONS) {
+                                            Slog.i(TAG, "Revoking runtime permission " + permission
+                                                    + " for " + pkgName
+                                                    + " as it is now requested");
+                                        }
+                                    }
+                                }
+
+                                List<String> fgPerms = mBackgroundPermissions.get(permission);
+                                if (fgPerms != null) {
+                                    int numFgPerms = fgPerms.size();
+                                    for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
+                                        String fgPerm = fgPerms.get(fgPermNum);
+
+                                        int mode = appOpsManager.unsafeCheckOpRaw(
+                                                permissionToOp(fgPerm),
+                                                getUid(userId, getAppId(pkg.applicationInfo.uid)),
+                                                pkgName);
+
+                                        if (mode == MODE_ALLOWED) {
+                                            setAppOpMode(fgPerm, pkg, userId, MODE_FOREGROUND);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return updatedUserIds;
+    }
+
+    /**
+     * {@code newPerm} is newly added; Inherit the state from {@code sourcePerms}.
+     *
+     * <p>A single new permission can be split off from several source permissions. In this case
+     * the most leniant state is inherited.
+     *
+     * <p>Warning: This does not handle foreground / background permissions
+     *
+     * @param sourcePerms The permissions to inherit from
+     * @param newPerm The permission to inherit to
+     * @param ps The permission state of the package
+     * @param pkg The package requesting the permissions
+     * @param userId The user the permission belongs to
+     */
+    private void inheritPermissionStateToNewImplicitPermissionLocked(
+            @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm,
+            @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+            @UserIdInt int userId) {
+        AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+        String pkgName = pkg.packageName;
+
+        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+            if (permissionToOp(newPerm) != null) {
+                int mostLenientSourceMode = MODE_ERRORED;
+
+                // Find most lenient source permission state.
+                int numSourcePerms = sourcePerms.size();
+                for (int i = 0; i < numSourcePerms; i++) {
+                    String sourcePerm = sourcePerms.valueAt(i);
+
+                    if (ps.hasRuntimePermission(sourcePerm, userId)) {
+                        String sourceOp = permissionToOp(sourcePerm);
+
+                        if (sourceOp != null) {
+                            int mode = appOpsManager.unsafeCheckOpRaw(sourceOp,
+                                    getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName);
+
+                            if (mode == MODE_FOREGROUND) {
+                                throw new IllegalArgumentException("split permission" + sourcePerm
+                                        + " has app-op state " + AppOpsManager.MODE_NAMES[mode]);
+                            }
+
+                            // Leniency order: allowed > ignored > default
+                            if (mode == MODE_ALLOWED) {
+                                mostLenientSourceMode = MODE_ALLOWED;
+                                break;
+                            } else if (mode == MODE_IGNORED) {
+                                mostLenientSourceMode = MODE_IGNORED;
+                            } else if (mode == MODE_DEFAULT
+                                    && mostLenientSourceMode != MODE_IGNORED) {
+                                mostLenientSourceMode = MODE_DEFAULT;
+                            }
+                        }
+                    }
+                }
+
+                if (mostLenientSourceMode != MODE_ERRORED) {
+                    if (DEBUG_PERMISSIONS) {
+                        Slog.i(TAG, newPerm + " inherits app-ops state " + mostLenientSourceMode
+                                + " from " + sourcePerms + " for " + pkgName);
+                    }
+
+                    setAppOpMode(newPerm, pkg, userId, mostLenientSourceMode);
+                }
+            }
+        } else {
+            boolean isGranted = false;
+
+            int numSourcePerm = sourcePerms.size();
+            for (int i = 0; i < numSourcePerm; i++) {
+                String sourcePerm = sourcePerms.valueAt(i);
+                if (ps.hasRuntimePermission(sourcePerm, userId)
+                        && ps.getRuntimePermissionState(sourcePerm, userId).isGranted()) {
+                    isGranted = true;
+                    break;
+                }
+            }
+
+            if (isGranted) {
+                if (DEBUG_PERMISSIONS) {
+                    Slog.i(TAG, newPerm + " inherits runtime perm grant from " + sourcePerms
+                            + " for " + pkgName);
+                }
+
+                ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId);
+            }
+        }
+    }
+
+    /**
+     * Set the state of a implicit permission that is seen for the first time.
+     *
+     * @param origPs The permission state of the package before the split
+     * @param ps The new permission state
+     * @param pkg The package the permission belongs to
+     * @param updatedUserIds List of users for which the permission state has already been changed
+     *
+     * @return  List of users for which the permission state has been changed
+     */
+    private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked(
+            @NonNull PermissionsState origPs,
+            @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+            @NonNull int[] updatedUserIds) {
+        AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+
+        String pkgName = pkg.packageName;
+        ArraySet<String> newImplicitPermissions = new ArraySet<>();
+
+        int numRequestedPerms = pkg.requestedPermissions.size();
+        for (int i = 0; i < numRequestedPerms; i++) {
+            BasePermission bp = mSettings.getPermissionLocked(pkg.requestedPermissions.get(i));
+            if (bp != null) {
+                String perm = bp.getName();
+
+                if (!origPs.hasRequestedPermission(perm) && pkg.implicitPermissions.contains(
+                        perm)) {
+                    newImplicitPermissions.add(perm);
+
+                    if (DEBUG_PERMISSIONS) {
+                        Slog.i(TAG, perm + " is newly added for " + pkgName);
+                    }
+                }
+            }
+        }
+
+        ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
+
+        int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size();
+        for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
+            PermissionManager.SplitPermissionInfo spi =
+                    PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum);
+
+            List<String> newPerms = spi.getNewPermissions();
+            int numNewPerms = newPerms.size();
+            for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
+                String newPerm = newPerms.get(newPermNum);
+
+                ArraySet<String> splitPerms = newToSplitPerms.get(newPerm);
+                if (splitPerms == null) {
+                    splitPerms = new ArraySet<>();
+                    newToSplitPerms.put(newPerm, splitPerms);
+                }
+
+                splitPerms.add(spi.getSplitPermission());
+            }
+        }
+
+        int numNewImplicitPerms = newImplicitPermissions.size();
+        for (int newImplicitPermNum = 0; newImplicitPermNum < numNewImplicitPerms;
+                newImplicitPermNum++) {
+            String newPerm = newImplicitPermissions.valueAt(newImplicitPermNum);
+            ArraySet<String> sourcePerms = newToSplitPerms.get(newPerm);
+
+            if (sourcePerms != null) {
+                if (!ps.hasInstallPermission(newPerm)) {
+                    BasePermission bp = mSettings.getPermissionLocked(newPerm);
+
+                    int[] users = UserManagerService.getInstance().getUserIds();
+                    int numUsers = users.length;
+                    for (int userNum = 0; userNum < numUsers; userNum++) {
+                        int userId = users[userNum];
+
+                        ps.updatePermissionFlags(bp, userId,
+                                FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
+                                FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
+                        updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+
+                        // SPECIAL BEHAVIOR for background location. Foreground only by default.
+                        if (newPerm.equals(ACCESS_BACKGROUND_LOCATION)) {
+                            int numSourcePerms = sourcePerms.size();
+                            for (int sourcePermNum = 0; sourcePermNum < numSourcePerms;
+                                    sourcePermNum++) {
+                                String sourcePerm = sourcePerms.valueAt(sourcePermNum);
+
+                                if (appOpsManager.unsafeCheckOpNoThrow(permissionToOp(sourcePerm),
+                                        getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName)
+                                        == MODE_ALLOWED) {
+                                    setAppOpMode(sourcePerm, pkg, userId, MODE_FOREGROUND);
+                                }
+                            }
+                        } else {
+                            if (!origPs.hasRequestedPermission(sourcePerms)) {
+                                // Both permissions are new, do nothing
+                                if (DEBUG_PERMISSIONS) {
+                                    Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms
+                                            + " for " + pkgName
+                                            + " as split permission is also new");
+                                }
+
+                                break;
+                            } else {
+                                inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms,
+                                        newPerm, ps, pkg, userId);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return updatedUserIds;
+    }
+
     private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
         boolean allowed = false;
         final int NP = PackageParser.NEW_PERMISSIONS.length;
@@ -1754,7 +2116,30 @@
         // and make sure there are no dangling permissions.
         flags = updatePermissions(changingPkgName, changingPkg, flags);
 
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "grantPermissions");
+        synchronized (mLock) {
+            if (mBackgroundPermissions == null) {
+                // Cache background -> foreground permission mapping.
+                // Only system declares background permissions, hence mapping does never change.
+                mBackgroundPermissions = new ArrayMap<>();
+                for (BasePermission bp : mSettings.getAllPermissionsLocked()) {
+                    if (bp.perm != null && bp.perm.info != null
+                            && bp.perm.info.backgroundPermission != null) {
+                        String fgPerm = bp.name;
+                        String bgPerm = bp.perm.info.backgroundPermission;
+
+                        List<String> fgPerms = mBackgroundPermissions.get(bgPerm);
+                        if (fgPerms == null) {
+                            fgPerms = new ArrayList<>();
+                            mBackgroundPermissions.put(bgPerm, fgPerms);
+                        }
+
+                        fgPerms.add(fgPerm);
+                    }
+                }
+            }
+        }
+
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "restorePermissionState");
         // Now update the permissions for all packages, in particular
         // replace the granted permissions of the system packages.
         if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {
@@ -1764,7 +2149,7 @@
                     final String volumeUuid = getVolumeUuidForPackage(pkg);
                     final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)
                             && Objects.equals(replaceVolumeUuid, volumeUuid);
-                    grantPermissions(pkg, replace, changingPkgName, callback);
+                    restorePermissionState(pkg, replace, changingPkgName, callback);
                 }
             }
         }
@@ -1774,7 +2159,7 @@
             final String volumeUuid = getVolumeUuidForPackage(changingPkg);
             final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
                     && Objects.equals(replaceVolumeUuid, volumeUuid);
-            grantPermissions(changingPkg, replace, changingPkgName, callback);
+            restorePermissionState(changingPkg, replace, changingPkgName, callback);
         }
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
@@ -2071,6 +2456,17 @@
         mMetricsLogger.write(log);
     }
 
+    /**
+     * Get the mapping of background permissions to their foreground permissions.
+     *
+     * <p>Only initialized in the system server.
+     *
+     * @return the map &lt;bg permission -> list&lt;fg perm&gt;&gt;
+     */
+    public @Nullable ArrayMap<String, List<String>> getBackgroundPermissions() {
+        return mBackgroundPermissions;
+    }
+
     private class PermissionManagerInternalImpl extends PermissionManagerInternal {
         @Override
         public void systemReady() {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1dae396..97af045 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -41,6 +41,7 @@
 import static android.os.Build.VERSION_CODES.O;
 import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.Display.STATE_OFF;
 import static android.view.WindowManager.DOCKED_LEFT;
 import static android.view.WindowManager.DOCKED_RIGHT;
@@ -155,6 +156,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
@@ -665,9 +667,6 @@
     SleepToken mDreamingSleepToken;
     SleepToken mScreenOffSleepToken;
     volatile boolean mKeyguardOccluded;
-    boolean mHomePressed;
-    boolean mHomeConsumed;
-    boolean mHomeDoubleTapPending;
     Intent mHomeIntent;
     Intent mCarDockIntent;
     Intent mDeskDockIntent;
@@ -865,7 +864,7 @@
                     launchVoiceAssistWithWakeLock();
                     break;
                 case MSG_POWER_DELAYED_PRESS:
-                    powerPress((Long)msg.obj, msg.arg1 != 0, msg.arg2);
+                    powerPress((Long) msg.obj, msg.arg1 != 0, msg.arg2);
                     finishPowerKeyPress();
                     break;
                 case MSG_POWER_LONG_PRESS:
@@ -1340,7 +1339,7 @@
                 case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
                     goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
                             PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
-                    launchHomeFromHotKey();
+                    launchHomeFromHotKey(DEFAULT_DISPLAY);
                     break;
                 case SHORT_PRESS_POWER_GO_HOME:
                     shortPressPowerGoHome();
@@ -1369,7 +1368,8 @@
     }
 
     private void shortPressPowerGoHome() {
-        launchHomeFromHotKey(true /* awakenFromDreams */, false /*respectKeyguard*/);
+        launchHomeFromHotKey(DEFAULT_DISPLAY, true /* awakenFromDreams */,
+                false /*respectKeyguard*/);
         if (isKeyguardShowingAndNotOccluded()) {
             // Notify keyguard so it can do any special handling for the power button since the
             // device will not power off and only launch home.
@@ -1505,7 +1505,8 @@
 
     private void sleepPress() {
         if (mShortPressOnSleepBehavior == SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME) {
-            launchHomeFromHotKey(false /* awakenDreams */, true /*respectKeyguard*/);
+            launchHomeFromHotKey(DEFAULT_DISPLAY, false /* awakenDreams */,
+                    true /*respectKeyguard*/);
         }
     }
 
@@ -1683,7 +1684,7 @@
                 Settings.Secure.TV_USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
     }
 
-    private void handleShortPressOnHome() {
+    private void handleShortPressOnHome(int displayId) {
         // Turn on the connected TV and switch HDMI input if we're a HDMI playback device.
         final HdmiControl hdmiControl = getHdmiControl();
         if (hdmiControl != null) {
@@ -1698,7 +1699,7 @@
         }
 
         // Go home!
-        launchHomeFromHotKey();
+        launchHomeFromHotKey(displayId);
     }
 
     /**
@@ -1745,26 +1746,6 @@
         }
     }
 
-    private void handleLongPressOnHome(int deviceId) {
-        if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_NOTHING) {
-            return;
-        }
-        mHomeConsumed = true;
-        performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
-                "Home - Long Press");
-        switch (mLongPressOnHomeBehavior) {
-            case LONG_PRESS_HOME_ALL_APPS:
-                launchAllAppsAction();
-                break;
-            case LONG_PRESS_HOME_ASSIST:
-                launchAssistAction(null, deviceId);
-                break;
-            default:
-                Log.w(TAG, "Undefined home long press behavior: " + mLongPressOnHomeBehavior);
-                break;
-        }
-    }
-
     private void launchAllAppsAction() {
         Intent intent = new Intent(Intent.ACTION_ALL_APPS);
         if (mHasFeatureLeanback) {
@@ -1781,13 +1762,6 @@
         startActivityAsUser(intent, UserHandle.CURRENT);
     }
 
-    private void handleDoubleTapOnHome() {
-        if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
-            mHomeConsumed = true;
-            toggleRecentApps();
-        }
-    }
-
     private void showPictureInPictureMenu(KeyEvent event) {
         if (DEBUG_INPUT) Log.d(TAG, "showPictureInPictureMenu event=" + event);
         mHandler.removeMessages(MSG_SHOW_PICTURE_IN_PICTURE_MENU);
@@ -1803,15 +1777,147 @@
         }
     }
 
-    private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
-        @Override
-        public void run() {
-            if (mHomeDoubleTapPending) {
-                mHomeDoubleTapPending = false;
-                handleShortPressOnHome();
+    /** A handler to handle home keys per display */
+    private class DisplayHomeButtonHandler {
+
+        private final int mDisplayId;
+
+        private boolean mHomeDoubleTapPending;
+        private boolean mHomePressed;
+        private boolean mHomeConsumed;
+
+        private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
+            @Override
+            public void run() {
+                if (mHomeDoubleTapPending) {
+                    mHomeDoubleTapPending = false;
+                    handleShortPressOnHome(mDisplayId);
+                }
+            }
+        };
+
+        DisplayHomeButtonHandler(int displayId) {
+            mDisplayId = displayId;
+        }
+
+        int handleHomeButton(WindowState win, KeyEvent event) {
+            final boolean keyguardOn = keyguardOn();
+            final int repeatCount = event.getRepeatCount();
+            final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+            final boolean canceled = event.isCanceled();
+
+            if (DEBUG_INPUT) {
+                Log.d(TAG, String.format("handleHomeButton in display#%d mHomePressed = %b",
+                        mDisplayId, mHomePressed));
+            }
+
+            // If we have released the home key, and didn't do anything else
+            // while it was pressed, then it is time to go home!
+            if (!down) {
+                if (mDisplayId == DEFAULT_DISPLAY) {
+                    cancelPreloadRecentApps();
+                }
+
+                mHomePressed = false;
+                if (mHomeConsumed) {
+                    mHomeConsumed = false;
+                    return -1;
+                }
+
+                if (canceled) {
+                    Log.i(TAG, "Ignoring HOME; event canceled.");
+                    return -1;
+                }
+
+                // Delay handling home if a double-tap is possible.
+                if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
+                    mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
+                    mHomeDoubleTapPending = true;
+                    mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
+                            ViewConfiguration.getDoubleTapTimeout());
+                    return -1;
+                }
+
+                handleShortPressOnHome(mDisplayId);
+                return -1;
+            }
+
+            // If a system window has focus, then it doesn't make sense
+            // right now to interact with applications.
+            WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
+            if (attrs != null) {
+                final int type = attrs.type;
+                if (type == TYPE_KEYGUARD_DIALOG
+                        || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+                    // the "app" is keyguard, so give it the key
+                    return 0;
+                }
+                for (int t : WINDOW_TYPES_WHERE_HOME_DOESNT_WORK) {
+                    if (type == t) {
+                        // don't do anything, but also don't pass it to the app
+                        return -1;
+                    }
+                }
+            }
+
+            // Remember that home is pressed and handle special actions.
+            if (repeatCount == 0) {
+                mHomePressed = true;
+                if (mHomeDoubleTapPending) {
+                    mHomeDoubleTapPending = false;
+                    mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
+                    handleDoubleTapOnHome();
+                // TODO(multi-display): Remove display id check once we support recents on
+                // multi-display
+                } else if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI
+                        && mDisplayId == DEFAULT_DISPLAY) {
+                    preloadRecentApps();
+                }
+            } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+                if (!keyguardOn) {
+                    handleLongPressOnHome(event.getDeviceId());
+                }
+            }
+            return -1;
+        }
+
+        private void handleDoubleTapOnHome() {
+            if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
+                mHomeConsumed = true;
+                toggleRecentApps();
             }
         }
-    };
+
+        private void handleLongPressOnHome(int deviceId) {
+            if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_NOTHING) {
+                return;
+            }
+            mHomeConsumed = true;
+            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
+                    "Home - Long Press");
+            switch (mLongPressOnHomeBehavior) {
+                case LONG_PRESS_HOME_ALL_APPS:
+                    launchAllAppsAction();
+                    break;
+                case LONG_PRESS_HOME_ASSIST:
+                    launchAssistAction(null, deviceId);
+                    break;
+                default:
+                    Log.w(TAG, "Undefined home long press behavior: "
+                            + mLongPressOnHomeBehavior);
+                    break;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("mDisplayId = %d, mHomePressed = %b", mDisplayId, mHomePressed);
+        }
+    }
+
+    /** A DisplayHomeButtonHandler map indexed by display id */
+    private final SparseArray<DisplayHomeButtonHandler> mDisplayHomeButtonHandlers =
+            new SparseArray<>();
 
     private boolean isRoundWindow() {
         return mContext.getResources().getConfiguration().isScreenRound();
@@ -3259,6 +3365,7 @@
             WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
         };
 
+    // TODO(b/117479243): handle it in InputPolicy
     /** {@inheritDoc} */
     @Override
     public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
@@ -3269,11 +3376,11 @@
         final int flags = event.getFlags();
         final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
         final boolean canceled = event.isCanceled();
+        final int displayId = event.getDisplayId();
 
         if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
-                    + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed
-                    + " canceled=" + canceled);
+                    + repeatCount + " keyguardOn=" + keyguardOn + " canceled=" + canceled);
         }
 
         // If we think we might have a volume down & power key chord on the way
@@ -3358,71 +3465,12 @@
         // it handle it, because that gives us the correct 5 second
         // timeout.
         if (keyCode == KeyEvent.KEYCODE_HOME) {
-
-            // If we have released the home key, and didn't do anything else
-            // while it was pressed, then it is time to go home!
-            if (!down) {
-                cancelPreloadRecentApps();
-
-                mHomePressed = false;
-                if (mHomeConsumed) {
-                    mHomeConsumed = false;
-                    return -1;
-                }
-
-                if (canceled) {
-                    Log.i(TAG, "Ignoring HOME; event canceled.");
-                    return -1;
-                }
-
-                // Delay handling home if a double-tap is possible.
-                if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
-                    mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
-                    mHomeDoubleTapPending = true;
-                    mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
-                            ViewConfiguration.getDoubleTapTimeout());
-                    return -1;
-                }
-
-                handleShortPressOnHome();
-                return -1;
+            DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(displayId);
+            if (handler == null) {
+                handler = new DisplayHomeButtonHandler(displayId);
+                mDisplayHomeButtonHandlers.put(displayId, handler);
             }
-
-            // If a system window has focus, then it doesn't make sense
-            // right now to interact with applications.
-            WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
-            if (attrs != null) {
-                final int type = attrs.type;
-                if (type == TYPE_KEYGUARD_DIALOG
-                        || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                    // the "app" is keyguard, so give it the key
-                    return 0;
-                }
-                final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
-                for (int i=0; i<typeCount; i++) {
-                    if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
-                        // don't do anything, but also don't pass it to the app
-                        return -1;
-                    }
-                }
-            }
-
-            // Remember that home is pressed and handle special actions.
-            if (repeatCount == 0) {
-                mHomePressed = true;
-                if (mHomeDoubleTapPending) {
-                    mHomeDoubleTapPending = false;
-                    mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
-                    handleDoubleTapOnHome();
-                } else if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
-                    preloadRecentApps();
-                }
-            } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
-                if (!keyguardOn) {
-                    handleLongPressOnHome(event.getDeviceId());
-                }
-            }
-            return -1;
+            return handler.handleHomeButton(win, event);
         } else if (keyCode == KeyEvent.KEYCODE_MENU) {
             // Hijack modified menu keys for debugging features
             final int chordBug = KeyEvent.META_SHIFT_ON;
@@ -3820,6 +3868,7 @@
         }
     }
 
+    // TODO(b/117479243): handle it in InputPolicy
     /** {@inheritDoc} */
     @Override
     public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
@@ -3862,7 +3911,7 @@
                         event.getAction(), fallbackAction.keyCode,
                         event.getRepeatCount(), fallbackAction.metaState,
                         event.getDeviceId(), event.getScanCode(),
-                        flags, event.getSource(), null);
+                        flags, event.getSource(), event.getDisplayId(), null);
 
                 if (!interceptFallback(win, fallbackEvent, policyFlags)) {
                     fallbackEvent.recycle();
@@ -3991,8 +4040,12 @@
     }
 
     private void startActivityAsUser(Intent intent, UserHandle handle) {
+        startActivityAsUser(intent, null, handle);
+    }
+
+    private void startActivityAsUser(Intent intent, Bundle bundle, UserHandle handle) {
         if (isUserSetupComplete()) {
-            mContext.startActivityAsUser(intent, handle);
+            mContext.startActivityAsUser(intent, bundle, handle);
         } else {
             Slog.i(TAG, "Not starting activity because user setup is in progress: " + intent);
         }
@@ -4067,15 +4120,16 @@
         }
     }
 
-    void launchHomeFromHotKey() {
-        launchHomeFromHotKey(true /* awakenFromDreams */, true /*respectKeyguard*/);
+    void launchHomeFromHotKey(int displayId) {
+        launchHomeFromHotKey(displayId, true /* awakenFromDreams */, true /*respectKeyguard*/);
     }
 
     /**
      * A home key -> launch home action was detected.  Take the appropriate action
      * given the situation with the keyguard.
      */
-    void launchHomeFromHotKey(final boolean awakenFromDreams, final boolean respectKeyguard) {
+    void launchHomeFromHotKey(int displayId, final boolean awakenFromDreams,
+            final boolean respectKeyguard) {
         // Abort possibly stuck animations.
         mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
 
@@ -4092,7 +4146,7 @@
                     @Override
                     public void onKeyguardExitResult(boolean success) {
                         if (success) {
-                            startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
+                            startDockOrHome(displayId, true /*fromHomeKey*/, awakenFromDreams);
                         }
                     }
                 });
@@ -4113,7 +4167,7 @@
             hideRecentApps(false, true);
         } else {
             // Otherwise, just launch Home
-            startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
+            startDockOrHome(displayId, true /*fromHomeKey*/, awakenFromDreams);
         }
     }
 
@@ -5677,7 +5731,7 @@
         mDefaultDisplayPolicy.setHdmiPlugged(plugged, true /* force */);
     }
 
-
+    // TODO(b/117479243): handle it in InputPolicy
     /** {@inheritDoc} */
     @Override
     public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
@@ -5690,6 +5744,7 @@
         final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
         final boolean canceled = event.isCanceled();
         final int keyCode = event.getKeyCode();
+        final int displayId = event.getDisplayId();
 
         final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
 
@@ -6193,7 +6248,7 @@
         return true;
     }
 
-
+    // TODO(b/117479243): handle it in InputPolicy
     /** {@inheritDoc} */
     @Override
     public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
@@ -7269,7 +7324,7 @@
         return null;
     }
 
-    void startDockOrHome(boolean fromHomeKey, boolean awakenFromDreams) {
+    void startDockOrHome(int displayId, boolean fromHomeKey, boolean awakenFromDreams) {
         try {
             ActivityManager.getService().stopAppSwitches();
         } catch (RemoteException e) {}
@@ -7299,8 +7354,13 @@
         } else {
             intent = mHomeIntent;
         }
+        final Bundle bundle = getLaunchDisplayIdBundle(displayId);
+        startActivityAsUser(intent, bundle, UserHandle.CURRENT);
+    }
 
-        startActivityAsUser(intent, UserHandle.CURRENT);
+    private @Nullable Bundle getLaunchDisplayIdBundle(int displayId) {
+        return (displayId == INVALID_DISPLAY) ? null
+                : ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
     }
 
     /**
@@ -7314,7 +7374,7 @@
         }
         if (false) {
             // This code always brings home to the front.
-            startDockOrHome(false /*fromHomeKey*/, true /* awakenFromDreams */);
+            startDockOrHome(DEFAULT_DISPLAY, false /*fromHomeKey*/, true /* awakenFromDreams */);
         } else {
             // This code brings home to the front or, if it is already
             // at the front, puts the device to sleep.
@@ -7325,7 +7385,7 @@
                 } else {
                     ActivityManager.getService().stopAppSwitches();
                     sendCloseSystemWindows();
-                    Intent dock = createHomeDockIntent();
+                    final Intent dock = createHomeDockIntent();
                     if (dock != null) {
                         int result = ActivityTaskManager.getService()
                                 .startActivityAsUser(null, null, dock,
@@ -8013,7 +8073,13 @@
                 pw.print(incallBackBehaviorToString(mIncallBackBehavior));
                 pw.print(" mEndcallBehavior=");
                 pw.println(endcallBehaviorToString(mEndcallBehavior));
-        pw.print(prefix); pw.print("mHomePressed="); pw.println(mHomePressed);
+        pw.print(prefix);
+        // TODO(b/117479243): handle it in InputPolicy
+        pw.print("mDisplayHomeButtonHandlers=");
+        for (int i = 0; i < mDisplayHomeButtonHandlers.size(); i++) {
+            final int key = mDisplayHomeButtonHandlers.keyAt(i);
+            pw.println(mDisplayHomeButtonHandlers.get(key));
+        }
         pw.print(prefix); pw.print("mDockLayer="); pw.print(mDockLayer);
                 pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
         pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 5323b1f..6d7b04c 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -57,9 +57,6 @@
 
     public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
 
-    // Secure setting for GPS behavior when battery saver mode is on.
-    public static final String SECURE_KEY_GPS_MODE = "batterySaverGpsMode";
-
     private static final String KEY_GPS_MODE = "gps_mode";
     private static final String KEY_VIBRATION_DISABLED = "vibration_disabled";
     private static final String KEY_ANIMATION_DISABLED = "animation_disabled";
@@ -101,6 +98,28 @@
     private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i";
     private static final String KEY_CPU_FREQ_NONINTERACTIVE = "cpufreq-n";
 
+    private static final Policy sDefaultPolicy = new Policy(
+            0.5f,  /* adjustBrightnessFactor */
+            true,  /* deferFullBackup */
+            true,  /* deferKeyValueBackup */
+            false, /* disableAnimation */
+            true,  /* disableAod */
+            true,  /* disableLaunchBoost */
+            true,  /* disableOptionalSensors */
+            true,  /* disableSoundTrigger */
+            true,  /* disableVibration */
+            false, /* enableAdjustBrightness */
+            false, /* enableDataSaver */
+            true,  /* enableFirewall */
+            false, /* enableQuickDoze */
+            new ArrayMap<>(), /* filesForInteractive */
+            new ArrayMap<>(), /* filesForNoninteractive */
+            true, /* forceAllAppsStandby */
+            true, /* forceBackgroundCheck */
+            PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF, /* gpsMode */
+            false /* sendTronLog */
+    );
+
     private final Object mLock;
     private final Handler mHandler;
 
@@ -120,146 +139,20 @@
     private String mEventLogKeys;
 
     /**
-     * {@code true} if vibration is disabled in battery saver mode.
-     *
-     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_VIBRATION_DISABLED
-     */
-    @GuardedBy("mLock")
-    private boolean mVibrationDisabledConfig;
-
-    /**
-     * Whether vibration should *really* be disabled -- i.e. {@link #mVibrationDisabledConfig}
+     * Whether vibration should *really* be disabled -- i.e. {@link Policy#disableVibration}
      * is true *and* {@link #mAccessibilityEnabled} is false.
      */
     @GuardedBy("mLock")
-    private boolean mVibrationDisabledEffective;
+    private boolean mDisableVibrationEffective;
 
     /**
-     * {@code true} if animation is disabled in battery saver mode.
-     *
-     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_ANIMATION_DISABLED
+     * Whether accessibility is currently enabled or not.
      */
     @GuardedBy("mLock")
-    private boolean mAnimationDisabled;
+    private boolean mAccessibilityEnabled;
 
-    /**
-     * {@code true} if sound trigger is disabled in battery saver mode
-     * in battery saver mode.
-     *
-     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_SOUNDTRIGGER_DISABLED
-     */
     @GuardedBy("mLock")
-    private boolean mSoundTriggerDisabled;
-
-    /**
-     * {@code true} if full backup is deferred in battery saver mode.
-     *
-     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_FULLBACKUP_DEFERRED
-     */
-    @GuardedBy("mLock")
-    private boolean mFullBackupDeferred;
-
-    /**
-     * {@code true} if key value backup is deferred in battery saver mode.
-     *
-     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_KEYVALUE_DEFERRED
-     */
-    @GuardedBy("mLock")
-    private boolean mKeyValueBackupDeferred;
-
-    /**
-     * {@code true} if network policy firewall should be turned on in battery saver mode.
-     *
-     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_ACTIVATE_FIREWALL_DISABLED
-     */
-    @GuardedBy("mLock")
-    private boolean mEnableFirewall;
-
-    /**
-     * {@code true} if low power mode brightness adjustment should be turned on in battery saver
-     * mode.
-     *
-     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
-     */
-    @GuardedBy("mLock")
-    private boolean mEnableAdjustBrightness;
-
-    /**
-     * {@code true} if data saver should be turned on in battery saver mode.
-     *
-     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_ACTIVATE_DATASAVER_DISABLED
-     */
-    @GuardedBy("mLock")
-    private boolean mEnableDataSaver;
-
-    /**
-     * {@code true} if launch boost should be disabled on battery saver.
-     */
-    @GuardedBy("mLock")
-    private boolean mLaunchBoostDisabled;
-
-    /**
-     * This is the flag to decide the gps mode in battery saver mode.
-     *
-     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_GPS_MODE
-     */
-    @GuardedBy("mLock")
-    private int mGpsMode;
-
-    /**
-     * This is the flag to decide the how much to adjust the screen brightness. This is
-     * the float value from 0 to 1 where 1 means don't change brightness.
-     *
-     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
-     */
-    @GuardedBy("mLock")
-    private float mAdjustBrightnessFactor;
-
-    /**
-     * Whether to put all apps in the stand-by mode.
-     */
-    @GuardedBy("mLock")
-    private boolean mForceAllAppsStandby;
-
-    /**
-     * Whether to put all apps in the stand-by mode.
-     */
-    @GuardedBy("mLock")
-    private boolean mForceBackgroundCheck;
-
-    /**
-     * Whether to show non-essential sensors (e.g. edge sensors) or not.
-     */
-    @GuardedBy("mLock")
-    private boolean mOptionalSensorsDisabled;
-
-    /**
-     * Whether AOD is enabled or not.
-     */
-    @GuardedBy("mLock")
-    private boolean mAodDisabled;
-
-    /**
-     * Whether Quick Doze is enabled or not.
-     */
-    @GuardedBy("mLock")
-    private boolean mQuickDozeEnabled;
-
-    /**
-     * Whether BatterySavingStats should send tron events.
-     */
-    @GuardedBy("mLock")
-    private boolean mSendTronLog;
+    private Policy mCurrPolicy = sDefaultPolicy;
 
     private final Context mContext;
     private final ContentResolver mContentResolver;
@@ -268,30 +161,6 @@
     @GuardedBy("mLock")
     private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>();
 
-    /**
-     * List of [Filename -> content] that should be written when battery saver is activated
-     * and the device is interactive.
-     *
-     * We use this to change the max CPU frequencies.
-     */
-    @GuardedBy("mLock")
-    private ArrayMap<String, String> mFilesForInteractive;
-
-    /**
-     * List of [Filename -> content] that should be written when battery saver is activated
-     * and the device is non-interactive.
-     *
-     * We use this to change the max CPU frequencies.
-     */
-    @GuardedBy("mLock")
-    private ArrayMap<String, String> mFilesForNoninteractive;
-
-    /**
-     * Whether accessibility is enabled or not.
-     */
-    @GuardedBy("mLock")
-    private boolean mAccessibilityEnabled;
-
     public interface BatterySaverPolicyListener {
         void onBatterySaverPolicyChanged(BatterySaverPolicy policy);
     }
@@ -399,36 +268,7 @@
 
         final KeyValueListParser parser = new KeyValueListParser(',');
 
-        // Non-device-specific parameters.
-        try {
-            parser.setString(setting);
-        } catch (IllegalArgumentException e) {
-            Slog.wtf(TAG, "Bad battery saver constants: " + setting);
-        }
-
-        mVibrationDisabledConfig = parser.getBoolean(KEY_VIBRATION_DISABLED, true);
-        mAnimationDisabled = parser.getBoolean(KEY_ANIMATION_DISABLED, false);
-        mSoundTriggerDisabled = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true);
-        mFullBackupDeferred = parser.getBoolean(KEY_FULLBACKUP_DEFERRED, true);
-        mKeyValueBackupDeferred = parser.getBoolean(KEY_KEYVALUE_DEFERRED, true);
-        mEnableFirewall = !parser.getBoolean(KEY_ACTIVATE_FIREWALL_DISABLED, false);
-        mEnableAdjustBrightness = !parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, true);
-        mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
-        mEnableDataSaver = !parser.getBoolean(KEY_ACTIVATE_DATASAVER_DISABLED, true);
-        mLaunchBoostDisabled = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED, true);
-        mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true);
-        mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
-        mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
-        mAodDisabled = parser.getBoolean(KEY_AOD_DISABLED, true);
-        mQuickDozeEnabled = parser.getBoolean(KEY_QUICK_DOZE_ENABLED, false);
-        mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, false);
-
-        // Get default value from Settings.Secure
-        final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
-                PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
-        mGpsMode = parser.getInt(KEY_GPS_MODE, defaultGpsMode);
-
-        // Non-device-specific parameters.
+        // Device-specific parameters.
         try {
             parser.setString(deviceSpecificSetting);
         } catch (IllegalArgumentException e) {
@@ -436,41 +276,280 @@
                     + deviceSpecificSetting);
         }
 
-        mFilesForInteractive = (new CpuFrequencies()).parseString(
-                parser.getString(KEY_CPU_FREQ_INTERACTIVE, "")).toSysFileMap();
+        final String cpuFreqInteractive = parser.getString(KEY_CPU_FREQ_INTERACTIVE, "");
+        final String cpuFreqNoninteractive = parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "");
 
-        mFilesForNoninteractive = (new CpuFrequencies()).parseString(
-                parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "")).toSysFileMap();
+        // Non-device-specific parameters.
+        try {
+            parser.setString(setting);
+        } catch (IllegalArgumentException e) {
+            Slog.wtf(TAG, "Bad battery saver constants: " + setting);
+        }
+
+        float adjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR,
+                sDefaultPolicy.adjustBrightnessFactor);
+        boolean deferFullBackup = parser.getBoolean(KEY_FULLBACKUP_DEFERRED,
+                sDefaultPolicy.deferFullBackup);
+        boolean deferKeyValueBackup = parser.getBoolean(KEY_KEYVALUE_DEFERRED,
+                sDefaultPolicy.deferKeyValueBackup);
+        boolean disableAnimation = parser.getBoolean(KEY_ANIMATION_DISABLED,
+                sDefaultPolicy.disableAnimation);
+        boolean disableAod = parser.getBoolean(KEY_AOD_DISABLED, sDefaultPolicy.disableAod);
+        boolean disableLaunchBoost = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED,
+                sDefaultPolicy.disableLaunchBoost);
+        boolean disableOptionalSensors = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED,
+                sDefaultPolicy.disableOptionalSensors);
+        boolean disableSoundTrigger = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED,
+                sDefaultPolicy.disableSoundTrigger);
+        boolean disableVibrationConfig = parser.getBoolean(KEY_VIBRATION_DISABLED,
+                sDefaultPolicy.disableVibration);
+        boolean enableAdjustBrightness = !parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED,
+                !sDefaultPolicy.enableAdjustBrightness);
+        boolean enableDataSaver = !parser.getBoolean(KEY_ACTIVATE_DATASAVER_DISABLED,
+                !sDefaultPolicy.enableDataSaver);
+        boolean enableFirewall = !parser.getBoolean(KEY_ACTIVATE_FIREWALL_DISABLED,
+                !sDefaultPolicy.enableFirewall);
+        boolean enableQuickDoze = parser.getBoolean(KEY_QUICK_DOZE_ENABLED,
+                sDefaultPolicy.enableQuickDoze);
+        boolean forceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY,
+                sDefaultPolicy.forceAllAppsStandby);
+        boolean forceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK,
+                sDefaultPolicy.forceBackgroundCheck);
+        int gpsMode = parser.getInt(KEY_GPS_MODE, sDefaultPolicy.gpsMode);
+        boolean sendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, sDefaultPolicy.sendTronLog);
+
+        mCurrPolicy = new Policy(
+                adjustBrightnessFactor,
+                deferFullBackup,
+                deferKeyValueBackup,
+                disableAnimation,
+                disableAod,
+                disableLaunchBoost,
+                disableOptionalSensors,
+                disableSoundTrigger,
+                /* disableVibration */
+                disableVibrationConfig,
+                enableAdjustBrightness,
+                enableDataSaver,
+                enableFirewall,
+                enableQuickDoze,
+                /* filesForInteractive */
+                (new CpuFrequencies()).parseString(cpuFreqInteractive).toSysFileMap(),
+                /* filesForNoninteractive */
+                (new CpuFrequencies()).parseString(cpuFreqNoninteractive).toSysFileMap(),
+                forceAllAppsStandby,
+                forceBackgroundCheck,
+                gpsMode,
+                sendTronLog
+        );
 
         // Update the effective policy.
-        mVibrationDisabledEffective = mVibrationDisabledConfig
+        mDisableVibrationEffective = mCurrPolicy.disableVibration
                 && !mAccessibilityEnabled; // Don't disable vibration when accessibility is on.
 
         final StringBuilder sb = new StringBuilder();
 
-        if (mForceAllAppsStandby) sb.append("A");
-        if (mForceBackgroundCheck) sb.append("B");
+        if (mCurrPolicy.forceAllAppsStandby) sb.append("A");
+        if (mCurrPolicy.forceBackgroundCheck) sb.append("B");
 
-        if (mVibrationDisabledEffective) sb.append("v");
-        if (mAnimationDisabled) sb.append("a");
-        if (mSoundTriggerDisabled) sb.append("s");
-        if (mFullBackupDeferred) sb.append("F");
-        if (mKeyValueBackupDeferred) sb.append("K");
-        if (mEnableFirewall) sb.append("f");
-        if (mEnableDataSaver) sb.append("d");
-        if (mEnableAdjustBrightness) sb.append("b");
+        if (mDisableVibrationEffective) sb.append("v");
+        if (mCurrPolicy.disableAnimation) sb.append("a");
+        if (mCurrPolicy.disableSoundTrigger) sb.append("s");
+        if (mCurrPolicy.deferFullBackup) sb.append("F");
+        if (mCurrPolicy.deferKeyValueBackup) sb.append("K");
+        if (mCurrPolicy.enableFirewall) sb.append("f");
+        if (mCurrPolicy.enableDataSaver) sb.append("d");
+        if (mCurrPolicy.enableAdjustBrightness) sb.append("b");
 
-        if (mLaunchBoostDisabled) sb.append("l");
-        if (mOptionalSensorsDisabled) sb.append("S");
-        if (mAodDisabled) sb.append("o");
-        if (mQuickDozeEnabled) sb.append("q");
-        if (mSendTronLog) sb.append("t");
+        if (mCurrPolicy.disableLaunchBoost) sb.append("l");
+        if (mCurrPolicy.disableOptionalSensors) sb.append("S");
+        if (mCurrPolicy.disableAod) sb.append("o");
+        if (mCurrPolicy.enableQuickDoze) sb.append("q");
+        if (mCurrPolicy.sendTronLog) sb.append("t");
 
-        sb.append(mGpsMode);
+        sb.append(mCurrPolicy.gpsMode);
 
         mEventLogKeys = sb.toString();
 
-        mBatterySavingStats.setSendTronLog(mSendTronLog);
+        mBatterySavingStats.setSendTronLog(mCurrPolicy.sendTronLog);
+    }
+
+    private static class Policy {
+        /**
+         * This is the flag to decide the how much to adjust the screen brightness. This is
+         * the float value from 0 to 1 where 1 means don't change brightness.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
+         */
+        public final float adjustBrightnessFactor;
+
+        /**
+         * {@code true} if full backup is deferred in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_FULLBACKUP_DEFERRED
+         */
+        public final boolean deferFullBackup;
+
+        /**
+         * {@code true} if key value backup is deferred in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_KEYVALUE_DEFERRED
+         */
+        public final boolean deferKeyValueBackup;
+
+        /**
+         * {@code true} if animation is disabled in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_ANIMATION_DISABLED
+         */
+        public final boolean disableAnimation;
+
+        /**
+         * {@code true} if AOD is disabled in battery saver mode.
+         */
+        public final boolean disableAod;
+
+        /**
+         * {@code true} if launch boost should be disabled on battery saver.
+         */
+        public final boolean disableLaunchBoost;
+
+        /**
+         * Whether to show non-essential sensors (e.g. edge sensors) or not.
+         */
+        public final boolean disableOptionalSensors;
+
+        /**
+         * {@code true} if sound trigger is disabled in battery saver mode
+         * in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_SOUNDTRIGGER_DISABLED
+         */
+        public final boolean disableSoundTrigger;
+
+        /**
+         * {@code true} if vibration is disabled in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_VIBRATION_DISABLED
+         */
+        public final boolean disableVibration;
+
+        /**
+         * {@code true} if low power mode brightness adjustment should be turned on in battery saver
+         * mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
+         */
+        public final boolean enableAdjustBrightness;
+
+        /**
+         * {@code true} if data saver should be turned on in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_ACTIVATE_DATASAVER_DISABLED
+         */
+        public final boolean enableDataSaver;
+
+        /**
+         * {@code true} if network policy firewall should be turned on in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_ACTIVATE_FIREWALL_DISABLED
+         */
+        public final boolean enableFirewall;
+
+        /**
+         * Whether Quick Doze is enabled or not.
+         */
+        public final boolean enableQuickDoze;
+
+        /**
+         * List of [Filename -> content] that should be written when battery saver is activated
+         * and the device is interactive.
+         *
+         * We use this to change the max CPU frequencies.
+         */
+        public final ArrayMap<String, String> filesForInteractive;
+
+        /**
+         * List of [Filename -> content] that should be written when battery saver is activated
+         * and the device is non-interactive.
+         *
+         * We use this to change the max CPU frequencies.
+         */
+        public final ArrayMap<String, String> filesForNoninteractive;
+
+        /**
+         * Whether to put all apps in the stand-by mode.
+         */
+        public final boolean forceAllAppsStandby;
+
+        /**
+         * Whether to put all apps in the stand-by mode.
+         */
+        public final boolean forceBackgroundCheck;
+
+        /**
+         * This is the flag to decide the gps mode in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_GPS_MODE
+         */
+        public final int gpsMode;
+
+        /**
+         * Whether BatterySavingStats should send tron events.
+         */
+        public final boolean sendTronLog;
+
+        Policy(
+                float adjustBrightnessFactor,
+                boolean deferFullBackup,
+                boolean deferKeyValueBackup,
+                boolean disableAnimation,
+                boolean disableAod,
+                boolean disableLaunchBoost,
+                boolean disableOptionalSensors,
+                boolean disableSoundTrigger,
+                boolean disableVibration,
+                boolean enableAdjustBrightness,
+                boolean enableDataSaver,
+                boolean enableFirewall,
+                boolean enableQuickDoze,
+                ArrayMap<String, String> filesForInteractive,
+                ArrayMap<String, String> filesForNoninteractive,
+                boolean forceAllAppsStandby,
+                boolean forceBackgroundCheck,
+                int gpsMode,
+                boolean sendTronLog) {
+
+            this.adjustBrightnessFactor = adjustBrightnessFactor;
+            this.deferFullBackup = deferFullBackup;
+            this.deferKeyValueBackup = deferKeyValueBackup;
+            this.disableAnimation = disableAnimation;
+            this.disableAod = disableAod;
+            this.disableLaunchBoost = disableLaunchBoost;
+            this.disableOptionalSensors = disableOptionalSensors;
+            this.disableSoundTrigger = disableSoundTrigger;
+            this.disableVibration = disableVibration;
+            this.enableAdjustBrightness = enableAdjustBrightness;
+            this.enableDataSaver = enableDataSaver;
+            this.enableFirewall = enableFirewall;
+            this.enableQuickDoze = enableQuickDoze;
+            this.filesForInteractive = filesForInteractive;
+            this.filesForNoninteractive = filesForNoninteractive;
+            this.forceAllAppsStandby = forceAllAppsStandby;
+            this.forceBackgroundCheck = forceBackgroundCheck;
+            this.gpsMode = gpsMode;
+            this.sendTronLog = sendTronLog;
+        }
     }
 
     /**
@@ -493,47 +572,47 @@
             switch (type) {
                 case ServiceType.GPS:
                     return builder.setBatterySaverEnabled(realMode)
-                            .setGpsMode(mGpsMode)
+                            .setGpsMode(mCurrPolicy.gpsMode)
                             .build();
                 case ServiceType.ANIMATION:
-                    return builder.setBatterySaverEnabled(mAnimationDisabled)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.disableAnimation)
                             .build();
                 case ServiceType.FULL_BACKUP:
-                    return builder.setBatterySaverEnabled(mFullBackupDeferred)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.deferFullBackup)
                             .build();
                 case ServiceType.KEYVALUE_BACKUP:
-                    return builder.setBatterySaverEnabled(mKeyValueBackupDeferred)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.deferKeyValueBackup)
                             .build();
                 case ServiceType.NETWORK_FIREWALL:
-                    return builder.setBatterySaverEnabled(mEnableFirewall)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.enableFirewall)
                             .build();
                 case ServiceType.SCREEN_BRIGHTNESS:
-                    return builder.setBatterySaverEnabled(mEnableAdjustBrightness)
-                            .setBrightnessFactor(mAdjustBrightnessFactor)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.enableAdjustBrightness)
+                            .setBrightnessFactor(mCurrPolicy.adjustBrightnessFactor)
                             .build();
                 case ServiceType.DATA_SAVER:
-                    return builder.setBatterySaverEnabled(mEnableDataSaver)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.enableDataSaver)
                             .build();
                 case ServiceType.SOUND:
-                    return builder.setBatterySaverEnabled(mSoundTriggerDisabled)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.disableSoundTrigger)
                             .build();
                 case ServiceType.VIBRATION:
-                    return builder.setBatterySaverEnabled(mVibrationDisabledEffective)
+                    return builder.setBatterySaverEnabled(mDisableVibrationEffective)
                             .build();
                 case ServiceType.FORCE_ALL_APPS_STANDBY:
-                    return builder.setBatterySaverEnabled(mForceAllAppsStandby)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.forceAllAppsStandby)
                             .build();
                 case ServiceType.FORCE_BACKGROUND_CHECK:
-                    return builder.setBatterySaverEnabled(mForceBackgroundCheck)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.forceBackgroundCheck)
                             .build();
                 case ServiceType.OPTIONAL_SENSORS:
-                    return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.disableOptionalSensors)
                             .build();
                 case ServiceType.AOD:
-                    return builder.setBatterySaverEnabled(mAodDisabled)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.disableAod)
                             .build();
                 case ServiceType.QUICK_DOZE:
-                    return builder.setBatterySaverEnabled(mQuickDozeEnabled)
+                    return builder.setBatterySaverEnabled(mCurrPolicy.enableQuickDoze)
                             .build();
                 default:
                     return builder.setBatterySaverEnabled(realMode)
@@ -544,19 +623,20 @@
 
     public int getGpsMode() {
         synchronized (mLock) {
-            return mGpsMode;
+            return mCurrPolicy.gpsMode;
         }
     }
 
     public ArrayMap<String, String> getFileValues(boolean interactive) {
         synchronized (mLock) {
-            return interactive ? mFilesForInteractive : mFilesForNoninteractive;
+            return interactive ? mCurrPolicy.filesForInteractive
+                    : mCurrPolicy.filesForNoninteractive;
         }
     }
 
     public boolean isLaunchBoostDisabled() {
         synchronized (mLock) {
-            return mLaunchBoostDisabled;
+            return mCurrPolicy.disableLaunchBoost;
         }
     }
 
@@ -580,31 +660,35 @@
 
             pw.println();
             pw.println("  mAccessibilityEnabled=" + mAccessibilityEnabled);
-            pw.println("  " + KEY_VIBRATION_DISABLED + ":config=" + mVibrationDisabledConfig);
-            pw.println("  " + KEY_VIBRATION_DISABLED + ":effective=" + mVibrationDisabledEffective);
-            pw.println("  " + KEY_ANIMATION_DISABLED + "=" + mAnimationDisabled);
-            pw.println("  " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred);
-            pw.println("  " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred);
-            pw.println("  " + KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !mEnableFirewall);
-            pw.println("  " + KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !mEnableDataSaver);
-            pw.println("  " + KEY_LAUNCH_BOOST_DISABLED + "=" + mLaunchBoostDisabled);
-            pw.println("  " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + !mEnableAdjustBrightness);
-            pw.println("  " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
-            pw.println("  " + KEY_GPS_MODE + "=" + mGpsMode);
-            pw.println("  " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby);
-            pw.println("  " + KEY_FORCE_BACKGROUND_CHECK + "=" + mForceBackgroundCheck);
-            pw.println("  " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
-            pw.println("  " + KEY_AOD_DISABLED + "=" + mAodDisabled);
-            pw.println("  " + KEY_QUICK_DOZE_ENABLED + "=" + mQuickDozeEnabled);
-            pw.println("  " + KEY_SEND_TRON_LOG + "=" + mSendTronLog);
+            pw.println("  " + KEY_VIBRATION_DISABLED + ":config=" + mCurrPolicy.disableVibration);
+            pw.println("  " + KEY_VIBRATION_DISABLED + ":effective=" + mDisableVibrationEffective);
+            pw.println("  " + KEY_ANIMATION_DISABLED + "=" + mCurrPolicy.disableAnimation);
+            pw.println("  " + KEY_FULLBACKUP_DEFERRED + "=" + mCurrPolicy.deferFullBackup);
+            pw.println("  " + KEY_KEYVALUE_DEFERRED + "=" + mCurrPolicy.deferKeyValueBackup);
+            pw.println("  " + KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !mCurrPolicy.enableFirewall);
+            pw.println("  " + KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !mCurrPolicy.enableDataSaver);
+            pw.println("  " + KEY_LAUNCH_BOOST_DISABLED + "=" + mCurrPolicy.disableLaunchBoost);
+            pw.println("  " + KEY_ADJUST_BRIGHTNESS_DISABLED + "="
+                    + !mCurrPolicy.enableAdjustBrightness);
+            pw.println(
+                    "  " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mCurrPolicy.adjustBrightnessFactor);
+            pw.println("  " + KEY_GPS_MODE + "=" + mCurrPolicy.gpsMode);
+            pw.println("  " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mCurrPolicy.forceAllAppsStandby);
+            pw.println("  " + KEY_FORCE_BACKGROUND_CHECK + "=" + mCurrPolicy.forceBackgroundCheck);
+            pw.println("  " + KEY_OPTIONAL_SENSORS_DISABLED + "="
+                    + mCurrPolicy.disableOptionalSensors);
+            pw.println("  " + KEY_AOD_DISABLED + "=" + mCurrPolicy.disableAod);
+            pw.println("  " + KEY_SOUNDTRIGGER_DISABLED + "=" + mCurrPolicy.disableSoundTrigger);
+            pw.println("  " + KEY_QUICK_DOZE_ENABLED + "=" + mCurrPolicy.enableQuickDoze);
+            pw.println("  " + KEY_SEND_TRON_LOG + "=" + mCurrPolicy.sendTronLog);
             pw.println();
 
             pw.print("  Interactive File values:\n");
-            dumpMap(pw, "    ", mFilesForInteractive);
+            dumpMap(pw, "    ", mCurrPolicy.filesForInteractive);
             pw.println();
 
             pw.print("  Noninteractive File values:\n");
-            dumpMap(pw, "    ", mFilesForNoninteractive);
+            dumpMap(pw, "    ", mCurrPolicy.filesForNoninteractive);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index e65095b..6034f81 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -789,7 +789,15 @@
         return startHomeOnDisplay(mCurrentUser, myReason, displayId);
     }
 
-    boolean canStartHomeOnDisplay(ActivityInfo homeInfo, int displayId) {
+    /**
+     * Check if home activity start should be allowed on a display.
+     * @param homeInfo {@code ActivityInfo} of the home activity that is going to be launched.
+     * @param displayId The id of the target display.
+     * @param allowInstrumenting Whether launching home should be allowed if being instrumented.
+     * @return {@code true} if allow to launch, {@code false} otherwise.
+     */
+    boolean canStartHomeOnDisplay(ActivityInfo homeInfo, int displayId,
+            boolean allowInstrumenting) {
         if (mService.mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                 && mService.mTopAction == null) {
             // We are running in factory test mode, but unable to find the factory test app, so
@@ -799,7 +807,7 @@
 
         final WindowProcessController app =
                 mService.getProcessController(homeInfo.processName, homeInfo.applicationInfo.uid);
-        if (app != null && app.isInstrumenting()) {
+        if (!allowInstrumenting && app != null && app.isInstrumenting()) {
             // Don't do this if the home app is currently being instrumented.
             return false;
         }
@@ -2618,8 +2626,7 @@
     }
 
     ActivityRecord getDefaultDisplayHomeActivityForUser(int userId) {
-        getActivityDisplay(DEFAULT_DISPLAY).getHomeActivityForUser(userId);
-        return null;
+        return getActivityDisplay(DEFAULT_DISPLAY).getHomeActivityForUser(userId);
     }
 
     void resizeStackLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
@@ -4246,7 +4253,7 @@
             return false;
         }
 
-        if (!canStartHomeOnDisplay(aInfo, displayId)) {
+        if (!canStartHomeOnDisplay(aInfo, displayId, false /* allowInstrumenting */)) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index afc946b..83db8de 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -53,6 +53,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -72,7 +73,6 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
-import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
 import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
 import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
 
@@ -114,9 +114,9 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.server.am.EventLogTags;
 import com.android.server.am.PendingIntentRecord;
+import com.android.server.pm.InstantAppResolver;
 import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch;
 import com.android.server.wm.LaunchParamsController.LaunchParams;
-import com.android.server.pm.InstantAppResolver;
 
 import java.io.PrintWriter;
 import java.text.DateFormat;
@@ -1284,8 +1284,8 @@
         // Do not start home activity if it cannot be launched on preferred display. We are not
         // doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
         // fallback to launch on other displays.
-        if (r.isActivityTypeHome()
-                && !mSupervisor.canStartHomeOnDisplay(r.info, mPreferredDisplayId)) {
+        if (r.isActivityTypeHome() && !mSupervisor.canStartHomeOnDisplay(r.info,
+                mPreferredDisplayId, true /* allowInstrumenting */)) {
             Slog.w(TAG, "Cannot launch home on display " + mPreferredDisplayId);
             return START_CANCELED;
         }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 89193f7..433c05a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6267,8 +6267,11 @@
                             FLAG_ACTIVITY_TASK_ON_HOME);
                     ActivityOptions activityOptions = options != null
                             ? new ActivityOptions(options) : ActivityOptions.makeBasic();
-                    activityOptions.setLaunchTaskId(
-                            mStackSupervisor.getDefaultDisplayHomeActivity().getTask().taskId);
+                    final ActivityRecord homeActivity =
+                            mStackSupervisor.getDefaultDisplayHomeActivity();
+                    if (homeActivity != null) {
+                        activityOptions.setLaunchTaskId(homeActivity.getTask().taskId);
+                    }
                     mContext.startActivityAsUser(intent, activityOptions.toBundle(),
                             UserHandle.CURRENT);
                 } finally {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e364e9a..933eac6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1627,7 +1627,7 @@
 
             if (hasFeatureFace || hasFeatureIris || hasFeatureFingerprint) {
                 // Start this service after all biometric services.
-                traceBeginAndSlog("StartBiometricPromptService");
+                traceBeginAndSlog("StartBiometricService");
                 mSystemServiceManager.startService(BiometricService.class);
                 traceEnd();
             }
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 ebac8fb..58c4bbf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -15,7 +15,10 @@
  */
 package com.android.server.pm;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -461,6 +464,7 @@
         pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo()));
         pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo()));
         pkg.requestedPermissions.add("foo7");
+        pkg.implicitPermissions.add("foo25");
 
         pkg.protectedBroadcasts = new ArrayList<>();
         pkg.protectedBroadcasts.add("foo8");
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index caaa0bb..41d5691 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -129,6 +129,7 @@
 
     static class MyInjector extends AppStandbyController.Injector {
         long mElapsedRealtime;
+        boolean mIsAppIdleEnabled = true;
         boolean mIsCharging;
         List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
         boolean mDisplayOn;
@@ -160,7 +161,7 @@
 
         @Override
         boolean isAppIdleEnabled() {
-            return true;
+            return mIsAppIdleEnabled;
         }
 
         @Override
@@ -277,6 +278,13 @@
         }
     }
 
+    private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
+        mInjector.mIsAppIdleEnabled = enabled;
+        if (controller != null) {
+            controller.setAppIdleEnabled(enabled);
+        }
+    }
+
     private AppStandbyController setupController() throws Exception {
         mInjector.mElapsedRealtime = 0;
         setupPm(mInjector.getContext().getPackageManager());
@@ -346,7 +354,7 @@
         public void onParoleStateChanged(boolean isParoleOn) {
             synchronized (this) {
                 // Only record information if it is being looked for
-                if (mLatch.getCount() > 0) {
+                if (mLatch != null && mLatch.getCount() > 0) {
                     mOnParole = isParoleOn;
                     mLastParoleChangeTime = getCurrentTime();
                     mLatch.countDown();
@@ -407,6 +415,74 @@
                 marginOfError);
     }
 
+    @Test
+    public void testEnabledState() throws Exception {
+        TestParoleListener paroleListener = new TestParoleListener();
+        mController.addListener(paroleListener);
+        long lastUpdateTime;
+
+        // Test that listeners are notified if enabled changes when the device is not in parole.
+        setChargingState(mController, false);
+
+        // Start off not enabled. Device is effectively on permanent parole.
+        setAppIdleEnabled(mController, false);
+
+        // Enable controller
+        paroleListener.rearmLatch();
+        setAppIdleEnabled(mController, true);
+        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+        assertFalse(paroleListener.mOnParole);
+        lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+        paroleListener.rearmLatch();
+        setAppIdleEnabled(mController, true);
+        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+        assertFalse(paroleListener.mOnParole);
+        // Make sure AppStandbyController doesn't notify listeners when there's no change.
+        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+        // Disable controller
+        paroleListener.rearmLatch();
+        setAppIdleEnabled(mController, false);
+        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+        assertTrue(paroleListener.mOnParole);
+        lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+        paroleListener.rearmLatch();
+        setAppIdleEnabled(mController, false);
+        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+        assertTrue(paroleListener.mOnParole);
+        // Make sure AppStandbyController doesn't notify listeners when there's no change.
+        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+
+        // Test that listeners aren't notified if enabled status changes when the device is already
+        // in parole.
+
+        // A device is in parole whenever it's charging.
+        setChargingState(mController, true);
+
+        // Start off not enabled.
+        paroleListener.rearmLatch();
+        setAppIdleEnabled(mController, false);
+        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+        assertTrue(paroleListener.mOnParole);
+        lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+        // Test that toggling doesn't notify the listener.
+        paroleListener.rearmLatch();
+        setAppIdleEnabled(mController, true);
+        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+        assertTrue(paroleListener.mOnParole);
+        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+        paroleListener.rearmLatch();
+        setAppIdleEnabled(mController, false);
+        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+        assertTrue(paroleListener.mOnParole);
+        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+    }
+
     private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
         mInjector.mElapsedRealtime = elapsedTime;
         controller.checkIdleStates(USER_ID);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 59eab3f..9da204f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -417,6 +417,7 @@
 
         verifyLights();
         assertTrue(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -429,6 +430,7 @@
         verifyNeverVibrate();
         verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -439,6 +441,7 @@
 
         verifyBeep();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -449,6 +452,7 @@
 
         verifyNeverBeep();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -461,6 +465,7 @@
         verifyNeverBeep();
         verifyNeverVibrate();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -473,6 +478,7 @@
         verifyNeverBeep();
         verifyNeverVibrate();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -489,6 +495,7 @@
         verifyBeepLooped();
         verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt());
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -517,6 +524,7 @@
 
         verifyNeverStopAudio();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -530,7 +538,9 @@
 
         verifyNeverStopAudio();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
         assertFalse(s.isInterruptive());
+        assertFalse(s.getAudiblyAlerted());
     }
 
     /**
@@ -567,6 +577,7 @@
         mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
         verifyNeverStopAudio();
         assertTrue(other.isInterruptive());
+        assertTrue(other.getAudiblyAlerted());
     }
 
     @Test
@@ -592,12 +603,14 @@
         // set up internal state
         mService.buzzBeepBlinkLocked(r);
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
         Mockito.reset(mRingtonePlayer);
 
         // quiet update should stop making noise
         mService.buzzBeepBlinkLocked(s);
         verifyStopAudio();
         assertFalse(s.isInterruptive());
+        assertFalse(s.getAudiblyAlerted());
     }
 
     @Test
@@ -609,12 +622,14 @@
         // set up internal state
         mService.buzzBeepBlinkLocked(r);
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
         Mockito.reset(mRingtonePlayer);
 
         // stop making noise - this is a weird corner case, but quiet should override once
         mService.buzzBeepBlinkLocked(s);
         verifyStopAudio();
         assertFalse(s.isInterruptive());
+        assertFalse(s.getAudiblyAlerted());
     }
 
     @Test
@@ -631,6 +646,7 @@
         verify(mService, times(1)).playInCallNotification();
         verifyNeverBeep(); // doesn't play normal beep
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -650,6 +666,7 @@
                 eq(effect), anyString(),
                 (AudioAttributes) anyObject());
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -667,6 +684,7 @@
         verifyNeverVibrate();
         verifyBeepLooped();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -686,6 +704,7 @@
         verify(mRingtonePlayer, never()).playAsync
                 (anyObject(), anyObject(), anyBoolean(), anyObject());
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -702,6 +721,7 @@
 
         verifyDelayedVibrateLooped();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -713,6 +733,7 @@
         verifyNeverBeep();
         verifyVibrate();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -722,6 +743,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyVibrateLooped();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -737,6 +759,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyVibrate();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -747,6 +770,7 @@
 
         verifyNeverBeep();
         assertFalse(child.isInterruptive());
+        assertFalse(child.getAudiblyAlerted());
     }
 
     @Test
@@ -759,6 +783,7 @@
         verifyBeepLooped();
         // summaries are never interruptive for notification counts
         assertFalse(summary.isInterruptive());
+        assertTrue(summary.getAudiblyAlerted());
     }
 
     @Test
@@ -769,6 +794,7 @@
 
         verifyBeepLooped();
         assertTrue(nonGroup.isInterruptive());
+        assertTrue(nonGroup.getAudiblyAlerted());
     }
 
     @Test
@@ -780,6 +806,7 @@
 
         verifyNeverBeep();
         assertFalse(summary.isInterruptive());
+        assertFalse(summary.getAudiblyAlerted());
     }
 
     @Test
@@ -790,6 +817,7 @@
 
         verifyBeepLooped();
         assertTrue(child.isInterruptive());
+        assertTrue(child.getAudiblyAlerted());
     }
 
     @Test
@@ -800,6 +828,7 @@
 
         verifyBeepLooped();
         assertTrue(nonGroup.isInterruptive());
+        assertTrue(nonGroup.getAudiblyAlerted());
     }
 
     @Test
@@ -810,6 +839,7 @@
 
         verifyBeepLooped();
         assertTrue(group.isInterruptive());
+        assertTrue(group.getAudiblyAlerted());
     }
 
     @Test
@@ -822,11 +852,13 @@
         mService.buzzBeepBlinkLocked(r);
         Mockito.reset(mVibrator);
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
 
         // update should not beep
         mService.buzzBeepBlinkLocked(s);
         verifyNeverVibrate();
         assertFalse(s.isInterruptive());
+        assertFalse(s.getAudiblyAlerted());
     }
 
     @Test
@@ -839,6 +871,7 @@
 
         verifyNeverStopVibrate();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
     }
 
     @Test
@@ -852,7 +885,9 @@
 
         verifyNeverStopVibrate();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
         assertFalse(s.isInterruptive());
+        assertFalse(s.getAudiblyAlerted());
     }
 
     @Test
@@ -871,8 +906,11 @@
         mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
         verifyNeverStopVibrate();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
         assertTrue(other.isInterruptive());
+        assertTrue(other.getAudiblyAlerted());
         assertFalse(s.isInterruptive());
+        assertFalse(s.getAudiblyAlerted());
     }
 
     @Test
@@ -888,6 +926,7 @@
         mService.buzzBeepBlinkLocked(other);
         verifyNeverStopVibrate();
         assertFalse(other.isInterruptive());
+        assertFalse(other.getAudiblyAlerted());
     }
 
     @Test
@@ -904,7 +943,9 @@
         mService.buzzBeepBlinkLocked(s);
         verifyStopVibrate();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
         assertFalse(s.isInterruptive());
+        assertFalse(s.getAudiblyAlerted());
     }
 
     @Test
@@ -921,7 +962,9 @@
         mService.buzzBeepBlinkLocked(s);
         verifyStopVibrate();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
         assertFalse(s.isInterruptive());
+        assertFalse(s.getAudiblyAlerted());
     }
 
     @Test
@@ -939,7 +982,9 @@
         mService.buzzBeepBlinkLocked(s);
         verifyStopVibrate();
         assertTrue(r.isInterruptive());
+        assertTrue(r.getAudiblyAlerted());
         assertFalse(s.isInterruptive());
+        assertFalse(s.getAudiblyAlerted());
     }
 
     @Test
@@ -957,6 +1002,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyNeverBeep();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -968,6 +1014,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyNeverBeep();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -1010,6 +1057,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyNeverBeep();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -1043,6 +1091,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -1052,6 +1101,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -1060,6 +1110,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyLights();
         assertTrue(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
 
         r = getLightsOnceNotification();
         r.isUpdate = true;
@@ -1067,6 +1118,7 @@
         // checks that lights happened once, i.e. this new call didn't trigger them again
         verifyLights();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -1076,6 +1128,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -1084,6 +1137,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -1093,6 +1147,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -1102,6 +1157,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -1111,6 +1167,7 @@
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
         assertFalse(r.isInterruptive());
+        assertFalse(r.getAudiblyAlerted());
     }
 
     @Test
@@ -1121,6 +1178,7 @@
 
         verifyNeverLights();
         assertFalse(child.isInterruptive());
+        assertFalse(child.getAudiblyAlerted());
     }
 
     @Test
@@ -1133,6 +1191,7 @@
         verifyLights();
         // summaries should never count for interruptiveness counts
         assertFalse(summary.isInterruptive());
+        assertFalse(summary.getAudiblyAlerted());
     }
 
     @Test
@@ -1143,6 +1202,7 @@
 
         verifyLights();
         assertTrue(nonGroup.isInterruptive());
+        assertFalse(nonGroup.getAudiblyAlerted());
     }
 
     @Test
@@ -1154,6 +1214,7 @@
 
         verifyNeverLights();
         assertFalse(summary.isInterruptive());
+        assertFalse(summary.getAudiblyAlerted());
     }
 
     @Test
@@ -1164,6 +1225,7 @@
 
         verifyLights();
         assertTrue(child.isInterruptive());
+        assertFalse(child.getAudiblyAlerted());
     }
 
     @Test
@@ -1174,6 +1236,7 @@
 
         verifyLights();
         assertTrue(nonGroup.isInterruptive());
+        assertFalse(nonGroup.getAudiblyAlerted());
     }
 
     @Test
@@ -1184,6 +1247,7 @@
 
         verifyLights();
         assertTrue(group.isInterruptive());
+        assertFalse(group.getAudiblyAlerted());
     }
 
     static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index f255d49..0d7b584 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -38,12 +38,10 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.Parcel;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -94,6 +92,7 @@
             assertEquals(getShowBadge(i), ranking.canShowBadge());
             assertEquals(getUserSentiment(i), ranking.getUserSentiment());
             assertEquals(getHidden(i), ranking.isSuspended());
+            assertEquals(audiblyAlerted(i), ranking.audiblyAlerted());
             assertActionsEqual(getSmartActions(key, i), ranking.getSmartActions());
             assertEquals(getSmartReplies(key, i), ranking.getSmartReplies());
         }
@@ -114,6 +113,7 @@
         Bundle mHidden = new Bundle();
         Bundle smartActions = new Bundle();
         Bundle smartReplies = new Bundle();
+        Bundle audiblyAlerted = new Bundle();
 
         for (int i = 0; i < mKeys.length; i++) {
             String key = mKeys[i];
@@ -133,12 +133,13 @@
             mHidden.putBoolean(key, getHidden(i));
             smartActions.putParcelableArrayList(key, getSmartActions(key, i));
             smartReplies.putCharSequenceArrayList(key, getSmartReplies(key, i));
+            audiblyAlerted.putBoolean(key, audiblyAlerted(i));
         }
         NotificationRankingUpdate update = new NotificationRankingUpdate(mKeys,
                 interceptedKeys.toArray(new String[0]), visibilityOverrides,
                 suppressedVisualEffects, importance, explanation, overrideGroupKeys,
                 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, mHidden,
-                smartActions, smartReplies);
+                smartActions, smartReplies, audiblyAlerted);
         return update;
     }
 
@@ -190,6 +191,10 @@
         return index % 2 == 0;
     }
 
+    private boolean audiblyAlerted(int index) {
+        return index < 2;
+    }
+
     private ArrayList<String> getPeople(String key, int index) {
         ArrayList<String> people = new ArrayList<>();
         for (int i = 0; i < index; i++) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 1b59e75..9b41fdd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -801,4 +801,16 @@
         assertEquals(1.0f, record.getContactAffinity());
         assertEquals(IMPORTANCE_LOW, record.getImportance());
     }
+
+    @Test
+    public void testSetAudiblyAlerted() {
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        record.setAudiblyAlerted(true);
+
+        assertTrue(record.getAudiblyAlerted());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index c2ef478..f692a57 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -25,12 +25,12 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
 
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
@@ -54,6 +54,8 @@
 
 import android.app.ActivityOptions;
 import android.app.WaitResult;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 
@@ -436,7 +438,7 @@
      * Tests that home activities can be started on the displays that supports system decorations.
      */
     @Test
-    public void testStartHomeOnAllDisplays() throws Exception {
+    public void testStartHomeOnAllDisplays() {
         // Create secondary displays.
         final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay());
         mSupervisor.addChild(secondDisplay, POSITION_TOP);
@@ -450,7 +452,7 @@
                 .create(any(), anyInt(), any(), any(), any(), any());
         doReturn(true).when(mService.mStackSupervisor)
                 .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
-        doReturn(true).when(mSupervisor).canStartHomeOnDisplay(any(), anyInt());
+        doReturn(true).when(mSupervisor).canStartHomeOnDisplay(any(), anyInt(), anyBoolean());
 
         mSupervisor.startHomeOnAllDisplays(0, "testStartHome");
 
@@ -463,7 +465,7 @@
      * Tests that home activities won't be started before booting when display added.
      */
     @Test
-    public void testNotStartHomeBeforeBoot() throws Exception {
+    public void testNotStartHomeBeforeBoot() {
         final int displayId = 1;
         final boolean isBooting = mService.mAmInternal.isBooting();
         final boolean isBooted = mService.mAmInternal.isBooted();
@@ -477,4 +479,30 @@
             mService.mAmInternal.setBooted(isBooted);
         }
     }
+
+    /**
+     * Tests whether home can be started if being instrumented.
+     */
+    @Test
+    public void testCanStartHomeWhenInstrumented() {
+        final ActivityInfo info = new ActivityInfo();
+        info.applicationInfo = new ApplicationInfo();
+        final WindowProcessController app = mock(WindowProcessController.class);
+        doReturn(app).when(mService).getProcessController(any(), anyInt());
+
+        // Can not start home if we don't want to start home while home is being instrumented.
+        doReturn(true).when(app).isInstrumenting();
+        assertFalse(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+                false /* allowInstrumenting*/));
+
+        // Can start home for other cases.
+        assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+                true /* allowInstrumenting*/));
+
+        doReturn(false).when(app).isInstrumenting();
+        assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+                false /* allowInstrumenting*/));
+        assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+                true /* allowInstrumenting*/));
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 6a74564..4f573a4 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -30,18 +30,19 @@
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
-import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
-import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
+
 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
 
@@ -340,14 +341,21 @@
     }
 
     void setAppIdleEnabled(boolean enabled) {
-        mAppIdleEnabled = enabled;
+        synchronized (mAppIdleLock) {
+            if (mAppIdleEnabled != enabled) {
+                final boolean oldParoleState = isParoledOrCharging();
+                mAppIdleEnabled = enabled;
+                if (isParoledOrCharging() != oldParoleState) {
+                    postParoleStateChanged();
+                }
+            }
+        }
     }
 
     public void onBootPhase(int phase) {
         mInjector.onBootPhase(phase);
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
             Slog.d(TAG, "Setting app idle enabled state");
-            setAppIdleEnabled(mInjector.isAppIdleEnabled());
             // Observe changes to the threshold
             SettingsObserver settingsObserver = new SettingsObserver(mHandler);
             settingsObserver.registerObserver();
@@ -1842,8 +1850,6 @@
                         mContext.getContentResolver(),
                         Global.APP_IDLE_CONSTANTS));
             }
-            // Check if app_idle_enabled has changed
-            setAppIdleEnabled(mInjector.isAppIdleEnabled());
 
             // Look at global settings for this.
             // TODO: Maybe apply different thresholds for different users.
@@ -1915,6 +1921,10 @@
                         (KEY_STABLE_CHARGING_THRESHOLD,
                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD);
             }
+
+            // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
+            // in case we need to change something based on the new values.
+            setAppIdleEnabled(mInjector.isAppIdleEnabled());
         }
 
         long[] parseLongArray(String values, long[] defaults) {
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index f62b170..7db6940 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.app.Service;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.os.Handler;
 import android.os.IBinder;
@@ -229,7 +230,8 @@
                         callDetails.getTelecomCallId(),
                         response.getRejectCall(),
                         !response.getSkipCallLog(),
-                        !response.getSkipNotification());
+                        !response.getSkipNotification(),
+                        new ComponentName(getPackageName(), getClass().getName()));
             } else {
                 mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
             }
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
index 2e0af27..d255ed1 100644
--- a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
@@ -16,6 +16,8 @@
 
 package com.android.internal.telecom;
 
+import android.content.ComponentName;
+
 /**
  * Internal remote callback interface for call screening services.
  *
@@ -30,5 +32,6 @@
             String callId,
             boolean shouldReject,
             boolean shouldAddToCallLog,
-            boolean shouldShowNotification);
+            boolean shouldShowNotification,
+            in ComponentName componentName);
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 99de4ca..3f9a533 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1257,20 +1257,11 @@
     public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
 
     /**
-     * Package name of the carrier settings activity.
-     * @see {@link #KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING}.
+     * Flatten {@link android.content.ComponentName} of the carrier's settings activity.
      * @hide
      */
-    public static final String KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING =
-            "carrier_settings_activity_package_name_string";
-
-    /**
-     * Class name of the carrier settings activity.
-     * @see {@link #KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING}.
-     * @hide
-     */
-    public static final String KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING =
-            "carrier_settings_activity_class_name_string";
+    public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING =
+            "carrier_settings_activity_component_name_string";
 
     // These variables are used by the MMS service and exposed through another API,
     // SmsManager. The variable names and string values are copied from there.
@@ -2615,8 +2606,7 @@
         sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
         sDefaults.putStringArray(KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_WORLD_MODE_ENABLED_BOOL, false);
-        sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING, "");
-        sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING, "");
+        sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING, "");
         sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
         sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false);
         sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 76a0026..6958d22 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -190,6 +190,7 @@
                         case CellInfo.TYPE_LTE: return CellIdentityLte.createFromParcelBody(in);
                         case CellInfo.TYPE_TDSCDMA:
                             return CellIdentityTdscdma.createFromParcelBody(in);
+                        case CellInfo.TYPE_NR: return CellIdentityNr.createFromParcelBody(in);
                         default: throw new IllegalArgumentException("Bad Cell identity Parcel");
                     }
                 }
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
new file mode 100644
index 0000000..6b1b84c
--- /dev/null
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+import android.os.Parcel;
+import android.telephony.gsm.GsmCellLocation;
+
+import java.util.Objects;
+
+/**
+ * Information to represent a unique 5G NR cell.
+ */
+public final class CellIdentityNr extends CellIdentity {
+    private static final String TAG = "CellIdentityNr";
+
+    private final int mNrArfcn;
+    private final int mPci;
+    private final int mTac;
+
+    /**
+     *
+     * @param pci Physical Cell Id in range [0, 1007].
+     * @param tac 16-bit Tracking Area Code.
+     * @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165].
+     * @param mccStr 3-digit Mobile Country Code in string format.
+     * @param mncStr 2 or 3-digit Mobile Network Code in string format.
+     * @param alphal long alpha Operator Name String or Enhanced Operator Name String.
+     * @param alphas short alpha Operator Name String or Enhanced Operator Name String.
+     *
+     * @hide
+     */
+    public CellIdentityNr(int pci, int tac, int nrArfcn,  String mccStr, String mncStr,
+            String alphal, String alphas) {
+        super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas);
+        mPci = pci;
+        mTac = tac;
+        mNrArfcn = nrArfcn;
+    }
+
+    /**
+     * @return a CellLocation object for this CellIdentity.
+     * @hide
+     */
+    @Override
+    public CellLocation asCellLocation() {
+        return new GsmCellLocation();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), mPci, mTac, mNrArfcn);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof CellIdentityNr)) {
+            return false;
+        }
+
+        CellIdentityNr o = (CellIdentityNr) other;
+        return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn;
+    }
+
+    /**
+     * Get the Absolute Radio Frequency Channel Number.
+     * @return Integer value in range [0, 3279165] or {@link CellInfo#UNAVAILABLE} if unknown.
+     */
+    @Override
+    public int getChannelNumber() {
+        return mNrArfcn;
+    }
+
+    /**
+     * Get the physical cell id.
+     * @return Integer value in range [0, 1007] or {@link CellInfo#UNAVAILABLE} if unknown.
+     */
+    public int getPci() {
+        return mPci;
+    }
+
+    /**
+     * Get the tracking area code.
+     * @return a 16 bit integer or {@link CellInfo#UNAVAILABLE} if unknown.
+     */
+    public int getTac() {
+        return mTac;
+    }
+
+    /**
+     * @return Mobile Country Code in string format, or {@code null} if unknown.
+     */
+    public String getMccString() {
+        return mMccStr;
+    }
+
+    /**
+     * @return Mobile Network Code in string fomrat, or {@code null} if unknown.
+     */
+    public String getMncString() {
+        return mMncStr;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder(TAG + ":{")
+                .append(" mPci = ").append(mPci)
+                .append(" mTac = ").append(mTac)
+                .append(" mNrArfcn = ").append(mNrArfcn)
+                .append(" mMcc = ").append(mMccStr)
+                .append(" mMnc = ").append(mMncStr)
+                .append(" mAlphaLong = ").append(mAlphaLong)
+                .append(" mAlphaShort = ").append(mAlphaShort)
+                .append(" }")
+                .toString();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int type) {
+        super.writeToParcel(dest, CellInfo.TYPE_NR);
+        dest.writeInt(mPci);
+        dest.writeInt(mTac);
+        dest.writeInt(mNrArfcn);
+    }
+
+    /** Construct from Parcel, type has already been processed */
+    private CellIdentityNr(Parcel in) {
+        super(TAG, CellInfo.TYPE_NR, in);
+        mPci = in.readInt();
+        mTac = in.readInt();
+        mNrArfcn = in.readInt();
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Creator<CellIdentityNr> CREATOR =
+            new Creator<CellIdentityNr>() {
+                @Override
+                public CellIdentityNr createFromParcel(Parcel in) {
+                    // Skip the type info.
+                    in.readInt();
+                    return createFromParcelBody(in);
+                }
+
+                @Override
+                public CellIdentityNr[] newArray(int size) {
+                    return new CellIdentityNr[size];
+                }
+            };
+
+    /** @hide */
+    protected static CellIdentityNr createFromParcelBody(Parcel in) {
+        return new CellIdentityNr(in);
+    }
+}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index 1c63e82..d0b2687 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -42,38 +42,51 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "TYPE_", value = {TYPE_GSM, TYPE_CDMA, TYPE_LTE, TYPE_WCDMA, TYPE_TDSCDMA})
+    @IntDef(prefix = "TYPE_",
+            value = {TYPE_GSM, TYPE_CDMA, TYPE_LTE, TYPE_WCDMA, TYPE_TDSCDMA, TYPE_NR})
     public @interface Type {}
+
     /**
      * Unknown cell identity type
      * @hide
      */
-    public static final int TYPE_UNKNOWN        = 0;
+    public static final int TYPE_UNKNOWN = 0;
+
     /**
      * GSM cell identity type
      * @hide
      */
-    public static final int TYPE_GSM            = 1;
+    public static final int TYPE_GSM = 1;
+
     /**
      * CDMA cell identity type
      * @hide
      */
-    public static final int TYPE_CDMA           = 2;
+    public static final int TYPE_CDMA = 2;
+
     /**
      * LTE cell identity type
      * @hide
      */
-    public static final int TYPE_LTE            = 3;
+    public static final int TYPE_LTE = 3;
+
     /**
      * WCDMA cell identity type
      * @hide
      */
-    public static final int TYPE_WCDMA          = 4;
+    public static final int TYPE_WCDMA = 4;
+
     /**
      * TD-SCDMA cell identity type
      * @hide
      */
-    public static final int TYPE_TDSCDMA        = 5;
+    public static final int TYPE_TDSCDMA = 5;
+
+    /**
+     * 5G cell identity type
+     * @hide
+     */
+    public static final int TYPE_NR = 6;
 
     // Type to distinguish where time stamp gets recorded.
 
@@ -277,6 +290,7 @@
                     case TYPE_LTE: return CellInfoLte.createFromParcelBody(in);
                     case TYPE_WCDMA: return CellInfoWcdma.createFromParcelBody(in);
                     case TYPE_TDSCDMA: return CellInfoTdscdma.createFromParcelBody(in);
+                    case TYPE_NR: return CellInfoNr.createFromParcelBody(in);
                     default: throw new RuntimeException("Bad CellInfo Parcel");
                 }
         }
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
new file mode 100644
index 0000000..11857a6
--- /dev/null
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+import android.os.Parcel;
+
+import java.util.Objects;
+
+/**
+ * A {@link CellInfo} representing an 5G NR cell that provides identity and measurement info.
+ */
+public final class CellInfoNr extends CellInfo {
+    private static final String TAG = "CellInfoNr";
+
+    private final CellIdentityNr mCellIdentity;
+    private final CellSignalStrengthNr mCellSignalStrength;
+
+    private CellInfoNr(Parcel in) {
+        super(in);
+        mCellIdentity = CellIdentityNr.CREATOR.createFromParcel(in);
+        mCellSignalStrength = CellSignalStrengthNr.CREATOR.createFromParcel(in);
+    }
+
+    @Override
+    public CellIdentity getCellIdentity() {
+        return mCellIdentity;
+    }
+
+    @Override
+    public CellSignalStrength getCellSignalStrength() {
+        return mCellSignalStrength;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), mCellIdentity, mCellSignalStrength);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof CellInfoNr)) {
+            return false;
+        }
+
+        CellInfoNr o = (CellInfoNr) other;
+        return super.equals(o) && mCellIdentity.equals(o.mCellIdentity)
+                && mCellSignalStrength.equals(o.mCellSignalStrength);
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append(TAG + ":{")
+                .append(" " + super.toString())
+                .append(" " + mCellIdentity)
+                .append(" " + mCellSignalStrength)
+                .append(" }")
+                .toString();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags, TYPE_NR);
+        mCellIdentity.writeToParcel(dest, flags);
+        mCellSignalStrength.writeToParcel(dest, flags);
+    }
+
+    public static final Creator<CellInfoNr> CREATOR = new Creator<CellInfoNr>() {
+        @Override
+        public CellInfoNr createFromParcel(Parcel in) {
+            // Skip the type info.
+            in.readInt();
+            return new CellInfoNr(in);
+        }
+
+        @Override
+        public CellInfoNr[] newArray(int size) {
+            return new CellInfoNr[size];
+        }
+    };
+
+    /** @hide */
+    protected static CellInfoNr createFromParcelBody(Parcel in) {
+        return new CellInfoNr(in);
+    }
+}
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index d6856b3..2ff75e6 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -19,7 +19,6 @@
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.Rlog;
 
 import java.util.Objects;
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
new file mode 100644
index 0000000..8079242
--- /dev/null
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * 5G NR signal strength related information.
+ */
+public final class CellSignalStrengthNr extends CellSignalStrength implements Parcelable {
+    /**
+     * The value is used to indicate that the asu level is unknown.
+     * Reference: 3GPP TS 27.007 section 8.69.
+     * @hide
+     */
+    public static final int UNKNOWN_ASU_LEVEL = 99;
+
+    private static final String TAG = "CellSignalStrengthNr";
+
+    /**
+     * These threshold values are copied from LTE.
+     * TODO: make it configurable via CarrierConfig.
+     */
+    private static final int SIGNAL_GREAT_THRESHOLD = -95;
+    private static final int SIGNAL_GOOD_THRESHOLD = -105;
+    private static final int SIGNAL_MODERATE_THRESHOLD = -115;
+
+    private int mCsiRsrp;
+    private int mCsiRsrq;
+    private int mCsiSinr;
+    private int mSsRsrp;
+    private int mSsRsrq;
+    private int mSsSinr;
+
+    /**
+     * @param csiRsrp CSI reference signal received power.
+     * @param csiRsrq CSI reference signal received quality.
+     * @param csiSinr CSI signal-to-noise and interference ratio.
+     * @param ssRsrp SS reference signal received power.
+     * @param ssRsrq SS reference signal received quality.
+     * @param ssSinr SS signal-to-noise and interference ratio.
+     * @hide
+     */
+    public CellSignalStrengthNr(
+            int csiRsrp, int csiRsrq, int csiSinr, int ssRsrp, int ssRsrq, int ssSinr) {
+        mCsiRsrp = csiRsrp;
+        mCsiRsrq = csiRsrq;
+        mCsiSinr = csiSinr;
+        mSsRsrp = ssRsrp;
+        mSsRsrq = ssRsrq;
+        mSsSinr = ssSinr;
+    }
+
+    /**
+     * Reference: 3GPP TS 38.215.
+     * Range: -140 dBm to -44 dBm.
+     * @return SS reference signal received power, {@link CellInfo#UNAVAILABLE} means unreported
+     * value.
+     */
+    public int getSsRsrp() {
+        return mSsRsrp;
+    }
+
+    /**
+     * Reference: 3GPP TS 38.215.
+     * Range: -20 dB to -3 dB.
+     * @return SS reference signal received quality, {@link CellInfo#UNAVAILABLE} means unreported
+     * value.
+     */
+    public int getSsRsrq() {
+        return mSsRsrq;
+    }
+
+    /**
+     * Reference: 3GPP TS 38.215 Sec 5.1.*, 3GPP TS 38.133 10.1.16.1
+     * Range: -23 dB to 40 dB
+     * @return SS signal-to-noise and interference ratio, {@link CellInfo#UNAVAILABLE} means
+     * unreported value.
+     */
+    public int getSsSinr() {
+        return mSsSinr;
+    }
+
+    /**
+     * Reference: 3GPP TS 38.215.
+     * Range: -140 dBm to -44 dBm.
+     * @return CSI reference signal received power, {@link CellInfo#UNAVAILABLE} means unreported
+     * value.
+     */
+    public int getCsiRsrp() {
+        return mCsiRsrp;
+    }
+
+    /**
+     * Reference: 3GPP TS 38.215.
+     * Range: -20 dB to -3 dB.
+     * @return CSI reference signal received quality, {@link CellInfo#UNAVAILABLE} means unreported
+     * value.
+     */
+    public int getCsiRsrq() {
+        return mCsiRsrq;
+    }
+
+    /**
+     * Reference: 3GPP TS 38.215 Sec 5.1.*, 3GPP TS 38.133 10.1.16.1
+     * Range: -23 dB to 23 dB
+     * @return CSI signal-to-noise and interference ratio, {@link CellInfo#UNAVAILABLE} means
+     * unreported value.
+     */
+    public int getCsiSinr() {
+        return mCsiSinr;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mCsiRsrp);
+        dest.writeInt(mCsiRsrq);
+        dest.writeInt(mCsiSinr);
+        dest.writeInt(mSsRsrp);
+        dest.writeInt(mSsRsrq);
+        dest.writeInt(mSsSinr);
+    }
+
+    private CellSignalStrengthNr(Parcel in) {
+        mCsiRsrp = in.readInt();
+        mCsiRsrq = in.readInt();
+        mCsiSinr = in.readInt();
+        mSsRsrp = in.readInt();
+        mSsRsrq = in.readInt();
+        mSsSinr = in.readInt();
+    }
+
+    /** @hide */
+    @Override
+    public void setDefaultValues() {
+        mCsiRsrp = CellInfo.UNAVAILABLE;
+        mCsiRsrq = CellInfo.UNAVAILABLE;
+        mCsiSinr = CellInfo.UNAVAILABLE;
+        mSsRsrp = CellInfo.UNAVAILABLE;
+        mSsRsrq = CellInfo.UNAVAILABLE;
+        mSsSinr = CellInfo.UNAVAILABLE;
+    }
+
+    @Override
+    public int getLevel() {
+        if (mCsiRsrp == CellInfo.UNAVAILABLE) {
+            return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        } else if (mCsiRsrp >= SIGNAL_GREAT_THRESHOLD) {
+            return SIGNAL_STRENGTH_GREAT;
+        } else if (mCsiRsrp >= SIGNAL_GOOD_THRESHOLD) {
+            return SIGNAL_STRENGTH_GOOD;
+        } else if (mCsiRsrp >= SIGNAL_MODERATE_THRESHOLD) {
+            return SIGNAL_STRENGTH_MODERATE;
+        } else {
+            return SIGNAL_STRENGTH_POOR;
+        }
+    }
+
+    /**
+     * Calculates the NR signal as an asu value between 0..97, 99 is unknown.
+     * Asu is calculated based on 3GPP RSRP, refer to 3GPP TS 27.007 section 8.69.
+     * @return an integer represent the asu level of the signal strength.
+     */
+    @Override
+    public int getAsuLevel() {
+        int asuLevel;
+        int nrDbm = getDbm();
+        if (nrDbm == CellInfo.UNAVAILABLE) {
+            asuLevel = UNKNOWN_ASU_LEVEL;
+        } else if (nrDbm <= -140) {
+            asuLevel = 0;
+        } else if (nrDbm >= -43) {
+            asuLevel = 97;
+        } else {
+            asuLevel = nrDbm + 140;
+        }
+        return asuLevel;
+    }
+
+    @Override
+    public int getDbm() {
+        return mCsiRsrp;
+    }
+
+    /** @hide */
+    @Override
+    public CellSignalStrength copy() {
+        return new CellSignalStrengthNr(
+                mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof CellSignalStrengthNr) {
+            CellSignalStrengthNr o = (CellSignalStrengthNr) obj;
+            return mCsiRsrp == o.mCsiRsrp && mCsiRsrq == o.mCsiRsrq && mCsiSinr == o.mCsiSinr
+                    && mSsRsrp == o.mSsRsrp && mSsRsrq == o.mSsRsrq && mSsSinr == o.mSsSinr;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append(TAG + ":{")
+                .append(" csiRsrp = " + mCsiRsrp)
+                .append(" csiRsrq = " + mCsiRsrq)
+                .append(" csiSinr = " + mCsiSinr)
+                .append(" ssRsrp = " + mSsRsrp)
+                .append(" ssRsrq = " + mSsRsrq)
+                .append(" ssSinr = " + mSsSinr)
+                .append(" }")
+                .toString();
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Parcelable.Creator<CellSignalStrengthNr> CREATOR =
+            new Parcelable.Creator<CellSignalStrengthNr>() {
+        @Override
+        public CellSignalStrengthNr createFromParcel(Parcel in) {
+            return new CellSignalStrengthNr(in);
+        }
+
+        @Override
+        public CellSignalStrengthNr[] newArray(int size) {
+            return new CellSignalStrengthNr[size];
+        }
+    };
+}
diff --git a/telephony/java/com/android/internal/telephony/NetworkScanResult.java b/telephony/java/com/android/internal/telephony/NetworkScanResult.java
index 95f39d7..d07d77c 100644
--- a/telephony/java/com/android/internal/telephony/NetworkScanResult.java
+++ b/telephony/java/com/android/internal/telephony/NetworkScanResult.java
@@ -19,6 +19,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.CellInfo;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -106,6 +107,17 @@
     }
 
     @Override
+    public String toString() {
+        return new StringBuilder()
+            .append("{")
+            .append("scanStatus=" + scanStatus)
+            .append(", scanError=" + scanError)
+            .append(", networkInfos=" + networkInfos)
+            .append("}")
+            .toString();
+    }
+
+    @Override
     public int hashCode () {
         return ((scanStatus * 31)
                 + (scanError * 23)
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index 414758e..2e717ff 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -248,6 +248,7 @@
             if (!split_entry->id) {
               split_entry->id = entry->id;
               split_entry->visibility = entry->visibility;
+              split_entry->overlayable_declarations = entry->overlayable_declarations;
             }
 
             // Copy the selected values into the new Split Entry.
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 5a4c898..e6892be 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -16,9 +16,13 @@
 
 package android.net.wifi.p2p;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
-import android.annotation.SystemService;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.net.wifi.WpsInfo;
@@ -480,6 +484,12 @@
     /** @hide */
     public static final int REPORT_NFC_HANDOVER_FAILED              = BASE + 81;
 
+    /** @hide */
+    public static final int FACTORY_RESET                           = BASE + 82;
+    /** @hide */
+    public static final int FACTORY_RESET_FAILED                    = BASE + 83;
+    /** @hide */
+    public static final int FACTORY_RESET_SUCCEEDED                 = BASE + 84;
 
     /**
      * Create a new WifiP2pManager instance. Applications use
@@ -776,6 +786,7 @@
                     case STOP_LISTEN_FAILED:
                     case SET_CHANNEL_FAILED:
                     case REPORT_NFC_HANDOVER_FAILED:
+                    case FACTORY_RESET_FAILED:
                         if (listener != null) {
                             ((ActionListener) listener).onFailure(message.arg1);
                         }
@@ -802,6 +813,7 @@
                     case STOP_LISTEN_SUCCEEDED:
                     case SET_CHANNEL_SUCCEEDED:
                     case REPORT_NFC_HANDOVER_SUCCEEDED:
+                    case FACTORY_RESET_SUCCEEDED:
                         if (listener != null) {
                             ((ActionListener) listener).onSuccess();
                         }
@@ -1521,4 +1533,21 @@
         c.mAsyncChannel.sendMessage(RESPONDER_REPORT_NFC_HANDOVER, 0,
                 c.putListener(listener), bundle);
     }
+
+    /**
+     * Removes all saved p2p groups.
+     * @param c is the channel created at {@link #initialize}.
+     * @param listener for callback on success or failure. Can be null.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public void factoryReset(@NonNull Channel c, @Nullable ActionListener listener) {
+        checkChannel(c);
+        Bundle callingPackage = new Bundle();
+        callingPackage.putString(CALLING_PACKAGE, c.mContext.getOpPackageName());
+        c.mAsyncChannel.sendMessage(FACTORY_RESET, 0, c.putListener(listener),
+                callingPackage);
+    }
+
 }
diff --git a/wifi/java/com/android/server/wifi/AbstractWifiService.java b/wifi/java/com/android/server/wifi/AbstractWifiService.java
new file mode 100644
index 0000000..eede23b
--- /dev/null
+++ b/wifi/java/com/android/server/wifi/AbstractWifiService.java
@@ -0,0 +1,415 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License") {
+ *  throw new UnsupportedOperationException();
+ }
+ * 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.wifi;
+
+import android.content.pm.ParceledListSlice;
+import android.net.DhcpInfo;
+import android.net.Network;
+import android.net.wifi.INetworkRequestMatchCallback;
+import android.net.wifi.ISoftApCallback;
+import android.net.wifi.ITrafficStateCallback;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.PasspointManagementObjectDefinition;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiActivityEnergyInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.hotspot2.IProvisioningCallback;
+import android.net.wifi.hotspot2.OsuProvider;
+import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.os.IBinder;
+import android.os.Messenger;
+import android.os.ResultReceiver;
+import android.os.WorkSource;
+import android.util.Slog;
+
+import java.util.List;
+
+/**
+ * Abstract class implementing IWifiManager with stub methods throwing runtime exceptions.
+ *
+ * This class is meant to be extended by real implementations of IWifiManager in order to facilitate
+ * cross-repo changes to WiFi internal APIs, including the introduction of new APIs, the removal of
+ * deprecated APIs, or the migration of existing API signatures.
+ *
+ * When an existing API is scheduled for removal, it can be removed from IWifiManager.aidl
+ * immediately and marked as @Deprecated first in this class. Children inheriting this class are
+ * then given a short grace period to update themselves before the @Deprecated stub is removed for
+ * good. If the API scheduled for removal has a replacement or an overload (signature change),
+ * these should be introduced before the stub is removed to allow children to migrate.
+ */
+public abstract class AbstractWifiService extends IWifiManager.Stub {
+
+    private static final String TAG = AbstractWifiService.class.getSimpleName();
+
+    @Override
+    public int getSupportedFeatures() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public WifiActivityEnergyInfo reportActivityInfo() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void requestActivityInfo(ResultReceiver result) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ParceledListSlice getConfiguredNetworks() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ParceledListSlice getPrivilegedConfiguredNetworks() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<WifiConfiguration> getAllMatchingWifiConfigs(ScanResult scanResult) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<OsuProvider> getMatchingOsuProviders(ScanResult scanResult) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean addOrUpdatePasspointConfiguration(
+            PasspointConfiguration config, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removePasspointConfiguration(String fqdn, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<PasspointConfiguration> getPasspointConfigurations() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void queryPasspointIcon(long bssid, String fileName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int matchProviderWithCurrentNetwork(String fqdn) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void deauthenticateNetwork(long holdoff, boolean ess) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeNetwork(int netId, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean enableNetwork(int netId, boolean disableOthers, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean disableNetwork(int netId, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean startScan(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<ScanResult> getScanResults(String callingPackage) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void disconnect(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void reconnect(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void reassociate(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public WifiInfo getConnectionInfo(String callingPackage) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean setWifiEnabled(String packageName, boolean enable) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getWifiEnabledState() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setCountryCode(String country) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCountryCode() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isDualBandSupported() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean needs5GHzToAnyApBandConversion() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DhcpInfo getDhcpInfo() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isScanAlwaysAvailable() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean acquireWifiLock(IBinder lock, int lockType, String tag, WorkSource ws) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean releaseWifiLock(IBinder lock) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void initializeMulticastFiltering() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isMulticastEnabled() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void acquireMulticastLock(IBinder binder, String tag) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void releaseMulticastLock(String tag) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void updateInterfaceIpState(String ifaceName, int mode) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean startSoftAp(WifiConfiguration wifiConfig) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean stopSoftAp() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void stopLocalOnlyHotspot() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void stopWatchLocalOnlyHotspot() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getWifiApEnabledState() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public WifiConfiguration getWifiApConfiguration() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void notifyUserOfApBandConversion(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Messenger getWifiServiceMessenger(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enableTdls(String remoteIPAddress, boolean enable) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCurrentNetworkWpsNfcConfigurationToken() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enableVerboseLogging(int verbose) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getVerboseLoggingLevel() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enableWifiConnectivityManager(boolean enabled) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void disableEphemeralNetwork(String SSID, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void factoryReset(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Network getCurrentNetwork() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public byte[] retrieveBackupData() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void restoreBackupData(byte[] data) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void startSubscriptionProvisioning(
+            OsuProvider provider, IProvisioningCallback callback) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void registerSoftApCallback(
+            IBinder binder, ISoftApCallback callback, int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unregisterSoftApCallback(int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void registerTrafficStateCallback(
+            IBinder binder, ITrafficStateCallback callback, int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unregisterTrafficStateCallback(int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void registerNetworkRequestMatchCallback(
+            IBinder binder, INetworkRequestMatchCallback callback, int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unregisterNetworkRequestMatchCallback(int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+}