Merge "Add new BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS binding flag and the mechanism to use it"
diff --git a/Android.bp b/Android.bp
index 4e7aa5f..e8f3561 100644
--- a/Android.bp
+++ b/Android.bp
@@ -636,7 +636,7 @@
         "wifi/java/android/net/wifi/ISoftApCallback.aidl",
         "wifi/java/android/net/wifi/ITrafficStateCallback.aidl",
         "wifi/java/android/net/wifi/IWifiManager.aidl",
-        "wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl",
+        "wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl",
         "wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl",
         "wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl",
         "wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl",
diff --git a/api/current.txt b/api/current.txt
index 135a5b4..f0b491a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6509,9 +6509,9 @@
 
   public class DelegatedAdminReceiver extends android.content.BroadcastReceiver {
     ctor public DelegatedAdminReceiver();
-    method public String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, String);
-    method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int);
-    method public void onReceive(android.content.Context, android.content.Intent);
+    method @Nullable public String onChoosePrivateKeyAlias(@NonNull android.content.Context, @NonNull android.content.Intent, int, @Nullable android.net.Uri, @Nullable String);
+    method public void onNetworkLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent, long, @IntRange(from=1) int);
+    method public final void onReceive(@NonNull android.content.Context, @NonNull android.content.Intent);
   }
 
   public final class DeviceAdminInfo implements android.os.Parcelable {
@@ -6544,38 +6544,38 @@
 
   public class DeviceAdminReceiver extends android.content.BroadcastReceiver {
     ctor public DeviceAdminReceiver();
-    method public android.app.admin.DevicePolicyManager getManager(android.content.Context);
-    method public android.content.ComponentName getWho(android.content.Context);
-    method public void onBugreportFailed(android.content.Context, android.content.Intent, int);
-    method public void onBugreportShared(android.content.Context, android.content.Intent, String);
-    method public void onBugreportSharingDeclined(android.content.Context, android.content.Intent);
-    method public String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, String);
-    method public CharSequence onDisableRequested(android.content.Context, android.content.Intent);
-    method public void onDisabled(android.content.Context, android.content.Intent);
-    method public void onEnabled(android.content.Context, android.content.Intent);
-    method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, String);
-    method public void onLockTaskModeExiting(android.content.Context, android.content.Intent);
-    method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int);
-    method @Deprecated public void onPasswordChanged(android.content.Context, android.content.Intent);
-    method public void onPasswordChanged(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method @Deprecated public void onPasswordExpiring(android.content.Context, android.content.Intent);
-    method public void onPasswordExpiring(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method @Deprecated public void onPasswordFailed(android.content.Context, android.content.Intent);
-    method public void onPasswordFailed(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method @Deprecated public void onPasswordSucceeded(android.content.Context, android.content.Intent);
-    method public void onPasswordSucceeded(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
-    method @Deprecated public void onReadyForUserInitialization(android.content.Context, android.content.Intent);
-    method public void onReceive(android.content.Context, android.content.Intent);
-    method public void onSecurityLogsAvailable(android.content.Context, android.content.Intent);
-    method public void onSystemUpdatePending(android.content.Context, android.content.Intent, long);
-    method public void onTransferAffiliatedProfileOwnershipComplete(android.content.Context, android.os.UserHandle);
+    method @NonNull public android.app.admin.DevicePolicyManager getManager(@NonNull android.content.Context);
+    method @NonNull public android.content.ComponentName getWho(@NonNull android.content.Context);
+    method public void onBugreportFailed(@NonNull android.content.Context, @NonNull android.content.Intent, int);
+    method public void onBugreportShared(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull String);
+    method public void onBugreportSharingDeclined(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method @Nullable public String onChoosePrivateKeyAlias(@NonNull android.content.Context, @NonNull android.content.Intent, int, @Nullable android.net.Uri, @Nullable String);
+    method @Nullable public CharSequence onDisableRequested(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onDisabled(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onEnabled(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onLockTaskModeEntering(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull String);
+    method public void onLockTaskModeExiting(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onNetworkLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent, long, @IntRange(from=1) int);
+    method @Deprecated public void onPasswordChanged(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onPasswordChanged(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
+    method @Deprecated public void onPasswordExpiring(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onPasswordExpiring(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
+    method @Deprecated public void onPasswordFailed(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onPasswordFailed(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
+    method @Deprecated public void onPasswordSucceeded(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onPasswordSucceeded(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
+    method public void onProfileProvisioningComplete(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method @Deprecated public void onReadyForUserInitialization(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onReceive(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onSecurityLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onSystemUpdatePending(@NonNull android.content.Context, @NonNull android.content.Intent, long);
+    method public void onTransferAffiliatedProfileOwnershipComplete(@NonNull android.content.Context, @NonNull android.os.UserHandle);
     method public void onTransferOwnershipComplete(@NonNull android.content.Context, @Nullable android.os.PersistableBundle);
-    method public void onUserAdded(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle);
-    method public void onUserRemoved(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle);
-    method public void onUserStarted(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle);
-    method public void onUserStopped(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle);
-    method public void onUserSwitched(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle);
+    method public void onUserAdded(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
+    method public void onUserRemoved(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
+    method public void onUserStarted(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
+    method public void onUserStopped(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
+    method public void onUserSwitched(@NonNull android.content.Context, @NonNull android.content.Intent, @NonNull android.os.UserHandle);
     field public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS";
     field public static final String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
     field public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
@@ -6949,7 +6949,7 @@
     field public static final int PRIVATE_DNS_MODE_UNKNOWN = 0; // 0x0
     field public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2; // 0x2
     field public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1; // 0x1
-    field public static final int PRIVATE_DNS_SET_SUCCESS = 0; // 0x0
+    field public static final int PRIVATE_DNS_SET_NO_ERROR = 0; // 0x0
     field public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1; // 0x1
     field public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2; // 0x2
     field public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 3; // 0x3
@@ -7966,9 +7966,9 @@
     method public boolean isMultipleAdvertisementSupported();
     method public boolean isOffloadedFilteringSupported();
     method public boolean isOffloadedScanBatchingSupported();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery();
@@ -8336,9 +8336,9 @@
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public int describeContents();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean fetchUuidsWithSdp();
@@ -14431,6 +14431,7 @@
     method @ColorInt public int getColor();
     method public android.graphics.ColorFilter getColorFilter();
     method @ColorLong public long getColorLong();
+    method public int getEndHyphenEdit();
     method public boolean getFillPath(android.graphics.Path, android.graphics.Path);
     method public int getFlags();
     method public String getFontFeatureSettings();
@@ -14441,7 +14442,6 @@
     method public float getFontSpacing();
     method public String getFontVariationSettings();
     method public int getHinting();
-    method public int getHyphenEdit();
     method public float getLetterSpacing();
     method public android.graphics.MaskFilter getMaskFilter();
     method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float);
@@ -14455,6 +14455,7 @@
     method public float getShadowLayerDx();
     method public float getShadowLayerDy();
     method public float getShadowLayerRadius();
+    method public int getStartHyphenEdit();
     method @Px public float getStrikeThruPosition();
     method @Px public float getStrikeThruThickness();
     method public android.graphics.Paint.Cap getStrokeCap();
@@ -14510,13 +14511,13 @@
     method public android.graphics.ColorFilter setColorFilter(android.graphics.ColorFilter);
     method public void setDither(boolean);
     method public void setElegantTextHeight(boolean);
+    method public void setEndHyphenEdit(int);
     method public void setFakeBoldText(boolean);
     method public void setFilterBitmap(boolean);
     method public void setFlags(int);
     method public void setFontFeatureSettings(String);
     method public boolean setFontVariationSettings(String);
     method public void setHinting(int);
-    method public void setHyphenEdit(int);
     method public void setLetterSpacing(float);
     method public void setLinearText(boolean);
     method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter);
@@ -14524,6 +14525,7 @@
     method public android.graphics.Shader setShader(android.graphics.Shader);
     method public void setShadowLayer(float, float, float, @ColorInt int);
     method public void setShadowLayer(float, float, float, @ColorLong long);
+    method public void setStartHyphenEdit(int);
     method public void setStrikeThruText(boolean);
     method public void setStrokeCap(android.graphics.Paint.Cap);
     method public void setStrokeJoin(android.graphics.Paint.Join);
@@ -14550,11 +14552,21 @@
     field public static final int DEV_KERN_TEXT_FLAG = 256; // 0x100
     field public static final int DITHER_FLAG = 4; // 0x4
     field public static final int EMBEDDED_BITMAP_TEXT_FLAG = 1024; // 0x400
+    field public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 3; // 0x3
+    field public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 2; // 0x2
+    field public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 4; // 0x4
+    field public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 5; // 0x5
+    field public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 6; // 0x6
+    field public static final int END_HYPHEN_EDIT_NO_EDIT = 0; // 0x0
+    field public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 1; // 0x1
     field public static final int FAKE_BOLD_TEXT_FLAG = 32; // 0x20
     field public static final int FILTER_BITMAP_FLAG = 2; // 0x2
     field public static final int HINTING_OFF = 0; // 0x0
     field public static final int HINTING_ON = 1; // 0x1
     field public static final int LINEAR_TEXT_FLAG = 64; // 0x40
+    field public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 1; // 0x1
+    field public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 2; // 0x2
+    field public static final int START_HYPHEN_EDIT_NO_EDIT = 0; // 0x0
     field public static final int STRIKE_THRU_TEXT_FLAG = 16; // 0x10
     field public static final int SUBPIXEL_TEXT_FLAG = 128; // 0x80
     field public static final int UNDERLINE_TEXT_FLAG = 8; // 0x8
@@ -15928,12 +15940,13 @@
   }
 
   public static class LineBreaker.Result {
+    method public int getEndLineHyphenEdit(int);
     method @Px public float getLineAscent(@IntRange(from=0) int);
     method @IntRange(from=0) public int getLineBreakOffset(@IntRange(from=0) int);
     method @IntRange(from=0) public int getLineCount();
     method @Px public float getLineDescent(@IntRange(from=0) int);
-    method public int getLineHyphenEdit(int);
     method @Px public float getLineWidth(@IntRange(from=0) int);
+    method public int getStartLineHyphenEdit(int);
     method public boolean hasLineTab(int);
   }
 
@@ -24740,6 +24753,10 @@
 
   public final class MediaDrm implements java.lang.AutoCloseable {
     ctor public MediaDrm(@NonNull java.util.UUID) throws android.media.UnsupportedSchemeException;
+    method public void clearOnEventListener();
+    method public void clearOnExpirationUpdateListener();
+    method public void clearOnKeyStatusChangeListener();
+    method public void clearOnSessionLostStateListener();
     method public void close();
     method public void closeSession(@NonNull byte[]);
     method @android.media.MediaDrm.HdcpLevel public int getConnectedHdcpLevel();
@@ -24776,9 +24793,14 @@
     method public void removeSecureStop(@NonNull byte[]);
     method public void restoreKeys(@NonNull byte[], @NonNull byte[]);
     method public void setOnEventListener(@Nullable android.media.MediaDrm.OnEventListener);
+    method public void setOnEventListener(@Nullable android.media.MediaDrm.OnEventListener, @Nullable android.os.Handler);
+    method public void setOnEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaDrm.OnEventListener);
     method public void setOnExpirationUpdateListener(@Nullable android.media.MediaDrm.OnExpirationUpdateListener, @Nullable android.os.Handler);
+    method public void setOnExpirationUpdateListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaDrm.OnExpirationUpdateListener);
     method public void setOnKeyStatusChangeListener(@Nullable android.media.MediaDrm.OnKeyStatusChangeListener, @Nullable android.os.Handler);
+    method public void setOnKeyStatusChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaDrm.OnKeyStatusChangeListener);
     method public void setOnSessionLostStateListener(@Nullable android.media.MediaDrm.OnSessionLostStateListener, @Nullable android.os.Handler);
+    method public void setOnSessionLostStateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaDrm.OnSessionLostStateListener);
     method public void setPropertyByteArray(@NonNull String, @NonNull byte[]);
     method public void setPropertyString(@NonNull String, @NonNull String);
     field @Deprecated public static final int EVENT_KEY_EXPIRED = 3; // 0x3
@@ -26399,7 +26421,7 @@
   public final class Session2Token implements android.os.Parcelable {
     ctor public Session2Token(@NonNull android.content.Context, @NonNull android.content.ComponentName);
     method public int describeContents();
-    method @Nullable public android.os.Bundle getExtras();
+    method @NonNull public android.os.Bundle getExtras();
     method @NonNull public String getPackageName();
     method @Nullable public String getServiceName();
     method public int getType();
@@ -45442,26 +45464,26 @@
   public static class ApnSetting.Builder {
     ctor public ApnSetting.Builder();
     method public android.telephony.data.ApnSetting build();
-    method public android.telephony.data.ApnSetting.Builder setApnName(String);
-    method public android.telephony.data.ApnSetting.Builder setApnTypeBitmask(int);
-    method public android.telephony.data.ApnSetting.Builder setAuthType(int);
-    method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setApnName(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setApnTypeBitmask(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setAuthType(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean);
     method @NonNull public android.telephony.data.ApnSetting.Builder setCarrierId(int);
-    method public android.telephony.data.ApnSetting.Builder setEntryName(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setEntryName(String);
     method @Deprecated public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.net.InetAddress);
-    method public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(String);
-    method public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int);
-    method public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri);
-    method public android.telephony.data.ApnSetting.Builder setMvnoType(int);
-    method public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int);
-    method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(String);
-    method public android.telephony.data.ApnSetting.Builder setPassword(String);
-    method public android.telephony.data.ApnSetting.Builder setProtocol(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setMvnoType(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setOperatorNumeric(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setPassword(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setProtocol(int);
     method @Deprecated public android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress);
-    method public android.telephony.data.ApnSetting.Builder setProxyAddress(String);
-    method public android.telephony.data.ApnSetting.Builder setProxyPort(int);
-    method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int);
-    method public android.telephony.data.ApnSetting.Builder setUser(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setProxyAddress(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setProxyPort(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setUser(String);
   }
 
 }
@@ -46004,22 +46026,6 @@
     method public void handleTag(boolean, String, android.text.Editable, org.xml.sax.XMLReader);
   }
 
-  public class Hyphenator {
-    method public static int packHyphenEdit(int, int);
-    method public static int unpackEndHyphenEdit(int);
-    method public static int unpackStartHyphenEdit(int);
-    field public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 3; // 0x3
-    field public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 2; // 0x2
-    field public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 4; // 0x4
-    field public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 5; // 0x5
-    field public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 6; // 0x6
-    field public static final int END_HYPHEN_EDIT_NO_EDIT = 0; // 0x0
-    field public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 1; // 0x1
-    field public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 1; // 0x1
-    field public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 2; // 0x2
-    field public static final int START_HYPHEN_EDIT_NO_EDIT = 0; // 0x0
-  }
-
   public interface InputFilter {
     method public CharSequence filter(CharSequence, int, int, android.text.Spanned, int, int);
   }
@@ -56388,10 +56394,10 @@
     method public int getWindowLayoutType();
     method public boolean isAboveAnchor();
     method public boolean isAttachedInDecor();
-    method public boolean isClipToScreenEnabled();
+    method public boolean isClippedToScreen();
     method public boolean isClippingEnabled();
     method public boolean isFocusable();
-    method public boolean isLayoutInScreenEnabled();
+    method public boolean isLaidOutInScreen();
     method public boolean isOutsideTouchable();
     method public boolean isShowing();
     method public boolean isSplitTouchEnabled();
@@ -56400,7 +56406,6 @@
     method public void setAnimationStyle(int);
     method public void setAttachedInDecor(boolean);
     method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setClipToScreenEnabled(boolean);
     method public void setClippingEnabled(boolean);
     method public void setContentView(android.view.View);
     method public void setElevation(float);
@@ -56411,7 +56416,8 @@
     method public void setHeight(int);
     method public void setIgnoreCheekPress();
     method public void setInputMethodMode(int);
-    method public void setLayoutInScreenEnabled(boolean);
+    method public void setIsClippedToScreen(boolean);
+    method public void setIsLaidOutInScreen(boolean);
     method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
     method public void setOutsideTouchable(boolean);
     method public void setOverlapAnchor(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 28104d5..921a6bf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1836,10 +1836,8 @@
 
   public final class RollbackManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
     field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
     field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
     field public static final int STATUS_FAILURE = 1; // 0x1
@@ -3489,6 +3487,7 @@
     method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy);
     method public void unregisterVolumeGroupCallback(@NonNull android.media.AudioManager.VolumeGroupCallback);
     field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
@@ -3722,10 +3721,6 @@
 
 package android.media.session {
 
-  public static final class MediaController.PlaybackInfo implements android.os.Parcelable {
-    ctor public MediaController.PlaybackInfo(int, int, int, int, android.media.AudioAttributes);
-  }
-
   public final class MediaSessionManager {
     method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler);
@@ -4070,7 +4065,7 @@
   }
 
   public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
-    method public void onEntitlementResult(int);
+    method public void onTetheringEntitlementResult(int);
   }
 
   public abstract static class ConnectivityManager.OnTetheringEventCallback {
@@ -4741,13 +4736,13 @@
   }
 
   public class WifiManager {
-    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void addWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiUsabilityStatsListener);
+    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
-    method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(java.util.List<android.net.wifi.ScanResult>);
+    method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>);
     method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
@@ -4756,7 +4751,7 @@
     method public boolean isPortableHotspotSupported();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
     method public boolean isWifiScannerSupported();
-    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.WifiUsabilityStatsListener);
+    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
     method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
@@ -4801,8 +4796,8 @@
     method public void onSuccess();
   }
 
-  public static interface WifiManager.WifiUsabilityStatsListener {
-    method public void onStatsUpdated(int, boolean, android.net.wifi.WifiUsabilityStatsEntry);
+  public static interface WifiManager.OnWifiUsabilityStatsListener {
+    method public void onWifiUsabilityStats(int, boolean, @NonNull android.net.wifi.WifiUsabilityStatsEntry);
   }
 
   public class WifiNetworkConnectionStatistics implements android.os.Parcelable {
@@ -4937,35 +4932,35 @@
 
   public final class WifiUsabilityStatsEntry implements android.os.Parcelable {
     method public int describeContents();
+    method public int getLinkSpeedMbps();
+    method public int getProbeElapsedTimeSinceLastUpdateMillis();
+    method public int getProbeMcsRateSinceLastUpdate();
+    method public int getProbeStatusSinceLastUpdate();
+    method public int getRssi();
+    method public int getRxLinkSpeedMbps();
+    method public long getTimeStampMillis();
+    method public long getTotalBackgroundScanTimeMillis();
+    method public long getTotalBeaconRx();
+    method public long getTotalCcaBusyFreqTimeMillis();
+    method public long getTotalHotspot2ScanTimeMillis();
+    method public long getTotalNanScanTimeMillis();
+    method public long getTotalPnoScanTimeMillis();
+    method public long getTotalRadioOnFreqTimeMillis();
+    method public long getTotalRadioOnTimeMillis();
+    method public long getTotalRadioRxTimeMillis();
+    method public long getTotalRadioTxTimeMillis();
+    method public long getTotalRoamScanTimeMillis();
+    method public long getTotalRxSuccess();
+    method public long getTotalScanTimeMillis();
+    method public long getTotalTxBad();
+    method public long getTotalTxRetries();
+    method public long getTotalTxSuccess();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiUsabilityStatsEntry> CREATOR;
     field public static final int PROBE_STATUS_FAILURE = 3; // 0x3
     field public static final int PROBE_STATUS_NO_PROBE = 1; // 0x1
     field public static final int PROBE_STATUS_SUCCESS = 2; // 0x2
     field public static final int PROBE_STATUS_UNKNOWN = 0; // 0x0
-    field public final int linkSpeedMbps;
-    field public final int probeElapsedTimeMsSinceLastUpdate;
-    field public final int probeMcsRateSinceLastUpdate;
-    field public final int probeStatusSinceLastUpdate;
-    field public final int rssi;
-    field public final int rxLinkSpeedMbps;
-    field public final long timeStampMs;
-    field public final long totalBackgroundScanTimeMs;
-    field public final long totalBeaconRx;
-    field public final long totalCcaBusyFreqTimeMs;
-    field public final long totalHotspot2ScanTimeMs;
-    field public final long totalNanScanTimeMs;
-    field public final long totalPnoScanTimeMs;
-    field public final long totalRadioOnFreqTimeMs;
-    field public final long totalRadioOnTimeMs;
-    field public final long totalRadioRxTimeMs;
-    field public final long totalRadioTxTimeMs;
-    field public final long totalRoamScanTimeMs;
-    field public final long totalRxSuccess;
-    field public final long totalScanTimeMs;
-    field public final long totalTxBad;
-    field public final long totalTxRetries;
-    field public final long totalTxSuccess;
   }
 
 }
@@ -5866,6 +5861,7 @@
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
     field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+    field public static final String NAMESPACE_DEX_BOOT = "dex_boot";
     field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
     field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
     field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
@@ -5881,12 +5877,6 @@
     field public static final String SERVICE_ENABLED = "service_enabled";
   }
 
-  public static interface DeviceConfig.DexBoot {
-    field public static final String NAMESPACE = "dex_boot";
-    field public static final String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled";
-    field public static final String PRIV_APPS_OOB_WHITELIST = "priv_apps_oob_whitelist";
-  }
-
   public static interface DeviceConfig.IntelligenceAttention {
     field public static final String ATTENTION_ENABLED = "attention_enabled";
     field public static final String ATTENTION_SETTINGS = "attention_settings";
@@ -8068,6 +8058,10 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
     method public boolean isDataConnectivityPossible();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
@@ -8103,7 +8097,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
     method public void updateServiceLocation();
-    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_DEBUG_EVENT = "android.telephony.action.DEBUG_EVENT";
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
@@ -8111,8 +8105,8 @@
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
     field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
-    field public static final String EXTRA_DEBUG_EVENT_DESCRIPTION = "android.telephony.extra.DEBUG_EVENT_DESCRIPTION";
-    field public static final String EXTRA_DEBUG_EVENT_ID = "android.telephony.extra.DEBUG_EVENT_ID";
+    field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
+    field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
     field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
     field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
     field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
diff --git a/api/test-current.txt b/api/test-current.txt
index 46e061b..2913743 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -11,8 +11,10 @@
     field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
     field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
     field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
+    field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
     field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+    field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
     field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
   }
@@ -596,6 +598,7 @@
     method public int getUserId();
     method public void setAutofillOptions(@Nullable android.content.AutofillOptions);
     method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
+    field public static final String ROLLBACK_SERVICE = "rollback";
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -603,6 +606,7 @@
   }
 
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
+    field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
     field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
   }
 
@@ -626,6 +630,12 @@
     ctor public LauncherApps(android.content.Context);
   }
 
+  public static class PackageInstaller.SessionParams implements android.os.Parcelable {
+    method public void setEnableRollback(boolean);
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
+  }
+
   public abstract class PackageManager {
     method public abstract boolean arePermissionsIndividuallyControlled();
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int);
@@ -686,6 +696,44 @@
 
 }
 
+package android.content.rollback {
+
+  public final class PackageRollbackInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getPackageName();
+    method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackFrom();
+    method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackTo();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
+  }
+
+  public final class RollbackInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<android.content.pm.VersionedPackage> getCausePackages();
+    method public int getCommittedSessionId();
+    method @NonNull public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
+    method public int getRollbackId();
+    method public boolean isStaged();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
+  }
+
+  public final class RollbackManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
+    field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
+    field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
+    field public static final int STATUS_FAILURE = 1; // 0x1
+    field public static final int STATUS_FAILURE_INSTALL = 3; // 0x3
+    field public static final int STATUS_FAILURE_ROLLBACK_UNAVAILABLE = 2; // 0x2
+    field public static final int STATUS_SUCCESS = 0; // 0x0
+  }
+
+}
+
 package android.database.sqlite {
 
   public class SQLiteCompatibilityWalFlags {
@@ -2015,8 +2063,8 @@
     method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(String, String, String);
     method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
     method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
-    method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String);
-    method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
+    method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean);
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
   }
@@ -2044,6 +2092,13 @@
     method @Nullable public String getString(@NonNull String, @Nullable String);
   }
 
+  public static interface DeviceConfig.Rollback {
+    field public static final String BOOT_NAMESPACE = "rollback_boot";
+    field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
+    field public static final String NAMESPACE = "rollback";
+    field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
+  }
+
   public final class MediaStore {
     method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index 3666d6a..469c964 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -2,9 +2,6 @@
     class core animation
     user graphics
     group graphics audio
-    # bootanimation depends on libandroidicu in the Runtime APEX.
-    # TODO(b/124939955): Remove this dependency on libandroidicu
-    updatable
     disabled
     oneshot
     writepid /dev/stune/top-app/tasks
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 7298da6..ce07d6d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -219,6 +219,7 @@
         "tests/anomaly/AnomalyTracker_test.cpp",
         "tests/ConfigManager_test.cpp",
         "tests/external/puller_util_test.cpp",
+        "tests/external/GpuStatsPuller_test.cpp",
         "tests/external/IncidentReportArgs_test.cpp",
         "tests/external/StatsPuller_test.cpp",
         "tests/indexed_priority_queue_test.cpp",
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4856f77..69372cd 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5759,7 +5759,7 @@
     optional string tzdb_version = 1;
 }
 
-/*
+/**
  * Logs the GPU stats global health information.
  *
  * Logged from:
@@ -5791,22 +5791,34 @@
     optional int64 vk_loading_failure_count = 8;
 }
 
-/*
+/**
+ * GPU driver loading time info.
+ */
+message GpuDriverLoadingTime {
+    // List of all the driver loading times for this app. The list size is
+    // capped at 50.
+    repeated int64 driver_loading_time = 1;
+}
+
+/**
  * Logs the GPU stats per app health information.
  *
  * Logged from:
  *   frameworks/native/services/gpuservice/gpustats/
  */
 message GpuStatsAppInfo {
-    // Package name of the application that loads the gpu driver.
+    // Package name of the application that loads the gpu driver. Total number
+    // of different packages is capped at 100.
     optional string app_package_name = 1;
 
     // Version code of the gpu driver this app loads.
     optional int64 driver_version_code = 2;
 
-    // List of all the gl driver loading times for this app.
-    repeated int64 gl_driver_loading_time = 3;
+    // gl driver loading time info.
+    optional GpuDriverLoadingTime gl_driver_loading_time = 3
+            [(android.os.statsd.log_mode) = MODE_BYTES];
 
-    // List of all the Vulkan driver laoding times for this app.
-    repeated int64 vk_driver_loading_time = 4;
+    // Vulkan driver loading time info.
+    optional GpuDriverLoadingTime vk_driver_loading_time = 4
+            [(android.os.statsd.log_mode) = MODE_BYTES];
 }
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
index 8445803..130bd85 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -70,6 +70,30 @@
     return true;
 }
 
+static bool pullGpuStatsAppInfo(const sp<IGpuService>& gpuService,
+                                std::vector<std::shared_ptr<LogEvent>>* data) {
+    std::vector<GpuStatsAppInfo> stats;
+    status_t status = gpuService->getGpuStatsAppInfo(&stats);
+    if (status != OK) {
+        return false;
+    }
+
+    data->clear();
+    data->reserve(stats.size());
+    for (const auto& info : stats) {
+        std::shared_ptr<LogEvent> event = make_shared<LogEvent>(
+                android::util::GPU_STATS_APP_INFO, getWallClockNs(), getElapsedRealtimeNs());
+        if (!event->write(info.appPackageName)) return false;
+        if (!event->write((int64_t)info.driverVersionCode)) return false;
+        if (!event->write(int64VectorToProtoByteString(info.glDriverLoadingTime))) return false;
+        if (!event->write(int64VectorToProtoByteString(info.vkDriverLoadingTime))) return false;
+        event->init();
+        data->emplace_back(event);
+    }
+
+    return true;
+}
+
 bool GpuStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) {
     const sp<IGpuService> gpuService = getGpuService();
     if (!gpuService) {
@@ -79,6 +103,8 @@
     switch (mTagId) {
         case android::util::GPU_STATS_GLOBAL_INFO:
             return pullGpuStatsGlobalInfo(gpuService, data);
+        case android::util::GPU_STATS_APP_INFO:
+            return pullGpuStatsAppInfo(gpuService, data);
         default:
             break;
     }
@@ -86,6 +112,35 @@
     return false;
 }
 
+static std::string protoOutputStreamToByteString(ProtoOutputStream& proto) {
+    if (!proto.size()) return "";
+
+    std::string byteString;
+    auto iter = proto.data();
+    while (iter.readBuffer() != nullptr) {
+        const size_t toRead = iter.currentToRead();
+        byteString.append((char*)iter.readBuffer(), toRead);
+        iter.rp()->move(toRead);
+    }
+
+    if (byteString.size() != proto.size()) return "";
+
+    return byteString;
+}
+
+std::string int64VectorToProtoByteString(const std::vector<int64_t>& value) {
+    if (value.empty()) return "";
+
+    ProtoOutputStream proto;
+    for (const auto& ele : value) {
+        proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+                            1 /* field id */,
+                    (long long)ele);
+    }
+
+    return protoOutputStreamToByteString(proto);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/external/GpuStatsPuller.h b/cmds/statsd/src/external/GpuStatsPuller.h
index 4c7a4d6..2da199c 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.h
+++ b/cmds/statsd/src/external/GpuStatsPuller.h
@@ -31,6 +31,12 @@
     bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) override;
 };
 
+// convert a int64_t vector into a byte string for proto message like:
+// message RepeatedInt64Wrapper {
+//   repeated int64 value = 1;
+// }
+std::string int64VectorToProtoByteString(const std::vector<int64_t>& value);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 924704b..4f87272 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -244,6 +244,9 @@
         // GpuStatsGlobalInfo
         {android::util::GPU_STATS_GLOBAL_INFO,
          {.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}},
+        // GpuStatsAppInfo
+        {android::util::GPU_STATS_APP_INFO,
+         {.puller = new GpuStatsPuller(android::util::GPU_STATS_APP_INFO)}},
 };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
new file mode 100644
index 0000000..8625487
--- /dev/null
+++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "GpuStatsPuller_test"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <graphicsenv/GpuStatsInfo.h>
+#include <log/log.h>
+
+#include "src/external/GpuStatsPuller.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// clang-format off
+static const std::string DRIVER_PACKAGE_NAME    = "TEST_DRIVER";
+static const std::string DRIVER_VERSION_NAME    = "TEST_DRIVER_VERSION";
+static const std::string APP_PACKAGE_NAME       = "TEST_APP";
+static const int64_t TIMESTAMP_WALLCLOCK        = 111;
+static const int64_t TIMESTAMP_ELAPSED          = 222;
+static const int64_t DRIVER_VERSION_CODE        = 333;
+static const int64_t DRIVER_BUILD_TIME          = 444;
+static const int64_t GL_LOADING_COUNT           = 3;
+static const int64_t GL_LOADING_FAILURE_COUNT   = 1;
+static const int64_t VK_LOADING_COUNT           = 4;
+static const int64_t VK_LOADING_FAILURE_COUNT   = 0;
+static const int64_t GL_DRIVER_LOADING_TIME_0   = 555;
+static const int64_t GL_DRIVER_LOADING_TIME_1   = 666;
+static const int64_t VK_DRIVER_LOADING_TIME_0   = 777;
+static const int64_t VK_DRIVER_LOADING_TIME_1   = 888;
+static const int64_t VK_DRIVER_LOADING_TIME_2   = 999;
+static const size_t NUMBER_OF_VALUES_GLOBAL     = 8;
+static const size_t NUMBER_OF_VALUES_APP        = 4;
+// clang-format on
+
+class MockGpuStatsPuller : public GpuStatsPuller {
+public:
+    MockGpuStatsPuller(const int tagId, vector<std::shared_ptr<LogEvent>>* data)
+        : GpuStatsPuller(tagId), mData(data){};
+
+private:
+    bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override {
+        *data = *mData;
+        return true;
+    }
+
+    vector<std::shared_ptr<LogEvent>>* mData;
+};
+
+class GpuStatsPuller_test : public ::testing::Test {
+public:
+    GpuStatsPuller_test() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    ~GpuStatsPuller_test() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+};
+
+TEST_F(GpuStatsPuller_test, PullGpuStatsGlobalInfo) {
+    vector<std::shared_ptr<LogEvent>> inData, outData;
+    std::shared_ptr<LogEvent> event = make_shared<LogEvent>(android::util::GPU_STATS_GLOBAL_INFO,
+                                                            TIMESTAMP_WALLCLOCK, TIMESTAMP_ELAPSED);
+    EXPECT_TRUE(event->write(DRIVER_PACKAGE_NAME));
+    EXPECT_TRUE(event->write(DRIVER_VERSION_NAME));
+    EXPECT_TRUE(event->write(DRIVER_VERSION_CODE));
+    EXPECT_TRUE(event->write(DRIVER_BUILD_TIME));
+    EXPECT_TRUE(event->write(GL_LOADING_COUNT));
+    EXPECT_TRUE(event->write(GL_LOADING_FAILURE_COUNT));
+    EXPECT_TRUE(event->write(VK_LOADING_COUNT));
+    EXPECT_TRUE(event->write(VK_LOADING_FAILURE_COUNT));
+    event->init();
+    inData.emplace_back(event);
+    MockGpuStatsPuller mockPuller(android::util::GPU_STATS_GLOBAL_INFO, &inData);
+    mockPuller.ForceClearCache();
+    mockPuller.Pull(&outData);
+
+    ASSERT_EQ(1, outData.size());
+    EXPECT_EQ(android::util::GPU_STATS_GLOBAL_INFO, outData[0]->GetTagId());
+    ASSERT_EQ(NUMBER_OF_VALUES_GLOBAL, outData[0]->size());
+    EXPECT_EQ(DRIVER_PACKAGE_NAME, outData[0]->getValues()[0].mValue.str_value);
+    EXPECT_EQ(DRIVER_VERSION_NAME, outData[0]->getValues()[1].mValue.str_value);
+    EXPECT_EQ(DRIVER_VERSION_CODE, outData[0]->getValues()[2].mValue.long_value);
+    EXPECT_EQ(DRIVER_BUILD_TIME, outData[0]->getValues()[3].mValue.long_value);
+    EXPECT_EQ(GL_LOADING_COUNT, outData[0]->getValues()[4].mValue.long_value);
+    EXPECT_EQ(GL_LOADING_FAILURE_COUNT, outData[0]->getValues()[5].mValue.long_value);
+    EXPECT_EQ(VK_LOADING_COUNT, outData[0]->getValues()[6].mValue.long_value);
+    EXPECT_EQ(VK_LOADING_FAILURE_COUNT, outData[0]->getValues()[7].mValue.long_value);
+}
+
+TEST_F(GpuStatsPuller_test, PullGpuStatsAppInfo) {
+    vector<std::shared_ptr<LogEvent>> inData, outData;
+    std::shared_ptr<LogEvent> event = make_shared<LogEvent>(android::util::GPU_STATS_APP_INFO,
+                                                            TIMESTAMP_WALLCLOCK, TIMESTAMP_ELAPSED);
+    EXPECT_TRUE(event->write(APP_PACKAGE_NAME));
+    EXPECT_TRUE(event->write(DRIVER_VERSION_CODE));
+    std::vector<int64_t> glDriverLoadingTime;
+    glDriverLoadingTime.emplace_back(GL_DRIVER_LOADING_TIME_0);
+    glDriverLoadingTime.emplace_back(GL_DRIVER_LOADING_TIME_1);
+    std::vector<int64_t> vkDriverLoadingTime;
+    vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_0);
+    vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_1);
+    vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_2);
+    EXPECT_TRUE(event->write(int64VectorToProtoByteString(glDriverLoadingTime)));
+    EXPECT_TRUE(event->write(int64VectorToProtoByteString(vkDriverLoadingTime)));
+    event->init();
+    inData.emplace_back(event);
+    MockGpuStatsPuller mockPuller(android::util::GPU_STATS_APP_INFO, &inData);
+    mockPuller.ForceClearCache();
+    mockPuller.Pull(&outData);
+
+    ASSERT_EQ(1, outData.size());
+    EXPECT_EQ(android::util::GPU_STATS_APP_INFO, outData[0]->GetTagId());
+    ASSERT_EQ(NUMBER_OF_VALUES_APP, outData[0]->size());
+    EXPECT_EQ(APP_PACKAGE_NAME, outData[0]->getValues()[0].mValue.str_value);
+    EXPECT_EQ(DRIVER_VERSION_CODE, outData[0]->getValues()[1].mValue.long_value);
+    EXPECT_EQ(int64VectorToProtoByteString(glDriverLoadingTime),
+              outData[0]->getValues()[2].mValue.str_value);
+    EXPECT_EQ(int64VectorToProtoByteString(vkDriverLoadingTime),
+              outData[0]->getValues()[3].mValue.str_value);
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 56bf8fa..694f6b0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -139,6 +139,8 @@
 import com.android.internal.app.WindowDecorActionBar;
 import com.android.internal.policy.PhoneWindow;
 
+import dalvik.system.VMRuntime;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -2491,6 +2493,7 @@
             try {
                 ActivityTaskManager.getService().reportActivityFullyDrawn(
                         mToken, mRestoredFromBundle);
+                VMRuntime.getRuntime().notifyStartupCompleted();
             } catch (RemoteException e) {
             }
         }
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index da45054..08cad04 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;
@@ -96,4 +97,18 @@
      * @param uid The uid
      */
     public abstract void setAllPkgModesToDefault(int code, int uid);
+
+    /**
+     * Get the (raw) mode of an app-op.
+     *
+     * <p>Does <u>not</u> verify that package belongs to uid. The caller needs to do that.
+     *
+     * @param code The code of the op
+     * @param uid The uid of the package the op belongs to
+     * @param packageName The package the op belongs to
+     *
+     * @return The mode of the op
+     */
+    public abstract @AppOpsManager.Mode int checkOperationUnchecked(int code, int uid,
+            @NonNull String packageName);
 }
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 2d9fbf9..35658fb 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1091,6 +1091,16 @@
      */
     @UnsupportedAppUsage
     public void appendLibAssetForMainAssetPath(String assetPath, String libAsset) {
+        appendLibAssetsForMainAssetPath(assetPath, new String[] { libAsset });
+    }
+
+    /**
+     * Appends the library asset paths to any ResourcesImpl object that contains the main
+     * assetPath.
+     * @param assetPath The main asset path for which to add the library asset path.
+     * @param libAssets The library asset paths to add.
+     */
+    public void appendLibAssetsForMainAssetPath(String assetPath, String[] libAssets) {
         synchronized (this) {
             // Record which ResourcesImpl need updating
             // (and what ResourcesKey they should update to).
@@ -1102,15 +1112,13 @@
                 final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
                 final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
                 if (impl != null && Objects.equals(key.mResDir, assetPath)) {
-                    if (!ArrayUtils.contains(key.mLibDirs, libAsset)) {
-                        final int newLibAssetCount = 1 +
-                                (key.mLibDirs != null ? key.mLibDirs.length : 0);
-                        final String[] newLibAssets = new String[newLibAssetCount];
-                        if (key.mLibDirs != null) {
-                            System.arraycopy(key.mLibDirs, 0, newLibAssets, 0, key.mLibDirs.length);
-                        }
-                        newLibAssets[newLibAssetCount - 1] = libAsset;
+                    String[] newLibAssets = key.mLibDirs;
+                    for (String libAsset : libAssets) {
+                        newLibAssets =
+                                ArrayUtils.appendElement(String.class, newLibAssets, libAsset);
+                    }
 
+                    if (newLibAssets != key.mLibDirs) {
                         updatedResourceKeys.put(impl, new ResourcesKey(
                                 key.mResDir,
                                 key.mSplitResDirs,
diff --git a/core/java/android/app/admin/DelegatedAdminReceiver.java b/core/java/android/app/admin/DelegatedAdminReceiver.java
index 9605382..f66de8d 100644
--- a/core/java/android/app/admin/DelegatedAdminReceiver.java
+++ b/core/java/android/app/admin/DelegatedAdminReceiver.java
@@ -24,6 +24,9 @@
 import static android.app.admin.DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT;
 import static android.app.admin.DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN;
 
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Service;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -63,20 +66,21 @@
      *
      * <p> This callback is only applicable if the delegated app has
      * {@link DevicePolicyManager#DELEGATION_CERT_SELECTION} capability. Additionally, it must
-     * declare an intent fitler for {@link DeviceAdminReceiver#ACTION_CHOOSE_PRIVATE_KEY_ALIAS}
-     * in the receiver's manifest in order to receive this callback.
+     * declare an intent filter for {@link DeviceAdminReceiver#ACTION_CHOOSE_PRIVATE_KEY_ALIAS}
+     * in the receiver's manifest in order to receive this callback. The default implementation
+     * simply throws {@link UnsupportedOperationException}.
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
-     * @param uid The uid asking for the private key and certificate pair.
+     * @param uid The uid of the app asking for the private key and certificate pair.
      * @param uri The URI to authenticate, may be null.
      * @param alias The alias preselected by the client, or null.
      * @return The private key alias to return and grant access to.
      * @see KeyChain#choosePrivateKeyAlias
      */
-    public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, Uri uri,
-            String alias) {
-        return null;
+    public @Nullable String onChoosePrivateKeyAlias(@NonNull Context context,
+            @NonNull Intent intent, int uid, @Nullable Uri uri, @Nullable String alias) {
+        throw new UnsupportedOperationException("onChoosePrivateKeyAlias should be implemented");
     }
 
     /**
@@ -91,8 +95,9 @@
      *
      * <p> This callback is only applicable if the delegated app has
      * {@link DevicePolicyManager#DELEGATION_NETWORK_LOGGING} capability. Additionally, it must
-     * declare an intent fitler for {@link DeviceAdminReceiver#ACTION_NETWORK_LOGS_AVAILABLE} in the
-     * receiver's manifest in order to receive this callback.
+     * declare an intent filter for {@link DeviceAdminReceiver#ACTION_NETWORK_LOGS_AVAILABLE} in the
+     * receiver's manifest in order to receive this callback. The default implementation
+     * simply throws {@link UnsupportedOperationException}.
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
@@ -100,8 +105,9 @@
      * @param networkLogsCount The total count of events in the current batch of network logs.
      * @see DevicePolicyManager#retrieveNetworkLogs
      */
-    public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken,
-            int networkLogsCount) {
+    public void onNetworkLogsAvailable(@NonNull Context context, @NonNull Intent intent,
+            long batchToken, @IntRange(from = 1) int networkLogsCount) {
+        throw new UnsupportedOperationException("onNetworkLogsAvailable should be implemented");
     }
 
     /**
@@ -109,7 +115,7 @@
      * this method; implement the convenience callbacks for each action instead.
      */
     @Override
-    public void onReceive(Context context, Intent intent) {
+    public final void onReceive(@NonNull Context context, @NonNull Intent intent) {
         String action = intent.getAction();
 
         if (ACTION_CHOOSE_PRIVATE_KEY_ALIAS.equals(action)) {
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 5a7124e..4771fd8 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -19,6 +19,7 @@
 import android.accounts.AccountManager;
 import android.annotation.BroadcastBehavior;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -515,7 +516,7 @@
      * Retrieve the DevicePolicyManager interface for this administrator to work
      * with the system.
      */
-    public DevicePolicyManager getManager(Context context) {
+    public @NonNull DevicePolicyManager getManager(@NonNull Context context) {
         if (mManager != null) {
             return mManager;
         }
@@ -529,7 +530,7 @@
      * use in {@link DevicePolicyManager} APIs that require the administrator to
      * identify itself.
      */
-    public ComponentName getWho(Context context) {
+    public @NonNull ComponentName getWho(@NonNull Context context) {
         if (mWho != null) {
             return mWho;
         }
@@ -550,7 +551,7 @@
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
      */
-    public void onEnabled(Context context, Intent intent) {
+    public void onEnabled(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -564,7 +565,8 @@
      * @return Return the warning message to display to the user before
      * being disabled; if null is returned, no message is displayed.
      */
-    public CharSequence onDisableRequested(Context context, Intent intent) {
+    public @Nullable CharSequence onDisableRequested(@NonNull Context context,
+            @NonNull Intent intent) {
         return null;
     }
 
@@ -576,7 +578,7 @@
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
      */
-    public void onDisabled(Context context, Intent intent) {
+    public void onDisabled(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -591,7 +593,7 @@
      *             {@link #onPasswordChanged(Context, Intent, UserHandle)} instead.
      */
     @Deprecated
-    public void onPasswordChanged(Context context, Intent intent) {
+    public void onPasswordChanged(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -605,7 +607,8 @@
      *        user is the current profile or a parent user, check for equality with
      *        {@link Process#myUserHandle}.
      */
-    public void onPasswordChanged(Context context, Intent intent, UserHandle user) {
+    public void onPasswordChanged(@NonNull Context context, @NonNull Intent intent,
+            @NonNull UserHandle user) {
         onPasswordChanged(context, intent);
     }
 
@@ -621,7 +624,7 @@
      *             {@link #onPasswordFailed(Context, Intent, UserHandle)} instead.
      */
     @Deprecated
-    public void onPasswordFailed(Context context, Intent intent) {
+    public void onPasswordFailed(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -635,7 +638,8 @@
      *        user is the current profile or a parent user, check for equality with
      *        {@link Process#myUserHandle}.
      */
-    public void onPasswordFailed(Context context, Intent intent, UserHandle user) {
+    public void onPasswordFailed(@NonNull Context context, @NonNull Intent intent,
+            @NonNull UserHandle user) {
         onPasswordFailed(context, intent);
     }
 
@@ -651,7 +655,7 @@
      *             {@link #onPasswordSucceeded(Context, Intent, UserHandle)} instead.
      */
     @Deprecated
-    public void onPasswordSucceeded(Context context, Intent intent) {
+    public void onPasswordSucceeded(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -665,7 +669,8 @@
      *        user is the current profile or a parent user, check for equality with
      *        {@link Process#myUserHandle}.
      */
-    public void onPasswordSucceeded(Context context, Intent intent, UserHandle user) {
+    public void onPasswordSucceeded(@NonNull Context context, @NonNull Intent intent,
+            @NonNull UserHandle user) {
         onPasswordSucceeded(context, intent);
     }
 
@@ -691,7 +696,7 @@
      *             {@link #onPasswordExpiring(Context, Intent, UserHandle)} instead.
      */
     @Deprecated
-    public void onPasswordExpiring(Context context, Intent intent) {
+    public void onPasswordExpiring(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -715,7 +720,8 @@
      *        user is the current profile or a parent user, check for equality with
      *        {@link Process#myUserHandle}.
      */
-    public void onPasswordExpiring(Context context, Intent intent, UserHandle user) {
+    public void onPasswordExpiring(@NonNull Context context, @NonNull Intent intent,
+            @NonNull UserHandle user) {
         onPasswordExpiring(context, intent);
     }
 
@@ -746,7 +752,7 @@
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
      */
-    public void onProfileProvisioningComplete(Context context, Intent intent) {
+    public void onProfileProvisioningComplete(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -758,7 +764,7 @@
      * @deprecated Do not use
      */
     @Deprecated
-    public void onReadyForUserInitialization(Context context, Intent intent) {
+    public void onReadyForUserInitialization(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -766,9 +772,10 @@
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
-     * @param pkg If entering, the authorized package using lock task mode, otherwise null.
+     * @param pkg The authorized package using lock task mode.
      */
-    public void onLockTaskModeEntering(Context context, Intent intent, String pkg) {
+    public void onLockTaskModeEntering(@NonNull Context context, @NonNull Intent intent,
+            @NonNull String pkg) {
     }
 
     /**
@@ -777,7 +784,7 @@
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
      */
-    public void onLockTaskModeExiting(Context context, Intent intent) {
+    public void onLockTaskModeExiting(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -787,14 +794,14 @@
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
-     * @param uid The uid asking for the private key and certificate pair.
+     * @param uid The uid of the app asking for the private key and certificate pair.
      * @param uri The URI to authenticate, may be null.
      * @param alias The alias preselected by the client, or null.
      * @return The private key alias to return and grant access to.
      * @see KeyChain#choosePrivateKeyAlias
      */
-    public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, Uri uri,
-            String alias) {
+    public @Nullable String onChoosePrivateKeyAlias(@NonNull Context context,
+            @NonNull Intent intent, int uid, @Nullable Uri uri, @Nullable String alias) {
         return null;
     }
 
@@ -818,7 +825,8 @@
      *        the current pending update was first available. -1 if no pending update is available.
      * @see DevicePolicyManager#getPendingSystemUpdate
      */
-    public void onSystemUpdatePending(Context context, Intent intent, long receivedTime) {
+    public void onSystemUpdatePending(@NonNull Context context, @NonNull Intent intent,
+            long receivedTime) {
     }
 
     /**
@@ -830,7 +838,7 @@
      * @param intent The received intent as per {@link #onReceive}.
      * @see DevicePolicyManager#requestBugreport
      */
-    public void onBugreportSharingDeclined(Context context, Intent intent) {
+    public void onBugreportSharingDeclined(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -845,7 +853,8 @@
      * @param bugreportHash SHA-256 hash of the bugreport file.
      * @see DevicePolicyManager#requestBugreport
      */
-    public void onBugreportShared(Context context, Intent intent, String bugreportHash) {
+    public void onBugreportShared(@NonNull Context context, @NonNull Intent intent,
+            @NonNull String bugreportHash) {
     }
 
     /**
@@ -860,7 +869,7 @@
      * or {@link #BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE}
      * @see DevicePolicyManager#requestBugreport
      */
-    public void onBugreportFailed(Context context, Intent intent,
+    public void onBugreportFailed(@NonNull Context context, @NonNull Intent intent,
             @BugreportFailureCode int failureCode) {
     }
 
@@ -879,7 +888,7 @@
      * @param intent The received intent as per {@link #onReceive}.
      * @see DevicePolicyManager#retrieveSecurityLogs(ComponentName)
      */
-    public void onSecurityLogsAvailable(Context context, Intent intent) {
+    public void onSecurityLogsAvailable(@NonNull Context context, @NonNull Intent intent) {
     }
 
     /**
@@ -900,8 +909,8 @@
      * @param networkLogsCount The total count of events in the current batch of network logs.
      * @see DevicePolicyManager#retrieveNetworkLogs
      */
-    public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken,
-            int networkLogsCount) {
+    public void onNetworkLogsAvailable(@NonNull Context context, @NonNull Intent intent,
+            long batchToken, @IntRange(from = 1) int networkLogsCount) {
     }
 
     /**
@@ -913,7 +922,8 @@
      * @param intent The received intent as per {@link #onReceive}.
      * @param newUser The {@link UserHandle} of the user that has just been added.
      */
-    public void onUserAdded(Context context, Intent intent, @NonNull UserHandle newUser) {
+    public void onUserAdded(@NonNull Context context, @NonNull Intent intent,
+            @NonNull UserHandle newUser) {
     }
 
     /**
@@ -925,7 +935,8 @@
      * @param intent The received intent as per {@link #onReceive}.
      * @param removedUser The {@link UserHandle} of the user that has just been removed.
      */
-    public void onUserRemoved(Context context, Intent intent, @NonNull UserHandle removedUser) {
+    public void onUserRemoved(@NonNull Context context, @NonNull Intent intent,
+            @NonNull UserHandle removedUser) {
     }
 
     /**
@@ -937,7 +948,8 @@
      * @param intent The received intent as per {@link #onReceive}.
      * @param startedUser The {@link UserHandle} of the user that has just been started.
      */
-    public void onUserStarted(Context context, Intent intent, @NonNull UserHandle startedUser) {
+    public void onUserStarted(@NonNull Context context, @NonNull Intent intent,
+            @NonNull UserHandle startedUser) {
     }
 
     /**
@@ -949,7 +961,8 @@
      * @param intent The received intent as per {@link #onReceive}.
      * @param stoppedUser The {@link UserHandle} of the user that has just been stopped.
      */
-    public void onUserStopped(Context context, Intent intent, @NonNull UserHandle stoppedUser) {
+    public void onUserStopped(@NonNull Context context, @NonNull Intent intent,
+            @NonNull UserHandle stoppedUser) {
     }
 
     /**
@@ -961,7 +974,8 @@
      * @param intent The received intent as per {@link #onReceive}.
      * @param switchedUser The {@link UserHandle} of the user that has just been switched to.
      */
-    public void onUserSwitched(Context context, Intent intent, @NonNull UserHandle switchedUser) {
+    public void onUserSwitched(@NonNull Context context, @NonNull Intent intent,
+            @NonNull UserHandle switchedUser) {
     }
 
     /**
@@ -995,7 +1009,8 @@
      * @param user the {@link UserHandle} of the affiliated user
      * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle)
      */
-    public void onTransferAffiliatedProfileOwnershipComplete(Context context, UserHandle user) {
+    public void onTransferAffiliatedProfileOwnershipComplete(@NonNull Context context,
+            @NonNull UserHandle user) {
     }
 
     /**
@@ -1004,7 +1019,7 @@
      * convenience callbacks for each action.
      */
     @Override
-    public void onReceive(Context context, Intent intent) {
+    public void onReceive(@NonNull Context context, @NonNull Intent intent) {
         String action = intent.getAction();
 
         if (ACTION_PASSWORD_CHANGED.equals(action)) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d82899e..f8ccb13 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2187,7 +2187,7 @@
      * {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} then it implies the supplied host is valid
      * and reachable.
      */
-    public static final int PRIVATE_DNS_SET_SUCCESS = 0;
+    public static final int PRIVATE_DNS_SET_NO_ERROR = 0;
 
     /**
      * If the {@code privateDnsHost} provided was of a valid hostname but that host was found
@@ -2204,7 +2204,7 @@
      * @hide
      */
     @IntDef(prefix = {"PRIVATE_DNS_SET_"}, value = {
-            PRIVATE_DNS_SET_SUCCESS,
+            PRIVATE_DNS_SET_NO_ERROR,
             PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING,
             PRIVATE_DNS_SET_ERROR_FAILURE_SETTING
     })
@@ -10478,7 +10478,7 @@
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with.
      *
-     * @return {@code PRIVATE_DNS_SET_SUCCESS} if the mode was set successfully, or
+     * @return {@code PRIVATE_DNS_SET_NO_ERROR} if the mode was set successfully, or
      *         {@code PRIVATE_DNS_SET_ERROR_FAILURE_SETTING} if it could not be set.
      *
      * @throws SecurityException if the caller is not the device owner.
@@ -10514,7 +10514,7 @@
      * @param admin which {@link DeviceAdminReceiver} this request is associated with.
      * @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858).
      *
-     * @return {@code PRIVATE_DNS_SET_SUCCESS} if the mode was set successfully,
+     * @return {@code PRIVATE_DNS_SET_NO_ERROR} if the mode was set successfully,
      *         {@code PRIVATE_DNS_SET_ERROR_FAILURE_SETTING} if it could not be set or
      *         {@code PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING} if the specified host does not
      *         implement RFC7858.
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 62b24e9..83c1d61 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -60,7 +60,7 @@
             in PendingIntent sessionEndCallbackIntent, String callingPackage);
     void unregisterUsageSessionObserver(int sessionObserverId, String callingPackage);
     void registerAppUsageLimitObserver(int observerId, in String[] packages, long timeLimitMs,
-            long timeRemainingMs, in PendingIntent callback, String callingPackage);
+            long timeUsedMs, in PendingIntent callback, String callingPackage);
     void unregisterAppUsageLimitObserver(int observerId, String callingPackage);
     void reportUsageStart(in IBinder activity, String token, String callingPackage);
     void reportPastUsageStart(in IBinder activity, String token, long timeAgoMs,
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index cee6b87..e47ec22 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -747,7 +747,7 @@
      */
     @Deprecated
     @UnsupportedAppUsage
-    // STOPSHIP b/126917290: remove this method once ag/6591106 is merged and it's not being used.
+    // STOPSHIP b/126917290: remove this method once b/126926550 is fixed.
     public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities,
             long timeLimit, @NonNull TimeUnit timeUnit, @Nullable PendingIntent callbackIntent) {
         final Duration timeLimitDuration = Duration.ofMillis(timeUnit.toMillis(timeLimit));
@@ -782,16 +782,17 @@
      *                         null and must include at least one package or token.
      * @param timeLimit The total time the set of apps can be in the foreground before the
      *                  {@code callbackIntent} is delivered. Must be at least one minute.
-     * @param timeRemaining The remaining time the set of apps can be in the foreground before the
-     *                      {@code callbackIntent} is delivered. Must be greater than
-     *                      {@code timeLimit}. Note: a limit of 0 can be set to indicate that the
-     *                      user has already exhausted the limit for a group, in which case,
-     *                      the given {@code callbackIntent} will be ignored.
+     * @param timeUsed The time that has already been used by the set of apps in
+     *                 {@code observedEntities}. Note: a time used equal to or greater than
+     *                 {@code timeLimit} can be set to indicate that the user has already exhausted
+     *                 the limit for a group, in which case, the given {@code callbackIntent} will
+     *                 be ignored.
      * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is
      *                       exceeded by the group of apps. The delivered Intent will also contain
      *                       the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and
      *                       {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is
-     *                       being registered with a {@code timeRemaining} of 0.
+     *                       being registered with a {@code timeUsed} equal to or greater than
+     *                       {@code timeLimit}.
      * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
      *                           permissions.
      * @hide
@@ -801,11 +802,11 @@
             android.Manifest.permission.SUSPEND_APPS,
             android.Manifest.permission.OBSERVE_APP_USAGE})
     public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities,
-            @NonNull Duration timeLimit, @NonNull Duration timeRemaining,
+            @NonNull Duration timeLimit, @NonNull Duration timeUsed,
             @Nullable PendingIntent callbackIntent) {
         try {
             mService.registerAppUsageLimitObserver(observerId, observedEntities,
-                    timeLimit.toMillis(), timeRemaining.toMillis(), callbackIntent,
+                    timeLimit.toMillis(), timeUsed.toMillis(), callbackIntent,
                     mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ab8c196..b8a741a 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -19,6 +19,7 @@
 
 import android.Manifest;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -3057,7 +3058,7 @@
      * permissions, or unable to start this CoC
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothServerSocket listenUsingL2capChannel()
+    public @NonNull BluetoothServerSocket listenUsingL2capChannel()
             throws IOException {
         BluetoothServerSocket socket =
                             new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true,
@@ -3115,7 +3116,7 @@
      * permissions, or unable to start this CoC
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothServerSocket listenUsingInsecureL2capChannel()
+    public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel()
             throws IOException {
         BluetoothServerSocket socket =
                             new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false,
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index f718415..fa2c9f8 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -17,6 +17,7 @@
 package android.bluetooth;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -2182,7 +2183,7 @@
      * permissions
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothSocket createL2capChannel(int psm) throws IOException {
+    public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException {
         if (!isBluetoothEnabled()) {
             Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
             throw new IOException();
@@ -2221,7 +2222,7 @@
      * permissions
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
+    public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
         if (!isBluetoothEnabled()) {
             Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
             throw new IOException();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 91ac9e0..5c99319 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4098,7 +4098,7 @@
      * @see #getSystemService(String)
      * @hide
      */
-    @SystemApi
+    @SystemApi @TestApi
     public static final String ROLLBACK_SERVICE = "rollback";
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0715572..a2d3f6a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2441,7 +2441,7 @@
      *
      * @hide
      */
-    @SystemApi
+    @SystemApi @TestApi
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_ROLLBACK_COMMITTED =
             "android.intent.action.ROLLBACK_COMMITTED";
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index f14b228..33b9c72 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -24,6 +24,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
@@ -1465,7 +1466,7 @@
          * @param enable set to {@code true} to enable, {@code false} to disable
          * @hide
          */
-        @SystemApi
+        @SystemApi @TestApi
         public void setEnableRollback(boolean enable) {
             if (enable) {
                 installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
@@ -1591,7 +1592,7 @@
          *
          * {@hide}
          */
-        @SystemApi
+        @SystemApi @TestApi
         @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
         public void setStaged() {
             this.isStaged = true;
@@ -1602,7 +1603,7 @@
          *
          * {@hide}
          */
-        @SystemApi
+        @SystemApi @TestApi
         @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
         public void setInstallAsApex() {
             installFlags |= PackageManager.INSTALL_APEX;
diff --git a/core/java/android/content/pm/PackageList.java b/core/java/android/content/pm/PackageList.java
index cfd99ab..f781758 100644
--- a/core/java/android/content/pm/PackageList.java
+++ b/core/java/android/content/pm/PackageList.java
@@ -45,16 +45,16 @@
     }
 
     @Override
-    public void onPackageAdded(String packageName) {
+    public void onPackageAdded(String packageName, int uid) {
         if (mWrappedObserver != null) {
-            mWrappedObserver.onPackageAdded(packageName);
+            mWrappedObserver.onPackageAdded(packageName, uid);
         }
     }
 
     @Override
-    public void onPackageRemoved(String packageName) {
+    public void onPackageRemoved(String packageName, int uid) {
         if (mWrappedObserver != null) {
-            mWrappedObserver.onPackageRemoved(packageName);
+            mWrappedObserver.onPackageRemoved(packageName, uid);
         }
     }
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d1ebcfd..9037759 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1389,6 +1389,14 @@
      */
     public static final int INSTALL_FAILED_BAD_SIGNATURE = -118;
 
+    /**
+     * Installation failed return code: a new staged session was attempted to be committed while
+     * there is already one in-progress.
+     *
+     * @hide
+     */
+    public static final int INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS = -119;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "DELETE_" }, value = {
             DELETE_KEEP_DATA,
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 2c1842c..0ef7656 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -78,9 +78,9 @@
     /** Observer called whenever the list of packages changes */
     public interface PackageListObserver {
         /** A package was added to the system. */
-        void onPackageAdded(@NonNull String packageName);
+        void onPackageAdded(@NonNull String packageName, int uid);
         /** A package was removed from the system. */
-        void onPackageRemoved(@NonNull String packageName);
+        void onPackageRemoved(@NonNull String packageName, int uid);
     }
 
     /** Interface to override permission checks via composition */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 89c0690..ec42134 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1618,7 +1618,7 @@
             }
 
             final AttributeSet attrs = parser;
-            return parseApkLite(apkPath, parser, attrs, signingDetails, flags);
+            return parseApkLite(apkPath, parser, attrs, signingDetails);
 
         } catch (XmlPullParserException | IOException | RuntimeException e) {
             Slog.w(TAG, "Failed to parse " + apkPath, e);
@@ -1705,7 +1705,7 @@
     }
 
     private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
-            SigningDetails signingDetails, int flags)
+            SigningDetails signingDetails)
             throws IOException, XmlPullParserException, PackageParserException {
         final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
 
@@ -1713,12 +1713,11 @@
         int versionCode = 0;
         int versionCodeMajor = 0;
         int revisionCode = 0;
-        int targetSdkVersion = 0;
         boolean coreApp = false;
         boolean debuggable = false;
         boolean multiArch = false;
         boolean use32bitAbi = false;
-        Boolean extractNativeLibsProvided = null;
+        boolean extractNativeLibs = true;
         boolean isolatedSplits = false;
         boolean isFeatureSplit = false;
         boolean isSplitRequired = false;
@@ -1783,8 +1782,7 @@
                         use32bitAbi = attrs.getAttributeBooleanValue(i, false);
                     }
                     if ("extractNativeLibs".equals(attr)) {
-                        extractNativeLibsProvided = Boolean.valueOf(
-                                attrs.getAttributeBooleanValue(i, true));
+                        extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
                     }
                     if ("useEmbeddedDex".equals(attr)) {
                         useEmbeddedDex = attrs.getAttributeBooleanValue(i, false);
@@ -1802,52 +1800,9 @@
                             PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                             "<uses-split> tag requires 'android:name' attribute");
                 }
-            } else if (TAG_USES_SDK.equals(parser.getName())) {
-                final String[] errorMsg = new String[1];
-                Pair<Integer, Integer> versions = deriveSdkVersions(new AbstractVersionsAccessor() {
-                    @Override public String getMinSdkVersionCode() {
-                        return getAttributeAsString("minSdkVersion");
-                    }
-
-                    @Override public int getMinSdkVersion() {
-                        return getAttributeAsInt("minSdkVersion");
-                    }
-
-                    @Override public String getTargetSdkVersionCode() {
-                        return getAttributeAsString("targetSdkVersion");
-                    }
-
-                    @Override public int getTargetSdkVersion() {
-                        return getAttributeAsInt("targetSdkVersion");
-                    }
-
-                    private String getAttributeAsString(String name) {
-                        return attrs.getAttributeValue(ANDROID_RESOURCES, name);
-                    }
-
-                    private int getAttributeAsInt(String name) {
-                        try {
-                            return attrs.getAttributeIntValue(ANDROID_RESOURCES, name, -1);
-                        } catch (NumberFormatException e) {
-                            return -1;
-                        }
-                    }
-                }, flags, errorMsg);
-
-                if (versions == null) {
-                    throw new PackageParserException(
-                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, errorMsg[0]);
-                }
-
-                targetSdkVersion = versions.second;
             }
         }
 
-        // TODO: flip the default based on targetSdkVersion when possible.  See b/128335904.
-        final boolean extractNativeLibsDefault = true;
-        final boolean extractNativeLibs = (extractNativeLibsProvided != null)
-                ? extractNativeLibsProvided : extractNativeLibsDefault;
-
         return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
                 configForSplit, usesSplitName, isSplitRequired, versionCode, versionCodeMajor,
                 revisionCode, installLocation, verifiers, signingDetails, coreApp, debuggable,
@@ -2253,60 +2208,64 @@
 
             } else if (tagName.equals(TAG_USES_SDK)) {
                 if (SDK_VERSION > 0) {
-                    sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
-                    final TypedArray saFinal = sa;
-                    Pair<Integer, Integer> versions = deriveSdkVersions(
-                            new AbstractVersionsAccessor() {
-                                @Override public String getMinSdkVersionCode() {
-                                    return getAttributeAsString(
-                                            R.styleable.AndroidManifestUsesSdk_minSdkVersion);
-                                }
+                    sa = res.obtainAttributes(parser,
+                            com.android.internal.R.styleable.AndroidManifestUsesSdk);
 
-                                @Override public int getMinSdkVersion() {
-                                    return getAttributeAsInt(
-                                            R.styleable.AndroidManifestUsesSdk_minSdkVersion);
-                                }
+                    int minVers = 1;
+                    String minCode = null;
+                    int targetVers = 0;
+                    String targetCode = null;
 
-                                @Override public String getTargetSdkVersionCode() {
-                                    return getAttributeAsString(
-                                            R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
-                                }
+                    TypedValue val = sa.peekValue(
+                            com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+                    if (val != null) {
+                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                            minCode = val.string.toString();
+                        } else {
+                            // If it's not a string, it's an integer.
+                            minVers = val.data;
+                        }
+                    }
 
-                                @Override public int getTargetSdkVersion() {
-                                    return getAttributeAsInt(
-                                            R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
-                                }
+                    val = sa.peekValue(
+                            com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+                    if (val != null) {
+                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                            targetCode = val.string.toString();
+                            if (minCode == null) {
+                                minCode = targetCode;
+                            }
+                        } else {
+                            // If it's not a string, it's an integer.
+                            targetVers = val.data;
+                        }
+                    } else {
+                        targetVers = minVers;
+                        targetCode = minCode;
+                    }
 
-                                private String getAttributeAsString(int index) {
-                                    TypedValue val = saFinal.peekValue(index);
-                                    if (val != null && val.type == TypedValue.TYPE_STRING
-                                            && val.string != null) {
-                                        return val.string.toString();
-                                    }
-                                    return null;
-                                }
+                    sa.recycle();
 
-                                private int getAttributeAsInt(int index) {
-                                    TypedValue val = saFinal.peekValue(index);
-                                    if (val != null && val.type != TypedValue.TYPE_STRING) {
-                                        // If it's not a string, it's an integer.
-                                        return val.data;
-                                    }
-                                    return -1;
-                                }
-                            }, flags, outError);
-
-                    if (versions == null) {
+                    final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode,
+                            SDK_VERSION, SDK_CODENAMES, outError);
+                    if (minSdkVersion < 0) {
                         mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
                         return null;
                     }
 
-                    pkg.applicationInfo.minSdkVersion = versions.first;
-                    pkg.applicationInfo.targetSdkVersion = versions.second;
+                    final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers,
+                            targetCode, SDK_CODENAMES, outError);
+                    if (targetSdkVersion < 0) {
+                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+                        return null;
+                    }
 
-                    sa.recycle();
+                    pkg.applicationInfo.minSdkVersion = minSdkVersion;
+                    pkg.applicationInfo.targetSdkVersion = targetSdkVersion;
                 }
+
                 XmlUtils.skipCurrentTag(parser);
+
             } else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
                 sa = res.obtainAttributes(parser,
                         com.android.internal.R.styleable.AndroidManifestSupportsScreens);
@@ -2717,66 +2676,6 @@
         return -1;
     }
 
-    private interface AbstractVersionsAccessor {
-        /** Returns minimum SDK version code string, or null if absent. */
-        String getMinSdkVersionCode();
-
-        /** Returns minimum SDK version code, or -1 if absent. */
-        int getMinSdkVersion();
-
-        /** Returns target SDK version code string, or null if absent. */
-        String getTargetSdkVersionCode();
-
-        /** Returns target SDK version code, or -1 if absent. */
-        int getTargetSdkVersion();
-    }
-
-    private static @Nullable Pair<Integer, Integer> deriveSdkVersions(
-            @NonNull AbstractVersionsAccessor accessor, int flags, String[] outError) {
-        int minVers = 1;
-        String minCode = null;
-        int targetVers = 0;
-        String targetCode = null;
-
-        String code = accessor.getMinSdkVersionCode();
-        int version = accessor.getMinSdkVersion();
-        // Check integer first since code is almost never a null string (e.g. "28").
-        if (version >= 0) {
-            minVers = version;
-        } else if (code != null) {
-            minCode = code;
-        }
-
-        code = accessor.getTargetSdkVersionCode();
-        version = accessor.getTargetSdkVersion();
-        // Check integer first since code is almost never a null string (e.g. "28").
-        if (version >= 0) {
-            targetVers = version;
-        } else if (code != null) {
-            targetCode = code;
-            if (minCode == null) {
-                minCode = targetCode;
-            }
-        } else {
-            targetVers = minVers;
-            targetCode = minCode;
-        }
-
-        final int minSdkVersion = computeMinSdkVersion(minVers, minCode,
-                SDK_VERSION, SDK_CODENAMES, outError);
-        if (minSdkVersion < 0) {
-            return null;
-        }
-
-        final int targetSdkVersion = computeTargetSdkVersion(targetVers,
-                targetCode, SDK_CODENAMES, outError);
-        if (targetSdkVersion < 0) {
-            return null;
-        }
-
-        return Pair.create(minSdkVersion, targetSdkVersion);
-    }
-
     /**
      * Computes the minSdkVersion to use at runtime. If the package is not
      * compatible with this platform, populates {@code outError[0]} with an
@@ -3719,7 +3618,6 @@
             ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
         }
 
-        // TODO: flip the default based on targetSdkVersion when possible.  See b/128335904.
         if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
                 true)) {
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index b0785b1..2014751 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.pm.VersionedPackage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -31,7 +32,7 @@
  *
  * @hide
  */
-@SystemApi
+@SystemApi @TestApi
 public final class PackageRollbackInfo implements Parcelable {
 
     private final VersionedPackage mVersionRolledBackFrom;
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index a363718..c09cfd5 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.pm.VersionedPackage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -30,7 +31,7 @@
  *
  * @hide
  */
-@SystemApi
+@SystemApi @TestApi
 public final class RollbackInfo implements Parcelable {
 
     /**
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 4e8c254..9038b03 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -16,16 +16,20 @@
 
 package android.content.rollback;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.content.IntentSender;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.VersionedPackage;
 import android.os.RemoteException;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 
 /**
@@ -38,7 +42,7 @@
  * @see PackageInstaller.SessionParams#setEnableRollback()
  * @hide
  */
-@SystemApi
+@SystemApi @TestApi
 @SystemService(Context.ROLLBACK_SERVICE)
 public final class RollbackManager {
     private final String mCallerPackageName;
@@ -112,6 +116,20 @@
             "android.content.rollback.extra.STATUS_MESSAGE";
 
     /**
+     * Status result of committing a rollback.
+     *
+     * @hide
+     */
+    @IntDef(prefix = "STATUS_", value = {
+            STATUS_SUCCESS,
+            STATUS_FAILURE,
+            STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
+            STATUS_FAILURE_INSTALL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Status {};
+
+    /**
      * The rollback was successfully committed.
      */
     public static final int STATUS_SUCCESS = 0;
@@ -175,8 +193,11 @@
      *
      * @throws SecurityException if the caller does not have the
      *            MANAGE_ROLLBACKS permission.
+     *
+     * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @TestApi
     public void reloadPersistedData() {
         try {
             mBinder.reloadPersistedData();
@@ -194,8 +215,11 @@
      * @param packageName the name of the package to expire data for.
      * @throws SecurityException if the caller does not have the
      *            MANAGE_ROLLBACKS permission.
+     *
+     * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @TestApi
     public void expireRollbackForPackage(@NonNull String packageName) {
         try {
             mBinder.expireRollbackForPackage(packageName);
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 23401432..d5d25c5 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -680,7 +680,7 @@
         }
 
         /**
-         * Notify registered clients about a change in the camera access priorities.
+         * Called whenever camera access priorities change.
          *
          * <p>Notification that camera access priorities have changed and the camera may
          * now be openable. An application that was previously denied camera access due to
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3f8410f..2a357ff 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2805,7 +2805,7 @@
          *         {@link #TETHER_ERROR_PROVISION_FAILED}, or
          *         {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}.
          */
-        void onEntitlementResult(@EntitlementResultCode int resultCode);
+        void onTetheringEntitlementResult(@EntitlementResultCode int resultCode);
     }
 
     /**
@@ -2855,7 +2855,7 @@
             protected void onReceiveResult(int resultCode, Bundle resultData) {
                 Binder.withCleanCallingIdentity(() ->
                             executor.execute(() -> {
-                                listener.onEntitlementResult(resultCode);
+                                listener.onTetheringEntitlementResult(resultCode);
                             }));
             }
         };
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 60f4f06..ff551d4 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -120,10 +120,6 @@
         mUsapPoolSecondarySocketAddress =
                 new LocalSocketAddress(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME,
                                        LocalSocketAddress.Namespace.RESERVED);
-
-        if (fetchUsapPoolEnabledProp()) {
-            informZygotesOfUsapPoolStatus();
-        }
     }
 
     public ZygoteProcess(LocalSocketAddress primarySocketAddress,
@@ -179,14 +175,18 @@
          * address
          * @throws IOException
          */
-        public static ZygoteState connect(LocalSocketAddress zygoteSocketAddress,
-                                          LocalSocketAddress usapSocketAddress)
+        public static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
+                                          @Nullable LocalSocketAddress usapSocketAddress)
                 throws IOException {
 
             DataInputStream zygoteInputStream = null;
             BufferedWriter zygoteOutputWriter = null;
             final LocalSocket zygoteSessionSocket = new LocalSocket();
 
+            if (zygoteSocketAddress == null) {
+                throw new IllegalArgumentException("zygoteSocketAddress can't be null");
+            }
+
             try {
                 zygoteSessionSocket.connect(zygoteSocketAddress);
                 zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
@@ -678,12 +678,15 @@
         return origVal != mUsapPoolEnabled;
     }
 
+    private boolean mIsFirstPropCheck = true;
     private long mLastPropCheckTimestamp = 0;
 
     private boolean fetchUsapPoolEnabledPropWithMinInterval() {
         final long currentTimestamp = SystemClock.elapsedRealtime();
 
-        if (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL) {
+        if (mIsFirstPropCheck
+                || (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL)) {
+            mIsFirstPropCheck = false;
             mLastPropCheckTimestamp = currentTimestamp;
             return fetchUsapPoolEnabledProp();
         }
@@ -919,11 +922,13 @@
                 return primaryZygoteState;
             }
 
-            // The primary zygote didn't match. Try the secondary.
-            attemptConnectionToSecondaryZygote();
+            if (mZygoteSecondarySocketAddress != null) {
+                // The primary zygote didn't match. Try the secondary.
+                attemptConnectionToSecondaryZygote();
 
-            if (secondaryZygoteState.matches(abi)) {
-                return secondaryZygoteState;
+                if (secondaryZygoteState.matches(abi)) {
+                    return secondaryZygoteState;
+                }
             }
         } catch (IOException ioe) {
             throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
@@ -1071,22 +1076,24 @@
                 return;
             }
 
-            try {
-                attemptConnectionToSecondaryZygote();
-
+            if (mZygoteSecondarySocketAddress != null) {
                 try {
-                    secondaryZygoteState.mZygoteOutputWriter.write(command);
-                    secondaryZygoteState.mZygoteOutputWriter.flush();
+                    attemptConnectionToSecondaryZygote();
 
-                    // Wait for the secondary Zygote to finish its work.
-                    secondaryZygoteState.mZygoteInputStream.readInt();
+                    try {
+                        secondaryZygoteState.mZygoteOutputWriter.write(command);
+                        secondaryZygoteState.mZygoteOutputWriter.flush();
+
+                        // Wait for the secondary Zygote to finish its work.
+                        secondaryZygoteState.mZygoteInputStream.readInt();
+                    } catch (IOException ioe) {
+                        throw new IllegalStateException(
+                                "USAP pool state change cause an irrecoverable error",
+                                ioe);
+                    }
                 } catch (IOException ioe) {
-                    throw new IllegalStateException(
-                            "USAP pool state change cause an irrecoverable error",
-                            ioe);
+                    // No secondary zygote present.  This is expected on some devices.
                 }
-            } catch (IOException ioe) {
-                // No secondary zygote present.  This is expected on some devices.
             }
 
             // Wait for the response from the primary zygote here so the primary/secondary zygotes
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index e4593e5..7a0bb91 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -31,6 +31,7 @@
 import android.net.Uri;
 import android.provider.Settings.ResetMode;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
@@ -105,6 +106,14 @@
     public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
 
     /**
+     * Namespace for how dex runs. The feature requires a reboot to reach a clean state.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_DEX_BOOT = "dex_boot";
+
+    /**
      * Namespace for all Game Driver features.
      *
      * @hide
@@ -290,18 +299,6 @@
     }
 
     /**
-     * Namespace for how dex runs.  The feature may requires reboot to a clean state.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface DexBoot {
-        String NAMESPACE = "dex_boot";
-        String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled";
-        String PRIV_APPS_OOB_WHITELIST = "priv_apps_oob_whitelist";
-    }
-
-    /**
      * Namespace for {@link AttentionManagerService} related features.
      *
      * @hide
@@ -322,7 +319,7 @@
      *
      * @hide
      */
-    @SystemApi
+    @SystemApi @TestApi
     public interface Rollback {
 
         /**
@@ -406,6 +403,7 @@
             new ArrayMap<>();
     @GuardedBy("sLock")
     private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>();
+    private static final String TAG = "DeviceConfig";
 
     // Should never be invoked
     private DeviceConfig() {
@@ -479,9 +477,13 @@
     @RequiresPermission(READ_DEVICE_CONFIG)
     public static int getInt(String namespace, String name, int defaultValue) {
         String value = getProperty(namespace, name);
+        if (value == null) {
+            return defaultValue;
+        }
         try {
             return Integer.parseInt(value);
         } catch (NumberFormatException e) {
+            Log.e(TAG, "Parsing integer failed for " + namespace + ":" + name);
             return defaultValue;
         }
     }
@@ -501,9 +503,13 @@
     @RequiresPermission(READ_DEVICE_CONFIG)
     public static long getLong(String namespace, String name, long defaultValue) {
         String value = getProperty(namespace, name);
+        if (value == null) {
+            return defaultValue;
+        }
         try {
             return Long.parseLong(value);
         } catch (NumberFormatException e) {
+            Log.e(TAG, "Parsing long failed for " + namespace + ":" + name);
             return defaultValue;
         }
     }
@@ -523,11 +529,13 @@
     @RequiresPermission(READ_DEVICE_CONFIG)
     public static float getFloat(String namespace, String name, float defaultValue) {
         String value = getProperty(namespace, name);
+        if (value == null) {
+            return defaultValue;
+        }
         try {
             return Float.parseFloat(value);
         } catch (NumberFormatException e) {
-            return defaultValue;
-        } catch (NullPointerException e) {
+            Log.e(TAG, "Parsing float failed for " + namespace + ":" + name);
             return defaultValue;
         }
     }
@@ -915,9 +923,13 @@
         public int getInt(@NonNull String name, int defaultValue) {
             Preconditions.checkNotNull(name);
             String value = mMap.get(name);
+            if (value == null) {
+                return defaultValue;
+            }
             try {
                 return Integer.parseInt(value);
             } catch (NumberFormatException e) {
+                Log.e(TAG, "Parsing int failed for " + name);
                 return defaultValue;
             }
         }
@@ -933,9 +945,13 @@
         public long getLong(@NonNull String name, long defaultValue) {
             Preconditions.checkNotNull(name);
             String value = mMap.get(name);
+            if (value == null) {
+                return defaultValue;
+            }
             try {
                 return Long.parseLong(value);
             } catch (NumberFormatException e) {
+                Log.e(TAG, "Parsing long failed for " + name);
                 return defaultValue;
             }
         }
@@ -951,11 +967,13 @@
         public float getFloat(@NonNull String name, float defaultValue) {
             Preconditions.checkNotNull(name);
             String value = mMap.get(name);
+            if (value == null) {
+                return defaultValue;
+            }
             try {
                 return Float.parseFloat(value);
             } catch (NumberFormatException e) {
-                return defaultValue;
-            } catch (NullPointerException e) {
+                Log.e(TAG, "Parsing float failed for " + name);
                 return defaultValue;
             }
         }
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index e931826..2814474 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -34,7 +34,6 @@
 import android.graphics.fonts.FontStyle;
 import android.graphics.fonts.FontVariationAxis;
 import android.net.Uri;
-import android.os.Build.VERSION_CODES;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -642,25 +641,35 @@
                 continue;
             }
             try {
-                final Font font = new Font.Builder(buffer)
+                Font font = null;
+                try {
+                    font = new Font.Builder(buffer)
                         .setWeight(fontInfo.getWeight())
                         .setSlant(fontInfo.isItalic()
                                 ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT)
                         .setTtcIndex(fontInfo.getTtcIndex())
                         .setFontVariationSettings(fontInfo.getAxes())
                         .build();
+                } catch (IllegalArgumentException e) {
+                    // The exception happens if the unsupported font is passed. We suppress this
+                    // exception and just ignore this font here since there is no way of
+                    // resolving this issue by users during inflating layout.
+                    Log.w(TAG, "Ignoring font file since failed to create font object."
+                            + " The font file is not supported on this platform.");
+                    continue;
+                }
                 if (familyBuilder == null) {
                     familyBuilder = new FontFamily.Builder(font);
                 } else {
                     try {
                         familyBuilder.addFont(font);
                     } catch (IllegalArgumentException e) {
-                        if (context.getApplicationInfo().targetSdkVersion <= VERSION_CODES.P) {
-                            // Surpress the IllegalArgumentException for keeping the backward
-                            // compatibility.
-                            continue;
-                        }
-                        throw e;
+                        // The exception happens if the same style font is added to the family.
+                        // We suppress this exception and just ignore this font here since there is
+                        // no way of resolving this issue by users during inflating layout.
+                        Log.w(TAG,
+                                "Ignoring font file since the same style font is already added.");
+                        continue;
                     }
                 }
             } catch (IOException e) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e8f91ca..a750c79 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5590,6 +5590,15 @@
         private static final Validator ALLOW_MOCK_LOCATION_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Setting to indicate that on device captions are enabled.
+         *
+         * @hide
+         */
+        public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
+
+        private static final Validator ODI_CAPTIONS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * On Android 8.0 (API level 26) and higher versions of the platform,
          * a 64-bit number (expressed as a hexadecimal string), unique to
          * each combination of app-signing key, user, and device.
@@ -8950,6 +8959,7 @@
             VALIDATORS.put(SILENCE_TIMER_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(SILENCE_CALL_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(SILENCE_NOTIFICATION_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
+            VALIDATORS.put(ODI_CAPTIONS_ENABLED, ODI_CAPTIONS_ENABLED_VALIDATOR);
         }
 
         /**
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index c928da1..32982f9 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -674,7 +674,8 @@
             objects[0] = reflowed.getLineDirections(i);
 
             final int end = (i == n - 1) ? where + after : reflowed.getLineStart(i + 1);
-            ints[HYPHEN] = reflowed.getHyphen(i) & HYPHEN_MASK;
+            ints[HYPHEN] = StaticLayout.packHyphenEdit(
+                    reflowed.getStartHyphenEdit(i), reflowed.getEndHyphenEdit(i));
             ints[MAY_PROTRUDE_FROM_TOP_OR_BOTTOM] |=
                     contentMayProtrudeFromLineTopOrBottom(text, start, end) ?
                             MAY_PROTRUDE_FROM_TOP_OR_BOTTOM_MASK : 0;
@@ -1056,8 +1057,16 @@
      * @hide
      */
     @Override
-    public int getHyphen(int line) {
-        return mInts.getValue(line, HYPHEN) & HYPHEN_MASK;
+    public @Paint.StartHyphenEdit int getStartHyphenEdit(int line) {
+        return StaticLayout.unpackStartHyphenEdit(mInts.getValue(line, HYPHEN) & HYPHEN_MASK);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public @Paint.EndHyphenEdit int getEndHyphenEdit(int line) {
+        return StaticLayout.unpackEndHyphenEdit(mInts.getValue(line, HYPHEN) & HYPHEN_MASK);
     }
 
     private boolean getContentMayProtrudeFromTopOrBottom(int line) {
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index e4200ac..6f0628a 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -16,142 +16,15 @@
 
 package android.text;
 
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
- * Provides constants and pack/unpack methods for the HyphenEdit.
+ * Does the native Hyphenator initialization.
  *
- * Hyphenator provides constant values for start of line and end of line modification.
- * For example, by passing {@link #END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010)
- * character is appended at the end of line.
- *
- * <pre>
- * <code>
- *   Paint paint = new Paint();
- *   paint.setHyphenEdit(Hyphenator.packHyphenEdit(
- *       Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
- *       Hyphenator.END_HYPHEN_EDIT_INSERT_HYPHEN));
- *   paint.measureText("abc", 0, 3);  // Returns the width of "abc‐"
- *   Canvas.drawText("abc", 0, 3, 0f, 0f, paint);  // Draws "abc‐"
- * </code>
- * </pre>
- *
- * @see android.graphics.Paint#setHyphenEdit(int)
+ * @hide
  */
 public class Hyphenator {
     private Hyphenator() {}
 
-    /** @hide */
-    @IntDef(prefix = { "START_HYPHEN_EDIT_" }, value = {
-        START_HYPHEN_EDIT_NO_EDIT,
-        START_HYPHEN_EDIT_INSERT_HYPHEN,
-        START_HYPHEN_EDIT_INSERT_ZWJ
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface StartHyphenEdit {}
-
-    /**
-     * An integer representing the starting of the line has no modification for hyphenation.
-     */
-    public static final int START_HYPHEN_EDIT_NO_EDIT = 0x00;
-
-    /**
-     * An integer representing the starting of the line has normal hyphen character (U+002D).
-     */
-    public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 0x01;
-
-    /**
-     * An integer representing the starting of the line has Zero-Width-Joiner (U+200D).
-     */
-    public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 0x02;
-
-    /** @hide */
-    @IntDef(prefix = { "END_HYPHEN_EDIT_" }, value = {
-        END_HYPHEN_EDIT_NO_EDIT,
-        END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN,
-        END_HYPHEN_EDIT_INSERT_HYPHEN,
-        END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN,
-        END_HYPHEN_EDIT_INSERT_MAQAF,
-        END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN,
-        END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface EndHyphenEdit {}
-
-    /**
-     * An integer representing the end of the line has no modification for hyphenation.
-     */
-    public static final int END_HYPHEN_EDIT_NO_EDIT = 0x00;
-
-    /**
-     * An integer representing the character at the end of the line is replaced with hyphen
-     * character (U+002D).
-     */
-    public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 0x01;
-
-    /**
-     * An integer representing the end of the line has normal hyphen character (U+002D).
-     */
-    public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 0x02;
-
-    /**
-     * An integer representing the end of the line has Armentian hyphen (U+058A).
-     */
-    public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 0x03;
-
-    /**
-     * An integer representing the end of the line has maqaf (Hebrew hyphen, U+05BE).
-     */
-    public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 0x04;
-
-    /**
-     * An integer representing the end of the line has Canadian Syllabics hyphen (U+1400).
-     */
-    public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 0x05;
-
-    /**
-     * An integer representing the end of the line has Zero-Width-Joiner (U+200D) followed by normal
-     * hyphen character (U+002D).
-     */
-    public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 0x06;
-
-    // Following three constants are used for packing start hyphen edit and end hyphen edit into
-    // single integer. Following encodings must be the same as the minikin's one.
-    // See frameworks/minikin/include/Hyphenator.h for more details.
-    private static final int END_HYPHEN_EDIT_MASK = 0x07;  // 0b00111
-    private static final int START_HYPHEN_EDIT_MASK = 0x18;  // 0b11000
-    private static final int START_HYPHEN_EDIT_SHIFT = 0x03;
-
-    /**
-     * Extract start hyphen edit from packed value.
-     */
-    public static @StartHyphenEdit int unpackStartHyphenEdit(int hyphenEdit) {
-        return (hyphenEdit & START_HYPHEN_EDIT_MASK) >> START_HYPHEN_EDIT_SHIFT;
-    }
-
-    /**
-     * Extract end hyphen edit from packed value.
-     */
-    public static @EndHyphenEdit int unpackEndHyphenEdit(int hyphenEdit) {
-        return hyphenEdit & END_HYPHEN_EDIT_MASK;
-    }
-
-    /**
-     * Pack the start hyphen edit and end hyphen edit into single integer.
-     */
-    public static int packHyphenEdit(@StartHyphenEdit int startHyphenEdit,
-            @EndHyphenEdit int endHyphenEdit) {
-        return ((startHyphenEdit << START_HYPHEN_EDIT_SHIFT) & START_HYPHEN_EDIT_MASK)
-                | (endHyphenEdit & END_HYPHEN_EDIT_MASK);
-    }
-
-
-    /**
-     * @hide
-     */
+    // This method is called from Zygote.
     public static void init() {
         nInit();
     }
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 2d5f3bf..fb6dc22 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -437,7 +437,8 @@
             previousLineEnd = getLineStart(lineNum + 1);
             final boolean justify = isJustificationRequired(lineNum);
             int end = getLineVisibleEnd(lineNum, start, previousLineEnd);
-            paint.setHyphenEdit(getHyphen(lineNum));
+            paint.setStartHyphenEdit(getStartHyphenEdit(lineNum));
+            paint.setEndHyphenEdit(getEndHyphenEdit(lineNum));
 
             int ltop = previousLineBottom;
             int lbottom = getLineTop(lineNum + 1);
@@ -910,12 +911,21 @@
     public abstract int getBottomPadding();
 
     /**
-     * Returns the hyphen edit for a line.
+     * Returns the start hyphen edit for a line.
      *
      * @hide
      */
-    public int getHyphen(int line) {
-        return 0;
+    public @Paint.StartHyphenEdit int getStartHyphenEdit(int line) {
+        return Paint.START_HYPHEN_EDIT_NO_EDIT;
+    }
+
+    /**
+     * Returns the end hyphen edit for a line.
+     *
+     * @hide
+     */
+    public @Paint.EndHyphenEdit int getEndHyphenEdit(int line) {
+        return Paint.END_HYPHEN_EDIT_NO_EDIT;
     }
 
     /**
@@ -1418,7 +1428,8 @@
         final TextLine tl = TextLine.obtain();
         final TextPaint paint = mWorkPaint;
         paint.set(mPaint);
-        paint.setHyphenEdit(getHyphen(line));
+        paint.setStartHyphenEdit(getStartHyphenEdit(line));
+        paint.setEndHyphenEdit(getEndHyphenEdit(line));
         tl.set(paint, mText, start, end, dir, directions, hasTabs, tabStops,
                 getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line));
         if (isJustificationRequired(line)) {
@@ -1447,7 +1458,8 @@
         final TextLine tl = TextLine.obtain();
         final TextPaint paint = mWorkPaint;
         paint.set(mPaint);
-        paint.setHyphenEdit(getHyphen(line));
+        paint.setStartHyphenEdit(getStartHyphenEdit(line));
+        paint.setEndHyphenEdit(getEndHyphenEdit(line));
         tl.set(paint, mText, start, end, dir, directions, hasTabs, tabStops,
                 getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line));
         if (isJustificationRequired(line)) {
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index defe2ce..9fefc83 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -779,7 +779,8 @@
                 ascents[i] = res.getLineAscent(i);
                 descents[i] = res.getLineDescent(i);
                 hasTabs[i] = res.hasLineTab(i);
-                hyphenEdits[i] = res.getLineHyphenEdit(i);
+                hyphenEdits[i] =
+                    packHyphenEdit(res.getStartLineHyphenEdit(i), res.getEndLineHyphenEdit(i));
             }
 
             final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
@@ -1258,20 +1259,42 @@
         return mBottomPadding;
     }
 
+    // To store into single int field, pack the pair of start and end hyphen edit.
+    static int packHyphenEdit(
+            @Paint.StartHyphenEdit int start, @Paint.EndHyphenEdit int end) {
+        return start << START_HYPHEN_BITS_SHIFT | end;
+    }
+
+    static int unpackStartHyphenEdit(int packedHyphenEdit) {
+        return (packedHyphenEdit & START_HYPHEN_MASK) >> START_HYPHEN_BITS_SHIFT;
+    }
+
+    static int unpackEndHyphenEdit(int packedHyphenEdit) {
+        return packedHyphenEdit & END_HYPHEN_MASK;
+    }
+
     /**
-     * Returns the packed hyphen edit value for this line.
-     *
-     * You can extract start hyphen edit and end hyphen edit by using
-     * {@link Hyphenator#unpackStartHyphenEdit(int)} and
-     * {@link Hyphenator#unpackEndHyphenEdit(int)}.
+     * Returns the start hyphen edit value for this line.
      *
      * @param lineNumber a line number
-     * @return A packed hyphen edit value.
+     * @return A start hyphen edit value.
      * @hide
      */
     @Override
-    public int getHyphen(int lineNumber) {
-        return mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK;
+    public @Paint.StartHyphenEdit int getStartHyphenEdit(int lineNumber) {
+        return unpackStartHyphenEdit(mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK);
+    }
+
+    /**
+     * Returns the packed hyphen edit value for this line.
+     *
+     * @param lineNumber a line number
+     * @return An end hyphen edit value.
+     * @hide
+     */
+    @Override
+    public @Paint.EndHyphenEdit int getEndHyphenEdit(int lineNumber) {
+        return unpackEndHyphenEdit(mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK);
     }
 
     /**
@@ -1395,6 +1418,9 @@
     private static final int DIR_SHIFT  = 30;
     private static final int TAB_MASK   = 0x20000000;
     private static final int HYPHEN_MASK = 0xFF;
+    private static final int START_HYPHEN_BITS_SHIFT = 3;
+    private static final int START_HYPHEN_MASK = 0x18; // 0b11000
+    private static final int END_HYPHEN_MASK = 0x7;  // 0b00111
 
     private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
 
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 915a18e..8665106 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -1012,19 +1012,14 @@
         return runIsRtl ? -ret : ret;
     }
 
-    private int adjustHyphenEdit(int start, int limit, int packedHyphenEdit) {
-        int result = packedHyphenEdit;
-        // Only draw hyphens on first or last run in line. Disable them otherwise.
-        if (start > 0) { // not the first run
-            result = Hyphenator.packHyphenEdit(Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
-                    Hyphenator.unpackEndHyphenEdit(packedHyphenEdit));
-        }
-        if (limit < mLen) { // not the last run
-            result = Hyphenator.packHyphenEdit(Hyphenator.unpackStartHyphenEdit(packedHyphenEdit),
-                    Hyphenator.END_HYPHEN_EDIT_NO_EDIT);
-            result &= ~Paint.HYPHENEDIT_MASK_END_OF_LINE;
-        }
-        return result;
+    private int adjustStartHyphenEdit(int start, @Paint.StartHyphenEdit int startHyphenEdit) {
+        // Only draw hyphens on first in line. Disable them otherwise.
+        return start > 0 ? Paint.START_HYPHEN_EDIT_NO_EDIT : startHyphenEdit;
+    }
+
+    private int adjustEndHyphenEdit(int limit, @Paint.EndHyphenEdit int endHyphenEdit) {
+        // Only draw hyphens on last run in line. Disable them otherwise.
+        return limit < mLen ? Paint.END_HYPHEN_EDIT_NO_EDIT : endHyphenEdit;
     }
 
     private static final class DecorationInfo {
@@ -1115,7 +1110,8 @@
         if (!needsSpanMeasurement) {
             final TextPaint wp = mWorkPaint;
             wp.set(mPaint);
-            wp.setHyphenEdit(adjustHyphenEdit(start, limit, wp.getHyphenEdit()));
+            wp.setStartHyphenEdit(adjustStartHyphenEdit(start, wp.getStartHyphenEdit()));
+            wp.setEndHyphenEdit(adjustEndHyphenEdit(limit, wp.getEndHyphenEdit()));
             return handleText(wp, start, limit, start, limit, runIsRtl, c, x, top,
                     y, bottom, fmi, needWidth, measureLimit, null);
         }
@@ -1193,8 +1189,10 @@
                     // The style of the present chunk of text is substantially different from the
                     // style of the previous chunk. We need to handle the active piece of text
                     // and restart with the present chunk.
-                    activePaint.setHyphenEdit(adjustHyphenEdit(
-                            activeStart, activeEnd, mPaint.getHyphenEdit()));
+                    activePaint.setStartHyphenEdit(
+                            adjustStartHyphenEdit(activeStart, mPaint.getStartHyphenEdit()));
+                    activePaint.setEndHyphenEdit(
+                            adjustEndHyphenEdit(activeEnd, mPaint.getEndHyphenEdit()));
                     x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x,
                             top, y, bottom, fmi, needWidth || activeEnd < measureLimit,
                             Math.min(activeEnd, mlimit), mDecorations);
@@ -1218,8 +1216,10 @@
                 }
             }
             // Handle the final piece of text.
-            activePaint.setHyphenEdit(adjustHyphenEdit(
-                    activeStart, activeEnd, mPaint.getHyphenEdit()));
+            activePaint.setStartHyphenEdit(
+                    adjustStartHyphenEdit(activeStart, mPaint.getStartHyphenEdit()));
+            activePaint.setEndHyphenEdit(
+                    adjustEndHyphenEdit(activeEnd, mPaint.getEndHyphenEdit()));
             x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x,
                     top, y, bottom, fmi, needWidth || activeEnd < measureLimit,
                     Math.min(activeEnd, mlimit), mDecorations);
@@ -1323,7 +1323,8 @@
                 && lp.getTextSkewX() == rp.getTextSkewX()
                 && lp.getLetterSpacing() == rp.getLetterSpacing()
                 && lp.getWordSpacing() == rp.getWordSpacing()
-                && lp.getHyphenEdit() == rp.getHyphenEdit()
+                && lp.getStartHyphenEdit() == rp.getStartHyphenEdit()
+                && lp.getEndHyphenEdit() == rp.getEndHyphenEdit()
                 && lp.bgColor == rp.bgColor
                 && lp.baselineShift == rp.baselineShift
                 && lp.linkColor == rp.linkColor
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 13ac9ff..98f58be 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -46,10 +46,10 @@
  * <p>
  * For example, an <code>ImagedSpan</code> can be used like this:
  * <pre>
- * SpannableString string = SpannableString("Bottom: span.\nBaseline: span.");
+ * SpannableString string = new SpannableString("Bottom: span.\nBaseline: span.");
  * // using the default alignment: ALIGN_BOTTOM
- * string.setSpan(ImageSpan(this, R.mipmap.ic_launcher), 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- * string.setSpan(ImageSpan(this, R.mipmap.ic_launcher, DynamicDrawableSpan.ALIGN_BASELINE),
+ * string.setSpan(new ImageSpan(this, R.mipmap.ic_launcher), 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * string.setSpan(new ImageSpan(this, R.mipmap.ic_launcher, DynamicDrawableSpan.ALIGN_BASELINE),
  * 22, 23, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  * </pre>
  * <img src="{@docRoot}reference/android/images/text/style/imagespan.png" />
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index e2af6f5..436cb4f 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -16,12 +16,12 @@
 
 package android.util;
 
+import libcore.util.EmptyArray;
+
 import android.annotation.UnsupportedAppUsage;
 
 import com.android.internal.util.ArrayUtils;
 
-import libcore.util.EmptyArray;
-
 import java.util.Collection;
 import java.util.ConcurrentModificationException;
 import java.util.Map;
@@ -453,10 +453,6 @@
      * @return Returns the key stored at the given index.
      */
     public K keyAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         return (K)mArray[index << 1];
     }
 
@@ -466,10 +462,6 @@
      * @return Returns the value stored at the given index.
      */
     public V valueAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         return (V)mArray[(index << 1) + 1];
     }
 
@@ -480,10 +472,6 @@
      * @return Returns the previous value at the given index.
      */
     public V setValueAt(int index, V value) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         index = (index << 1) + 1;
         V old = (V)mArray[index];
         mArray[index] = value;
@@ -677,11 +665,6 @@
      * @return Returns the value that was stored at this index.
      */
     public V removeAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
-
         final Object old = mArray[(index << 1) + 1];
         final int osize = mSize;
         final int nsize;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c4f815b..aee1d6a 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -51,7 +51,6 @@
         DEFAULT_FLAGS.put("settings_network_and_internet_v2", "true");
         DEFAULT_FLAGS.put("settings_slice_injection", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
-        DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true");
         DEFAULT_FLAGS.put("settings_mainline_module", "false");
         DEFAULT_FLAGS.put("settings_dynamic_android", "false");
         DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index e4de704..cf49803 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -21,6 +21,9 @@
 
 import libcore.util.EmptyArray;
 
+import java.util.Arrays;
+import java.util.Objects;
+
 /**
  * SparseArray mapping longs to Objects.  Unlike a normal array of Objects,
  * there can be gaps in the indices.  It is intended to be more memory efficient
@@ -144,10 +147,6 @@
      * Removes the mapping at the specified index.
      */
     public void removeAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         if (mValues[index] != DELETED) {
             mValues[index] = DELETED;
             mGarbage = true;
@@ -237,10 +236,6 @@
      * key.</p>
      */
     public long keyAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         if (mGarbage) {
             gc();
         }
@@ -261,10 +256,6 @@
      */
     @SuppressWarnings("unchecked")
     public E valueAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         if (mGarbage) {
             gc();
         }
@@ -278,10 +269,6 @@
      * LongSparseArray stores.
      */
     public void setValueAt(int index, E value) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         if (mGarbage) {
             gc();
         }
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index f167f00..8dcdb40 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -16,13 +16,14 @@
 
 package android.util;
 
-import android.annotation.UnsupportedAppUsage;
-
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
+import android.annotation.UnsupportedAppUsage;
 import libcore.util.EmptyArray;
 
+import java.util.Arrays;
+
 /**
  * Map of {@code long} to {@code long}. Unlike a normal array of longs, there
  * can be gaps in the indices. It is intended to be more memory efficient than using a
@@ -172,10 +173,6 @@
      * key.</p>
      */
     public long keyAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         return mKeys[index];
     }
 
@@ -191,10 +188,6 @@
      * associated with the largest key.</p>
      */
     public long valueAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         return mValues[index];
     }
 
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 67dfb02..89ea2d3 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -16,11 +16,10 @@
 
 package android.util;
 
-import android.annotation.UnsupportedAppUsage;
-
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
+import android.annotation.UnsupportedAppUsage;
 import libcore.util.EmptyArray;
 
 /**
@@ -172,10 +171,6 @@
      * the behavior is undefined.</p>
      */
     public void removeAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         if (mValues[index] != DELETED) {
             mValues[index] = DELETED;
             mGarbage = true;
@@ -284,10 +279,6 @@
      * the behavior is undefined.</p>
      */
     public int keyAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         if (mGarbage) {
             gc();
         }
@@ -311,10 +302,6 @@
      */
     @SuppressWarnings("unchecked")
     public E valueAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         if (mGarbage) {
             gc();
         }
@@ -330,10 +317,6 @@
      * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined.</p>
      */
     public void setValueAt(int index, E value) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         if (mGarbage) {
             gc();
         }
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index 03fa1c9..d4c4095 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -16,11 +16,10 @@
 
 package android.util;
 
-import android.annotation.UnsupportedAppUsage;
-
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
+import android.annotation.UnsupportedAppUsage;
 import libcore.util.EmptyArray;
 
 /**
@@ -168,10 +167,6 @@
      * key.</p>
      */
     public int keyAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         return mKeys[index];
     }
 
@@ -187,10 +182,6 @@
      * associated with the largest key.</p>
      */
     public boolean valueAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         return mValues[index];
     }
 
@@ -198,19 +189,11 @@
      * Directly set the value at a particular index.
      */
     public void setValueAt(int index, boolean value) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         mValues[index] = value;
     }
 
     /** @hide */
     public void setKeyAt(int index, int key) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         mKeys[index] = key;
     }
 
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index c68dc4e..9e6bad1 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -16,15 +16,14 @@
 
 package android.util;
 
-import android.annotation.UnsupportedAppUsage;
-
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
-import libcore.util.EmptyArray;
-
 import java.util.Arrays;
 
+import android.annotation.UnsupportedAppUsage;
+import libcore.util.EmptyArray;
+
 /**
  * SparseIntArrays map integers to integers.  Unlike a normal array of integers,
  * there can be gaps in the indices.  It is intended to be more memory efficient
@@ -172,10 +171,6 @@
      * key.</p>
      */
     public int keyAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         return mKeys[index];
     }
 
@@ -191,10 +186,6 @@
      * associated with the largest key.</p>
      */
     public int valueAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         return mValues[index];
     }
 
@@ -202,10 +193,6 @@
      * Directly set the value at a particular index.
      */
     public void setValueAt(int index, int value) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         mValues[index] = value;
     }
 
diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java
index 37a9202..81db2b7 100644
--- a/core/java/android/util/SparseLongArray.java
+++ b/core/java/android/util/SparseLongArray.java
@@ -182,10 +182,6 @@
      * key.</p>
      */
     public int keyAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         return mKeys[index];
     }
 
@@ -201,10 +197,6 @@
      * associated with the largest key.</p>
      */
     public long valueAt(int index) {
-        if (index >= mSize) {
-            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
-            throw new ArrayIndexOutOfBoundsException(index);
-        }
         return mValues[index];
     }
 
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 998ad2a..cd075bf 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -63,6 +63,7 @@
 import java.io.Closeable;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.Objects;
 
 /**
  * Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
@@ -196,6 +197,9 @@
     private static native boolean nativeGetProtectedContentSupport();
     private static native void nativeSetMetadata(long transactionObj, int key, Parcel data);
     private static native void nativeSyncInputWindows(long transactionObj);
+    private static native boolean nativeGetDisplayBrightnessSupport(IBinder displayToken);
+    private static native boolean nativeSetDisplayBrightness(IBinder displayToken,
+            float brightness);
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
     private String mName;
@@ -1961,6 +1965,47 @@
     }
 
     /**
+     * Returns whether brightness operations are supported on a display.
+     *
+     * @param displayToken
+     *      The token for the display.
+     *
+     * @return Whether brightness operations are supported on the display.
+     *
+     * @hide
+     */
+    public static boolean getDisplayBrightnessSupport(IBinder displayToken) {
+        return nativeGetDisplayBrightnessSupport(displayToken);
+    }
+
+    /**
+     * Sets the brightness of a display.
+     *
+     * @param displayToken
+     *      The token for the display whose brightness is set.
+     * @param brightness
+     *      A number between 0.0f (minimum brightness) and 1.0f (maximum brightness), or -1.0f to
+     *      turn the backlight off.
+     *
+     * @return Whether the method succeeded or not.
+     *
+     * @throws IllegalArgumentException if:
+     *      - displayToken is null;
+     *      - brightness is NaN or greater than 1.0f.
+     *
+     * @hide
+     */
+    public static boolean setDisplayBrightness(IBinder displayToken, float brightness) {
+        Objects.requireNonNull(displayToken);
+        if (Float.isNaN(brightness) || brightness > 1.0f
+                || (brightness < 0.0f && brightness != -1.0f)) {
+            throw new IllegalArgumentException("brightness must be a number between 0.0f and 1.0f,"
+                    + " or -1 to turn the backlight off.");
+        }
+        return nativeSetDisplayBrightness(displayToken, brightness);
+    }
+
+    /**
      * An atomic set of changes to a set of SurfaceControl.
      */
     public static class Transaction implements Closeable {
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 3d3d941..f5657df 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -209,19 +209,17 @@
      * Adds the WebView asset path to {@link android.content.res.AssetManager}.
      */
     public void addWebViewAssetPath(Context context) {
-        final String newAssetPath = WebViewFactory.getLoadedPackageInfo().applicationInfo.sourceDir;
-
+        final String[] newAssetPaths =
+                WebViewFactory.getLoadedPackageInfo().applicationInfo.getAllApkPaths();
         final ApplicationInfo appInfo = context.getApplicationInfo();
-        final String[] libs = appInfo.sharedLibraryFiles;
-        if (!ArrayUtils.contains(libs, newAssetPath)) {
-            // Build the new library asset path list.
-            final int newLibAssetsCount = 1 + (libs != null ? libs.length : 0);
-            final String[] newLibAssets = new String[newLibAssetsCount];
-            if (libs != null) {
-                System.arraycopy(libs, 0, newLibAssets, 0, libs.length);
-            }
-            newLibAssets[newLibAssetsCount - 1] = newAssetPath;
 
+        // Build the new library asset path list.
+        String[] newLibAssets = appInfo.sharedLibraryFiles;
+        for (String newAssetPath : newAssetPaths) {
+            newLibAssets = ArrayUtils.appendElement(String.class, newLibAssets, newAssetPath);
+        }
+
+        if (newLibAssets != appInfo.sharedLibraryFiles) {
             // Update the ApplicationInfo object with the new list.
             // We know this will persist and future Resources created via ResourcesManager
             // will include the shared library because this ApplicationInfo comes from the
@@ -230,8 +228,8 @@
             appInfo.sharedLibraryFiles = newLibAssets;
 
             // Update existing Resources with the WebView library.
-            ResourcesManager.getInstance().appendLibAssetForMainAssetPath(
-                    appInfo.getBaseResourcePath(), newAssetPath);
+            ResourcesManager.getInstance().appendLibAssetsForMainAssetPath(
+                    appInfo.getBaseResourcePath(), newAssetPaths);
         }
     }
 
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 6d88530..528a6a8 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -448,8 +448,7 @@
 
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
             try {
-                initialApplication.getAssets().addAssetPathAsSharedLibrary(
-                        webViewContext.getApplicationInfo().sourceDir);
+                new WebViewDelegate().addWebViewAssetPath(initialApplication);
                 ClassLoader clazzLoader = webViewContext.getClassLoader();
 
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 25e5dd3..16b903d 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -702,7 +702,7 @@
 
             mPopup.setWidth(widthSpec);
             mPopup.setHeight(heightSpec);
-            mPopup.setClipToScreenEnabled(true);
+            mPopup.setIsClippedToScreen(true);
 
             // use outside touchable to dismiss drop down when touching outside of it, so
             // only set this if the dropdown is not always visible
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 2798296..03e7e10 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -887,9 +887,9 @@
      *
      * @return true if popup will be clipped to the screen instead of the window, false otherwise
      *
-     * @see #setClipToScreenEnabled(boolean)
+     * @see #setIsClippedToScreen(boolean)
      */
-    public boolean isClipToScreenEnabled() {
+    public boolean isClippedToScreen() {
         return mClipToScreen;
     }
 
@@ -902,9 +902,9 @@
      *
      * @param enabled true to clip to the screen.
      *
-     * @see #isClipToScreenEnabled()
+     * @see #isClippedToScreen()
      */
-    public void setClipToScreenEnabled(boolean enabled) {
+    public void setIsClippedToScreen(boolean enabled) {
         mClipToScreen = enabled;
     }
 
@@ -961,9 +961,9 @@
      *
      * @return true if the window will always be positioned in screen coordinates.
      *
-     * @see #setLayoutInScreenEnabled(boolean)
+     * @see #setIsLaidOutInScreen(boolean)
      */
-    public boolean isLayoutInScreenEnabled() {
+    public boolean isLaidOutInScreen() {
         return mLayoutInScreen;
     }
 
@@ -974,9 +974,9 @@
      *
      * @param enabled true if the popup should always be positioned in screen coordinates
      *
-     * @see #isLayoutInScreenEnabled()
+     * @see #isLaidOutInScreen()
      */
-    public void setLayoutInScreenEnabled(boolean enabled) {
+    public void setIsLaidOutInScreen(boolean enabled) {
         mLayoutInScreen = enabled;
     }
 
@@ -1016,7 +1016,7 @@
      * This will cause the popup to inset its content to account for system windows overlaying
      * the screen, such as the status bar.
      *
-     * <p>This will often be combined with {@link #setLayoutInScreenEnabled(boolean)}.
+     * <p>This will often be combined with {@link #setIsLaidOutInScreen(boolean)}.
      *
      * @param enabled true if the popup's views should inset content to account for system windows,
      *                the way that decor views behave for full-screen windows.
@@ -2114,7 +2114,7 @@
      *     <li>{@link #setTouchable(boolean)}</li>
      *     <li>{@link #setAnimationStyle(int)}</li>
      *     <li>{@link #setTouchModal(boolean)} (boolean)}</li>
-     *     <li>{@link #setClipToScreenEnabled(boolean)}</li>
+     *     <li>{@link #setIsClippedToScreen(boolean)}</li>
      * </ul>
      */
     public void update() {
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 8ee31e2..37bed65 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -35,6 +35,9 @@
 import android.view.ViewHierarchyEncoder;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.inspector.InspectableProperty;
+import android.view.inspector.InspectionCompanion;
+import android.view.inspector.PropertyMapper;
+import android.view.inspector.PropertyReader;
 import android.widget.RemoteViews.RemoteView;
 
 import com.android.internal.R;
@@ -1286,7 +1289,6 @@
          * the anchor's visibility is GONE.
          */
         @ViewDebug.ExportedProperty(category = "layout")
-        @InspectableProperty(name = "layout_alignWithParentIfMissing")
         public boolean alignWithParent;
 
         public LayoutParams(Context c, AttributeSet attrs) {
@@ -1723,6 +1725,146 @@
             super.encodeProperties(encoder);
             encoder.addProperty("layout:alignWithParent", alignWithParent);
         }
+
+        /** @hide */
+        public static final class InspectionCompanion
+                implements android.view.inspector.InspectionCompanion<LayoutParams> {
+            private boolean mPropertiesMapped;
+
+            private int mAboveId;
+            private int mAlignBaselineId;
+            private int mAlignBottomId;
+            private int mAlignEndId;
+            private int mAlignLeftId;
+            private int mAlignParentBottomId;
+            private int mAlignParentEndId;
+            private int mAlignParentLeftId;
+            private int mAlignParentRightId;
+            private int mAlignParentStartId;
+            private int mAlignParentTopId;
+            private int mAlignRightId;
+            private int mAlignStartId;
+            private int mAlignTopId;
+            private int mAlignWithParentIfMissingId;
+            private int mBelowId;
+            private int mCenterHorizontalId;
+            private int mCenterInParentId;
+            private int mCenterVerticalId;
+            private int mToEndOfId;
+            private int mToLeftOfId;
+            private int mToRightOfId;
+            private int mToStartOfId;
+
+            @Override
+            public void mapProperties(@NonNull PropertyMapper propertyMapper) {
+                mPropertiesMapped = true;
+
+                mAboveId = propertyMapper.mapResourceId("layout_above", R.attr.layout_above);
+
+                mAlignBaselineId = propertyMapper.mapResourceId(
+                        "layout_alignBaseline", R.attr.layout_alignBaseline);
+
+                mAlignBottomId = propertyMapper.mapResourceId(
+                        "layout_alignBottom", R.attr.layout_alignBottom);
+
+                mAlignEndId = propertyMapper.mapResourceId(
+                        "layout_alignEnd", R.attr.layout_alignEnd);
+
+                mAlignLeftId = propertyMapper.mapResourceId(
+                        "layout_alignLeft", R.attr.layout_alignLeft);
+
+                mAlignParentBottomId = propertyMapper.mapBoolean(
+                        "layout_alignParentBottom", R.attr.layout_alignParentBottom);
+
+                mAlignParentEndId = propertyMapper.mapBoolean(
+                        "layout_alignParentEnd", R.attr.layout_alignParentEnd);
+
+                mAlignParentLeftId = propertyMapper.mapBoolean(
+                        "layout_alignParentLeft", R.attr.layout_alignParentLeft);
+
+                mAlignParentRightId = propertyMapper.mapBoolean(
+                        "layout_alignParentRight", R.attr.layout_alignParentRight);
+
+                mAlignParentStartId = propertyMapper.mapBoolean(
+                        "layout_alignParentStart", R.attr.layout_alignParentStart);
+
+                mAlignParentTopId = propertyMapper.mapBoolean(
+                        "layout_alignParentTop", R.attr.layout_alignParentTop);
+
+                mAlignRightId = propertyMapper.mapResourceId(
+                        "layout_alignRight", R.attr.layout_alignRight);
+
+                mAlignStartId = propertyMapper.mapResourceId(
+                        "layout_alignStart", R.attr.layout_alignStart);
+
+                mAlignTopId = propertyMapper.mapResourceId(
+                        "layout_alignTop", R.attr.layout_alignTop);
+
+                mAlignWithParentIfMissingId = propertyMapper.mapBoolean(
+                        "layout_alignWithParentIfMissing",
+                        R.attr.layout_alignWithParentIfMissing);
+
+                mBelowId = propertyMapper.mapResourceId("layout_below", R.attr.layout_below);
+
+                mCenterHorizontalId = propertyMapper.mapBoolean(
+                        "layout_centerHorizontal", R.attr.layout_centerHorizontal);
+
+                mCenterInParentId = propertyMapper.mapBoolean(
+                        "layout_centerInParent", R.attr.layout_centerInParent);
+
+                mCenterVerticalId = propertyMapper.mapBoolean(
+                        "layout_centerVertical", R.attr.layout_centerVertical);
+
+                mToEndOfId = propertyMapper.mapResourceId(
+                        "layout_toEndOf", R.attr.layout_toEndOf);
+
+                mToLeftOfId = propertyMapper.mapResourceId(
+                        "layout_toLeftOf", R.attr.layout_toLeftOf);
+
+                mToRightOfId = propertyMapper.mapResourceId(
+                        "layout_toRightOf", R.attr.layout_toRightOf);
+
+                mToStartOfId = propertyMapper.mapResourceId(
+                        "layout_toStartOf", R.attr.layout_toStartOf);
+            }
+
+            @Override
+            public void readProperties(
+                    @NonNull LayoutParams node,
+                    @NonNull PropertyReader propertyReader
+            ) {
+                if (!mPropertiesMapped) {
+                    throw new UninitializedPropertyMapException();
+                }
+
+                final int[] rules = node.getRules();
+
+                propertyReader.readResourceId(mAboveId, rules[ABOVE]);
+                propertyReader.readResourceId(mAlignBaselineId, rules[ALIGN_BASELINE]);
+                propertyReader.readResourceId(mAlignBottomId, rules[ALIGN_BOTTOM]);
+                propertyReader.readResourceId(mAlignEndId, rules[ALIGN_END]);
+                propertyReader.readResourceId(mAlignLeftId, rules[ALIGN_LEFT]);
+                propertyReader.readBoolean(
+                        mAlignParentBottomId, rules[ALIGN_PARENT_BOTTOM] == TRUE);
+                propertyReader.readBoolean(mAlignParentEndId, rules[ALIGN_PARENT_END] == TRUE);
+                propertyReader.readBoolean(mAlignParentLeftId, rules[ALIGN_PARENT_LEFT] == TRUE);
+                propertyReader.readBoolean(mAlignParentRightId, rules[ALIGN_PARENT_RIGHT] == TRUE);
+                propertyReader.readBoolean(mAlignParentStartId, rules[ALIGN_PARENT_START] == TRUE);
+                propertyReader.readBoolean(mAlignParentTopId, rules[ALIGN_PARENT_TOP] == TRUE);
+                propertyReader.readResourceId(mAlignRightId, rules[ALIGN_RIGHT]);
+                propertyReader.readResourceId(mAlignStartId, rules[ALIGN_START]);
+                propertyReader.readResourceId(mAlignTopId, rules[ALIGN_TOP]);
+                propertyReader.readBoolean(mAlignWithParentIfMissingId, node.alignWithParent);
+                propertyReader.readResourceId(mBelowId, rules[BELOW]);
+                propertyReader.readBoolean(mCenterHorizontalId, rules[CENTER_HORIZONTAL] == TRUE);
+                propertyReader.readBoolean(mCenterInParentId, rules[CENTER_IN_PARENT] == TRUE);
+                propertyReader.readBoolean(mCenterVerticalId, rules[CENTER_VERTICAL] == TRUE);
+                propertyReader.readResourceId(mToEndOfId, rules[END_OF]);
+                propertyReader.readResourceId(mToLeftOfId, rules[LEFT_OF]);
+                propertyReader.readResourceId(mToRightOfId, rules[RIGHT_OF]);
+                propertyReader.readResourceId(mToStartOfId, rules[START_OF]);
+            }
+        }
     }
 
     private static class DependencyGraph {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 91928b5..79cf4c42 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -236,7 +236,6 @@
                     mServiceConnections.remove(sri.connection);
                     if (mServiceConnections.isEmpty()) {
                         sendVoiceChoicesIfNeeded();
-                        mChooserListAdapter.setShowServiceTargets(true);
                     }
                     break;
 
@@ -250,7 +249,6 @@
                     unbindRemainingServices();
                     sendVoiceChoicesIfNeeded();
                     mChooserListAdapter.completeServiceTargetLoading();
-                    mChooserListAdapter.setShowServiceTargets(true);
                     break;
 
                 case SHORTCUT_MANAGER_SHARE_TARGET_RESULT:
@@ -265,7 +263,6 @@
 
                 case SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED:
                     sendVoiceChoicesIfNeeded();
-                    mChooserListAdapter.setShowServiceTargets(true);
                     break;
 
                 default:
@@ -446,6 +443,11 @@
         mChooserRowServiceSpacing = getResources()
                                         .getDimensionPixelSize(R.dimen.chooser_service_spacing);
 
+        // expand/shrink direct share 4 -> 8 viewgroup
+        if (mResolverDrawerLayout != null) {
+            mResolverDrawerLayout.setOnScrollChangeListener(this::handleScroll);
+        }
+
         if (DEBUG) {
             Log.d(TAG, "System Time Cost is " + systemCost);
         }
@@ -1756,18 +1758,26 @@
         }
     }
 
+    private void handleScroll(View view, int x, int y, int oldx, int oldy) {
+        if (mChooserRowAdapter != null) {
+            mChooserRowAdapter.handleScroll(view, y, oldy);
+        }
+    }
+
     public class ChooserListAdapter extends ResolveListAdapter {
         public static final int TARGET_BAD = -1;
         public static final int TARGET_CALLER = 0;
         public static final int TARGET_SERVICE = 1;
         public static final int TARGET_STANDARD = 2;
 
-        private static final int MAX_SERVICE_TARGETS = 4;
+        private static final int MAX_SUGGESTED_APP_TARGETS = 4;
         private static final int MAX_TARGETS_PER_SERVICE = 2;
 
+        private static final int MAX_SERVICE_TARGETS = 8;
+
         // Reserve spots for incoming direct share targets by adding placeholders
         private ChooserTargetInfo mPlaceHolderTargetInfo = new PlaceHolderTargetInfo();
-        private List<ChooserTargetInfo> mServiceTargets;
+        private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
         private final List<TargetInfo> mCallerTargets = new ArrayList<>();
         private boolean mShowServiceTargets;
 
@@ -1786,7 +1796,7 @@
             super(context, payloadIntents, null, rList, launchedFromUid, filterLastUsed,
                     resolverListController);
 
-            mServiceTargets = createPlaceHolders();
+            createPlaceHolders();
 
             if (initialIntents != null) {
                 final PackageManager pm = getPackageManager();
@@ -1840,12 +1850,11 @@
             }
         }
 
-        private List<ChooserTargetInfo> createPlaceHolders() {
-            List<ChooserTargetInfo> list = new ArrayList<>();
+        private void createPlaceHolders() {
+            mServiceTargets.clear();
             for (int i = 0; i < MAX_SERVICE_TARGETS; i++) {
-                list.add(mPlaceHolderTargetInfo);
+                mServiceTargets.add(mPlaceHolderTargetInfo);
             }
-            return list;
         }
 
         @Override
@@ -1913,7 +1922,7 @@
         }
 
         public int getCallerTargetCount() {
-            return mCallerTargets.size();
+            return Math.min(mCallerTargets.size(), MAX_SUGGESTED_APP_TARGETS);
         }
 
         /**
@@ -1940,18 +1949,18 @@
         public int getPositionTargetType(int position) {
             int offset = 0;
 
-            final int callerTargetCount = getCallerTargetCount();
-            if (position < callerTargetCount) {
-                return TARGET_CALLER;
-            }
-            offset += callerTargetCount;
-
             final int serviceTargetCount = getServiceTargetCount();
-            if (position - offset < serviceTargetCount) {
+            if (position < serviceTargetCount) {
                 return TARGET_SERVICE;
             }
             offset += serviceTargetCount;
 
+            final int callerTargetCount = getCallerTargetCount();
+            if (position - offset < callerTargetCount) {
+                return TARGET_CALLER;
+            }
+            offset += callerTargetCount;
+
             final int standardTargetCount = super.getCount();
             if (position - offset < standardTargetCount) {
                 return TARGET_STANDARD;
@@ -1969,19 +1978,19 @@
         public TargetInfo targetInfoForPosition(int position, boolean filtered) {
             int offset = 0;
 
-            final int callerTargetCount = getCallerTargetCount();
-            if (position < callerTargetCount) {
-                return mCallerTargets.get(position);
-            }
-            offset += callerTargetCount;
-
             final int serviceTargetCount = filtered ? getServiceTargetCount() :
                                                getSelectableServiceTargetCount();
-            if (position - offset < serviceTargetCount) {
-                return mServiceTargets.get(position - offset);
+            if (position < serviceTargetCount) {
+                return mServiceTargets.get(position);
             }
             offset += serviceTargetCount;
 
+            final int callerTargetCount = getCallerTargetCount();
+            if (position - offset < callerTargetCount) {
+                return mCallerTargets.get(position - offset);
+            }
+            offset += callerTargetCount;
+
             return filtered ? super.getItem(position - offset)
                     : getDisplayInfoAt(position - offset);
         }
@@ -1995,7 +2004,7 @@
             if (mTargetsNeedPruning && targets.size() > 0) {
                 // First proper update since we got an onListRebuilt() with (transient) 0 items.
                 // Clear out the target list and rebuild.
-                mServiceTargets = createPlaceHolders();
+                createPlaceHolders();
                 mTargetsNeedPruning = false;
 
                 // Add back any app-supplied direct share targets that may have been
@@ -2037,26 +2046,6 @@
         }
 
         /**
-         * Set to true to reveal all service targets at once.
-         */
-        public void setShowServiceTargets(boolean show) {
-            // mShowServiceTargets is only flipped once to show direct share targets. But after the
-            // initial display the list can be re-sorted and the user will see the target list
-            // change. This will log the initial show and the subsequent shuffle to help us get
-            // accurate timing of the UX.
-            if (show) {
-                getMetricsLogger().write(
-                        new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN_DIRECT_TARGET)
-                                .setSubtype(mShowServiceTargets ? MetricsEvent.PREVIOUSLY_VISIBLE
-                                        : MetricsEvent.PREVIOUSLY_HIDDEN));
-            }
-            if (show != mShowServiceTargets) {
-                mShowServiceTargets = show;
-                notifyDataSetChanged();
-            }
-        }
-
-        /**
          * Calling this marks service target loading complete, and will attempt to no longer
          * update the direct share area.
          */
@@ -2102,9 +2091,13 @@
     class ChooserRowAdapter extends BaseAdapter {
         private ChooserListAdapter mChooserListAdapter;
         private final LayoutInflater mLayoutInflater;
-        private final int mColumnCount = 4;
         private int mAnimationCount = 0;
 
+        private DirectShareViewHolder mDirectShareViewHolder;
+
+        private static final int VIEW_TYPE_DIRECT_SHARE = 0;
+        private static final int VIEW_TYPE_NORMAL = 1;
+
         public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
             mChooserListAdapter = wrappedAdapter;
             mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
@@ -2124,22 +2117,29 @@
             });
         }
 
+        private int getMaxTargetsPerRow() {
+            // this will soon hold logic for portrait/landscape
+            return 4;
+        }
+
         @Override
         public int getCount() {
             return (int) (
                     getCallerTargetRowCount()
                             + getServiceTargetRowCount()
                             + Math.ceil(
-                            (float) mChooserListAdapter.getStandardTargetCount() / mColumnCount)
+                            (float) mChooserListAdapter.getStandardTargetCount()
+                                    / getMaxTargetsPerRow())
             );
         }
 
         public int getCallerTargetRowCount() {
             return (int) Math.ceil(
-                    (float) mChooserListAdapter.getCallerTargetCount() / mColumnCount);
+                    (float) mChooserListAdapter.getCallerTargetCount() / getMaxTargetsPerRow());
         }
 
-        // There can be at most one row of service targets.
+        // There can be at most one row in the listview, that is internally
+        // a ViewGroup with 2 rows
         public int getServiceTargetRowCount() {
             return 1;
         }
@@ -2158,29 +2158,48 @@
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             final RowViewHolder holder;
+            int viewType = getItemViewType(position);
+
             if (convertView == null) {
-                holder = createViewHolder(parent);
+                holder = createViewHolder(viewType, parent);
             } else {
                 holder = (RowViewHolder) convertView.getTag();
             }
-            bindViewHolder(position, holder);
 
-            return holder.row;
+            bindViewHolder(position, holder, viewType == VIEW_TYPE_DIRECT_SHARE
+                    ? ChooserListAdapter.MAX_SERVICE_TARGETS : getMaxTargetsPerRow());
+
+            return holder.getViewGroup();
         }
 
-        RowViewHolder createViewHolder(ViewGroup parent) {
-            final ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
-                    parent, false);
-            final RowViewHolder holder = new RowViewHolder(row, mColumnCount);
-            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        @Override
+        public int getItemViewType(int position) {
+            final int start = getFirstRowPosition(position);
+            final int startType = mChooserListAdapter.getPositionTargetType(start);
 
-            for (int i = 0; i < mColumnCount; i++) {
-                final View v = mChooserListAdapter.createView(row);
+            if (startType == ChooserListAdapter.TARGET_SERVICE) {
+                return VIEW_TYPE_DIRECT_SHARE;
+            }
+
+            return VIEW_TYPE_NORMAL;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 2;
+        }
+
+        private RowViewHolder loadViewsIntoRow(RowViewHolder holder) {
+            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            int columnCount = holder.getColumnCount();
+
+            for (int i = 0; i < columnCount; i++) {
+                final View v = mChooserListAdapter.createView(holder.getRow(i));
                 final int column = i;
                 v.setOnClickListener(new OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        startSelected(holder.itemIndices[column], false, true);
+                        startSelected(holder.getItemIndex(column), false, true);
                     }
                 });
                 v.setOnLongClickListener(new OnLongClickListener() {
@@ -2188,12 +2207,11 @@
                     public boolean onLongClick(View v) {
                         showTargetDetails(
                                 mChooserListAdapter.resolveInfoForPosition(
-                                        holder.itemIndices[column], true));
+                                        holder.getItemIndex(column), true));
                         return true;
                     }
                 });
-                row.addView(v);
-                holder.cells[i] = v;
+                ViewGroup row = holder.addView(i, v);
 
                 // Force height to be a given so we don't have visual disruption during scaling.
                 LayoutParams lp = v.getLayoutParams();
@@ -2204,47 +2222,75 @@
                 } else {
                     lp.height = v.getMeasuredHeight();
                 }
-                if (i != (mColumnCount - 1)) {
-                    row.addView(new Space(ChooserActivity.this),
-                            new LinearLayout.LayoutParams(0, 0, 1));
-                }
             }
 
+            final ViewGroup viewGroup = holder.getViewGroup();
+
             // Pre-measure so we can scale later.
             holder.measure();
-            LayoutParams lp = row.getLayoutParams();
+            LayoutParams lp = viewGroup.getLayoutParams();
             if (lp == null) {
-                lp = new LayoutParams(LayoutParams.MATCH_PARENT, holder.measuredRowHeight);
-                row.setLayoutParams(lp);
+                lp = new LayoutParams(LayoutParams.MATCH_PARENT, holder.getMeasuredRowHeight());
+                viewGroup.setLayoutParams(lp);
             } else {
-                lp.height = holder.measuredRowHeight;
+                lp.height = holder.getMeasuredRowHeight();
             }
-            row.setTag(holder);
+
+            viewGroup.setTag(holder);
+
             return holder;
         }
 
-        void bindViewHolder(int rowPosition, RowViewHolder holder) {
+        RowViewHolder createViewHolder(int viewType, ViewGroup parent) {
+            if (viewType == VIEW_TYPE_DIRECT_SHARE) {
+                ViewGroup parentGroup = (ViewGroup) mLayoutInflater.inflate(
+                        R.layout.chooser_row_direct_share, parent, false);
+                ViewGroup row1 = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
+                        parentGroup, false);
+                ViewGroup row2 = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
+                        parentGroup, false);
+                parentGroup.addView(row1);
+                parentGroup.addView(row2);
+
+                mDirectShareViewHolder = new DirectShareViewHolder(parentGroup,
+                        Lists.newArrayList(row1, row2), getMaxTargetsPerRow());
+                loadViewsIntoRow(mDirectShareViewHolder);
+
+                return mDirectShareViewHolder;
+            } else {
+                ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, parent,
+                        false);
+                RowViewHolder holder = new SingleRowViewHolder(row, getMaxTargetsPerRow());
+                loadViewsIntoRow(holder);
+
+                return holder;
+            }
+        }
+
+        void bindViewHolder(int rowPosition, RowViewHolder holder, int columnCount) {
             final int start = getFirstRowPosition(rowPosition);
             final int startType = mChooserListAdapter.getPositionTargetType(start);
 
             final int lastStartType = mChooserListAdapter.getPositionTargetType(
                     getFirstRowPosition(rowPosition - 1));
 
+            final ViewGroup row = holder.getViewGroup();
+
             if (startType != lastStartType || rowPosition == 0) {
-                holder.row.setBackground(mChooserRowLayer);
-                setVertPadding(holder, mChooserRowServiceSpacing, 0);
+                row.setBackground(mChooserRowLayer);
+                setVertPadding(row, mChooserRowServiceSpacing, 0);
             } else {
-                holder.row.setBackground(null);
-                setVertPadding(holder, 0, 0);
+                row.setBackground(null);
+                setVertPadding(row, 0, 0);
             }
 
-            int end = start + mColumnCount - 1;
+            int end = start + columnCount - 1;
             while (mChooserListAdapter.getPositionTargetType(end) != startType && end >= start) {
                 end--;
             }
 
             if (end == start && mChooserListAdapter.getItem(start) instanceof EmptyTargetInfo) {
-                final TextView textView = holder.row.findViewById(R.id.chooser_row_text_option);
+                final TextView textView = row.findViewById(R.id.chooser_row_text_option);
 
                 if (textView.getVisibility() != View.VISIBLE) {
                     textView.setAlpha(0.0f);
@@ -2269,12 +2315,12 @@
                 }
             }
 
-            for (int i = 0; i < mColumnCount; i++) {
-                final View v = holder.cells[i];
+            for (int i = 0; i < columnCount; i++) {
+                final View v = holder.getView(i);
                 if (start + i <= end) {
                     setCellVisibility(holder, i, View.VISIBLE);
-                    holder.itemIndices[i] = start + i;
-                    mChooserListAdapter.bindView(holder.itemIndices[i], v);
+                    holder.setItemIndex(i, start + i);
+                    mChooserListAdapter.bindView(holder.getItemIndex(i), v);
                 } else {
                     setCellVisibility(holder, i, View.INVISIBLE);
                 }
@@ -2282,13 +2328,13 @@
         }
 
         private void setCellVisibility(RowViewHolder holder, int i, int visibility) {
-            final View v = holder.cells[i];
+            final View v = holder.getView(i);
             if (visibility == View.VISIBLE) {
-                holder.cellVisibility[i] = true;
+                holder.setViewVisibility(i, true);
                 v.setVisibility(visibility);
                 v.setAlpha(1.0f);
-            } else if (visibility == View.INVISIBLE && holder.cellVisibility[i]) {
-                holder.cellVisibility[i] = false;
+            } else if (visibility == View.INVISIBLE && holder.getViewVisibility(i)) {
+                holder.setViewVisibility(i, false);
 
                 ValueAnimator fadeAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0f);
                 fadeAnim.setDuration(NO_DIRECT_SHARE_ANIM_IN_MILLIS);
@@ -2302,49 +2348,218 @@
             }
         }
 
-        private void setVertPadding(RowViewHolder holder, int top, int bottom) {
-            holder.row.setPadding(holder.row.getPaddingLeft(), top,
-                    holder.row.getPaddingRight(), bottom);
+        private void setVertPadding(ViewGroup row, int top, int bottom) {
+            row.setPadding(row.getPaddingLeft(), top, row.getPaddingRight(), bottom);
         }
 
         int getFirstRowPosition(int row) {
-            final int callerCount = mChooserListAdapter.getCallerTargetCount();
-            final int callerRows = (int) Math.ceil((float) callerCount / mColumnCount);
-
-            if (row < callerRows) {
-                return row * mColumnCount;
+            final int serviceCount = mChooserListAdapter.getServiceTargetCount();
+            final int serviceRows = (int) Math.ceil((float) serviceCount
+                    / ChooserListAdapter.MAX_SERVICE_TARGETS);
+            if (row < serviceRows) {
+                return row * getMaxTargetsPerRow();
             }
 
-            final int serviceCount = mChooserListAdapter.getServiceTargetCount();
-            final int serviceRows = (int) Math.ceil((float) serviceCount / mColumnCount);
-
+            final int callerCount = mChooserListAdapter.getCallerTargetCount();
+            final int callerRows = (int) Math.ceil((float) callerCount / getMaxTargetsPerRow());
             if (row < callerRows + serviceRows) {
-                return callerCount + (row - callerRows) * mColumnCount;
+                return serviceCount + (row - serviceRows) * getMaxTargetsPerRow();
             }
 
             return callerCount + serviceCount
-                    + (row - callerRows - serviceRows) * mColumnCount;
+                    + (row - callerRows - serviceRows) * getMaxTargetsPerRow();
+        }
+
+        public void handleScroll(View v, int y, int oldy) {
+            if (mDirectShareViewHolder != null) {
+                mDirectShareViewHolder.handleScroll(mAdapterView, y, oldy, getMaxTargetsPerRow());
+            }
         }
     }
 
-    static class RowViewHolder {
-        public final View[] cells;
-        public final boolean [] cellVisibility;
-        public final ViewGroup row;
-        int measuredRowHeight;
-        int[] itemIndices;
+    abstract class RowViewHolder {
+        protected int mMeasuredRowHeight;
+        private int[] mItemIndices;
+        protected final View[] mCells;
+        private final boolean[] mCellVisibility;
+        private final int mColumnCount;
 
-        public RowViewHolder(ViewGroup row, int cellCount) {
-            this.row = row;
-            this.cells = new View[cellCount];
-            this.cellVisibility = new boolean[cellCount];
-            this.itemIndices = new int[cellCount];
+        RowViewHolder(int cellCount) {
+            this.mCells = new View[cellCount];
+            this.mItemIndices = new int[cellCount];
+            this.mCellVisibility = new boolean[cellCount];
+            this.mColumnCount = cellCount;
+        }
+
+        abstract ViewGroup addView(int index, View v);
+
+        abstract ViewGroup getViewGroup();
+
+        abstract ViewGroup getRow(int index);
+
+        public int getColumnCount() {
+            return mColumnCount;
+        }
+
+        public void setViewVisibility(int index, boolean visibility) {
+            mCellVisibility[index] = visibility;
+        }
+
+        public boolean getViewVisibility(int index) {
+            return mCellVisibility[index];
         }
 
         public void measure() {
             final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-            row.measure(spec, spec);
-            measuredRowHeight = row.getMeasuredHeight();
+            getViewGroup().measure(spec, spec);
+            mMeasuredRowHeight = getViewGroup().getMeasuredHeight();
+        }
+
+        public int getMeasuredRowHeight() {
+            return mMeasuredRowHeight;
+        }
+
+        protected void addSpacer(ViewGroup row) {
+            row.addView(new Space(ChooserActivity.this),
+                    new LinearLayout.LayoutParams(0, 0, 1));
+        }
+
+        public void setItemIndex(int itemIndex, int listIndex) {
+            mItemIndices[itemIndex] = listIndex;
+        }
+
+        public int getItemIndex(int itemIndex) {
+            return mItemIndices[itemIndex];
+        }
+
+        public View getView(int index) {
+            return mCells[index];
+        }
+    }
+
+    class SingleRowViewHolder extends RowViewHolder {
+        private final ViewGroup mRow;
+
+        SingleRowViewHolder(ViewGroup row, int cellCount) {
+            super(cellCount);
+
+            this.mRow = row;
+        }
+
+        public ViewGroup getViewGroup() {
+            return mRow;
+        }
+
+        public ViewGroup getRow(int index) {
+            return mRow;
+        }
+
+        public ViewGroup addView(int index, View v) {
+            mRow.addView(v);
+            mCells[index] = v;
+
+            if (index != (mCells.length - 1)) {
+                addSpacer(mRow);
+            }
+
+            return mRow;
+        }
+    }
+
+    class DirectShareViewHolder extends RowViewHolder {
+        private final ViewGroup mParent;
+        private final List<ViewGroup> mRows;
+        private int mCellCountPerRow;
+
+        private boolean mHideDirectShareExpansion = false;
+        private int mDirectShareMinHeight = 0;
+        private int mDirectShareCurrHeight = 0;
+        private int mDirectShareMaxHeight = 0;
+
+        DirectShareViewHolder(ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow) {
+            super(rows.size() * cellCountPerRow);
+
+            this.mParent = parent;
+            this.mRows = rows;
+            this.mCellCountPerRow = cellCountPerRow;
+        }
+
+        public ViewGroup addView(int index, View v) {
+            ViewGroup row = getRow(index);
+            row.addView(v);
+            mCells[index] = v;
+
+            if (index % mCellCountPerRow != (mCellCountPerRow - 1)) {
+                addSpacer(row);
+            }
+
+            return row;
+        }
+
+        public ViewGroup getViewGroup() {
+            return mParent;
+        }
+
+        public ViewGroup getRow(int index) {
+            return mRows.get(index / mCellCountPerRow);
+        }
+
+        public void measure() {
+            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            getRow(0).measure(spec, spec);
+            getRow(1).measure(spec, spec);
+
+            // uses ChooserActiivty state variables to track height
+            mDirectShareMinHeight = getRow(0).getMeasuredHeight();
+            mDirectShareCurrHeight = mDirectShareCurrHeight > 0
+                                         ? mDirectShareCurrHeight : mDirectShareMinHeight;
+            mDirectShareMaxHeight = 2 * mDirectShareMinHeight;
+        }
+
+        public int getMeasuredRowHeight() {
+            return mDirectShareCurrHeight;
+        }
+
+        public void handleScroll(AbsListView view, int y, int oldy, int maxTargetsPerRow) {
+            // only expand if we have more than 4 targets, and delay that decision until
+            // they start to scroll
+            if (mHideDirectShareExpansion) {
+                return;
+            }
+
+            if (mChooserListAdapter.getSelectableServiceTargetCount() <= maxTargetsPerRow) {
+                mHideDirectShareExpansion = true;
+                return;
+            }
+
+            int yDiff = (int) ((oldy - y) * 0.7f);
+
+            int prevHeight = mDirectShareCurrHeight;
+            mDirectShareCurrHeight = Math.min(mDirectShareCurrHeight + yDiff,
+                    mDirectShareMaxHeight);
+            mDirectShareCurrHeight = Math.max(mDirectShareCurrHeight, mDirectShareMinHeight);
+            yDiff = mDirectShareCurrHeight - prevHeight;
+
+            if (view == null || view.getChildCount() == 0) {
+                return;
+            }
+
+            ViewGroup expansionGroup = (ViewGroup) view.getChildAt(0);
+            int widthSpec = MeasureSpec.makeMeasureSpec(expansionGroup.getWidth(),
+                    MeasureSpec.EXACTLY);
+            int heightSpec = MeasureSpec.makeMeasureSpec(mDirectShareCurrHeight,
+                    MeasureSpec.EXACTLY);
+            expansionGroup.measure(widthSpec, heightSpec);
+            expansionGroup.getLayoutParams().height = expansionGroup.getMeasuredHeight();
+            expansionGroup.layout(expansionGroup.getLeft(), expansionGroup.getTop(),
+                    expansionGroup.getRight(),
+                    expansionGroup.getTop() + expansionGroup.getMeasuredHeight());
+
+            // reposition list items
+            int items = view.getChildCount();
+            for (int i = 1; i < items; i++) {
+                view.getChildAt(i).offsetTopAndBottom(yDiff);
+            }
         }
     }
 
@@ -2525,7 +2740,7 @@
                     mCachedView = null;
                 }
                 final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView);
-                int height = ((RowViewHolder) (v.getTag())).measuredRowHeight;
+                int height = ((RowViewHolder) (v.getTag())).getMeasuredRowHeight();
 
                 offset += (int) (height);
 
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 011cc04..c60a96b 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -99,7 +99,7 @@
 
     protected ResolveListAdapter mAdapter;
     private boolean mSafeForwardingMode;
-    private AbsListView mAdapterView;
+    protected AbsListView mAdapterView;
     private Button mAlwaysButton;
     private Button mOnceButton;
     private Button mSettingsButton;
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index 2442d0b..8b25e2d 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -66,7 +66,7 @@
      */
     public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
         byte[] buffer = new byte[32*1024];
-        int len;
+        int len = 0;
         boolean wakeup_sources;
         final long startTime = SystemClock.uptimeMillis();
 
@@ -87,7 +87,11 @@
                 }
             }
 
-            len = is.read(buffer);
+            int cnt;
+            while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
+                len += cnt;
+            }
+
             is.close();
         } catch (java.io.IOException e) {
             Slog.wtf(TAG, "failed to read kernel wakelocks", e);
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 6595317..4aff912 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -277,17 +277,31 @@
                                 Integer.parseInt(usapPoolRefillThresholdPropString),
                                 mUsapPoolSizeMax);
             }
+
+            // Sanity check
+
+            if (mUsapPoolSizeMin >= mUsapPoolSizeMax) {
+                Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size."
+                        + "  Restoring default values.");
+
+                mUsapPoolSizeMax = Integer.parseInt(USAP_POOL_SIZE_MAX_DEFAULT);
+                mUsapPoolSizeMin = Integer.parseInt(USAP_POOL_SIZE_MIN_DEFAULT);
+                mUsapPoolRefillThreshold = mUsapPoolSizeMax / 2;
+            }
         }
     }
 
+    private boolean mIsFirstPropertyCheck = true;
     private long mLastPropCheckTimestamp = 0;
 
     private void fetchUsapPoolPolicyPropsWithMinInterval() {
         final long currentTimestamp = SystemClock.elapsedRealtime();
 
-        if (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL) {
-            fetchUsapPoolPolicyProps();
+        if (mIsFirstPropertyCheck
+                || (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL)) {
+            mIsFirstPropertyCheck = false;
             mLastPropCheckTimestamp = currentTimestamp;
+            fetchUsapPoolPolicyProps();
         }
     }
 
@@ -304,6 +318,9 @@
     Runnable fillUsapPool(int[] sessionSocketRawFDs) {
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool");
 
+        // Ensure that the pool properties have been fetched.
+        fetchUsapPoolPolicyPropsWithMinInterval();
+
         int usapPoolCount = Zygote.getUsapPoolCount();
         int numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount;
 
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 42fb1f5..bb7423a 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -33,7 +33,6 @@
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.util.Size;
-import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -593,7 +592,7 @@
             refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
             preparePopupContent();
             // We need to specify the position in window coordinates.
-            // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
+            // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can
             // specify the popup position in screen coordinates.
             mPopupWindow.showAtLocation(
                     mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x, mCoordsOnWindow.y);
@@ -661,7 +660,7 @@
             refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
             preparePopupContent();
             // We need to specify the position in window coordinates.
-            // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
+            // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can
             // specify the popup position in screen coordinates.
             mPopupWindow.update(
                     mCoordsOnWindow.x, mCoordsOnWindow.y,
@@ -755,7 +754,7 @@
             // and screen coordiantes, where the offset between them should be equal to the window
             // origin, and 2) we can use an arbitrary for this calculation while calculating the
             // location of the rootview is supposed to be least expensive.
-            // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can avoid
+            // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can avoid
             // the following calculation.
             mParent.getRootView().getLocationOnScreen(mTmpCoords);
             int rootViewLeftOnScreen = mTmpCoords[0];
@@ -1722,7 +1721,7 @@
     private static PopupWindow createPopupWindow(ViewGroup content) {
         ViewGroup popupContentHolder = new LinearLayout(content.getContext());
         PopupWindow popupWindow = new PopupWindow(popupContentHolder);
-        // TODO: Use .setLayoutInScreenEnabled(true) instead of .setClippingEnabled(false)
+        // TODO: Use .setIsLaidOutInScreen(true) instead of .setClippingEnabled(false)
         // unless FLAG_LAYOUT_IN_SCREEN has any unintentional side-effects.
         popupWindow.setClippingEnabled(false);
         popupWindow.setWindowLayoutType(
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index ee8637d8..9722fcb 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -502,6 +502,7 @@
                         new LogMaker(MetricsEvent.ACTION_SHARESHEET_COLLAPSED_CHANGED)
                         .setSubtype(isCollapsedNew ? 1 : 0));
             }
+            onScrollChanged(0, (int) newPos, 0, (int) (newPos - dy));
             postInvalidateOnAnimation();
             return dy;
         }
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 85f1159..cd7346e 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -923,14 +923,24 @@
         paint->setWordSpacing(wordSpacing);
     }
 
-    static jint getHyphenEdit(jlong paintHandle, jint hyphen) {
+    static jint getStartHyphenEdit(jlong paintHandle, jint hyphen) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        return paint->getHyphenEdit();
+        return static_cast<jint>(paint->getStartHyphenEdit());
     }
 
-    static void setHyphenEdit(jlong paintHandle, jint hyphen) {
+    static jint getEndHyphenEdit(jlong paintHandle, jint hyphen) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        paint->setHyphenEdit((uint32_t)hyphen);
+        return static_cast<jint>(paint->getEndHyphenEdit());
+    }
+
+    static void setStartHyphenEdit(jlong paintHandle, jint hyphen) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        paint->setStartHyphenEdit((uint32_t)hyphen);
+    }
+
+    static void setEndHyphenEdit(jlong paintHandle, jint hyphen) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        paint->setEndHyphenEdit((uint32_t)hyphen);
     }
 
     static jfloat ascent(jlong paintHandle) {
@@ -1105,8 +1115,10 @@
     {"nSetLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing},
     {"nGetWordSpacing","(J)F", (void*) PaintGlue::getWordSpacing},
     {"nSetWordSpacing","(JF)V", (void*) PaintGlue::setWordSpacing},
-    {"nGetHyphenEdit", "(J)I", (void*) PaintGlue::getHyphenEdit},
-    {"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit},
+    {"nGetStartHyphenEdit", "(J)I", (void*) PaintGlue::getStartHyphenEdit},
+    {"nGetEndHyphenEdit", "(J)I", (void*) PaintGlue::getEndHyphenEdit},
+    {"nSetStartHyphenEdit", "(JI)V", (void*) PaintGlue::setStartHyphenEdit},
+    {"nSetEndHyphenEdit", "(JI)V", (void*) PaintGlue::setEndHyphenEdit},
     {"nAscent","(J)F", (void*) PaintGlue::ascent},
     {"nDescent","(J)F", (void*) PaintGlue::descent},
     {"nGetUnderlinePosition","(J)F", (void*) PaintGlue::getUnderlinePosition},
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 89d908b..4a6c72b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1164,6 +1164,25 @@
     }
 }
 
+static jboolean nativeGetDisplayBrightnessSupport(JNIEnv* env, jclass clazz,
+        jobject displayTokenObject) {
+    sp<IBinder> displayToken(ibinderForJavaObject(env, displayTokenObject));
+    if (displayToken == nullptr) {
+        return JNI_FALSE;
+    }
+    return static_cast<jboolean>(SurfaceComposerClient::getDisplayBrightnessSupport(displayToken));
+}
+
+static jboolean nativeSetDisplayBrightness(JNIEnv* env, jclass clazz, jobject displayTokenObject,
+        jfloat brightness) {
+    sp<IBinder> displayToken(ibinderForJavaObject(env, displayTokenObject));
+    if (displayToken == nullptr) {
+        return JNI_FALSE;
+    }
+    status_t error = SurfaceComposerClient::setDisplayBrightness(displayToken, brightness);
+    return error == OK ? JNI_TRUE : JNI_FALSE;
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod sSurfaceControlMethods[] = {
@@ -1308,7 +1327,11 @@
     {"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
             (void*)nativeSetGeometry },
     {"nativeSyncInputWindows", "(J)V",
-            (void*)nativeSyncInputWindows }
+            (void*)nativeSyncInputWindows },
+    {"nativeGetDisplayBrightnessSupport", "(Landroid/os/IBinder;)Z",
+            (void*)nativeGetDisplayBrightnessSupport },
+    {"nativeSetDisplayBrightness", "(Landroid/os/IBinder;F)Z",
+            (void*)nativeSetDisplayBrightness },
 };
 
 int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
index 21717d8..a82326f 100644
--- a/core/proto/android/server/connectivity/data_stall_event.proto
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -25,6 +25,7 @@
     VALID = 1;
     INVALID = 2;
     PORTAL = 3;
+    PARTIAL = 4;
 }
 
 enum ApBand {
@@ -86,4 +87,4 @@
     repeated int32 dns_return_code = 1;
     // Indicate the timestamp of the dns event.
     repeated int64 dns_time = 2;
-}
\ No newline at end of file
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 67bff6b..ea300aa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2524,7 +2524,7 @@
     <permission android:name="android.permission.WRITE_GSERVICES"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi @hide Allows an application to modify config settings.
+    <!-- @SystemApi @TestApi @hide Allows an application to modify config settings.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WRITE_DEVICE_CONFIG"
         android:protectionLevel="signature|configurator"/>
@@ -3917,7 +3917,7 @@
     <permission android:name="android.permission.PACKAGE_ROLLBACK_AGENT"
         android:protectionLevel="signature" />
 
-    <!-- @SystemApi @hide Allows managing apk level rollbacks. -->
+    <!-- @SystemApi @TestApi @hide Allows managing apk level rollbacks. -->
     <permission android:name="android.permission.MANAGE_ROLLBACKS"
         android:protectionLevel="signature|verifier" />
 
diff --git a/core/res/res/layout/chooser_row_direct_share.xml b/core/res/res/layout/chooser_row_direct_share.xml
new file mode 100644
index 0000000..d7e36ee
--- /dev/null
+++ b/core/res/res/layout/chooser_row_direct_share.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="200dp">
+
+</LinearLayout>
+
+
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bfb6d24..dce144a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3513,6 +3513,12 @@
     -->
     <string name="config_defaultAttentionService" translatable="false"></string>
 
+    <!-- The component name for the system-wide captions service.
+         This service must be trusted, as it controls part of the UI of the volume bar.
+         Example: "com.android.captions/.SystemCaptionsService"
+    -->
+    <string name="config_defaultSystemCaptionsService" translatable="false"></string>
+
     <!-- The package name for the incident report approver app.
         This app is usually PermissionController or an app that replaces it.  When
         a bugreport or incident report with EXPLICT-level sharing flags is going to be
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a69655a..bf7c8f2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -525,8 +525,8 @@
     <!-- label for screenshot item in power menu -->
     <string name="global_action_screenshot">Screenshot</string>
 
-    <!-- Take bug report menu title [CHAR LIMIT=NONE] -->
-    <string name="bugreport_title">Take bug report</string>
+    <!-- Take bug report menu title [CHAR LIMIT=20] -->
+    <string name="bugreport_title">Bug report</string>
     <!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
     <!-- TODO: remove if not used anymore -->
     <string name="bugreport_message">This will collect information about your
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 69def5b..503bbce 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2770,6 +2770,7 @@
   <java-symbol type="drawable" name="scroll_indicator_material" />
 
   <java-symbol type="layout" name="chooser_row" />
+  <java-symbol type="layout" name="chooser_row_direct_share" />
   <java-symbol type="id" name="target_badge" />
   <java-symbol type="bool" name="config_supportDoubleTapWake" />
   <java-symbol type="drawable" name="ic_perm_device_info" />
@@ -3382,6 +3383,7 @@
   <java-symbol type="string" name="config_defaultAppPredictionService" />
   <java-symbol type="string" name="config_defaultContentSuggestionsService" />
   <java-symbol type="string" name="config_defaultAttentionService" />
+  <java-symbol type="string" name="config_defaultSystemCaptionsService" />
 
   <java-symbol type="string" name="notification_channel_foreground_service" />
   <java-symbol type="string" name="foreground_service_app_in_background" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 43f8db1..7322a54 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -655,6 +655,7 @@
                  Settings.Secure.NIGHT_DISPLAY_ACTIVATED,
                  Settings.Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
                  Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
+                 Settings.Secure.ODI_CAPTIONS_ENABLED,
                  Settings.Secure.PACKAGE_VERIFIER_STATE,
                  Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT,
                  Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index b1c896e..0ebf03f 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Paint.FontMetricsInt;
 import android.os.LocaleList;
 import android.platform.test.annotations.Presubmit;
@@ -799,11 +800,13 @@
     @Test
     public void testLayoutDoesntModifyPaint() {
         final TextPaint paint = new TextPaint();
-        paint.setHyphenEdit(31);
+        paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN);
+        paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN);
         final StaticLayout layout = StaticLayout.Builder.obtain("", 0, 0, paint, 100).build();
         final Canvas canvas = new Canvas();
         layout.drawText(canvas, 0, 0);
-        assertEquals(31, paint.getHyphenEdit());
+        assertEquals(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN, paint.getStartHyphenEdit());
+        assertEquals(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN, paint.getEndHyphenEdit());
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 585360f..0617caf 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -209,7 +209,8 @@
         int lineCount = layout.getLineCount();
         boolean hyphenationHappend = false;
         for (int i = 0; i < lineCount; ++i) {
-            if (layout.getHyphen(i) == 0) {
+            if (layout.getStartHyphenEdit(i) == Paint.START_HYPHEN_EDIT_NO_EDIT
+                    && layout.getEndHyphenEdit(i) == Paint.END_HYPHEN_EDIT_NO_EDIT) {
                 continue;  // Hyphantion does not happen.
             }
             hyphenationHappend = true;
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 9eeb43b..452f7c9 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -364,19 +364,79 @@
      */
     private static final int CURSOR_OPT_MAX_VALUE = CURSOR_AT;
 
-    /**
-     * Mask for hyphen edits that happen at the end of a line. Keep in sync with the definition in
-     * Minikin's Hyphenator.h.
-     * @hide
-     */
-    public static final int HYPHENEDIT_MASK_END_OF_LINE = 0x07;
+    /** @hide */
+    @IntDef(prefix = { "START_HYPHEN_EDIT_" }, value = {
+        START_HYPHEN_EDIT_NO_EDIT,
+        START_HYPHEN_EDIT_INSERT_HYPHEN,
+        START_HYPHEN_EDIT_INSERT_ZWJ
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StartHyphenEdit {}
 
     /**
-     * Mask for hyphen edits that happen at the start of a line. Keep in sync with the definition in
-     * Minikin's Hyphenator.h.
-     * @hide
+     * An integer representing the starting of the line has no modification for hyphenation.
      */
-    public static final int HYPHENEDIT_MASK_START_OF_LINE = 0x03 << 3;
+    public static final int START_HYPHEN_EDIT_NO_EDIT = 0x00;
+
+    /**
+     * An integer representing the starting of the line has normal hyphen character (U+002D).
+     */
+    public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 0x01;
+
+    /**
+     * An integer representing the starting of the line has Zero-Width-Joiner (U+200D).
+     */
+    public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 0x02;
+
+    /** @hide */
+    @IntDef(prefix = { "END_HYPHEN_EDIT_" }, value = {
+        END_HYPHEN_EDIT_NO_EDIT,
+        END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN,
+        END_HYPHEN_EDIT_INSERT_HYPHEN,
+        END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN,
+        END_HYPHEN_EDIT_INSERT_MAQAF,
+        END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN,
+        END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EndHyphenEdit {}
+
+    /**
+     * An integer representing the end of the line has no modification for hyphenation.
+     */
+    public static final int END_HYPHEN_EDIT_NO_EDIT = 0x00;
+
+    /**
+     * An integer representing the character at the end of the line is replaced with hyphen
+     * character (U+002D).
+     */
+    public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 0x01;
+
+    /**
+     * An integer representing the end of the line has normal hyphen character (U+002D).
+     */
+    public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 0x02;
+
+    /**
+     * An integer representing the end of the line has Armentian hyphen (U+058A).
+     */
+    public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 0x03;
+
+    /**
+     * An integer representing the end of the line has maqaf (Hebrew hyphen, U+05BE).
+     */
+    public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 0x04;
+
+    /**
+     * An integer representing the end of the line has Canadian Syllabics hyphen (U+1400).
+     */
+    public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 0x05;
+
+    /**
+     * An integer representing the end of the line has Zero-Width-Joiner (U+200D) followed by normal
+     * hyphen character (U+002D).
+     */
+    public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 0x06;
 
     /**
      * The Style specifies if the primitive being drawn is filled, stroked, or
@@ -1873,54 +1933,80 @@
     }
 
     /**
-     * Get the current value of packed hyphen edit.
+     * Get the current value of start hyphen edit.
      *
-     * You can extract start hyphen edit and end hyphen edit by using
-     * {@link android.text.Hyphenator#unpackStartHyphenEdit(int)} and
-     * {@link android.text.Hyphenator#unpackEndHyphenEdit(int)}.
+     * The default value is 0 which is equivalent to {@link #START_HYPHEN_EDIT_NO_EDIT}.
      *
-     * The default value is 0 which is equivalent to packed value of
-     * {@link android.text.Hyphenator#START_HYPHEN_EDIT_NO_EDIT} and
-     * {@link android.text.Hyphenator#END_HYPHEN_EDIT_NO_EDIT}.
-     *
-     * @return the current hyphen edit value
-     * @see #setHyphenEdit(int)
+     * @return the current starting hyphen edit value
+     * @see #setStartHyphenEdit(int)
      */
-    public int getHyphenEdit() {
-        return nGetHyphenEdit(mNativePaint);
+    public @StartHyphenEdit int getStartHyphenEdit() {
+        return nGetStartHyphenEdit(mNativePaint);
     }
 
     /**
-     * Set a packed hyphen edit on the paint.
+     * Get the current value of end hyphen edit.
      *
-     * By setting hyphen edit, the measurement and drawing is performed with modifying hyphenation
-     * at the start of line and end of line. For example, by passing
-     * {@link android.text.Hyphenator#END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010)
+     * The default value is 0 which is equivalent to {@link #END_HYPHEN_EDIT_NO_EDIT}.
+     *
+     * @return the current starting hyphen edit value
+     * @see #setStartHyphenEdit(int)
+     */
+    public @EndHyphenEdit int getEndHyphenEdit() {
+        return nGetEndHyphenEdit(mNativePaint);
+    }
+
+    /**
+     * Set a start hyphen edit on the paint.
+     *
+     * By setting start hyphen edit, the measurement and drawing is performed with modifying
+     * hyphenation at the start of line. For example, by passing
+     * {@link #START_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010)
+     * character is appended at the start of line.
+     *
+     * <pre>
+     * <code>
+     *   Paint paint = new Paint();
+     *   paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN);
+     *   paint.measureText("abc", 0, 3);  // Returns the width of "‐abc"
+     *   Canvas.drawText("abc", 0, 3, 0f, 0f, paint);  // Draws "‐abc"
+     * </code>
+     * </pre>
+     *
+     * The default value is 0 which is equivalent to
+     * {@link #START_HYPHEN_EDIT_NO_EDIT}.
+     *
+     * @param startHyphen a start hyphen edit value.
+     * @see #getStartHyphenEdit()
+     */
+    public void setStartHyphenEdit(@StartHyphenEdit int startHyphen) {
+        nSetStartHyphenEdit(mNativePaint, startHyphen);
+    }
+
+    /**
+     * Set a end hyphen edit on the paint.
+     *
+     * By setting end hyphen edit, the measurement and drawing is performed with modifying
+     * hyphenation at the end of line. For example, by passing
+     * {@link #END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010)
      * character is appended at the end of line.
      *
      * <pre>
      * <code>
      *   Paint paint = new Paint();
-     *   paint.setHyphenEdit(Hyphenator.packHyphenEdit(
-     *       Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
-     *       Hyphenator.END_HYPHEN_EDIT_INSERT_HYPHEN));
+     *   paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN);
      *   paint.measureText("abc", 0, 3);  // Returns the width of "abc‐"
      *   Canvas.drawText("abc", 0, 3, 0f, 0f, paint);  // Draws "abc‐"
      * </code>
      * </pre>
      *
-     * You can pack start hyphen edit and end hyphen edit by
-     * {@link android.text.Hyphenator#packHyphenEdit(int,int)}
+     * The default value is 0 which is equivalent to {@link #END_HYPHEN_EDIT_NO_EDIT}.
      *
-     * The default value is 0 which is equivalent to packed value of
-     * {@link android.text.Hyphenator#START_HYPHEN_EDIT_NO_EDIT} and
-     * {@link android.text.Hyphenator#END_HYPHEN_EDIT_NO_EDIT}.
-     *
-     * @param hyphen a packed hyphen edit value.
-     * @see #getHyphenEdit()
+     * @param endHyphen a end hyphen edit value.
+     * @see #getEndHyphenEdit()
      */
-    public void setHyphenEdit(int hyphen) {
-        nSetHyphenEdit(mNativePaint, hyphen);
+    public void setEndHyphenEdit(@EndHyphenEdit int endHyphen) {
+        nSetEndHyphenEdit(mNativePaint, endHyphen);
     }
 
     /**
@@ -3063,9 +3149,13 @@
     @CriticalNative
     private static native void nSetWordSpacing(long paintPtr, float wordSpacing);
     @CriticalNative
-    private static native int nGetHyphenEdit(long paintPtr);
+    private static native int nGetStartHyphenEdit(long paintPtr);
     @CriticalNative
-    private static native void nSetHyphenEdit(long paintPtr, int hyphen);
+    private static native int nGetEndHyphenEdit(long paintPtr);
+    @CriticalNative
+    private static native void nSetStartHyphenEdit(long paintPtr, int hyphen);
+    @CriticalNative
+    private static native void nSetEndHyphenEdit(long paintPtr, int hyphen);
     @CriticalNative
     private static native void nSetStrokeMiter(long paintPtr, float miter);
     @CriticalNative
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 9518714..86f658b 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -33,12 +33,12 @@
 import android.graphics.fonts.FontVariationAxis;
 import android.graphics.fonts.SystemFonts;
 import android.os.Build;
-import android.os.Build.VERSION_CODES;
 import android.os.ParcelFileDescriptor;
 import android.provider.FontRequest;
 import android.provider.FontsContract;
 import android.text.FontConfig;
 import android.util.Base64;
+import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.LruCache;
 import android.util.SparseArray;
@@ -48,7 +48,6 @@
 import com.android.internal.util.Preconditions;
 
 import dalvik.annotation.optimization.CriticalNative;
-import dalvik.system.VMRuntime;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -262,18 +261,29 @@
                             ?  FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);
                 }
 
+                Font font = null;
+                try {
+                    font = fontBuilder.build();
+                } catch (IllegalArgumentException e) {
+                    // The exception happens if the unsupported font is passed. We suppress this
+                    // exception and just ignore this font here since there is no way of
+                    // resolving this issue by users during inflating layout.
+                    Log.w(TAG, "Ignoring font file since failed to create font object."
+                            + " The font file is not supported on this platform.");
+                    continue;
+                }
                 if (familyBuilder == null) {
-                    familyBuilder = new FontFamily.Builder(fontBuilder.build());
+                    familyBuilder = new FontFamily.Builder(font);
                 } else {
                     try {
-                        familyBuilder.addFont(fontBuilder.build());
+                        familyBuilder.addFont(font);
                     } catch (IllegalArgumentException e) {
-                        if (VMRuntime.getRuntime().getTargetSdkVersion() <= VERSION_CODES.P) {
-                            // Surpress the IllegalArgumentException for keeping the backward
-                            // compatibility.
-                            continue;
-                        }
-                        throw e;
+                        // The exception happens if the same style is added to the family.
+                        // We suppress this exception and just ignore this font here since there is
+                        // no way of resolving this issue by users during inflating layout.
+                        Log.w(TAG,
+                                "Ignoring font file since the same style font is already added.");
+                        continue;
                     }
                 }
             }
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index f715f43..f92802f 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -354,6 +354,10 @@
 
         /**
          * Creates the font based on the configured values.
+         *
+         * If the font is not supported by the platform, this function will fail with
+         * {@link IllegalArgumentException}.
+         *
          * @return the Font object
          */
         public @Nullable Font build() throws IOException {
diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java
index 046bbcf..9cabf1c 100644
--- a/graphics/java/android/graphics/text/LineBreaker.java
+++ b/graphics/java/android/graphics/text/LineBreaker.java
@@ -342,8 +342,12 @@
      */
     public static class Result {
         // Following two contstant must be synced with minikin's line breaker.
+        // TODO(nona): Remove these constatns by introducing native methods.
         private static final int TAB_MASK = 0x20000000;
         private static final int HYPHEN_MASK = 0xFF;
+        private static final int START_HYPHEN_MASK = 0x18;  // 0b11000
+        private static final int END_HYPHEN_MASK = 0x7;  // 0b00111
+        private static final int START_HYPHEN_BITS_SHIFT = 3;
 
         private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
                 Result.class.getClassLoader(), nGetReleaseResultFunc(), 32);
@@ -414,17 +418,29 @@
         }
 
         /**
-         * Returns a packed hyphen edit for the line.
+         * Returns a start hyphen edit for the line.
          *
          * @param lineIndex an index of the line.
-         * @return a packed hyphen edit for the line.
+         * @return a start hyphen edit for the line.
          *
-         * @see android.text.Hyphenator#unpackStartHyphenEdit(int)
-         * @see android.text.Hyphenator#unpackEndHyphenEdit(int)
-         * @see android.text.Hyphenator#packHyphenEdit(int,int)
+         * @see android.graphics.Paint#setStartHyphenEdit
+         * @see android.graphics.Paint#getStartHyphenEdit
          */
-        public int getLineHyphenEdit(int lineIndex) {
-            return (nGetLineFlag(mPtr, lineIndex) & HYPHEN_MASK);
+        public int getStartLineHyphenEdit(int lineIndex) {
+            return (nGetLineFlag(mPtr, lineIndex) & START_HYPHEN_MASK) >> START_HYPHEN_BITS_SHIFT;
+        }
+
+        /**
+         * Returns an end hyphen edit for the line.
+         *
+         * @param lineIndex an index of the line.
+         * @return an end hyphen edit for the line.
+         *
+         * @see android.graphics.Paint#setEndHyphenEdit
+         * @see android.graphics.Paint#getEndHyphenEdit
+         */
+        public int getEndLineHyphenEdit(int lineIndex) {
+            return nGetLineFlag(mPtr, lineIndex) & END_HYPHEN_MASK;
         }
     }
 
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index 733f8e4..5f6b53a 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -58,9 +58,8 @@
     const minikin::U16StringPiece textBuf(buf, bufSize);
     const minikin::Range range(start, start + count);
     const minikin::Range contextRange(contextStart, contextStart + contextCount);
-    const minikin::HyphenEdit hyphenEdit = static_cast<minikin::HyphenEdit>(paint->getHyphenEdit());
-    const minikin::StartHyphenEdit startHyphen = minikin::startHyphenEdit(hyphenEdit);
-    const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit);
+    const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit();
+    const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit();
 
     if (mt == nullptr) {
         return minikin::Layout(textBuf.substr(contextRange), range - contextStart, bidiFlags,
@@ -76,9 +75,8 @@
     minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
     const minikin::U16StringPiece textBuf(buf, bufSize);
     const minikin::Range range(start, start + count);
-    const minikin::HyphenEdit hyphenEdit = static_cast<minikin::HyphenEdit>(paint->getHyphenEdit());
-    const minikin::StartHyphenEdit startHyphen = minikin::startHyphenEdit(hyphenEdit);
-    const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit);
+    const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit();
+    const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit();
 
     return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen,
                                         endHyphen, advances);
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 601b3c2..9b2fa9d 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -27,6 +27,7 @@
 
 #include <minikin/FontFamily.h>
 #include <minikin/FamilyVariant.h>
+#include <minikin/Hyphenator.h>
 
 namespace android {
 
@@ -89,9 +90,25 @@
 
     minikin::FamilyVariant getFamilyVariant() const { return mFamilyVariant; }
 
-    void setHyphenEdit(uint32_t hyphen) { mHyphenEdit = hyphen; }
+    void setStartHyphenEdit(uint32_t startHyphen) {
+        mHyphenEdit = minikin::packHyphenEdit(
+            static_cast<minikin::StartHyphenEdit>(startHyphen),
+            minikin::endHyphenEdit(mHyphenEdit));
+    }
 
-    uint32_t getHyphenEdit() const { return mHyphenEdit; }
+    void setEndHyphenEdit(uint32_t endHyphen) {
+        mHyphenEdit = minikin::packHyphenEdit(
+            minikin::startHyphenEdit(mHyphenEdit),
+            static_cast<minikin::EndHyphenEdit>(endHyphen));
+    }
+
+    minikin::StartHyphenEdit getStartHyphenEdit() const {
+        return minikin::startHyphenEdit(mHyphenEdit);
+    }
+
+    minikin::EndHyphenEdit getEndHyphenEdit() const {
+        return minikin::endHyphenEdit(mHyphenEdit);
+    }
 
     void setAndroidTypeface(Typeface* typeface) { mTypeface = typeface; }
 
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index ed74333..673b411 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -150,7 +150,7 @@
     private Bundle mExtras = null;
 
     // A bitmask of fields present in this object (see HAS_* constants defined above).
-    private byte mFieldsMask = 0;
+    private int mFieldsMask = 0;
 
     /**
      * Construct a new Location with a named provider.
@@ -1137,7 +1137,7 @@
             l.mTime = in.readLong();
             l.mElapsedRealtimeNanos = in.readLong();
             l.mElapsedRealtimeUncertaintyNanos = in.readLong();
-            l.mFieldsMask = in.readByte();
+            l.mFieldsMask = in.readInt();
             l.mLatitude = in.readDouble();
             l.mLongitude = in.readDouble();
             l.mAltitude = in.readDouble();
@@ -1168,7 +1168,7 @@
         parcel.writeLong(mTime);
         parcel.writeLong(mElapsedRealtimeNanos);
         parcel.writeLong(mElapsedRealtimeUncertaintyNanos);
-        parcel.writeByte(mFieldsMask);
+        parcel.writeInt(mFieldsMask);
         parcel.writeDouble(mLatitude);
         parcel.writeDouble(mLongitude);
         parcel.writeDouble(mAltitude);
diff --git a/media/apex/java/android/media/MediaSession2.java b/media/apex/java/android/media/MediaSession2.java
index 09ac9ca..d63de09 100644
--- a/media/apex/java/android/media/MediaSession2.java
+++ b/media/apex/java/android/media/MediaSession2.java
@@ -511,7 +511,8 @@
         }
 
         /**
-         * Set extras for the session token.
+         * Set extras for the session token. If null or not set, {@link Session2Token#getExtras()}
+         * will return {@link Bundle#EMPTY}.
          *
          * @return The Builder to allow chaining
          * @see Session2Token#getExtras()
diff --git a/media/apex/java/android/media/Session2Token.java b/media/apex/java/android/media/Session2Token.java
index dc970ae..d7cb978 100644
--- a/media/apex/java/android/media/Session2Token.java
+++ b/media/apex/java/android/media/Session2Token.java
@@ -216,10 +216,11 @@
 
     /**
      * @return extras of the token
+     * @see MediaSession2.Builder#setExtras(Bundle)
      */
-    @Nullable
+    @NonNull
     public Bundle getExtras() {
-        return mExtras;
+        return mExtras == null ? Bundle.EMPTY : mExtras;
     }
 
     Session2Link getSessionLink() {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7783a4d..c11f446 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3308,6 +3308,7 @@
 
     /**
      * @hide
+     * Unregisters an {@link AudioPolicy} asynchronously.
      * @param policy the non-null {@link AudioPolicy} to unregister.
      */
     @SystemApi
@@ -3329,6 +3330,27 @@
         }
     }
 
+    /**
+     * @hide
+     * Unregisters an {@link AudioPolicy} synchronously.
+     * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
+     * associated with mixes of this policy.
+     * @param policy the non-null {@link AudioPolicy} to unregister.
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
+        Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
+        final IAudioService service = getService();
+        try {
+            policy.invalidateCaptorsAndInjectors();
+            service.unregisterAudioPolicy(policy.cb());
+            policy.setRegistration(null);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     //====================================================================
     // Notification of playback activity & playback configuration
     /**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 0285667..95d89bb 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -199,6 +199,8 @@
 
     oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb);
 
+    void unregisterAudioPolicy(in IAudioPolicyCallback pcb);
+
     int addMixForPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb);
 
     int removeMixForPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 9258b85..f5abb24 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -24,6 +25,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
@@ -36,8 +38,13 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+import java.util.function.Function;
 
 
 /**
@@ -131,21 +138,6 @@
 
     private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
 
-    private EventHandler mEventHandler;
-    private EventHandler mKeyStatusChangeHandler;
-    private EventHandler mExpirationUpdateHandler;
-    private EventHandler mSessionLostStateHandler;
-
-    private OnEventListener mOnEventListener;
-    private OnKeyStatusChangeListener mOnKeyStatusChangeListener;
-    private OnExpirationUpdateListener mOnExpirationUpdateListener;
-    private OnSessionLostStateListener mOnSessionLostStateListener;
-
-    private final Object mEventLock = new Object();
-    private final Object mKeyStatusChangeLock = new Object();
-    private final Object mExpirationUpdateLock = new Object();
-    private final Object mSessionLostStateLock = new Object();
-
     private long mNativeContext;
 
     /**
@@ -227,35 +219,19 @@
     private static final native boolean isCryptoSchemeSupportedNative(
             @NonNull byte[] uuid, @Nullable String mimeType, @SecurityLevel int securityLevel);
 
-    private EventHandler createHandler() {
+    private Handler createHandler() {
         Looper looper;
-        EventHandler handler;
+        Handler handler;
         if ((looper = Looper.myLooper()) != null) {
-            handler = new EventHandler(this, looper);
+            handler = new Handler(looper);
         } else if ((looper = Looper.getMainLooper()) != null) {
-            handler = new EventHandler(this, looper);
+            handler = new Handler(looper);
         } else {
             handler = null;
         }
         return handler;
     }
 
-    private EventHandler updateHandler(Handler handler) {
-        Looper looper;
-        EventHandler newHandler = null;
-        if (handler != null) {
-            looper = handler.getLooper();
-        } else {
-            looper = Looper.myLooper();
-        }
-        if (looper != null) {
-            if (handler == null || handler.getLooper() != looper) {
-                newHandler = new EventHandler(this, looper);
-            }
-        }
-        return newHandler;
-    }
-
     /**
      * Instantiate a MediaDrm object
      *
@@ -265,11 +241,6 @@
      * specified scheme UUID
      */
     public MediaDrm(@NonNull UUID uuid) throws UnsupportedSchemeException {
-        mEventHandler = createHandler();
-        mKeyStatusChangeHandler = createHandler();
-        mExpirationUpdateHandler = createHandler();
-        mSessionLostStateHandler = createHandler();
-
         /* Native setup requires a weak reference to our object.
          * It's easier to create it here than in C++.
          */
@@ -368,12 +339,30 @@
      */
     public void setOnExpirationUpdateListener(
             @Nullable OnExpirationUpdateListener listener, @Nullable Handler handler) {
-        synchronized(mExpirationUpdateLock) {
-            if (listener != null) {
-                mExpirationUpdateHandler = updateHandler(handler);
-            }
-            mOnExpirationUpdateListener = listener;
-        }
+        setListenerWithHandler(EXPIRATION_UPDATE, handler, listener,
+                this::createOnExpirationUpdateListener);
+    }
+    /**
+     * Register a callback to be invoked when a session expiration update
+     * occurs.
+     *
+     * @see #setOnExpirationUpdateListener(OnExpirationUpdateListener, Handler)
+     *
+     * @param executor the executor through which the listener should be invoked
+     * @param listener the callback that will be run.
+     */
+    public void setOnExpirationUpdateListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnExpirationUpdateListener listener) {
+        setListenerWithExecutor(EXPIRATION_UPDATE, executor, listener,
+                this::createOnExpirationUpdateListener);
+    }
+
+    /**
+     * Clear the {@link OnExpirationUpdateListener}.
+     */
+    public void clearOnExpirationUpdateListener() {
+        clearGenericListener(EXPIRATION_UPDATE);
     }
 
     /**
@@ -407,12 +396,31 @@
      */
     public void setOnKeyStatusChangeListener(
             @Nullable OnKeyStatusChangeListener listener, @Nullable Handler handler) {
-        synchronized(mKeyStatusChangeLock) {
-            if (listener != null) {
-                mKeyStatusChangeHandler = updateHandler(handler);
-            }
-            mOnKeyStatusChangeListener = listener;
-        }
+        setListenerWithHandler(KEY_STATUS_CHANGE, handler, listener,
+                this::createOnKeyStatusChangeListener);
+    }
+
+    /**
+     * Register a callback to be invoked when the state of keys in a session
+     * change.
+     *
+     * @see #setOnKeyStatusChangeListener(OnKeyStatusChangeListener, Handler)
+     *
+     * @param listener the callback that will be run when key status changes.
+     * @param executor the executor on which the listener should be invoked.
+     */
+    public void setOnKeyStatusChangeListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnKeyStatusChangeListener listener) {
+        setListenerWithExecutor(KEY_STATUS_CHANGE, executor, listener,
+                this::createOnKeyStatusChangeListener);
+    }
+
+    /**
+     * Clear the {@link OnKeyStatusChangeListener}.
+     */
+    public void clearOnKeyStatusChangeListener() {
+        clearGenericListener(KEY_STATUS_CHANGE);
     }
 
     /**
@@ -453,12 +461,31 @@
      */
     public void setOnSessionLostStateListener(
             @Nullable OnSessionLostStateListener listener, @Nullable Handler handler) {
-        synchronized(mSessionLostStateLock) {
-            if (listener != null) {
-                mSessionLostStateHandler = updateHandler(handler);
-            }
-            mOnSessionLostStateListener = listener;
-        }
+        setListenerWithHandler(SESSION_LOST_STATE, handler, listener,
+                this::createOnSessionLostStateListener);
+    }
+
+    /**
+     * Register a callback to be invoked when session state has been
+     * lost.
+     *
+     * @see #setOnSessionLostStateListener(OnSessionLostStateListener, Handler)
+     *
+     * @param listener the callback that will be run.
+     * @param executor the executor on which the listener should be invoked.
+     */
+    public void setOnSessionLostStateListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @Nullable OnSessionLostStateListener listener) {
+        setListenerWithExecutor(SESSION_LOST_STATE, executor, listener,
+                this::createOnSessionLostStateListener);
+    }
+
+    /**
+     * Clear the {@link OnSessionLostStateListener}.
+     */
+    public void clearOnSessionLostStateListener() {
+        clearGenericListener(SESSION_LOST_STATE);
     }
 
     /**
@@ -552,14 +579,48 @@
     /**
      * Register a callback to be invoked when an event occurs
      *
+     * @see #setOnEventListener(OnEventListener, Handler)
+     *
      * @param listener the callback that will be run.  Use {@code null} to
      *        stop receiving event callbacks.
      */
     public void setOnEventListener(@Nullable OnEventListener listener)
     {
-        synchronized(mEventLock) {
-            mOnEventListener = listener;
-        }
+        setOnEventListener(listener, null);
+    }
+
+    /**
+     * Register a callback to be invoked when an event occurs
+     *
+     * @param listener the callback that will be run.  Use {@code null} to
+     *        stop receiving event callbacks.
+     * @param handler the handler on which the listener should be invoked, or
+     *        null if the listener should be invoked on the calling thread's looper.
+     */
+
+    public void setOnEventListener(@Nullable OnEventListener listener, @Nullable Handler handler)
+    {
+        setListenerWithHandler(DRM_EVENT, handler, listener, this::createOnEventListener);
+    }
+
+    /**
+     * Register a callback to be invoked when an event occurs
+     *
+     * @see #setOnEventListener(OnEventListener)
+     *
+     * @param executor the executor through which the listener should be invoked
+     * @param listener the callback that will be run.
+     */
+    public void setOnEventListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull OnEventListener listener) {
+        setListenerWithExecutor(DRM_EVENT, executor, listener, this::createOnEventListener);
+    }
+
+    /**
+     * Clear the {@link OnEventListener}.
+     */
+    public void clearOnEventListener() {
+        clearGenericListener(DRM_EVENT);
     }
 
     /**
@@ -637,99 +698,112 @@
     private static final int KEY_STATUS_CHANGE = 202;
     private static final int SESSION_LOST_STATE = 203;
 
-    private class EventHandler extends Handler
-    {
-        private MediaDrm mMediaDrm;
+    // Use ConcurrentMap to support concurrent read/write to listener settings.
+    // ListenerWithExecutor is immutable so we shouldn't need further locks.
+    private final Map<Integer, ListenerWithExecutor> mListenerMap = new ConcurrentHashMap<>();
 
-        public EventHandler(@NonNull MediaDrm md, @NonNull Looper looper) {
-            super(looper);
-            mMediaDrm = md;
+    // called by old-style set*Listener APIs using Handlers; listener & handler are Nullable
+    private <T> void setListenerWithHandler(int what, Handler handler, T listener,
+            Function<T, Consumer<ListenerArgs>> converter) {
+        if (listener == null) {
+            clearGenericListener(what);
+        } else {
+            handler = handler == null ? createHandler() : handler;
+            final HandlerExecutor executor = new HandlerExecutor(handler);
+            setGenericListener(what, executor, listener, converter);
         }
+    }
 
-        @Override
-        public void handleMessage(@NonNull Message msg) {
-            if (mMediaDrm.mNativeContext == 0) {
-                Log.w(TAG, "MediaDrm went away with unhandled events");
-                return;
+    // called by new-style set*Listener APIs using Executors; listener & executor must be NonNull
+    private <T> void setListenerWithExecutor(int what, Executor executor, T listener,
+            Function<T, Consumer<ListenerArgs>> converter) {
+        if (executor == null || listener == null) {
+            final String errMsg = String.format("executor %s listener %s", executor, listener);
+            throw new IllegalArgumentException(errMsg);
+        }
+        setGenericListener(what, executor, listener, converter);
+    }
+
+    private <T> void setGenericListener(int what, Executor executor, T listener,
+            Function<T, Consumer<ListenerArgs>> converter) {
+        mListenerMap.put(what, new ListenerWithExecutor(executor, converter.apply(listener)));
+    }
+
+    private void clearGenericListener(int what) {
+        mListenerMap.remove(what);
+    }
+
+    private Consumer<ListenerArgs> createOnEventListener(OnEventListener listener) {
+        return args -> {
+            byte[] sessionId = args.parcel.createByteArray();
+            if (sessionId.length == 0) {
+                sessionId = null;
             }
-            switch(msg.what) {
-
-            case DRM_EVENT:
-                synchronized(mEventLock) {
-                    if (mOnEventListener != null) {
-                        if (msg.obj != null && msg.obj instanceof Parcel) {
-                            Parcel parcel = (Parcel)msg.obj;
-                            byte[] sessionId = parcel.createByteArray();
-                            if (sessionId.length == 0) {
-                                sessionId = null;
-                            }
-                            byte[] data = parcel.createByteArray();
-                            if (data.length == 0) {
-                                data = null;
-                            }
-
-                            Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
-                            mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
-                        }
-                    }
-                }
-                return;
-
-            case KEY_STATUS_CHANGE:
-                synchronized(mKeyStatusChangeLock) {
-                    if (mOnKeyStatusChangeListener != null) {
-                        if (msg.obj != null && msg.obj instanceof Parcel) {
-                            Parcel parcel = (Parcel)msg.obj;
-                            byte[] sessionId = parcel.createByteArray();
-                            if (sessionId.length > 0) {
-                                List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel);
-                                boolean hasNewUsableKey = (parcel.readInt() != 0);
-
-                                Log.i(TAG, "Drm key status changed");
-                                mOnKeyStatusChangeListener.onKeyStatusChange(mMediaDrm, sessionId,
-                                        keyStatusList, hasNewUsableKey);
-                            }
-                        }
-                    }
-                }
-                return;
-
-            case EXPIRATION_UPDATE:
-                synchronized(mExpirationUpdateLock) {
-                    if (mOnExpirationUpdateListener != null) {
-                        if (msg.obj != null && msg.obj instanceof Parcel) {
-                            Parcel parcel = (Parcel)msg.obj;
-                            byte[] sessionId = parcel.createByteArray();
-                            if (sessionId.length > 0) {
-                                long expirationTime = parcel.readLong();
-
-                                Log.i(TAG, "Drm key expiration update: " + expirationTime);
-                                mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId,
-                                        expirationTime);
-                            }
-                        }
-                    }
-                }
-                return;
-
-            case SESSION_LOST_STATE:
-                synchronized(mSessionLostStateLock) {
-                    if (mOnSessionLostStateListener != null) {
-                        if (msg.obj != null && msg.obj instanceof Parcel) {
-                            Parcel parcel = (Parcel)msg.obj;
-                            byte[] sessionId = parcel.createByteArray();
-                            Log.i(TAG, "Drm session lost state event: ");
-                            mOnSessionLostStateListener.onSessionLostState(mMediaDrm,
-                                    sessionId);
-                        }
-                    }
-                }
-                return;
-
-            default:
-                Log.e(TAG, "Unknown message type " + msg.what);
-                return;
+            byte[] data = args.parcel.createByteArray();
+            if (data.length == 0) {
+                data = null;
             }
+
+            Log.i(TAG, "Drm event (" + args.arg1 + "," + args.arg2 + ")");
+            listener.onEvent(this, sessionId, args.arg1, args.arg2, data);
+        };
+    }
+
+    private Consumer<ListenerArgs> createOnKeyStatusChangeListener(
+            OnKeyStatusChangeListener listener) {
+        return args -> {
+            byte[] sessionId = args.parcel.createByteArray();
+            if (sessionId.length > 0) {
+                List<KeyStatus> keyStatusList = keyStatusListFromParcel(args.parcel);
+                boolean hasNewUsableKey = (args.parcel.readInt() != 0);
+
+                Log.i(TAG, "Drm key status changed");
+                listener.onKeyStatusChange(this, sessionId, keyStatusList, hasNewUsableKey);
+            }
+        };
+    }
+
+    private Consumer<ListenerArgs> createOnExpirationUpdateListener(
+            OnExpirationUpdateListener listener) {
+        return args -> {
+            byte[] sessionId = args.parcel.createByteArray();
+            if (sessionId.length > 0) {
+                long expirationTime = args.parcel.readLong();
+
+                Log.i(TAG, "Drm key expiration update: " + expirationTime);
+                listener.onExpirationUpdate(this, sessionId, expirationTime);
+            }
+        };
+    }
+
+    private Consumer<ListenerArgs> createOnSessionLostStateListener(
+            OnSessionLostStateListener listener) {
+        return args -> {
+            byte[] sessionId = args.parcel.createByteArray();
+            Log.i(TAG, "Drm session lost state event: ");
+            listener.onSessionLostState(this, sessionId);
+        };
+    }
+
+    private static class ListenerArgs {
+        private final Parcel parcel;
+        private final int arg1;
+        private final int arg2;
+
+        public ListenerArgs(Parcel parcel, int arg1, int arg2) {
+            this.parcel = parcel;
+            this.arg1 = arg1;
+            this.arg2 = arg2;
+        }
+    }
+
+    private static class ListenerWithExecutor {
+        private final Consumer<ListenerArgs> mConsumer;
+        private final Executor mExecutor;
+
+        public ListenerWithExecutor(Executor executor, Consumer<ListenerArgs> consumer) {
+            this.mExecutor = executor;
+            this.mConsumer = consumer;
         }
     }
 
@@ -764,35 +838,22 @@
         }
         switch (what) {
             case DRM_EVENT:
-                synchronized(md.mEventLock) {
-                    if (md.mEventHandler != null) {
-                        Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj);
-                        md.mEventHandler.sendMessage(m);
-                    }
-                }
-                break;
             case EXPIRATION_UPDATE:
-                synchronized(md.mExpirationUpdateLock) {
-                    if (md.mExpirationUpdateHandler != null) {
-                        Message m = md.mExpirationUpdateHandler.obtainMessage(what, obj);
-                        md.mExpirationUpdateHandler.sendMessage(m);
-                    }
-                }
-                break;
             case KEY_STATUS_CHANGE:
-                synchronized(md.mKeyStatusChangeLock) {
-                    if (md.mKeyStatusChangeHandler != null) {
-                        Message m = md.mKeyStatusChangeHandler.obtainMessage(what, obj);
-                        md.mKeyStatusChangeHandler.sendMessage(m);
-                    }
-                }
-                break;
             case SESSION_LOST_STATE:
-                synchronized(md.mSessionLostStateLock) {
-                    if (md.mSessionLostStateHandler != null) {
-                        Message m = md.mSessionLostStateHandler.obtainMessage(what, obj);
-                        md.mSessionLostStateHandler.sendMessage(m);
-                    }
+                ListenerWithExecutor listener  = md.mListenerMap.get(what);
+                if (listener != null) {
+                    final Runnable command = () -> {
+                        if (md.mNativeContext == 0) {
+                            Log.w(TAG, "MediaDrm went away with unhandled events");
+                            return;
+                        }
+                        if (obj != null && obj instanceof Parcel) {
+                            Parcel p = (Parcel)obj;
+                            listener.mConsumer.accept(new ListenerArgs(p, eventType, extra));
+                        }
+                    };
+                    listener.mExecutor.execute(command);
                 }
                 break;
             default:
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 5f65d58..978583e 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -43,8 +43,11 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -74,6 +77,19 @@
     private boolean mIsFocusPolicy;
 
     /**
+     * The list of AudioTrack instances created to inject audio into the associated mixes
+     * Lazy initialization in {@link #createAudioTrackSource(AudioMix)}
+     */
+    @GuardedBy("mLock")
+    @Nullable private ArrayList<WeakReference<AudioTrack>> mInjectors;
+    /**
+     * The list AudioRecord instances created to capture audio from the associated mixes
+     * Lazy initialization in {@link #createAudioRecordSink(AudioMix)}
+     */
+    @GuardedBy("mLock")
+    @Nullable private ArrayList<WeakReference<AudioRecord>> mCaptors;
+
+    /**
      * The behavior of a policy with regards to audio focus where it relies on the application
      * to do the ducking, the is the legacy and default behavior.
      */
@@ -606,6 +622,12 @@
                         AudioFormat.CHANNEL_IN_STEREO, mix.getFormat().getEncoding()),
                 AudioManager.AUDIO_SESSION_ID_GENERATE
                 );
+        synchronized (mLock) {
+            if (mCaptors == null) {
+                mCaptors = new ArrayList<>(1);
+            }
+            mCaptors.add(new WeakReference<AudioRecord>(ar));
+        }
         return ar;
     }
 
@@ -638,9 +660,47 @@
                 AudioTrack.MODE_STREAM,
                 AudioManager.AUDIO_SESSION_ID_GENERATE
                 );
+        synchronized (mLock) {
+            if (mInjectors == null) {
+                mInjectors = new ArrayList<>(1);
+            }
+            mInjectors.add(new WeakReference<AudioTrack>(at));
+        }
         return at;
     }
 
+    /**
+     * @hide
+     */
+    public void invalidateCaptorsAndInjectors() {
+        if (!policyReadyToUse()) {
+            return;
+        }
+        synchronized (mLock) {
+            if (mInjectors != null) {
+                for (final WeakReference<AudioTrack> weakTrack : mInjectors) {
+                    final AudioTrack track = weakTrack.get();
+                    if (track == null) {
+                        break;
+                    }
+                    // TODO: add synchronous versions
+                    track.stop();
+                    track.flush();
+                }
+            }
+            if (mCaptors != null) {
+                for (final WeakReference<AudioRecord> weakRecord : mCaptors) {
+                    final AudioRecord record = weakRecord.get();
+                    if (record == null) {
+                        break;
+                    }
+                    // TODO: if needed: implement an invalidate method
+                    record.stop();
+                }
+            }
+        }
+    }
+
     public int getStatus() {
         return mStatus;
     }
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index e85461f..cfcc294 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -55,8 +55,8 @@
     void addSession2TokensListener(in ISession2TokensListener listener, int userId);
     void removeSession2TokensListener(in ISession2TokensListener listener);
 
-    // This is for the system volume UI only
-    void setRemoteVolumeController(in IRemoteVolumeController rvc);
+    void registerRemoteVolumeController(in IRemoteVolumeController rvc);
+    void unregisterRemoteVolumeController(in IRemoteVolumeController rvc);
 
     // For PhoneWindowManager to precheck media keys
     boolean isGlobalPriorityActive();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 5ee52ce..7334044 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -954,7 +953,6 @@
         /**
          * @hide
          */
-        @SystemApi
         public PlaybackInfo(int type, int control, int max, int current, AudioAttributes attrs) {
             mVolumeType = type;
             mVolumeControl = control;
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index fde4f88..f530442 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -424,17 +424,33 @@
     }
 
     /**
-     * Set the remote volume controller to receive volume updates on. Only for
-     * use by system UI.
+     * Set the remote volume controller to receive volume updates on.
+     * Only for use by System UI and Settings application.
      *
      * @param rvc The volume controller to receive updates on.
      * @hide
      */
-    public void setRemoteVolumeController(IRemoteVolumeController rvc) {
+    public void registerRemoteVolumeController(IRemoteVolumeController rvc) {
         try {
-            mService.setRemoteVolumeController(rvc);
+            mService.registerRemoteVolumeController(rvc);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error in setRemoteVolumeController.", e);
+            Log.e(TAG, "Error in registerRemoteVolumeController.", e);
+        }
+    }
+
+    /**
+     * Unregisters the remote volume controller which was previously registered with
+     * {@link #registerRemoteVolumeController(IRemoteVolumeController)}.
+     * Only for use by System UI and Settings application.
+     *
+     * @param rvc The volume controller which was registered.
+     * @hide
+     */
+    public void unregisterRemoteVolumeController(IRemoteVolumeController rvc) {
+        try {
+            mService.unregisterRemoteVolumeController(rvc);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in unregisterRemoteVolumeController.", e);
         }
     }
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
index 0c35204..3b278b4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
@@ -20,9 +20,11 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.car.CarNotificationEntryManager;
 import com.android.systemui.car.CarNotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.car.CarFacetButtonController;
 import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.volume.CarVolumeDialogComponent;
@@ -54,7 +56,7 @@
     }
 
     public StatusBarKeyguardViewManager createStatusBarKeyguardViewManager(Context context,
-        ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) {
+            ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) {
         return new CarStatusBarKeyguardViewManager(context, viewMediatorCallback, lockPatternUtils);
     }
 
@@ -92,4 +94,12 @@
     public interface CarDependencyComponent {
         CarFacetButtonController getCarFacetButtonController();
     }
+
+    /**
+     * Use {@link CarNotificationEntryManager}, which does nothing when adding a notification.
+     */
+    @Singleton
+    public NotificationEntryManager provideNotificationEntryManager(Context context) {
+        return new CarNotificationEntryManager(context);
+    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
new file mode 100644
index 0000000..6d9c7ba
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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.car;
+
+import android.content.Context;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+
+/**
+ * Car specific notification entry manager that does nothing when adding a notification.
+ *
+ * <p> This is because system UI notifications are disabled and we have a different implementation.
+ * Please see {@link com.android.car.notification}.
+ */
+public class CarNotificationEntryManager extends NotificationEntryManager {
+    public CarNotificationEntryManager(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void addNotification(
+            StatusBarNotification notification, NotificationListenerService.RankingMap ranking) {
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index bd0e0b8..8732524 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -606,4 +606,8 @@
         getComponent(NotificationsUI.class).toggleShowingCarNotifications();
     }
 
+    @Override
+    public void maybeEscalateHeadsUp() {
+        // Never send full screen intent in car.
+    }
 }
diff --git a/packages/DynamicAndroidInstallationService/res/values/strings.xml b/packages/DynamicAndroidInstallationService/res/values/strings.xml
index 221e1d7..aee67e1 100644
--- a/packages/DynamicAndroidInstallationService/res/values/strings.xml
+++ b/packages/DynamicAndroidInstallationService/res/values/strings.xml
@@ -13,7 +13,7 @@
     <string name="keyguard_description">Please enter your password and continue to AndroidOnTap installation</string>
 
     <!-- Displayed on notification: DynAndroid installation is completed [CHAR LIMIT=128] -->
-    <string name="notification_install_completed">Installation is completed, you can reboot into the new installed system now.</string>
+    <string name="notification_install_completed">New system is ready, you can reboot into it or discard it.</string>
     <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] -->
     <string name="notification_install_inprogress">Installation is in progress.</string>
     <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] -->
@@ -30,4 +30,6 @@
     <!-- Action on notification: Reboot to AndroidOnTap [CHAR LIMIT=16] -->
     <string name="notification_action_reboot_to_dynandroid">Reboot</string>
 
+    <!-- Toast when installed AndroidOnTap is discarded [CHAR LIMIT=64] -->
+    <string name="toast_dynandroid_discarded">Installed AndroidOnTap is discarded.</string>
 </resources>
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
index 719417e..63ac8c7 100644
--- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
@@ -54,6 +54,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.util.Log;
+import android.widget.Toast;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -73,6 +74,8 @@
      */
     private static final String ACTION_CANCEL_INSTALL =
             "com.android.dynandroid.ACTION_CANCEL_INSTALL";
+    private static final String ACTION_DISCARD_INSTALL =
+            "com.android.dynandroid.ACTION_DISCARD_INSTALL";
     private static final String ACTION_REBOOT_TO_DYN_ANDROID =
             "com.android.dynandroid.ACTION_REBOOT_TO_DYN_ANDROID";
     private static final String ACTION_REBOOT_TO_NORMAL =
@@ -118,10 +121,6 @@
     private long mInstalledSize;
     private boolean mJustCancelledByUser;
 
-    private PendingIntent mPiCancel;
-    private PendingIntent mPiRebootToDynamicAndroid;
-    private PendingIntent mPiUninstallAndReboot;
-
     private InstallationAsyncTask mInstallTask;
 
 
@@ -155,6 +154,8 @@
             executeInstallCommand(intent);
         } else if (ACTION_CANCEL_INSTALL.equals(action)) {
             executeCancelCommand();
+        } else if (ACTION_DISCARD_INSTALL.equals(action)) {
+            executeDiscardCommand();
         } else if (ACTION_REBOOT_TO_DYN_ANDROID.equals(action)) {
             executeRebootToDynAndroidCommand();
         } else if (ACTION_REBOOT_TO_NORMAL.equals(action)) {
@@ -210,7 +211,7 @@
         }
 
         if (mInstallTask != null) {
-            Log.e(TAG, "There is already an install task running");
+            Log.e(TAG, "There is already an installation task running");
             return;
         }
 
@@ -234,10 +235,8 @@
     }
 
     private void executeCancelCommand() {
-        if (mInstallTask == null || mInstallTask.getStatus() == PENDING) {
+        if (mInstallTask == null || mInstallTask.getStatus() != RUNNING) {
             Log.e(TAG, "Cancel command triggered, but there is no task running");
-            mNM.cancel(NOTIFICATION_ID);
-
             return;
         }
 
@@ -247,17 +246,34 @@
             // Will cleanup and post status in onCancelled()
             Log.d(TAG, "Cancel request filed successfully");
         } else {
-            Log.d(TAG, "Requested cancel, completed task will be discarded");
+            Log.e(TAG, "Trying to cancel installation while it's already completed.");
+        }
+    }
 
-            resetTaskAndStop();
-            postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
+    private void executeDiscardCommand() {
+        if (isInDynamicAndroid()) {
+            Log.e(TAG, "We are now running in AOT, please reboot to normal system first");
+            return;
         }
 
+        if (getStatus() != STATUS_READY) {
+            Log.e(TAG, "Trying to discard AOT while there is no complete installation");
+            return;
+        }
+
+        Toast.makeText(this,
+                getString(R.string.toast_dynandroid_discarded),
+                Toast.LENGTH_LONG).show();
+
+        resetTaskAndStop();
+        postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
+
+        mDynAndroid.remove();
     }
 
     private void executeRebootToDynAndroidCommand() {
         if (mInstallTask == null || mInstallTask.getStatus() != FINISHED) {
-            Log.e(TAG, "Trying to reboot to DynamicAndroid, but there is no complete installation");
+            Log.e(TAG, "Trying to reboot to AOT while there is no complete installation");
             return;
         }
 
@@ -277,8 +293,13 @@
     }
 
     private void executeRebootToNormalCommand() {
-        mDynAndroid.remove();
+        if (!isInDynamicAndroid()) {
+            Log.e(TAG, "It's already running in normal system.");
+            return;
+        }
 
+        // Per current design, we don't have disable() API. AOT is disabled on next reboot.
+        // TODO: Use better status query when b/125079548 is done.
         PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
 
         if (powerManager != null) {
@@ -287,9 +308,14 @@
     }
 
     private void executeNotifyIfInUseCommand() {
-        if (isInDynamicAndroid()) {
+        int status = getStatus();
+
+        if (status == STATUS_IN_USE) {
             startForeground(NOTIFICATION_ID,
                     buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED));
+        } else if (status == STATUS_READY) {
+            startForeground(NOTIFICATION_ID,
+                    buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED));
         }
     }
 
@@ -312,18 +338,12 @@
         if (mNM != null) {
             mNM.createNotificationChannel(chan);
         }
+    }
 
-        Intent intentCancel = new Intent(this, DynamicAndroidInstallationService.class);
-        intentCancel.setAction(ACTION_CANCEL_INSTALL);
-        mPiCancel = PendingIntent.getService(this, 0, intentCancel, 0);
-
-        Intent intentRebootToDyn = new Intent(this, DynamicAndroidInstallationService.class);
-        intentRebootToDyn.setAction(ACTION_REBOOT_TO_DYN_ANDROID);
-        mPiRebootToDynamicAndroid = PendingIntent.getService(this, 0, intentRebootToDyn, 0);
-
-        Intent intentUninstallAndReboot = new Intent(this, DynamicAndroidInstallationService.class);
-        intentUninstallAndReboot.setAction(ACTION_REBOOT_TO_NORMAL);
-        mPiUninstallAndReboot = PendingIntent.getService(this, 0, intentUninstallAndReboot, 0);
+    private PendingIntent createPendingIntent(String action) {
+        Intent intent = new Intent(this, DynamicAndroidInstallationService.class);
+        intent.setAction(action);
+        return PendingIntent.getService(this, 0, intent, 0);
     }
 
     private Notification buildNotification(int status, int cause) {
@@ -342,7 +362,7 @@
 
                 builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_cancel),
-                        mPiCancel).build());
+                        createPendingIntent(ACTION_CANCEL_INSTALL)).build());
 
                 break;
 
@@ -351,11 +371,11 @@
 
                 builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_reboot_to_dynandroid),
-                        mPiRebootToDynamicAndroid).build());
+                        createPendingIntent(ACTION_REBOOT_TO_DYN_ANDROID)).build());
 
                 builder.addAction(new Notification.Action.Builder(
-                        null, getString(R.string.notification_action_cancel),
-                        mPiCancel).build());
+                        null, getString(R.string.notification_action_discard),
+                        createPendingIntent(ACTION_DISCARD_INSTALL)).build());
 
                 break;
 
@@ -364,7 +384,7 @@
 
                 builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_uninstall),
-                        mPiUninstallAndReboot).build());
+                        createPendingIntent(ACTION_REBOOT_TO_NORMAL)).build());
 
                 break;
 
@@ -427,10 +447,10 @@
     private int getStatus() {
         if (isInDynamicAndroid()) {
             return STATUS_IN_USE;
-
+        } else if (isDynamicAndroidInstalled()) {
+            return STATUS_READY;
         } else if (mInstallTask == null) {
             return STATUS_NOT_STARTED;
-
         }
 
         switch (mInstallTask.getStatus()) {
@@ -458,6 +478,10 @@
         return mDynAndroid.isInUse();
     }
 
+    private boolean isDynamicAndroidInstalled() {
+        return mDynAndroid.isInstalled();
+    }
+
     void handleMessage(Message msg) {
         switch (msg.what) {
             case DynamicAndroidClient.MSG_REGISTER_LISTENER:
diff --git a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java b/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
index d1ca109..e23f10f 100644
--- a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
+++ b/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
@@ -48,6 +48,8 @@
             return DataStallEventProto.VALID;
         } else if (result.isPortal()) {
             return DataStallEventProto.PORTAL;
+        } else if (result.isPartialConnectivity()) {
+            return DataStallEventProto.PARTIAL;
         } else {
             return DataStallEventProto.INVALID;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
index 4ed1154..f6cd971 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
@@ -95,7 +95,7 @@
         mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler);
         mInit = true;
         postUpdateSessions();
-        mMgr.setRemoteVolumeController(mRvc);
+        mMgr.registerRemoteVolumeController(mRvc);
     }
 
     protected void postUpdateSessions() {
@@ -110,6 +110,7 @@
         if (D.BUG) Log.d(TAG, "destroy");
         mInit = false;
         mMgr.removeOnActiveSessionsChangedListener(mSessionsListener);
+        mMgr.unregisterRemoteVolumeController(mRvc);
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 59fbb72..800c401 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -307,6 +307,7 @@
     public AccessPoint(Context context, WifiConfiguration config) {
         mContext = context;
         loadConfig(config);
+        updateKey();
     }
 
     /**
@@ -317,6 +318,7 @@
         mContext = context;
         mFqdn = config.getHomeSp().getFqdn();
         mProviderFriendlyName = config.getHomeSp().getFriendlyName();
+        updateKey();
     }
 
     /**
@@ -355,7 +357,6 @@
         security = getSecurity(config);
         networkId = config.networkId;
         mConfig = config;
-        updateKey();
     }
 
     /** Updates {@link #mKey} and should only called upon object creation/initialization. */
@@ -363,6 +364,8 @@
         // TODO(sghuman): Consolidate Key logic on ScanResultMatchInfo
         if (isPasspoint()) {
             mKey = getKey(mConfig);
+        } else if (isPasspointConfig()) {
+            mKey = getKey(mFqdn);
         } else if (isOsuProvider()) {
             mKey = getKey(mOsuProvider);
         } else { // Non-Passpoint AP
@@ -618,15 +621,22 @@
      */
     public static String getKey(WifiConfiguration config) {
         if (config.isPasspoint()) {
-            return new StringBuilder()
-                    .append(KEY_PREFIX_FQDN)
-                    .append(config.FQDN).toString();
+            return getKey(config.FQDN);
         } else {
             return getKey(removeDoubleQuotes(config.SSID), config.BSSID, getSecurity(config));
         }
     }
 
     /**
+     * Returns the AccessPoint key corresponding to a Passpoint network by its FQDN.
+     */
+    public static String getKey(String fqdn) {
+        return new StringBuilder()
+                .append(KEY_PREFIX_FQDN)
+                .append(fqdn).toString();
+    }
+
+    /**
      * Returns the AccessPoint key corresponding to the OsuProvider.
      */
     public static String getKey(OsuProvider provider) {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 7c367c7..9c8e3f4 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -1250,6 +1250,14 @@
         AccessPoint passpointAp = new AccessPoint(mContext, spyConfig, mScanResults, null);
         assertThat(passpointAp.getKey()).isEqualTo(AccessPoint.getKey(spyConfig));
 
+        PasspointConfiguration passpointConfig = new PasspointConfiguration();
+        HomeSp homeSp = new HomeSp();
+        homeSp.setFqdn("fqdn");
+        homeSp.setFriendlyName("Test Provider");
+        passpointConfig.setHomeSp(homeSp);
+        AccessPoint passpointConfigAp = new AccessPoint(mContext, passpointConfig);
+        assertThat(passpointConfigAp.getKey()).isEqualTo(AccessPoint.getKey("fqdn"));
+
         OsuProvider provider = createOsuProvider();
         AccessPoint osuAp = new AccessPoint(mContext, provider, mScanResults);
         assertThat(osuAp.getKey()).isEqualTo(AccessPoint.getKey(provider));
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 9425941..c2495b5 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -58,7 +58,6 @@
         "androidx.arch.core_core-runtime",
         "androidx.lifecycle_lifecycle-extensions",
         "androidx.dynamicanimation_dynamicanimation",
-        "iconloader_base",
         "SystemUI-tags",
         "SystemUI-proto",
         "dagger2-2.19",
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
index 5f4cf03..2b10ccb 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@@ -58,6 +58,10 @@
     void userActivity();
     void getState();
 
+    boolean areCaptionsEnabled();
+    void setCaptionsEnabled(boolean isEnabled);
+    void getCaptionsComponentState();
+
     @ProvidesInterface(version = StreamState.VERSION)
     public static final class StreamState {
         public static final int VERSION = 1;
@@ -186,5 +190,6 @@
         void onScreenOff();
         void onShowSafetyWarning(int flags);
         void onAccessibilityModeChanged(Boolean showA11yStream);
+        void onCaptionComponentStateChanged(Boolean isComponentEnabled);
     }
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index bca3530..42600c1 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -247,27 +247,6 @@
         }
     }
 
-
-    @ProvidesInterface(version = AirplaneBooleanState.VERSION)
-    public static class AirplaneBooleanState extends BooleanState {
-        public static final int VERSION = 1;
-        public boolean isAirplaneMode;
-
-        @Override
-        public boolean copyTo(State other) {
-            final AirplaneBooleanState o = (AirplaneBooleanState) other;
-            final boolean changed = super.copyTo(other) || o.isAirplaneMode != isAirplaneMode;
-            o.isAirplaneMode = isAirplaneMode;
-            return changed;
-        }
-
-        public State copy() {
-            AirplaneBooleanState state = new AirplaneBooleanState();
-            copyTo(state);
-            return state;
-        }
-    }
-
     @ProvidesInterface(version = SlashState.VERSION)
     public static class SlashState {
         public static final int VERSION = 2;
diff --git a/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml b/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml
new file mode 100644
index 0000000..9b90729
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml
@@ -0,0 +1,24 @@
+<!--
+     Copyright (C) 2019 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="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M20,4C21.1,4 22,4.9 22,6L22,18C22,19.1 21.1,20 20,20L4,20C2.9,20 2,19.1 2,18L2,6C2,4.9 2.9,4 4,4L20,4ZM20,18L20,6L4,6L4,18L20,18ZM6,10L8,10L8,12L6,12L6,10ZM6,14L14,14L14,16L6,16L6,14ZM16,14L18,14L18,16L16,16L16,14ZM10,10L18,10L18,12L10,12L10,10Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml b/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml
new file mode 100644
index 0000000..f3d8d3b9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml
@@ -0,0 +1,24 @@
+<!--
+     Copyright (C) 2019 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="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M16.9675,14L18,14L18,15.0275L16.9675,14ZM20,17.0176L20,6L8.9281,6L6.9182,4L20,4C21.1,4 22,4.9 22,6L22,18C22,18.2949 21.9353,18.5755 21.8194,18.8281L20,17.0176ZM12.9478,10L18,10L18,12L14.9576,12L12.9478,10ZM1.2823,0.8824L22.8489,22.4489L21.6337,23.6641L17.9696,20L4,20C2.9,20 2,19.1 2,18L2,6C2,5.4577 2.2188,4.964 2.5724,4.6028L0.0672,2.0975L1.2823,0.8824ZM13.9696,16L6,16L6,14L11.9696,14L8,10.0304L8,12L6,12L6,10L7.9696,10L4,6.0304L4,18L15.9696,18L13.9696,16Z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid.xml b/packages/SystemUI/res/layout-land/global_actions_grid.xml
index 235d0fc..c51e71b 100644
--- a/packages/SystemUI/res/layout-land/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout-land/global_actions_grid.xml
@@ -7,7 +7,8 @@
     android:orientation="horizontal"
     android:clipToPadding="false"
     android:theme="@style/qs_theme"
-    android:gravity="top|right"
+    android:paddingLeft="@dimen/global_actions_top_padding"
+    android:gravity="top|left"
     android:clipChildren="false"
 >
     <LinearLayout
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
index e028214..de853c7 100644
--- a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
+++ b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
@@ -7,7 +7,8 @@
     android:orientation="horizontal"
     android:clipToPadding="false"
     android:theme="@style/qs_theme"
-    android:gravity="top|left"
+    android:gravity="top|right"
+    android:paddingRight="@dimen/global_actions_top_padding"
     android:clipChildren="false"
 >
     <LinearLayout
diff --git a/packages/SystemUI/res/layout/global_actions_grid.xml b/packages/SystemUI/res/layout/global_actions_grid.xml
index a620a8e..d90d5e9 100644
--- a/packages/SystemUI/res/layout/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid.xml
@@ -6,8 +6,9 @@
     android:layout_height="match_parent"
     android:orientation="horizontal"
     android:clipToPadding="false"
+    android:paddingTop="@dimen/global_actions_top_padding"
     android:theme="@style/qs_theme"
-    android:gravity="bottom|center"
+    android:gravity="top|center"
     android:clipChildren="false"
 >
     <LinearLayout
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index ca34c23..130be89 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -98,5 +98,27 @@
             </FrameLayout>
         </LinearLayout>
 
+        <FrameLayout
+            android:id="@+id/odi_captions"
+            android:layout_width="@dimen/volume_dialog_caption_size"
+            android:layout_height="@dimen/volume_dialog_caption_size"
+            android:layout_marginTop="@dimen/volume_dialog_spacer"
+            android:translationZ="@dimen/volume_dialog_elevation"
+            android:layout_gravity="right"
+            android:clipToPadding="false"
+            android:visibility="gone"
+            android:background="@drawable/rounded_bg_full">
+            <com.android.keyguard.AlphaOptimizedImageButton
+                android:id="@+id/odi_captions_icon"
+                android:src="@drawable/ic_volume_odi_captions_disabled"
+                style="@style/VolumeButtons"
+                android:background="@drawable/rounded_ripple"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:tint="@color/accent_tint_color_selector"
+                android:layout_gravity="center"
+                android:soundEffectsEnabled="false" />
+        </FrameLayout>
+
     </LinearLayout>
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c83cb59..30c29dc 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -336,6 +336,8 @@
 
     <dimen name="volume_dialog_ringer_size">64dp</dimen>
 
+    <dimen name="volume_dialog_caption_size">64dp</dimen>
+
     <dimen name="volume_dialog_tap_target_size">48dp</dimen>
 
     <dimen name="volume_dialog_spacer">4dp</dimen>
@@ -865,10 +867,12 @@
 
     <!-- Global actions power menu -->
     <dimen name="global_actions_panel_width">120dp</dimen>
-    <dimen name="global_actions_top_padding">120dp</dimen>
     <dimen name="global_actions_padding">12dp</dimen>
     <dimen name="global_actions_translate">9dp</dimen>
 
+    <!-- Distance from the top of screen in pixels, to position the power menu near the button. -->
+    <dimen name="global_actions_top_padding">330px</dimen>
+
     <!-- Global actions grid layout -->
     <dimen name="global_actions_grid_side_margin">4dp</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 5086c99..72ab02c 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -215,7 +215,7 @@
         } else {
             rotateLeft();
         }
-        if (mSeparated) {
+        if (mAdapter.hasSeparatedItems()) {
             if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
                 // Separated view has top margin, so seascape separated view need special rotation,
                 // not a full left or right rotation.
@@ -257,10 +257,10 @@
 
     @Override
     public void onUpdateList() {
-        removeAllItems();
+        super.onUpdateList();
         ArrayList<GlobalActionsDialog.Action> separatedActions =
-                mAdapter.getSeparatedItems(mSeparated);
-        ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems(mSeparated);
+                mAdapter.getSeparatedItems();
+        ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems();
 
         for (int i = 0; i < mAdapter.getCount(); i++) {
             Object action = mAdapter.getItem(i);
@@ -461,8 +461,9 @@
         if (mList == null) return;
         // If got separated button, setRotatedBackground to false,
         // all items won't get white background.
-        mListBackground.setRotatedBackground(mSeparated);
-        mSeparatedViewBackground.setRotatedBackground(mSeparated);
+        boolean separated = mAdapter.hasSeparatedItems();
+        mListBackground.setRotatedBackground(separated);
+        mSeparatedViewBackground.setRotatedBackground(separated);
         if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
             int index = mRotatedBackground ? 0 : 1;
             mDivision.getLocationOnScreen(mTmp2);
@@ -508,26 +509,27 @@
         int screenHeight;
         int totalHeight;
         int targetGravity;
+        boolean separated = mAdapter.hasSeparatedItems();
         MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
         switch (RotationUtils.getRotation(getContext())) {
             case RotationUtils.ROTATION_LANDSCAPE:
                 defaultTopPadding = getPaddingLeft();
                 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = mSeparated ? params.leftMargin : 0;
+                separatedViewTopMargin = separated ? params.leftMargin : 0;
                 screenHeight = getMeasuredWidth();
                 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
                 break;
             case RotationUtils.ROTATION_SEASCAPE:
                 defaultTopPadding = getPaddingRight();
                 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = mSeparated ? params.leftMargin : 0;
+                separatedViewTopMargin = separated ? params.leftMargin : 0;
                 screenHeight = getMeasuredWidth();
                 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
                 break;
             default: // Portrait
                 defaultTopPadding = getPaddingTop();
                 viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
-                separatedViewTopMargin = mSeparated ? params.topMargin : 0;
+                separatedViewTopMargin = separated ? params.topMargin : 0;
                 screenHeight = getMeasuredHeight();
                 targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
index 2bc4720..d063a0f 100644
--- a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -33,8 +33,8 @@
  */
 public abstract class MultiListLayout extends LinearLayout {
     protected boolean mHasOutsideTouch;
-    protected boolean mSeparated;
     protected MultiListAdapter mAdapter;
+    protected boolean mSnapToEdge;
 
     protected int mRotation;
     protected RotationListener mRotationListener;
@@ -70,12 +70,10 @@
     }
 
     /**
-     * Sets whether the separated view should be shown, and handles updating visibility on
-     * that view.
+     * Sets whether the GlobalActions view should snap to the edge of the screen.
      */
-    public void setSeparated(boolean separated) {
-        mSeparated = separated;
-        setSeparatedViewVisibility(separated);
+    public void setSnapToEdge(boolean snap) {
+        mSnapToEdge = snap;
     }
 
     /**
@@ -123,7 +121,9 @@
         onUpdateList();
     }
 
-    protected abstract void onUpdateList();
+    protected void onUpdateList() {
+        setSeparatedViewVisibility(mAdapter.hasSeparatedItems());
+    }
 
     public void setRotationListener(RotationListener listener) {
         mRotationListener = listener;
@@ -156,13 +156,13 @@
          * Creates an ArrayList of items which should be rendered in the separated view.
          * @param useSeparatedView is true if the separated view will be used, false otherwise.
          */
-        public abstract ArrayList getSeparatedItems(boolean useSeparatedView);
+        public abstract ArrayList getSeparatedItems();
 
         /**
          * Creates an ArrayList of items which should be rendered in the list view.
          * @param useSeparatedView True if the separated view will be used, false otherwise.
          */
-        public abstract ArrayList getListItems(boolean useSeparatedView);
+        public abstract ArrayList getListItems();
 
         /**
          * Callback to run when an individual item is clicked or pressed.
@@ -176,5 +176,13 @@
          * @return True if the long-click was handled, false otherwise.
          */
         public abstract boolean onLongClickItem(int position);
+
+        /**
+         * Determines whether the mAdapter contains any separated items, used to determine whether
+         * or not to hide the separated list from view.
+         */
+        public boolean hasSeparatedItems() {
+            return getSeparatedItems().size() > 0;
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index b2f707f..bc3f48d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -28,6 +28,7 @@
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.hardware.display.AmbientDisplayConfiguration;
+import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -35,7 +36,10 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.Preconditions;
+import com.android.systemui.Dependency;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.Assert;
@@ -79,6 +83,7 @@
     private long mNotificationPulseTime;
     private boolean mPulsePending;
 
+    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
             AlarmManager alarmManager, AmbientDisplayConfiguration config,
@@ -159,8 +164,15 @@
                     if (screenX != -1 && screenY != -1) {
                         mDozeHost.onSlpiTap(screenX, screenY);
                     }
+                    // Logs screen wake up reason of either single or double tap.
+                    mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
+                            .setType(MetricsEvent.TYPE_UPDATE).setSubtype(pulseReason));
                     mMachine.wakeUp();
                 } else if (isPickup) {
+                    // Logs screen wake up reason of lift.
+                    mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
+                            .setType(MetricsEvent.TYPE_UPDATE)
+                            .setSubtype(DozeLog.REASON_SENSOR_PICKUP));
                     mMachine.wakeUp();
                 } else {
                     mDozeHost.extendPulse();
@@ -298,6 +310,10 @@
                 continuePulseRequest(reason);
             }
         }, !mDozeParameters.getProxCheckBeforePulse() || performedProxCheck, reason);
+
+        // Logs request pulse reason on AOD screen.
+        mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
+                .setType(MetricsEvent.TYPE_UPDATE).setSubtype(reason));
     }
 
     private boolean canPulse() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index b07f909..ce58895 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -38,7 +38,6 @@
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
@@ -156,7 +155,6 @@
     private boolean mHasVibrator;
     private boolean mHasLogoutButton;
     private boolean mHasLockdownButton;
-    private boolean mUseSeparatedList;
     private final boolean mShowSilentToggle;
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
     private final ScreenshotHelper mScreenshotHelper;
@@ -334,7 +332,6 @@
         ArraySet<String> addedKeys = new ArraySet<String>();
         mHasLogoutButton = false;
         mHasLockdownButton = false;
-        mUseSeparatedList = true;
         for (int i = 0; i < defaultActions.length; i++) {
             String actionKey = defaultActions[i];
             if (addedKeys.contains(actionKey)) {
@@ -382,7 +379,7 @@
                     mHasLogoutButton = true;
                 }
             } else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
-                if (mUseSeparatedList
+                if (shouldUseSeparatedView()
                         && !mEmergencyAffordanceManager.needsEmergencyAffordance()) {
                     mItems.add(new EmergencyDialerAction());
                 }
@@ -407,8 +404,7 @@
                             }
                         })
                         : null;
-        ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, mUseSeparatedList,
-                panelViewController);
+        ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController);
         dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
         dialog.setKeyguardShowing(mKeyguardShowing);
 
@@ -636,14 +632,6 @@
         public boolean showBeforeProvisioning() {
             return false;
         }
-
-        @Override
-        public String getStatus() {
-            return mContext.getString(
-                    R.string.bugreport_status,
-                    Build.VERSION.RELEASE,
-                    Build.ID);
-        }
     }
 
     private final class LogoutAction extends SinglePressAction {
@@ -702,7 +690,7 @@
 
     private Action getEmergencyAction() {
         Drawable emergencyIcon = mContext.getDrawable(R.drawable.emergency_icon);
-        if (!mUseSeparatedList) {
+        if (!shouldUseSeparatedView()) {
             // use un-colored legacy treatment
             emergencyIcon.setTintList(null);
         }
@@ -931,9 +919,9 @@
         }
 
         @Override
-        public ArrayList<Action> getSeparatedItems(boolean shouldUseSeparatedView) {
+        public ArrayList<Action> getSeparatedItems() {
             ArrayList<Action> separatedActions = new ArrayList<Action>();
-            if (!shouldUseSeparatedView) {
+            if (!shouldUseSeparatedView()) {
                 return separatedActions;
             }
             for (int i = 0; i < mItems.size(); i++) {
@@ -946,8 +934,8 @@
         }
 
         @Override
-        public ArrayList<Action> getListItems(boolean shouldUseSeparatedView) {
-            if (!shouldUseSeparatedView) {
+        public ArrayList<Action> getListItems() {
+            if (!shouldUseSeparatedView()) {
                 return new ArrayList<Action>(mItems);
             }
             ArrayList<Action> listActions = new ArrayList<Action>();
@@ -1495,17 +1483,15 @@
         private final ColorExtractor mColorExtractor;
         private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
         private boolean mKeyguardShowing;
-        private boolean mUseSeparatedList;
         private boolean mShowing;
         private final float mScrimAlpha;
 
-        ActionsDialog(Context context, MyAdapter adapter, boolean separated,
+        ActionsDialog(Context context, MyAdapter adapter,
                 GlobalActionsPanelPlugin.PanelViewController plugin) {
             super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
             mContext = context;
             mAdapter = adapter;
             mColorExtractor = Dependency.get(SysuiColorExtractor.class);
-            mUseSeparatedList = separated;
 
             // Window initialization
             Window window = getWindow();
@@ -1569,7 +1555,6 @@
             mGlobalActionsLayout = (MultiListLayout)
                     findViewById(com.android.systemui.R.id.global_actions_view);
             mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
-            mGlobalActionsLayout.setSeparated(mUseSeparatedList);
             mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
                 @Override
                 public boolean dispatchPopulateAccessibilityEvent(
@@ -1581,11 +1566,8 @@
             });
             mGlobalActionsLayout.setRotationListener(this::onRotate);
             mGlobalActionsLayout.setAdapter(mAdapter);
-        }
-
-        private boolean isPanelEnabled(Context context) {
-            return FeatureFlagUtils.isEnabled(
-                    context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);
+            mGlobalActionsLayout.setSnapToEdge(isPanelEnabled(mContext)
+                    && mPanelController != null);
         }
 
         private int getGlobalActionsLayoutId(Context context) {
@@ -1726,9 +1708,24 @@
     }
 
     /**
-     * Determines whether or not the Global Actions Dialog should use the newer grid-style layout.
+     * Determines whether or not the Global Actions menu should use the newer grid-style layout.
      */
-    public static boolean isGridEnabled(Context context) {
+    private static boolean isGridEnabled(Context context) {
         return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.GLOBAL_ACTIONS_GRID_ENABLED);
     }
+
+    /**
+     * Determines whether or not the Global Actions Panel should appear when the power button
+     * is held.
+     */
+    private static boolean isPanelEnabled(Context context) {
+        return FeatureFlagUtils.isEnabled(
+                context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);    }
+
+    /**
+     * Determines whether the Global Actions menu should use a separated view for emergency actions.
+     */
+    private static boolean shouldUseSeparatedView() {
+        return true;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
index cda7669..058ea60 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -71,10 +72,10 @@
 
     @Override
     public void onUpdateList() {
-        removeAllItems();
+        super.onUpdateList();
         ArrayList<GlobalActionsDialog.Action> separatedActions =
-                mAdapter.getSeparatedItems(mSeparated);
-        ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems(mSeparated);
+                mAdapter.getSeparatedItems();
+        ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems();
         setExpectedListItemCount(listActions.size());
         int rotation = RotationUtils.getRotation(mContext);
 
@@ -108,6 +109,7 @@
                 parent.addView(v);
             }
         }
+        updateSnapPosition();
     }
 
     @Override
@@ -115,6 +117,19 @@
         return findViewById(com.android.systemui.R.id.separated_button);
     }
 
+    private void updateSnapPosition() {
+        if (mSnapToEdge) {
+            setPadding(0, 0, 0, 0);
+            if (mRotation == RotationUtils.ROTATION_LANDSCAPE) {
+                setGravity(Gravity.RIGHT);
+            } else if (mRotation == RotationUtils.ROTATION_SEASCAPE) {
+                setGravity(Gravity.LEFT);
+            } else {
+                setGravity(Gravity.BOTTOM);
+            }
+        }
+    }
+
     @Override
     protected ListGridLayout getListView() {
         return findViewById(android.R.id.list);
@@ -148,7 +163,7 @@
     }
 
     /**
-     * Not used in this implementation of the Global Actions Menu, but necessary for some others.
+     * Not ued in this implementation of the Global Actions Menu, but necessary for some others.
      */
     @Override
     public void setDivisionView(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
index 6c106df..048f801 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
@@ -114,7 +114,7 @@
         if (mExpectedCount == 3) {
             return 1;
         }
-        return (int) Math.ceil(Math.sqrt(mExpectedCount));
+        return (int) Math.round(Math.sqrt(mExpectedCount));
     }
 
     private int getColumnCount() {
@@ -122,6 +122,6 @@
         if (mExpectedCount == 3) {
             return 3;
         }
-        return (int) Math.round(Math.sqrt(mExpectedCount));
+        return (int) Math.ceil(Math.sqrt(mExpectedCount));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index b7e07f8..5e6f18e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -20,14 +20,12 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.os.UserManager;
-import android.provider.Settings.Global;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSTile.AirplaneBooleanState;
-import com.android.systemui.qs.GlobalSetting;
+import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.DataSaverController;
@@ -36,7 +34,7 @@
 import javax.inject.Inject;
 
 /** Quick settings tile: Hotspot **/
-public class HotspotTile extends QSTileImpl<AirplaneBooleanState> {
+public class HotspotTile extends QSTileImpl<BooleanState> {
     private static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
             "com.android.settings", "com.android.settings.TetherSettings"));
 
@@ -46,7 +44,6 @@
     private final DataSaverController mDataSaverController;
 
     private final HotspotAndDataSaverCallbacks mCallbacks = new HotspotAndDataSaverCallbacks();
-    private final GlobalSetting mAirplaneMode;
     private boolean mListening;
 
     @Inject
@@ -55,12 +52,6 @@
         super(host);
         mHotspotController = hotspotController;
         mDataSaverController = dataSaverController;
-        mAirplaneMode = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
-            @Override
-            protected void handleValueChanged(int value) {
-                refreshState();
-            }
-        };
         mHotspotController.observe(this, mCallbacks);
         mDataSaverController.observe(this, mCallbacks);
     }
@@ -76,18 +67,12 @@
     }
 
     @Override
-    public AirplaneBooleanState newTileState() {
-        return new AirplaneBooleanState();
-    }
-
-    @Override
     public void handleSetListening(boolean listening) {
         if (mListening == listening) return;
         mListening = listening;
         if (listening) {
             refreshState();
         }
-        mAirplaneMode.setListening(listening);
     }
 
     @Override
@@ -96,10 +81,14 @@
     }
 
     @Override
+    public BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
     protected void handleClick() {
         final boolean isEnabled = mState.value;
-        if (!isEnabled &&
-                (mAirplaneMode.getValue() != 0 || mDataSaverController.isDataSaverEnabled())) {
+        if (!isEnabled && mDataSaverController.isDataSaverEnabled()) {
             return;
         }
         // Immediately enter transient enabling state when turning hotspot on.
@@ -113,7 +102,7 @@
     }
 
     @Override
-    protected void handleUpdateState(AirplaneBooleanState state, Object arg) {
+    protected void handleUpdateState(BooleanState state, Object arg) {
         final boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING;
         if (state.slash == null) {
             state.slash = new SlashState();
@@ -138,7 +127,6 @@
 
         state.icon = mEnabledStatic;
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
-        state.isAirplaneMode = mAirplaneMode.getValue() != 0;
         state.isTransient = isTransient;
         state.slash.isSlashed = !state.value && !state.isTransient;
         if (state.isTransient) {
@@ -147,7 +135,7 @@
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.contentDescription = state.label;
 
-        final boolean isTileUnavailable = (state.isAirplaneMode || isDataSaverEnabled);
+        final boolean isTileUnavailable = isDataSaverEnabled;
         final boolean isTileActive = (state.value || state.isTransient);
 
         if (isTileUnavailable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
index 409d60f..2d54970 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
@@ -16,203 +16,159 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
 import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.view.SurfaceControl;
+import android.view.CompositionSamplingListener;
 import android.view.View;
 
-import com.android.systemui.R;
+import java.io.PrintWriter;
 
-public class NavBarTintController {
+/**
+ * Updates the nav bar tint based on the color of the content behind the nav bar.
+ */
+public class NavBarTintController implements View.OnAttachStateChangeListener,
+        View.OnLayoutChangeListener {
+
     public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400;
     public static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1700;
 
-    private final HandlerThread mColorAdaptHandlerThread = new HandlerThread("ColorExtractThread");
-    private Handler mColorAdaptionHandler;
-
-    // Poll time for each iteration to color sample
-    private static final int COLOR_ADAPTION_TIMEOUT = 300;
-
     // Passing the threshold of this luminance value will make the button black otherwise white
     private static final float LUMINANCE_THRESHOLD = 0.3f;
 
-    // The margin from the bounds of the view to color sample around
-    private static final int COLOR_SAMPLE_MARGIN = 10;
-
-    private boolean mRunning;
-
+    private final Handler mHandler = new Handler();
     private final NavigationBarView mNavigationBarView;
     private final LightBarTransitionsController mLightBarController;
-    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
-    private final int mBarRadius;
-    private final int mBarBottom;
+
+    private final CompositionSamplingListener mSamplingListener;
+    private final Runnable mUpdateSamplingListener = this::updateSamplingListener;
+    private final Rect mSamplingBounds = new Rect();
+    private boolean mSamplingEnabled = false;
+    private boolean mSamplingListenerRegistered = false;
+
+    private float mLastMediaLuma;
+    private boolean mUpdateOnNextDraw;
 
     public NavBarTintController(NavigationBarView navigationBarView,
             LightBarTransitionsController lightBarController) {
+        mSamplingListener = new CompositionSamplingListener(
+                navigationBarView.getContext().getMainExecutor()) {
+            @Override
+            public void onSampleCollected(float medianLuma) {
+                updateTint(medianLuma);
+            }
+        };
         mNavigationBarView = navigationBarView;
+        mNavigationBarView.addOnAttachStateChangeListener(this);
+        mNavigationBarView.addOnLayoutChangeListener(this);
         mLightBarController = lightBarController;
-
-        final Resources res = navigationBarView.getResources();
-        mBarRadius = res.getDimensionPixelSize(R.dimen.navigation_handle_radius);
-        mBarBottom = res.getDimensionPixelSize(R.dimen.navigation_handle_bottom);
     }
 
-    public void start() {
+    void onDraw() {
+        if (mUpdateOnNextDraw) {
+            mUpdateOnNextDraw = false;
+            requestUpdateSamplingListener();
+        }
+    }
+
+    void start() {
         if (!isEnabled(mNavigationBarView.getContext())) {
             return;
         }
-        if (mColorAdaptionHandler == null) {
-            mColorAdaptHandlerThread.start();
-            mColorAdaptionHandler = new Handler(mColorAdaptHandlerThread.getLooper());
-        }
-        mColorAdaptionHandler.removeCallbacksAndMessages(null);
-        mColorAdaptionHandler.post(this::updateTint);
-        mRunning = true;
+        mSamplingEnabled = true;
+        // Defer calling updateSamplingListener since we may have just reinflated prior to this
+        requestUpdateSamplingListener();
     }
 
-    public void end() {
-        if (mColorAdaptionHandler != null) {
-            mColorAdaptionHandler.removeCallbacksAndMessages(null);
-        }
-        mRunning = false;
+    void stop() {
+        mSamplingEnabled = false;
+        requestUpdateSamplingListener();
     }
 
-    public void stop() {
-        end();
-        if (mColorAdaptionHandler != null) {
-            mColorAdaptHandlerThread.quitSafely();
-        }
+    @Override
+    public void onViewAttachedToWindow(View view) {
+        requestUpdateSamplingListener();
     }
 
-    private void updateTint() {
-        int[] navPos = new int[2];
-        int[] butPos = new int[2];
+    @Override
+    public void onViewDetachedFromWindow(View view) {
+        // Defer calling updateSamplingListener the attach info has not yet been reset
+        requestUpdateSamplingListener();
+    }
+
+    @Override
+    public void onLayoutChange(View v, int left, int top, int right, int bottom,
+            int oldLeft, int oldTop, int oldRight, int oldBottom) {
+        mSamplingBounds.setEmpty();
+        // TODO: Extend this to 2/3 button layout as well
         View view = mNavigationBarView.getHomeHandle().getCurrentView();
-        if (view == null) {
-            return;
+        if (view != null) {
+            int[] pos = new int[2];
+            view.getLocationOnScreen(pos);
+            final Rect samplingBounds = new Rect(pos[0], pos[1],
+                    pos[0] + view.getWidth(), pos[1] + view.getHeight());
+            if (!samplingBounds.equals(mSamplingBounds)) {
+                mSamplingBounds.set(samplingBounds);
+                requestUpdateSamplingListener();
+            }
         }
-
-        // Determine the area of the icon within its view bounds
-        view.getLocationInSurface(butPos);
-        final int navWidth = view.getWidth();
-        final int navHeight = view.getHeight();
-        int viewBottom = butPos[1] + navHeight - mBarBottom;
-        final Rect viewIconRect = new Rect(butPos[0], viewBottom - mBarRadius * 2,
-                butPos[0] + navWidth, viewBottom);
-
-        if (mNavigationBarView.getCurrentView() == null || viewIconRect.isEmpty()) {
-            scheduleColorAdaption();
-            return;
-        }
-        mNavigationBarView.getCurrentView().getLocationOnScreen(navPos);
-        viewIconRect.offset(navPos[0], navPos[1]);
-
-        // Apply a margin area around the button region to sample the colors, crop from screenshot
-        final Rect cropRect = new Rect(viewIconRect);
-        cropRect.inset(-COLOR_SAMPLE_MARGIN, -COLOR_SAMPLE_MARGIN);
-        if (cropRect.isEmpty()) {
-            scheduleColorAdaption();
-            return;
-        }
-
-        // Determine the size of the home area
-        Rect homeArea = new Rect(COLOR_SAMPLE_MARGIN, COLOR_SAMPLE_MARGIN,
-                viewIconRect.width() + COLOR_SAMPLE_MARGIN,
-                viewIconRect.height() + COLOR_SAMPLE_MARGIN);
-
-        // Get the screenshot around the home button icon to determine the color
-        DisplayMetrics mDisplayMetrics = new DisplayMetrics();
-        mNavigationBarView.getContext().getDisplay().getRealMetrics(mDisplayMetrics);
-        final Bitmap hardBitmap = SurfaceControl
-                .screenshot(new Rect(), mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
-                        mNavigationBarView.getContext().getDisplay().getRotation());
-        if (hardBitmap != null && cropRect.bottom <= hardBitmap.getHeight()
-                && cropRect.left + cropRect.width() <= hardBitmap.getWidth()) {
-            final Bitmap cropBitmap = Bitmap.createBitmap(hardBitmap, cropRect.left, cropRect.top,
-                    cropRect.width(), cropRect.height());
-            final Bitmap softBitmap = cropBitmap.copy(Config.ARGB_8888, false);
-
-            // Get the luminance value to determine if the home button should be black or white
-            final int[] pixels = new int[softBitmap.getByteCount() / 4];
-            softBitmap.getPixels(pixels, 0, softBitmap.getWidth(), 0, 0, softBitmap.getWidth(),
-                    softBitmap.getHeight());
-            float r = 0, g = 0, blue = 0;
-
-            int width = cropRect.width();
-            int total = 0;
-            for (int i = 0; i < pixels.length; i += 4) {
-                int x = i % width;
-                int y = i / width;
-                if (!homeArea.contains(x, y)) {
-                    r += Color.red(pixels[i]);
-                    g += Color.green(pixels[i]);
-                    blue += Color.blue(pixels[i]);
-                    total++;
-                }
-            }
-
-            r /= total;
-            g /= total;
-            blue /= total;
-
-            r = Math.max(Math.min(r / 255f, 1), 0);
-            g = Math.max(Math.min(g / 255f, 1), 0);
-            blue = Math.max(Math.min(blue / 255f, 1), 0);
-
-            if (r <= 0.03928) {
-                r /= 12.92;
-            } else {
-                r = (float) Math.pow((r + 0.055) / 1.055, 2.4);
-            }
-            if (g <= 0.03928) {
-                g /= 12.92;
-            } else {
-                g = (float) Math.pow((g + 0.055) / 1.055, 2.4);
-            }
-            if (blue <= 0.03928) {
-                blue /= 12.92;
-            } else {
-                blue = (float) Math.pow((blue + 0.055) / 1.055, 2.4);
-            }
-
-            if (r * 0.2126 + g * 0.7152 + blue * 0.0722 > LUMINANCE_THRESHOLD) {
-                // Black
-                mMainHandler.post(
-                        () -> mLightBarController
-                                .setIconsDark(true /* dark */, true /* animate */));
-            } else {
-                // White
-                mMainHandler.post(
-                        () -> mLightBarController
-                                .setIconsDark(false /* dark */, true /* animate */));
-            }
-            cropBitmap.recycle();
-            hardBitmap.recycle();
-        }
-        scheduleColorAdaption();
     }
 
-    private void scheduleColorAdaption() {
-        mColorAdaptionHandler.removeCallbacksAndMessages(null);
-        if (!mRunning || !isEnabled(mNavigationBarView.getContext())) {
-            return;
+    private void requestUpdateSamplingListener() {
+        mHandler.removeCallbacks(mUpdateSamplingListener);
+        mHandler.post(mUpdateSamplingListener);
+    }
+
+    private void updateSamplingListener() {
+        if (mSamplingListenerRegistered) {
+            mSamplingListenerRegistered = false;
+            CompositionSamplingListener.unregister(mSamplingListener);
         }
-        mColorAdaptionHandler.postDelayed(this::updateTint, COLOR_ADAPTION_TIMEOUT);
+        if (mSamplingEnabled && !mSamplingBounds.isEmpty()
+                && mNavigationBarView.isAttachedToWindow()) {
+            if (!mNavigationBarView.getViewRootImpl().getSurfaceControl().isValid()) {
+                // The view may still be attached, but the surface backing the window can be
+                // destroyed, so wait until the next draw to update the listener again
+                mUpdateOnNextDraw = true;
+                return;
+            }
+            mSamplingListenerRegistered = true;
+            CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
+                    mNavigationBarView.getViewRootImpl().getSurfaceControl().getHandle(),
+                    mSamplingBounds);
+        }
+    }
+
+    private void updateTint(float medianLuma) {
+        mLastMediaLuma = medianLuma;
+        if (medianLuma > LUMINANCE_THRESHOLD) {
+            // Black
+            mLightBarController.setIconsDark(true /* dark */, true /* animate */);
+        } else {
+            // White
+            mLightBarController.setIconsDark(false /* dark */, true /* animate */);
+        }
+    }
+
+    void dump(PrintWriter pw) {
+        pw.println("NavBarTintController:");
+        pw.println("  navBar isAttached: " + mNavigationBarView.isAttachedToWindow());
+        pw.println("  navBar isScValid: " + (mNavigationBarView.isAttachedToWindow()
+                ? mNavigationBarView.getViewRootImpl().getSurfaceControl().isValid()
+                : "false"));
+        pw.println("  mSamplingListenerRegistered: " + mSamplingListenerRegistered);
+        pw.println("  mSamplingBounds: " + mSamplingBounds);
+        pw.println("  mLastMediaLuma: " + mLastMediaLuma);
     }
 
     public static boolean isEnabled(Context context) {
-        return Settings.Global.getInt(context.getContentResolver(),
-                NavigationPrototypeController.NAV_COLOR_ADAPT_ENABLE_SETTING, 0) == 1
-            && Settings.Global.getInt(context.getContentResolver(),
-                NavigationPrototypeController.SHOW_HOME_HANDLE_SETTING, 0) == 1;
+        return context.getDisplayId() == DEFAULT_DISPLAY
+                && Settings.Global.getInt(context.getContentResolver(),
+                        NavigationPrototypeController.NAV_COLOR_ADAPT_ENABLE_SETTING, 0) == 1
+                && Settings.Global.getInt(context.getContentResolver(),
+                        NavigationPrototypeController.SHOW_HOME_HANDLE_SETTING, 0) == 1;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index b68c7c6..0978901 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -991,7 +991,7 @@
                     }
                 } else {
                     // Screen off disable it
-                    mNavigationBarView.getColorAdaptionController().end();
+                    mNavigationBarView.getColorAdaptionController().stop();
                 }
             }
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index b540fb4..a64ff0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -333,7 +333,7 @@
             if (enabled) {
                 mColorAdaptionController.start();
             } else {
-                mColorAdaptionController.end();
+                mColorAdaptionController.stop();
             }
         }
 
@@ -486,6 +486,12 @@
         }
     }
 
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+        mColorAdaptionController.onDraw();
+    }
+
     private void updateNavigationGestures() {
         if (mGestureHelper instanceof QuickStepController) {
             final int[] assignedMap = mPrototypeController.getGestureActionMap();
@@ -990,7 +996,7 @@
         if (visible) {
             mColorAdaptionController.start();
         } else {
-            mColorAdaptionController.end();
+            mColorAdaptionController.stop();
         }
     }
 
@@ -1244,7 +1250,7 @@
         if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
             mColorAdaptionController.start();
         } else {
-            mColorAdaptionController.end();
+            mColorAdaptionController.stop();
         }
     }
 
@@ -1330,7 +1336,6 @@
         Dependency.get(PluginManager.class).addPluginListener(this,
                 NavGesture.class, false /* Only one */);
         setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
-        mColorAdaptionController.start();
 
         if (mPrototypeController.isEnabled()) {
             WindowManager wm = (WindowManager) getContext()
@@ -1363,7 +1368,6 @@
             mGestureHelper.destroy();
         }
         mPrototypeController.unregister();
-        mColorAdaptionController.stop();
         setUpSwipeUpOnboarding(false);
         for (int i = 0; i < mButtonDispatchers.size(); ++i) {
             mButtonDispatchers.valueAt(i).onDestroy();
@@ -1454,6 +1458,7 @@
             mGestureHelper.dump(pw);
         }
         mRecentsOnboarding.dump(pw);
+        mColorAdaptionController.dump(pw);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 0461057..d1a2253 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -26,8 +26,10 @@
 import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.view.accessibility.AccessibilityManager;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -55,9 +57,11 @@
     protected int mUser;
 
     private final ArrayMap<String, Long> mSnoozedPackages;
+    private final AccessibilityManagerWrapper mAccessibilityMgr;
 
     public HeadsUpManager(@NonNull final Context context) {
         mContext = context;
+        mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
         Resources resources = context.getResources();
         mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
         mAutoDismissNotificationDecay = resources.getInteger(R.integer.heads_up_notification_decay);
@@ -409,5 +413,22 @@
             // The actual post time will be just after the heads-up really slided in
             return super.calculatePostTime() + mTouchAcceptanceDelay;
         }
+
+        @Override
+        protected long calculateFinishTime() {
+            return mPostTime + getRecommendedTimeoutMillis();
+        }
+
+        /**
+         * Get user-preferred or default timeout duration. The larger one will be returned.
+         * @return milliseconds before auto-dismiss
+         */
+        private int getRecommendedTimeoutMillis() {
+            return mAccessibilityMgr.getRecommendedTimeoutMillis(
+                    mAutoDismissNotificationDecay,
+                    AccessibilityManager.FLAG_CONTENT_CONTROLS
+                            | AccessibilityManager.FLAG_CONTENT_ICONS
+                            | AccessibilityManager.FLAG_CONTENT_TEXT);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index f79ad71..f4d6237 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -21,7 +21,9 @@
 import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT;
 import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE;
 import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT;
+import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
 
+import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
 import static com.android.systemui.Dependency.BG_LOOPER_NAME;
 
 import android.content.BroadcastReceiver;
@@ -41,6 +43,7 @@
 import android.os.PersistableBundle;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
@@ -107,6 +110,16 @@
     private final CurrentUserTracker mUserTracker;
     private Config mConfig;
 
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onActiveDataSubscriptionIdChanged(int subId) {
+            mActiveMobileDataSubscription = subId;
+            doUpdateMobileControllers();
+        }
+    };
+
+    private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
     // Subcontrollers.
     @VisibleForTesting
     final WifiSignalController mWifiSignalController;
@@ -281,6 +294,7 @@
             mSubscriptionListener = new SubListener();
         }
         mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
+        mPhone.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
 
         // broadcasts
         IntentFilter filter = new IntentFilter();
@@ -525,6 +539,7 @@
 
     @VisibleForTesting
     void handleConfigurationChanged() {
+        updateMobileControllers();
         for (int i = 0; i < mMobileSignalControllers.size(); i++) {
             MobileSignalController controller = mMobileSignalControllers.valueAt(i);
             controller.setConfiguration(mConfig);
@@ -539,13 +554,39 @@
         doUpdateMobileControllers();
     }
 
+    private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
+        if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) {
+            SubscriptionInfo info1 = subscriptions.get(0);
+            SubscriptionInfo info2 = subscriptions.get(1);
+            if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
+                // If both subscriptions are primary, show both.
+                if (!info1.isOpportunistic() && !info2.isOpportunistic()) return;
+
+                // If carrier required, always show signal bar of primary subscription.
+                // Otherwise, show whichever subscription is currently active for Internet.
+                boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig()
+                        .getBoolean(CarrierConfigManager
+                        .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN);
+                if (alwaysShowPrimary) {
+                    subscriptions.remove(info1.isOpportunistic() ? info1 : info2);
+                } else {
+                    subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription
+                            ? info2 : info1);
+                }
+            }
+        }
+    }
+
     @VisibleForTesting
     void doUpdateMobileControllers() {
         List<SubscriptionInfo> subscriptions = mSubscriptionManager
-                .getActiveSubscriptionInfoList(true);
+                .getActiveSubscriptionInfoList(false);
         if (subscriptions == null) {
             subscriptions = Collections.emptyList();
         }
+
+        filterMobileSubscriptionInSameGroup(subscriptions);
+
         // If there have been no relevant changes to any of the subscriptions, we can leave as is.
         if (hasCorrectMobileControllers(subscriptions)) {
             // Even if the controllers are correct, make sure we have the right no sims state.
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 1596ddb..6e740b8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -55,6 +55,7 @@
     public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode)
     public static final int EVENT_SHOW_USB_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool)
     public static final int EVENT_DISMISS_USB_OVERHEAT_ALARM = 20; // (reason|int) (keyguard|bool)
+    public static final int EVENT_ODI_CAPTIONS_CLICK = 21;
 
     private static final String[] EVENT_TAGS = {
             "show_dialog",
@@ -77,7 +78,8 @@
             "zen_mode_config_changed",
             "ringer_toggle",
             "show_usb_overheat_alarm",
-            "dismiss_usb_overheat_alarm"
+            "dismiss_usb_overheat_alarm",
+            "odi_captions_click"
     };
 
     public static final int DISMISS_REASON_UNKNOWN = 0;
@@ -90,6 +92,7 @@
     public static final int DISMISS_STREAM_GONE = 7;
     public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8;
     public static final int DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED = 9;
+    public static final int DISMISS_REASON_ODI_CAPTIONS_CLICKED = 10;
     public static final String[] DISMISS_REASONS = {
             "unknown",
             "touch_outside",
@@ -100,7 +103,8 @@
             "done_clicked",
             "a11y_stream_changed",
             "output_chooser",
-            "usb_temperature_below_threshold"
+            "usb_temperature_below_threshold",
+            "odi_captions_clicked"
     };
 
     public static final int SHOW_REASON_UNKNOWN = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 4c16297..9192a25 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -48,6 +48,7 @@
 import android.provider.Settings;
 import android.service.notification.Condition;
 import android.service.notification.ZenModeConfig;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.accessibility.AccessibilityManager;
@@ -270,6 +271,22 @@
         mWorker.sendEmptyMessage(W.GET_STATE);
     }
 
+    public boolean areCaptionsEnabled() {
+        int currentValue = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.ODI_CAPTIONS_ENABLED, 0);
+        return currentValue == 1;
+    }
+
+    public void setCaptionsEnabled(boolean isEnabled) {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0);
+    }
+
+    public void getCaptionsComponentState() {
+        if (mDestroyed) return;
+        mWorker.sendEmptyMessage(W.GET_CAPTIONS_COMPONENT_STATE);
+    }
+
     public void notifyVisible(boolean visible) {
         if (mDestroyed) return;
         mWorker.obtainMessage(W.NOTIFY_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
@@ -365,6 +382,38 @@
         }
     }
 
+    private void onGetCaptionsComponentStateW() {
+        try {
+            String componentNameString = mContext.getString(
+                    com.android.internal.R.string.config_defaultSystemCaptionsService);
+            if (TextUtils.isEmpty(componentNameString)) {
+                // component doesn't exist
+                mCallbacks.onCaptionComponentStateChanged(false);
+                return;
+            }
+
+            if (D.BUG) {
+                Log.i(TAG, String.format(
+                        "isCaptionsServiceEnabled componentNameString=%s", componentNameString));
+            }
+
+            ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
+            if (componentName == null) {
+                mCallbacks.onCaptionComponentStateChanged(false);
+                return;
+            }
+
+            PackageManager packageManager = mContext.getPackageManager();
+            mCallbacks.onCaptionComponentStateChanged(
+                    packageManager.getComponentEnabledSetting(componentName)
+                    == PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+        } catch (Exception ex) {
+            Log.e(TAG,
+                    "isCaptionsServiceEnabled failed to check for captions component", ex);
+            mCallbacks.onCaptionComponentStateChanged(false);
+        }
+    }
+
     private void onAccessibilityModeChanged(Boolean showA11yStream) {
         mCallbacks.onAccessibilityModeChanged(showA11yStream);
     }
@@ -718,6 +767,7 @@
         private static final int USER_ACTIVITY = 13;
         private static final int SHOW_SAFETY_WARNING = 14;
         private static final int ACCESSIBILITY_MODE_CHANGED = 15;
+        private static final int GET_CAPTIONS_COMPONENT_STATE = 16;
 
         W(Looper looper) {
             super(looper);
@@ -740,8 +790,8 @@
                 case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0); break;
                 case USER_ACTIVITY: onUserActivityW(); break;
                 case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break;
+                case GET_CAPTIONS_COMPONENT_STATE: onGetCaptionsComponentStateW(); break;
                 case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj);
-
             }
         }
     }
@@ -881,6 +931,15 @@
                 });
             }
         }
+
+        @Override
+        public void onCaptionComponentStateChanged(Boolean isComponentEnabled) {
+            boolean componentEnabled = isComponentEnabled == null ? false : isComponentEnabled;
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(
+                        () -> entry.getKey().onCaptionComponentStateChanged(componentEnabled));
+            }
+        }
     }
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index ffd8206..398b309 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -29,6 +29,7 @@
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 
+import static com.android.systemui.volume.Events.DISMISS_REASON_ODI_CAPTIONS_CLICKED;
 import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
 
 import android.animation.ObjectAnimator;
@@ -125,6 +126,8 @@
     private ViewGroup mDialogRowsView;
     private ViewGroup mRinger;
     private ImageButton mRingerIcon;
+    private ViewGroup mODICaptionsView;
+    private ImageButton mODICaptionsIcon;
     private View mSettingsView;
     private ImageButton mSettingsIcon;
     private FrameLayout mZenIcon;
@@ -240,6 +243,10 @@
             mRingerIcon = mRinger.findViewById(R.id.ringer_icon);
             mZenIcon = mRinger.findViewById(R.id.dnd_icon);
         }
+        mODICaptionsView = mDialog.findViewById(R.id.odi_captions);
+        if (mODICaptionsView != null) {
+            mODICaptionsIcon = mODICaptionsView.findViewById(R.id.odi_captions_icon);
+        }
         mSettingsView = mDialog.findViewById(R.id.settings_container);
         mSettingsIcon = mDialog.findViewById(R.id.settings);
 
@@ -270,6 +277,7 @@
         updateRowsH(getActiveRow());
         initRingerH();
         initSettingsH();
+        initODICaptionsH();
     }
 
     protected ViewGroup getDialogView() {
@@ -478,6 +486,42 @@
         updateRingerH();
     }
 
+    private void initODICaptionsH() {
+        if (mODICaptionsIcon != null) {
+            mODICaptionsIcon.setOnClickListener(v -> {
+                onCaptionIconClicked();
+                Events.writeEvent(mContext, Events.EVENT_ODI_CAPTIONS_CLICK);
+                dismissH(DISMISS_REASON_ODI_CAPTIONS_CLICKED);
+            });
+        }
+
+        mController.getCaptionsComponentState();
+    }
+
+    private void updateODICaptionsH(boolean isServiceComponentEnabled) {
+        if (mODICaptionsView != null) {
+            mODICaptionsView.setVisibility(isServiceComponentEnabled ? VISIBLE : GONE);
+        }
+
+        if (!isServiceComponentEnabled) return;
+
+        updateCaptionsIcon();
+    }
+
+    private void updateCaptionsIcon() {
+        mHandler.post(
+                mODICaptionsIcon.setImageResourceAsync(
+                        mController.areCaptionsEnabled()
+                                ? R.drawable.ic_volume_odi_captions
+                                : R.drawable.ic_volume_odi_captions_disabled));
+    }
+
+    private void onCaptionIconClicked() {
+        boolean isEnabled = mController.areCaptionsEnabled();
+        mController.setCaptionsEnabled(!isEnabled);
+        updateCaptionsIcon();
+    }
+
     private void incrementManualToggleCount() {
         ContentResolver cr = mContext.getContentResolver();
         int ringerCount = Settings.Secure.getInt(cr, Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT, 0);
@@ -558,6 +602,7 @@
         mDialog.show();
         Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
         mController.notifyVisible(true);
+        mController.getCaptionsComponentState();
     }
 
     protected void rescheduleTimeoutH() {
@@ -1151,6 +1196,11 @@
             }
 
         }
+
+        @Override
+        public void onCaptionComponentStateChanged(Boolean isComponentEnabled) {
+            updateODICaptionsH(isComponentEnabled);
+        }
     };
 
     private final class H extends Handler {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 7797cb3..7bd4158 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -19,8 +19,10 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.when;
 
+import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
@@ -31,6 +33,7 @@
 import com.android.systemui.statusbar.AlertingNotificationManagerTest;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -53,15 +56,29 @@
     @Mock private VisualStabilityManager mVSManager;
     @Mock private StatusBar mBar;
 
+    private final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
+        TestableHeadsUpManagerPhone(Context context, View statusBarWindowView,
+                NotificationGroupManager groupManager, StatusBar bar,
+                VisualStabilityManager vsManager) {
+            super(context, statusBarWindowView, groupManager, bar, vsManager);
+            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
+            mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
+        }
+    }
+
     protected AlertingNotificationManager createAlertingNotificationManager() {
         return mHeadsUpManager;
     }
 
     @Before
     public void setUp() {
+        AccessibilityManagerWrapper mAccessibilityMgr =
+                mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
+        when(mAccessibilityMgr.getRecommendedTimeoutMillis(anyInt(), anyInt()))
+                .thenReturn(TEST_AUTO_DISMISS_TIME);
         when(mVSManager.isReorderingAllowed()).thenReturn(true);
-        mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarWindowView, mGroupManager,
-                mBar, mVSManager);
+        mHeadsUpManager = new TestableHeadsUpManagerPhone(mContext, mStatusBarWindowView,
+                mGroupManager, mBar, mVSManager);
         super.setUp();
         mHeadsUpManager.mHandler = mTestHandler;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
new file mode 100644
index 0000000..6b83fed
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.statusbar.AlertingNotificationManager;
+import com.android.systemui.statusbar.AlertingNotificationManagerTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
+    private static final int TEST_A11Y_AUTO_DISMISS_TIME = 600;
+    private static final int TEST_A11Y_TIMEOUT_TIME = 5_000;
+
+    private AccessibilityManagerWrapper mAccessibilityMgr;
+    private HeadsUpManager mHeadsUpManager;
+    private boolean mLivesPastNormalTime;
+
+    private final class TestableHeadsUpManager extends HeadsUpManager {
+        TestableHeadsUpManager(Context context) {
+            super(context);
+            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
+            mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
+        }
+    }
+
+    protected AlertingNotificationManager createAlertingNotificationManager() {
+        return mHeadsUpManager;
+    }
+
+    @Before
+    public void setUp() {
+        mAccessibilityMgr = mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
+
+        mHeadsUpManager = new TestableHeadsUpManager(mContext);
+        super.setUp();
+        mHeadsUpManager.mHandler = mTestHandler;
+    }
+
+    @Test
+    public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
+        doReturn(TEST_A11Y_AUTO_DISMISS_TIME).when(mAccessibilityMgr)
+                .getRecommendedTimeoutMillis(anyInt(), anyInt());
+        mHeadsUpManager.showNotification(mEntry);
+        Runnable pastNormalTimeRunnable =
+                () -> mLivesPastNormalTime = mHeadsUpManager.isAlerting(mEntry.key);
+        mTestHandler.postDelayed(pastNormalTimeRunnable,
+                        (TEST_A11Y_AUTO_DISMISS_TIME + TEST_AUTO_DISMISS_TIME) / 2);
+        mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_A11Y_TIMEOUT_TIME);
+
+        TestableLooper.get(this).processMessages(2);
+
+        assertFalse("Test timed out", mTimedOut);
+        assertTrue("Heads up should live long enough", mLivesPastNormalTime);
+        assertFalse(mHeadsUpManager.isAlerting(mEntry.key));
+    }
+}
+
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 9673a84..bc42863 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -260,6 +260,18 @@
     PREVIOUSLY_VISIBLE = 2;
   }
 
+  // Explanations for notification importance, derived from
+  // NotificationRecord.mImportanceExplanation.
+  enum NotificationImportanceExplanation {
+    IMPORTANCE_EXPLANATION_UNKNOWN = 0;
+    IMPORTANCE_EXPLANATION_APP = 1;     // App-specified channel importance.
+    IMPORTANCE_EXPLANATION_USER = 2;    // User-specified channel importance.
+    IMPORTANCE_EXPLANATION_ASST = 3;    // Notification Assistant override.
+    IMPORTANCE_EXPLANATION_SYSTEM = 4;  // System override.
+    // Like _APP, but based on pre-channels priority signal.
+    IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS = 5;
+  }
+
   // Known visual elements: views or controls.
   enum View {
     // Unknown view
@@ -7090,6 +7102,21 @@
     // Panel for Wifi
     PANEL_WIFI = 1687;
 
+    // Custom tag for NotificationItem. A NotificationImportanceExplanation.
+    FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION = 1688;
+
+    // Custom tag for NotificationItem. The initial "natural" importance.
+    FIELD_NOTIFICATION_IMPORTANCE_INITIAL = 1689;
+
+    // Custom tag for NotificationItem.  A NotificationImportanceExplanation.
+    // The source of the "natural" importance, if it was overridden.
+    FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION = 1690;
+
+    // Custom tag for NotificationItem. The Notification Assistant's
+    // override of importance. Logged separately only if it was
+    // overridden by the system.
+    FIELD_NOTIFICATION_IMPORTANCE_ASST = 1691;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 9f049cf..0d17f22 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1957,7 +1957,7 @@
   optional LinkProbeStatus probe_status_since_last_update = 24;
 
   // The elapsed time of the most recent link probe since last stats update;
-  optional int32 probe_elapsed_time_ms_since_last_update = 25;
+  optional int32 probe_elapsed_time_since_last_update_ms = 25;
 
   // The MCS rate of the most recent link probe since last stats update
   optional int32 probe_mcs_rate_since_last_update = 26;
@@ -2291,13 +2291,13 @@
   optional int32 count = 3;
 }
 
-// Single entry in a map from int32 => int32
-message MapEntryInt32Int32 {
+// Counts occurrences of a int32 key
+message Int32Count {
   // the key
   optional int32 key = 1;
 
-  // the value
-  optional int32 value = 2;
+  // the count
+  optional int32 count = 2;
 }
 
 message LinkProbeStats {
@@ -2328,16 +2328,16 @@
   }
 
   // Counts the occurrences of RSSI values when a link probe succeeds.
-  repeated MapEntryInt32Int32 success_rssi_counts = 1;
+  repeated Int32Count success_rssi_counts = 1;
 
   // Counts the occurrences of RSSI values when a link probe fails.
-  repeated MapEntryInt32Int32 failure_rssi_counts = 2;
+  repeated Int32Count failure_rssi_counts = 2;
 
   // Counts the occurrences of Link Speed values when a link probe succeeds.
-  repeated MapEntryInt32Int32 success_link_speed_counts = 3;
+  repeated Int32Count success_link_speed_counts = 3;
 
   // Counts the occurrences of Link Speed values when a link probe fails.
-  repeated MapEntryInt32Int32 failure_link_speed_counts = 4;
+  repeated Int32Count failure_link_speed_counts = 4;
 
   // Histogram for the number of seconds since the last TX success when a link probe succeeds.
   repeated HistogramBucketInt32 success_seconds_since_last_tx_success_histogram = 5;
@@ -2364,7 +2364,7 @@
   // same network selection as experiment2.
   // The keys are the number of network choices, and the values are the number of occurrences of
   // this number of network choices when exp1 and exp2 make the same network selection.
-  repeated MapEntryInt32Int32 same_selection_num_choices_counter = 3;
+  repeated Int32Count same_selection_num_choices_counter = 3;
 
   // Counts occurrences of the number of network choices there were when experiment1 makes the
   // same network selection as experiment2.
@@ -2372,7 +2372,7 @@
   // this number of network choices when exp1 and exp2 make different network selections.
   // Note that it is possible for the network selection to be different even when there only exists
   // a single network choice, since choosing not to connect to that network is a valid choice.
-  repeated MapEntryInt32Int32 different_selection_num_choices_counter = 4;
+  repeated Int32Count different_selection_num_choices_counter = 4;
 }
 
 // NetworkRequest API metrics.
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 4293157..85c82bc 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -16,12 +16,6 @@
 
 package android.renderscript;
 
-import java.io.File;
-import java.lang.reflect.Method;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.AssetManager;
@@ -32,6 +26,12 @@
 import android.util.Log;
 import android.view.Surface;
 
+import java.io.File;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
 // TODO: Clean up the whitespace that separates methods in this class.
 
 /**
@@ -114,8 +114,9 @@
                 Class<?> vm_runtime = Class.forName("dalvik.system.VMRuntime");
                 Method get_runtime = vm_runtime.getDeclaredMethod("getRuntime");
                 sRuntime = get_runtime.invoke(null);
-                registerNativeAllocation = vm_runtime.getDeclaredMethod("registerNativeAllocation", Integer.TYPE);
-                registerNativeFree = vm_runtime.getDeclaredMethod("registerNativeFree", Integer.TYPE);
+                registerNativeAllocation =
+                        vm_runtime.getDeclaredMethod("registerNativeAllocation", Long.TYPE);
+                registerNativeFree = vm_runtime.getDeclaredMethod("registerNativeFree", Long.TYPE);
             } catch (Exception e) {
                 Log.e(LOG_TAG, "Error loading GC methods: " + e);
                 throw new RSRuntimeException("Error loading GC methods: " + e);
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
index 1bf4e3a..6018f00 100644
--- a/services/core/java/com/android/server/BluetoothService.java
+++ b/services/core/java/com/android/server/BluetoothService.java
@@ -18,15 +18,26 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
+import android.os.SystemProperties;
 
 class BluetoothService extends SystemService {
+    private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless";
+
     private BluetoothManagerService mBluetoothManagerService;
+    private boolean mInitialized = false;
 
     public BluetoothService(Context context) {
         super(context);
         mBluetoothManagerService = new BluetoothManagerService(context);
     }
 
+    private void initialize() {
+        if (!mInitialized) {
+            mBluetoothManagerService.handleOnBootPhase();
+            mInitialized = true;
+        }
+    }
+
     @Override
     public void onStart() {
     }
@@ -36,13 +47,15 @@
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
             publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
                     mBluetoothManagerService);
-        } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
-            mBluetoothManagerService.handleOnBootPhase();
+        } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY &&
+                !SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false)) {
+            initialize();
         }
     }
 
     @Override
     public void onSwitchUser(int userHandle) {
+        initialize();
         mBluetoothManagerService.handleOnSwitchUser(userHandle);
     }
 
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 70733ef..ea23081 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -477,14 +477,22 @@
         // when processNextBroadcastLocked() next finds this uid as a receiver identity.
         if (!r.timeoutExempt) {
             if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
-                if (DEBUG_BROADCAST_DEFERRAL) {
-                    Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1)
-                            + " was slow: " + receiver + " br=" + r);
-                }
-                if (r.curApp != null) {
-                    mDispatcher.startDeferring(r.curApp.uid);
+                // Core system packages are exempt from deferral policy
+                if (!UserHandle.isCore(r.curApp.uid)) {
+                    if (DEBUG_BROADCAST_DEFERRAL) {
+                        Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1)
+                                + " was slow: " + receiver + " br=" + r);
+                    }
+                    if (r.curApp != null) {
+                        mDispatcher.startDeferring(r.curApp.uid);
+                    } else {
+                        Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r);
+                    }
                 } else {
-                    Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r);
+                    if (DEBUG_BROADCAST_DEFERRAL) {
+                        Slog.i(TAG_BROADCAST, "Core uid " + r.curApp.uid
+                                + " receiver was slow but not deferring: " + receiver + " br=" + r);
+                    }
                 }
             }
         } else {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 1e406c0..676cc33 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1547,8 +1547,8 @@
                     }
                     builder.append(" asks to run as user ");
                     builder.append(userId);
-                    builder.append(" but is calling from user ");
-                    builder.append(UserHandle.getUserId(callingUid));
+                    builder.append(" but is calling from uid ");
+                    UserHandle.formatUid(builder, callingUid);
                     builder.append("; this requires ");
                     builder.append(INTERACT_ACROSS_USERS_FULL);
                     if (allowMode != ALLOW_FULL_ONLY) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index ba7288e..9c26526 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1742,10 +1742,31 @@
         return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
     }
 
-    private int checkOperationUnchecked(int code, int uid, String packageName,
-                boolean raw) {
+    /**
+     * @see #checkOperationUnchecked(int, int, String, boolean, boolean)
+     */
+    private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
+            boolean raw) {
+        return checkOperationUnchecked(code, uid, packageName, raw, true);
+    }
+
+    /**
+     * Get the mode of an app-op.
+     *
+     * @param code The code of the op
+     * @param uid The uid of the package the op belongs to
+     * @param packageName The package the op belongs to
+     * @param raw If the raw state of eval-ed state should be checked.
+     * @param verify If the code should check the package belongs to the uid
+     *
+     * @return The mode of the op
+     */
+    private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
+                boolean raw, boolean verify) {
         synchronized (this) {
-            checkPackage(uid, packageName);
+            if (verify) {
+                checkPackage(uid, packageName);
+            }
             if (isOpRestrictedLocked(uid, code, packageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
@@ -1756,7 +1777,7 @@
                 final int rawMode = uidState.opModes.get(code);
                 return raw ? rawMode : uidState.evalMode(code, rawMode);
             }
-            Op op = getOpLocked(code, uid, packageName, false, true, false);
+            Op op = getOpLocked(code, uid, packageName, false, verify, false);
             if (op == null) {
                 return AppOpsManager.opToDefaultMode(code);
             }
@@ -2359,7 +2380,7 @@
         throw new IllegalArgumentException("Bad operation #" + op);
     }
 
-    private @NonNull UidState getUidStateLocked(int uid, boolean edit) {
+    private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
         UidState uidState = mUidStates.get(uid);
         if (uidState == null) {
             if (!edit) {
@@ -4535,5 +4556,10 @@
         public void setAllPkgModesToDefault(int code, int uid) {
             AppOpsService.this.setAllPkgModesToDefault(code, uid);
         }
+
+        @Override
+        public @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName) {
+            return AppOpsService.this.checkOperationUnchecked(code, uid, packageName, true, false);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 41a3c98..cb0bbd9 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -858,11 +858,20 @@
         if (musicDevice == AudioSystem.DEVICE_NONE) {
             musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC);
         }
-        // ignore condition on device being actually used for music when in communication
+
+        // always ignore condition on device being actually used for music when in communication
         // because music routing is altered in this case.
-        // also checks whether media routing if affected by a dynamic policy
+        // also checks whether media routing if affected by a dynamic policy or mirroring
         if (((device == musicDevice) || mDeviceBroker.isInCommunication())
-                && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy()) {
+                && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy()
+                        && ((musicDevice & AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) == 0)) {
+            if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/)) {
+                // no media playback, not a "becoming noisy" situation, otherwise it could cause
+                // the pausing of some apps that are playing remotely
+                AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+                        "dropping ACTION_AUDIO_BECOMING_NOISY, no media playback")).printLog(TAG));
+                return 0;
+            }
             mDeviceBroker.postBroadcastBecomingNoisy();
             delay = 1000;
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 91d19de..100113c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6387,7 +6387,28 @@
         return mProjectionService;
     }
 
-    public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
+    /**
+     * See {@link AudioManager#unregisterAudioPolicyAsync(AudioPolicy)}
+     * Declared oneway
+     * @param pcb nullable because on service interface
+     */
+    public void unregisterAudioPolicyAsync(@Nullable IAudioPolicyCallback pcb) {
+        unregisterAudioPolicy(pcb);
+    }
+
+    /**
+     * See {@link AudioManager#unregisterAudioPolicy(AudioPolicy)}
+     * @param pcb nullable because on service interface
+     */
+    public void unregisterAudioPolicy(@Nullable IAudioPolicyCallback pcb) {
+        if (pcb == null) {
+            return;
+        }
+        unregisterAudioPolicyInt(pcb);
+    }
+
+
+    private void unregisterAudioPolicyInt(@NonNull IAudioPolicyCallback pcb) {
         mDynPolicyLogger.log((new AudioEventLogger.StringEvent("unregisterAudioPolicyAsync for "
                 + pcb.asBinder()).printLog(TAG)));
         synchronized (mAudioPolicies) {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index d84a4d2..123564e 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -46,13 +46,11 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -84,20 +82,14 @@
     // Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission.
     private final Map<Integer, Boolean> mApps = new HashMap<>();
 
-    // Keys are App packageNames, Values are app uids. . We need to keep track of this information
-    // because PackageListObserver#onPackageRemoved does not pass the UID.
-    @GuardedBy("mPackageNameUidMap")
-    private final Map<String, Integer> mPackageNameUidMap = new HashMap<>();
-
     private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
         @Override
-        public void onPackageAdded(String packageName) {
+        public void onPackageAdded(String packageName, int uid) {
             final PackageInfo app = getPackageInfo(packageName);
             if (app == null) {
                 Slog.wtf(TAG, "Failed to get information of installed package: " + packageName);
                 return;
             }
-            int uid = (app.applicationInfo != null) ? app.applicationInfo.uid : INVALID_UID;
             if (uid == INVALID_UID) {
                 Slog.wtf(TAG, "Failed to get the uid of installed package: " + packageName
                         + "uid: " + uid);
@@ -107,29 +99,21 @@
                 return;
             }
             sendPackagePermissionsForUid(uid,
-                    filterPermission(Arrays.asList(app.requestedPermissions)));
-            synchronized (mPackageNameUidMap) {
-                mPackageNameUidMap.put(packageName, uid);
-            }
+                    getNetdPermissionMask(app.requestedPermissions));
         }
 
         @Override
-        public void onPackageRemoved(String packageName) {
-            int uid;
-            synchronized (mPackageNameUidMap) {
-                if (!mPackageNameUidMap.containsKey(packageName)) {
-                    return;
-                }
-                uid = mPackageNameUidMap.get(packageName);
-                mPackageNameUidMap.remove(packageName);
-            }
+        public void onPackageRemoved(String packageName, int uid) {
             int permission = 0;
+            // If there are still packages remain under the same uid, check the permission of the
+            // remaining packages. We only remove the permission for a given uid when all packages
+            // for that uid no longer have that permission.
             String[] packages = mPackageManager.getPackagesForUid(uid);
             if (packages != null && packages.length > 0) {
                 for (String name : packages) {
                     final PackageInfo app = getPackageInfo(name);
                     if (app != null && app.requestedPermissions != null) {
-                        permission |= filterPermission(Arrays.asList(app.requestedPermissions));
+                        permission |= getNetdPermissionMask(app.requestedPermissions);
                     }
                 }
             }
@@ -184,12 +168,9 @@
 
             //TODO: unify the management of the permissions into one codepath.
             if (app.requestedPermissions != null) {
-                int otherNetdPerms = filterPermission(Arrays.asList(app.requestedPermissions));
+                int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions);
                 if (otherNetdPerms != 0) {
                     netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
-                    synchronized (mPackageNameUidMap) {
-                        mPackageNameUidMap.put(app.applicationInfo.packageName, uid);
-                    }
                 }
             }
         }
@@ -422,13 +403,15 @@
         }
     }
 
-    private static int filterPermission(List<String> requestedPermissions) {
+    private static int getNetdPermissionMask(String[] requestedPermissions) {
         int permissions = 0;
-        if (requestedPermissions.contains(INTERNET)) {
-            permissions |= INetd.PERMISSION_INTERNET;
-        }
-        if (requestedPermissions.contains(UPDATE_DEVICE_STATS)) {
-            permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
+        for (String permissionName : requestedPermissions) {
+            if (permissionName.equals(INTERNET)) {
+                permissions |= INetd.PERMISSION_INTERNET;
+            }
+            if (permissionName.equals(UPDATE_DEVICE_STATS)) {
+                permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
+            }
         }
         return permissions;
     }
@@ -439,8 +422,6 @@
                     | MATCH_ANY_USER);
             return app;
         } catch (NameNotFoundException e) {
-            // App not found.
-            loge("NameNotFoundException " + packageName);
             return null;
         }
     }
diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/Light.java
index b5ec603..717e3da 100644
--- a/services/core/java/com/android/server/lights/Light.java
+++ b/services/core/java/com/android/server/lights/Light.java
@@ -16,8 +16,8 @@
 
 package com.android.server.lights;
 
-import android.hardware.light.V2_0.Flash;
 import android.hardware.light.V2_0.Brightness;
+import android.hardware.light.V2_0.Flash;
 
 public abstract class Light {
     public static final int LIGHT_FLASH_NONE = Flash.NONE;
@@ -39,8 +39,16 @@
      */
     public static final int BRIGHTNESS_MODE_LOW_PERSISTENCE = Brightness.LOW_PERSISTENCE;
 
+    /**
+     * Set the brightness of a display.
+     */
     public abstract void setBrightness(int brightness);
+
+    /**
+     * Set the brightness and mode of a display.
+     */
     public abstract void setBrightness(int brightness, int brightnessMode);
+
     public abstract void setColor(int color);
     public abstract void setFlashing(int color, int mode, int onMS, int offMS);
     public abstract void pulse();
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index a94ed60..ac906bb 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -15,15 +15,18 @@
 
 package com.android.server.lights;
 
-import com.android.server.SystemService;
-
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.Trace;
 import android.provider.Settings;
 import android.util.Slog;
+import android.view.SurfaceControl;
+
+import com.android.server.SystemService;
 
 public class LightsService extends SystemService {
     static final String TAG = "LightsService";
@@ -33,8 +36,25 @@
 
     private final class LightImpl extends Light {
 
-        private LightImpl(int id) {
+        private final IBinder mDisplayToken;
+        private final int mSurfaceControlMaximumBrightness;
+
+        private LightImpl(Context context, int id) {
             mId = id;
+            mDisplayToken = SurfaceControl.getInternalDisplayToken();
+            final boolean brightnessSupport = SurfaceControl.getDisplayBrightnessSupport(
+                    mDisplayToken);
+            if (DEBUG) {
+                Slog.d(TAG, "Display brightness support: " + brightnessSupport);
+            }
+            int maximumBrightness = 0;
+            if (brightnessSupport) {
+                PowerManager pm = context.getSystemService(PowerManager.class);
+                if (pm != null) {
+                    maximumBrightness = pm.getMaximumScreenBrightnessSetting();
+                }
+            }
+            mSurfaceControlMaximumBrightness = maximumBrightness;
         }
 
         @Override
@@ -51,10 +71,26 @@
                             ": brightness=0x" + Integer.toHexString(brightness));
                     return;
                 }
-
-                int color = brightness & 0x000000ff;
-                color = 0xff000000 | (color << 16) | (color << 8) | color;
-                setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
+                // Ideally, we'd like to set the brightness mode through the SF/HWC as well, but
+                // right now we just fall back to the old path through Lights brightessMode is
+                // anything but USER or the device shouldBeInLowPersistenceMode().
+                if (brightnessMode == BRIGHTNESS_MODE_USER && !shouldBeInLowPersistenceMode()
+                        && mSurfaceControlMaximumBrightness == 255) {
+                    // TODO: the last check should be mSurfaceControlMaximumBrightness != 0; the
+                    // reason we enforce 255 right now is to stay consistent with the old path. In
+                    // the future, the framework should be refactored so that brightness is a float
+                    // between 0.0f and 1.0f, and the actual number of supported brightness levels
+                    // is determined in the device-specific implementation.
+                    if (DEBUG) {
+                        Slog.d(TAG, "Using new setBrightness path!");
+                    }
+                    SurfaceControl.setDisplayBrightness(mDisplayToken,
+                            (float) brightness / mSurfaceControlMaximumBrightness);
+                } else {
+                    int color = brightness & 0x000000ff;
+                    color = 0xff000000 | (color << 16) | (color << 8) | color;
+                    setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
+                }
             }
         }
 
@@ -172,7 +208,7 @@
         super(context);
 
         for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
-            mLights[i] = new LightImpl(i);
+            mLights[i] = new LightImpl(context, i);
         }
     }
 
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index b86328b..94f289f 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -64,6 +64,7 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -138,9 +139,9 @@
     private MediaSessionRecord mGlobalPrioritySession;
     private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
 
-    // Used to notify system UI when remote volume was changed. TODO find a
-    // better way to handle this.
-    private IRemoteVolumeController mRvc;
+    // Used to notify System UI and Settings when remote volume was changed.
+    final RemoteCallbackList<IRemoteVolumeController> mRemoteVolumeControllers =
+            new RemoteCallbackList<>();
 
     public MediaSessionServiceImpl(Context context) {
         mContext = context;
@@ -281,20 +282,23 @@
     }
 
     /**
-     * Tells the system UI that volume has changed on an active remote session.
+     * Tells the System UI and Settings app that volume has changed on an active remote session.
      */
     public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
-        synchronized (mLock) {
-            if (mRvc == null || !session.isActive()) {
-                return;
-            }
+        if (!session.isActive()) {
+            return;
+        }
+        int size = mRemoteVolumeControllers.beginBroadcast();
+        MediaSession.Token token = session.getSessionToken();
+        for (int i = size - 1; i >= 0; i--) {
             try {
-                mRvc.remoteVolumeChanged(session.getSessionToken(), flags);
+                IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
+                cb.remoteVolumeChanged(token, flags);
             } catch (Exception e) {
-                Log.w(TAG, "Error sending volume change to system UI.", e);
-                mRvc = null;
+                Log.w(TAG, "Error sending volume change.", e);
             }
         }
+        mRemoteVolumeControllers.finishBroadcast();
     }
 
     @Override
@@ -497,7 +501,7 @@
      */
     private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
             int resolvedUserId) {
-        if (isCurrentVolumeController(pid, uid)) return;
+        if (hasStatusBarServicePermission(pid, uid)) return;
         if (mContext
                 .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
                 != PackageManager.PERMISSION_GRANTED
@@ -507,14 +511,14 @@
         }
     }
 
-    private boolean isCurrentVolumeController(int pid, int uid) {
+    private boolean hasStatusBarServicePermission(int pid, int uid) {
         return mContext.checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
                 pid, uid) == PackageManager.PERMISSION_GRANTED;
     }
 
-    private void enforceSystemUiPermission(String action, int pid, int uid) {
-        if (!isCurrentVolumeController(pid, uid)) {
-            throw new SecurityException("Only system ui may " + action);
+    private void enforceStatusBarServicePermission(String action, int pid, int uid) {
+        if (!hasStatusBarServicePermission(pid, uid)) {
+            throw new SecurityException("Only System UI and Settings may " + action);
         }
     }
 
@@ -638,20 +642,25 @@
     }
 
     private void pushRemoteVolumeUpdateLocked(int userId) {
-        if (mRvc != null) {
+        FullUserRecord user = getFullUserRecordLocked(userId);
+        if (user == null) {
+            Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
+            return;
+        }
+
+        int size = mRemoteVolumeControllers.beginBroadcast();
+        MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
+        MediaSession.Token token = record == null ? null : record.getSessionToken();
+
+        for (int i = size - 1; i >= 0; i--) {
             try {
-                FullUserRecord user = getFullUserRecordLocked(userId);
-                if (user == null) {
-                    Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
-                    return;
-                }
-                MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
-                mRvc.updateRemoteController(record == null ? null : record.getSessionToken());
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error sending default remote volume to sys ui.", e);
-                mRvc = null;
+                IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
+                cb.updateRemoteController(token);
+            } catch (Exception e) {
+                Log.w(TAG, "Error sending default remote volume.", e);
             }
         }
+        mRemoteVolumeControllers.finishBroadcast();
     }
 
     void pushSession2TokensChangedLocked(int userId) {
@@ -1661,15 +1670,26 @@
         }
 
         @Override
-        public void setRemoteVolumeController(IRemoteVolumeController rvc) {
+        public void registerRemoteVolumeController(IRemoteVolumeController rvc) {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                enforceSystemUiPermission("listen for volume changes", pid, uid);
-                synchronized (mLock) {
-                    mRvc = rvc;
-                }
+                enforceStatusBarServicePermission("listen for volume changes", pid, uid);
+                mRemoteVolumeControllers.register(rvc);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void unregisterRemoteVolumeController(IRemoteVolumeController rvc) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                enforceStatusBarServicePermission("listen for volume changes", pid, uid);
+                mRemoteVolumeControllers.unregister(rvc);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1755,8 +1775,8 @@
 
         private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
                 int pid, int uid) throws RemoteException {
-            // Allow API calls from the System UI
-            if (isCurrentVolumeController(pid, uid)) {
+            // Allow API calls from the System UI and Settings
+            if (hasStatusBarServicePermission(pid, uid)) {
                 return true;
             }
 
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 46ce4bf..d9ab132 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -149,7 +149,10 @@
     private int mImportance = IMPORTANCE_UNSPECIFIED;
     // Field used in global sort key to bypass normal notifications
     private int mCriticality = CriticalNotificationExtractor.NORMAL;
-    private CharSequence mImportanceExplanation = null;
+    // A MetricsEvent.NotificationImportanceExplanation, tracking source of mImportance.
+    private int mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN;
+    // A MetricsEvent.NotificationImportanceExplanation for initial importance.
+    private int mInitialImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN;
 
     private int mSuppressedVisualEffects = 0;
     private String mUserExplanation;
@@ -332,14 +335,18 @@
 
     private int calculateInitialImportance() {
         final Notification n = sbn.getNotification();
-        int importance = getChannel().getImportance();
-        int requestedImportance = IMPORTANCE_DEFAULT;
+        int importance = getChannel().getImportance();  // Post-channels notifications use this
+        mInitialImportanceExplanationCode = getChannel().hasUserSetImportance()
+                ? MetricsEvent.IMPORTANCE_EXPLANATION_USER
+                : MetricsEvent.IMPORTANCE_EXPLANATION_APP;
 
-        // Migrate notification flags to scores
+        // Migrate notification priority flag to a priority value.
         if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
             n.priority = Notification.PRIORITY_MAX;
         }
 
+        // Convert priority value to an importance value, used only for pre-channels notifications.
+        int requestedImportance = IMPORTANCE_DEFAULT;
         n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN,
                 Notification.PRIORITY_MAX);
         switch (n.priority) {
@@ -360,10 +367,11 @@
         stats.requestedImportance = requestedImportance;
         stats.isNoisy = mSound != null || mVibration != null;
 
+        // For pre-channels notifications, apply system overrides and then use requestedImportance
+        // as importance.
         if (mPreChannelsNotification
                 && (importance == IMPORTANCE_UNSPECIFIED
-                || (getChannel().getUserLockedFields()
-                & USER_LOCKED_IMPORTANCE) == 0)) {
+                || (!getChannel().hasUserSetImportance()))) {
             if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) {
                 requestedImportance = IMPORTANCE_LOW;
             }
@@ -378,6 +386,8 @@
                 requestedImportance = IMPORTANCE_HIGH;
             }
             importance = requestedImportance;
+            mInitialImportanceExplanationCode =
+                    MetricsEvent.IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS;
         }
 
         stats.naturalImportance = importance;
@@ -540,7 +550,7 @@
                 + NotificationListenerService.Ranking.importanceToString(mAssistantImportance));
         pw.println(prefix + "mImportance="
                 + NotificationListenerService.Ranking.importanceToString(mImportance));
-        pw.println(prefix + "mImportanceExplanation=" + mImportanceExplanation);
+        pw.println(prefix + "mImportanceExplanation=" + getImportanceExplanation());
         pw.println(prefix + "mIsAppImportanceLocked=" + mIsAppImportanceLocked);
         pw.println(prefix + "mIntercept=" + mIntercept);
         pw.println(prefix + "mHidden==" + mHidden);
@@ -760,23 +770,23 @@
     }
 
     /**
-     * Recalculates the importance of the record after fields affecting importance have changed
+     * Recalculates the importance of the record after fields affecting importance have changed,
+     * and records an explanation.
      */
     protected void calculateImportance() {
         mImportance = calculateInitialImportance();
-        mImportanceExplanation = "app";
-        if (getChannel().hasUserSetImportance()) {
-            mImportanceExplanation = "user";
-        }
+        mImportanceExplanationCode = mInitialImportanceExplanationCode;
+
+        // Consider Notification Assistant and system overrides to importance. If both, system wins.
         if (!getChannel().hasUserSetImportance()
                 && mAssistantImportance != IMPORTANCE_UNSPECIFIED
                 && !getChannel().isImportanceLockedByOEM()) {
             mImportance = mAssistantImportance;
-            mImportanceExplanation = "asst";
+            mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_ASST;
         }
         if (mSystemImportance != IMPORTANCE_UNSPECIFIED) {
             mImportance = mSystemImportance;
-            mImportanceExplanation = "system";
+            mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM;
         }
     }
 
@@ -785,7 +795,20 @@
     }
 
     public CharSequence getImportanceExplanation() {
-        return mImportanceExplanation;
+        switch (mImportanceExplanationCode) {
+            case MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN:
+                return null;
+            case MetricsEvent.IMPORTANCE_EXPLANATION_APP:
+            case MetricsEvent.IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS:
+                return "app";
+            case MetricsEvent.IMPORTANCE_EXPLANATION_USER:
+                return "user";
+            case MetricsEvent.IMPORTANCE_EXPLANATION_ASST:
+                return "asst";
+            case MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM:
+                return "system";
+        }
+        return null;
     }
 
     public boolean setIntercepted(boolean intercept) {
@@ -1242,14 +1265,37 @@
     }
 
     public LogMaker getLogMaker(long now) {
-        return sbn.getLogMaker()
-                .clearTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX)
+        LogMaker lm = sbn.getLogMaker()
                 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance)
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now))
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS,
                         getInterruptionMs(now));
+        // Record results of the calculateImportance() calculation if available.
+        if (mImportanceExplanationCode != MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN) {
+            lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION,
+                    mImportanceExplanationCode);
+            // To avoid redundancy, we log the initial importance information only if it was
+            // overridden.
+            if (((mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_ASST)
+                    || (mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM))
+                    && (stats.naturalImportance != IMPORTANCE_UNSPECIFIED)) {
+                // stats.naturalImportance is due to one of the 3 sources of initial importance.
+                lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION,
+                        mInitialImportanceExplanationCode);
+                lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL,
+                        stats.naturalImportance);
+            }
+            // Log Assistant override if it was itself overridden by System. Since System can't be
+            // overridden, it never needs logging.
+            if (mImportanceExplanationCode == MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM
+                    && mAssistantImportance != IMPORTANCE_UNSPECIFIED) {
+                lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST,
+                        mAssistantImportance);
+            }
+        }
+        return lm;
     }
 
     public LogMaker getLogMaker() {
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 3c1ee3e..cd0cbd6 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -10,76 +10,48 @@
 toddke@google.com
 
 # apex support
-per-file ApexManager.java = dariofreni@google.com, narayan@google.com, toddke@android.com, toddke@google.com
-per-file StagingManager.java = dariofreni@google.com, narayan@google.com, toddke@android.com, toddke@google.com
+per-file ApexManager.java = dariofreni@google.com
+per-file StagingManager.java = dariofreni@google.com
 
 # dex
-per-file AbstractStatsBase.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file AbstractStatsBase.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file AbstractStatsBase.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file BackgroundDexOptService.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file BackgroundDexOptService.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file BackgroundDexOptService.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file CompilerStats.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file CompilerStats.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file CompilerStats.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file DynamicCodeLoggingService.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file DynamicCodeLoggingService.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file DynamicCodeLoggingService.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file InstructionSets.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file InstructionSets.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file InstructionSets.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptService.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptService.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptService.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptShellCommand.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptShellCommand.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptShellCommand.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageDexOptimizer.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageDexOptimizer.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageDexOptimizer.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageManagerServiceCompilerMapping.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageManagerServiceCompilerMapping.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageManagerServiceCompilerMapping.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageUsage.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageUsage.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageUsage.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
+per-file AbstractStatsBase.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file BackgroundDexOptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file CompilerStats.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file DynamicCodeLoggingService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file InstructionSets.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file OtaDexoptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file OtaDexoptShellCommand.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file PackageDexOptimizer.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file PackageManagerServiceCompilerMapping.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file PackageUsage.java = agampe@google.com, calin@google.com, ngeoffray@google.com
 
 # multi user / cross profile
-per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file CrossProfileAppsServiceImpl.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file CrossProfileAppsService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file CrossProfileAppsService.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file CrossProfileIntentFilter.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file CrossProfileIntentFilter.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file CrossProfileIntentResolver.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file UserManagerService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file UserManagerService.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file UserRestrictionsUtils.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file UserRestrictionsUtils.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file UserRestrictionsUtils.java = rubinxu@google.com, yamasani@google.com, hackbod@google.com
-per-file UserRestrictionsUtils.java = sandness@google.com, yamasani@google.com, hackbod@google.com
+per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com
+per-file CrossProfileAppsService.java = omakoto@google.com, yamasani@google.com
+per-file CrossProfileIntentFilter.java = omakoto@google.com, yamasani@google.com
+per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com
+per-file UserManagerService.java = omakoto@google.com, yamasani@google.com
+per-file UserRestrictionsUtils.java = omakoto@google.com, rubinxu@google.com, sandness@google.com, yamasani@google.com
 
 # security
-per-file KeySetHandle.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com
-per-file KeySetManagerService.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com
-per-file PackageKeySetData.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com
-per-file PackageSignatures.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com
-per-file SELinuxMMAC.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com
+per-file KeySetHandle.java = cbrubaker@google.com
+per-file KeySetManagerService.java = cbrubaker@google.com
+per-file PackageKeySetData.java = cbrubaker@google.com
+per-file PackageSignatures.java = cbrubaker@google.com
+per-file SELinuxMMAC.java = cbrubaker@google.com
 
 # shortcuts
-per-file LauncherAppsService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShareTargetInfo.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutBitmapSaver.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutDumpFiles.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutLauncher.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutNonPersistentUser.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutPackage.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutPackageInfo.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutPackageItem.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutParser.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutRequestPinProcessor.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutUser.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
+per-file LauncherAppsService.java = omakoto@google.com, yamasani@google.com
+per-file ShareTargetInfo.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutBitmapSaver.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutDumpFiles.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutLauncher.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutNonPersistentUser.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutPackage.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutPackageInfo.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutPackageItem.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutParser.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutRequestPinProcessor.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutService.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutUser.java = omakoto@google.com, yamasani@google.com
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 45b3b5b..2de50e2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -510,6 +510,13 @@
         }
     }
 
+    /** {@hide} */
+    boolean isCommitted() {
+        synchronized (mLock) {
+            return mCommitted;
+        }
+    }
+
     @GuardedBy("mLock")
     private void assertPreparedAndNotSealedLocked(String cookie) {
         assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
@@ -1064,7 +1071,13 @@
 
     private void handleCommit() {
         if (params.isStaged) {
-            mStagingManager.commitSession(this);
+            try {
+                mStagingManager.commitSession(this);
+            } catch (StagingManager.AlreadyInProgressStagedSessionException e) {
+                dispatchSessionFinished(
+                        PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
+                        e.getMessage(), null);
+            }
             destroyInternal();
             dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
             return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4dcab5e..6f006e7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1952,7 +1952,7 @@
             }
 
             if (allNewUsers && !update) {
-                notifyPackageAdded(packageName);
+                notifyPackageAdded(packageName, res.uid);
             }
 
             // Log current value of "unknown sources" setting
@@ -12317,7 +12317,7 @@
     }
 
     @Override
-    public void notifyPackageAdded(String packageName) {
+    public void notifyPackageAdded(String packageName, int uid) {
         final PackageListObserver[] observers;
         synchronized (mPackages) {
             if (mPackageListObservers.size() == 0) {
@@ -12328,7 +12328,7 @@
             observers = mPackageListObservers.toArray(observerArray);
         }
         for (int i = observers.length - 1; i >= 0; --i) {
-            observers[i].onPackageAdded(packageName);
+            observers[i].onPackageAdded(packageName, uid);
         }
     }
 
@@ -12339,7 +12339,7 @@
     };
 
     @Override
-    public void notifyPackageRemoved(String packageName) {
+    public void notifyPackageRemoved(String packageName, int uid) {
         final PackageListObserver[] observers;
         synchronized (mPackages) {
             if (mPackageListObservers.size() == 0) {
@@ -12350,7 +12350,7 @@
             observers = mPackageListObservers.toArray(observerArray);
         }
         for (int i = observers.length - 1; i >= 0; --i) {
-            observers[i].onPackageRemoved(packageName);
+            observers[i].onPackageRemoved(packageName, uid);
         }
     }
 
@@ -17904,7 +17904,8 @@
                 return;
             }
             Bundle extras = new Bundle(2);
-            extras.putInt(Intent.EXTRA_UID, removedAppId >= 0  ? removedAppId : uid);
+            final int removedUid = removedAppId >= 0  ? removedAppId : uid;
+            extras.putInt(Intent.EXTRA_UID, removedUid);
             extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
             extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
             if (isUpdate || isRemovedPackageSystemUpdate) {
@@ -17925,7 +17926,7 @@
                         removedPackage, extras,
                         Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
                         null, null, broadcastUsers, instantUserIds);
-                    packageSender.notifyPackageRemoved(removedPackage);
+                    packageSender.notifyPackageRemoved(removedPackage, removedUid);
                 }
             }
             if (removedAppId >= 0) {
@@ -24410,6 +24411,6 @@
         final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds);
     void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
         boolean includeStopped, int appId, int[] userIds, int[] instantUserIds);
-    void notifyPackageAdded(String packageName);
-    void notifyPackageRemoved(String packageName);
+    void notifyPackageAdded(String packageName, int uid);
+    void notifyPackageRemoved(String packageName, int uid);
 }
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 4ee6eaf..088146d 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.apex.ApexInfo;
 import android.apex.ApexInfoList;
 import android.apex.ApexSessionInfo;
@@ -479,11 +480,42 @@
         return true;
     }
 
-    void commitSession(@NonNull PackageInstallerSession session) {
+    void commitSession(@NonNull PackageInstallerSession session)
+            throws AlreadyInProgressStagedSessionException {
+        PackageInstallerSession activeSession = getActiveSession();
+        boolean anotherSessionAlreadyInProgress =
+                activeSession != null && session.sessionId != activeSession.sessionId;
         updateStoredSession(session);
+        if (anotherSessionAlreadyInProgress) {
+            session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                    "There is already in-progress committed staged session "
+                            + activeSession.sessionId);
+            throw new AlreadyInProgressStagedSessionException(activeSession.sessionId);
+        }
         mBgHandler.post(() -> preRebootVerification(session));
     }
 
+    @Nullable
+    private PackageInstallerSession getActiveSession() {
+        synchronized (mStagedSessions) {
+            for (int i = 0; i < mStagedSessions.size(); i++) {
+                final PackageInstallerSession session = mStagedSessions.valueAt(i);
+                if (!session.isCommitted()) {
+                    continue;
+                }
+                if (session.hasParentSessionId()) {
+                    // Staging manager will finalize only parent session. Ignore child sessions
+                    // picking the active.
+                    continue;
+                }
+                if (!session.isStagedSessionApplied() && !session.isStagedSessionFailed()) {
+                    return session;
+                }
+            }
+        }
+        return null;
+    }
+
     void createSession(@NonNull PackageInstallerSession sessionInfo) {
         synchronized (mStagedSessions) {
             mStagedSessions.append(sessionInfo.sessionId, sessionInfo);
@@ -497,8 +529,8 @@
     }
 
     void abortCommittedSession(@NonNull PackageInstallerSession session) {
-        if (session.isStagedSessionApplied()) {
-            Slog.w(TAG, "Cannot abort applied session!");
+        if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) {
+            Slog.w(TAG, "Cannot abort already finalized session : " + session.sessionId);
             return;
         }
         abortSession(session);
@@ -618,4 +650,12 @@
             }
         }
     }
+
+    static final class AlreadyInProgressStagedSessionException extends Exception {
+
+        AlreadyInProgressStagedSessionException(int sessionId) {
+            super("There is already in-progress committed staged session "
+                    + sessionId);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 3b805d51..f56231f 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -16,7 +16,7 @@
 
 package com.android.server.pm.dex;
 
-import static android.provider.DeviceConfig.DexBoot;
+import static android.provider.DeviceConfig.NAMESPACE_DEX_BOOT;
 
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
@@ -72,6 +72,10 @@
     private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
             "pm.dexopt.priv-apps-oob-list";
 
+    // flags for Device Config API
+    private static final String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled";
+    private static final String PRIV_APPS_OOB_WHITELIST = "priv_apps_oob_whitelist";
+
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final Context mContext;
@@ -713,8 +717,8 @@
         return isPackageSelectedToRunOobInternal(
                 SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false),
                 SystemProperties.get(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, "ALL"),
-                DeviceConfig.getProperty(DexBoot.NAMESPACE, DexBoot.PRIV_APPS_OOB_ENABLED),
-                DeviceConfig.getProperty(DexBoot.NAMESPACE, DexBoot.PRIV_APPS_OOB_WHITELIST),
+                DeviceConfig.getProperty(NAMESPACE_DEX_BOOT, PRIV_APPS_OOB_ENABLED),
+                DeviceConfig.getProperty(NAMESPACE_DEX_BOOT, PRIV_APPS_OOB_WHITELIST),
                 packageNamesInSameProcess);
     }
 
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 f7d8e0e..897b885 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1273,7 +1273,7 @@
             @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm,
             @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
             @UserIdInt int userId) {
-        AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+        AppOpsManagerInternal appOpsManager = LocalServices.getService(AppOpsManagerInternal.class);
         String pkgName = pkg.packageName;
 
         if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
@@ -1287,10 +1287,10 @@
                     String sourcePerm = sourcePerms.valueAt(i);
 
                     if (ps.hasRuntimePermission(sourcePerm, userId)) {
-                        String sourceOp = permissionToOp(sourcePerm);
+                        int sourceOp = permissionToOpCode(sourcePerm);
 
-                        if (sourceOp != null) {
-                            int mode = appOpsManager.unsafeCheckOpRaw(sourceOp,
+                        if (sourceOp != OP_NONE) {
+                            int mode = appOpsManager.checkOperationUnchecked(sourceOp,
                                     getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName);
 
                             if (mode == MODE_FOREGROUND || mode == MODE_ERRORED) {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 871f9f8..952399b 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -684,7 +684,8 @@
      * @param status the RollbackManager.STATUS_* code with the failure.
      * @param message the failure message.
      */
-    private void sendFailure(IntentSender statusReceiver, int status, String message) {
+    private void sendFailure(IntentSender statusReceiver, @RollbackManager.Status int status,
+            String message) {
         Log.e(TAG, message);
         try {
             final Intent fillIn = new Intent();
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 86dc66d..d364a37 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -306,10 +306,10 @@
 
     private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
         @Override
-        public void onPackageAdded(String packageName) { }
+        public void onPackageAdded(String packageName, int uid) { }
 
         @Override
-        public void onPackageRemoved(String packageName) {
+        public void onPackageRemoved(String packageName, int uid) {
             removeRecordForPackage(packageName);
         }
     }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 300cd17..db7613a 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -193,8 +193,8 @@
     }
 
     DisplayContent getTopFocusedDisplayContent() {
-        return getDisplayContent(mTopFocusedDisplayId == INVALID_DISPLAY
-                ? DEFAULT_DISPLAY : mTopFocusedDisplayId);
+        final DisplayContent dc = getDisplayContent(mTopFocusedDisplayId);
+        return dc != null ? dc : getDisplayContent(DEFAULT_DISPLAY);
     }
 
     @Override
@@ -1045,6 +1045,15 @@
         mWmService.scheduleAnimationLocked();
     }
 
+    @Override
+    protected void removeChild(DisplayContent dc) {
+        super.removeChild(dc);
+        if (mTopFocusedDisplayId == dc.getDisplayId()) {
+            mWmService.updateFocusedWindowLocked(
+                    UPDATE_FOCUS_NORMAL, true /* updateInputWindows */);
+        }
+    }
+
     /**
      * For all display at or below this call the callback.
      *
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c16de5b..3999edd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -65,7 +65,7 @@
 import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
 import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN;
 import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
-import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_SUCCESS;
+import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_NO_ERROR;
 import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
 import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
@@ -14010,7 +14010,7 @@
                             "Host provided for opportunistic mode, but is not needed.");
                 }
                 putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, null);
-                return PRIVATE_DNS_SET_SUCCESS;
+                return PRIVATE_DNS_SET_NO_ERROR;
             case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
                 if (TextUtils.isEmpty(privateDnsHost)
                         || !NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
@@ -14023,7 +14023,7 @@
                 putPrivateDnsSettings(
                         ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
                         privateDnsHost);
-                return PRIVATE_DNS_SET_SUCCESS;
+                return PRIVATE_DNS_SET_NO_ERROR;
             default:
                 throw new IllegalArgumentException(
                         String.format("Provided mode, %d, is not a valid mode.", mode));
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 111fb74..4cfd098 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -56,11 +56,11 @@
             }
 
             @Override
-            public void notifyPackageAdded(String packageName) {
+            public void notifyPackageAdded(String packageName, int uid) {
             }
 
             @Override
-            public void notifyPackageRemoved(String packageName) {
+            public void notifyPackageRemoved(String packageName, int uid) {
             }
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
index 1f86171..958b23f 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -175,9 +175,9 @@
     /** Verify app usage limit observer is added */
     @Test
     public void testAppUsageLimitObserver_AddObserver() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1));
-        addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, 0);
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID2));
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1));
     }
@@ -203,7 +203,7 @@
     /** Verify app usage limit observer is removed */
     @Test
     public void testAppUsageLimitObserver_RemoveObserver() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1));
         mController.removeAppUsageLimitObserver(UID, OBS_ID1, USER_ID);
         assertFalse("Observer wasn't removed", hasAppUsageLimitObserver(UID, OBS_ID1));
@@ -290,9 +290,9 @@
     /** Re-adding an observer should result in only one copy */
     @Test
     public void testAppUsageLimitObserver_ObserverReAdd() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1));
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, TIME_10_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, 0);
         assertTrue("Observer wasn't added",
                 getAppUsageLimitObserver(UID, OBS_ID1).getTimeLimitMs() == TIME_10_MIN);
         mController.removeAppUsageLimitObserver(UID, OBS_ID1, USER_ID);
@@ -304,7 +304,7 @@
     public void testAllObservers_ExclusiveObserverIds() {
         addAppUsageObserver(OBS_ID1, GROUP1, TIME_10_MIN);
         addUsageSessionObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_1_MIN);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, TIME_10_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, 0);
         assertTrue("Observer wasn't added", hasAppUsageObserver(UID, OBS_ID1));
         assertTrue("Observer wasn't added", hasUsageSessionObserver(UID, OBS_ID1));
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1));
@@ -396,7 +396,7 @@
     @Test
     public void testAppUsageLimitObserver_Accumulation() throws Exception {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         startUsage(PKG_SOC1);
         // Add 10 mins
         setTime(TIME_10_MIN);
@@ -456,7 +456,7 @@
     @Test
     public void testAppUsageLimitObserver_TimeoutOtherApp() throws Exception {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 4_000L);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 0);
         startUsage(PKG_SOC2);
         assertFalse(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS));
         setTime(6_000L);
@@ -498,7 +498,7 @@
     @Test
     public void testAppUsageLimitObserver_Timeout() throws Exception {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 4_000L);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 0);
         startUsage(PKG_SOC1);
         setTime(6_000L);
         assertTrue(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS));
@@ -551,7 +551,7 @@
         setTime(TIME_10_MIN);
         startUsage(PKG_GAME1);
         setTime(TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, 0);
         setTime(TIME_30_MIN + TIME_10_MIN);
         stopUsage(PKG_GAME1);
         assertFalse(mLimitReachedLatch.await(1_000L, TimeUnit.MILLISECONDS));
@@ -612,7 +612,7 @@
         startUsage(PKG_SOC1);
         setTime(TIME_10_MIN);
         // 10 second time limit
-        addAppUsageLimitObserver(OBS_ID1, GROUP_SOC, 10_000L, 10_000L);
+        addAppUsageLimitObserver(OBS_ID1, GROUP_SOC, 10_000L, 0);
         setTime(TIME_10_MIN + 5_000L);
         // Shouldn't call back in 6 seconds
         assertFalse(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS));
@@ -692,23 +692,23 @@
     public void testAppUsageLimitObserver_MaxObserverLimit() throws Exception {
         boolean receivedException = false;
         int ANOTHER_UID = UID + 1;
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID2, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID3, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID4, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID6, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID7, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID8, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID9, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID10, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID2, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID3, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID4, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID6, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID7, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID8, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID9, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID10, GROUP1, TIME_30_MIN, 0);
         // Readding an observer should not cause an IllegalStateException
-        addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, 0);
         // Adding an observer for a different uid shouldn't cause an IllegalStateException
         mController.addAppUsageLimitObserver(
-                ANOTHER_UID, OBS_ID11, GROUP1, TIME_30_MIN, TIME_30_MIN, null, USER_ID);
+                ANOTHER_UID, OBS_ID11, GROUP1, TIME_30_MIN, 0, null, USER_ID);
         try {
-            addAppUsageLimitObserver(OBS_ID11, GROUP1, TIME_30_MIN, TIME_30_MIN);
+            addAppUsageLimitObserver(OBS_ID11, GROUP1, TIME_30_MIN, 0);
         } catch (IllegalStateException ise) {
             receivedException = true;
         }
@@ -748,9 +748,9 @@
     public void testAppUsageLimitObserver_MinimumTimeLimit() throws Exception {
         boolean receivedException = false;
         // adding an observer with a one minute time limit should not cause an exception
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT, MIN_TIME_LIMIT);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT, 0);
         try {
-            addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT - 1, MIN_TIME_LIMIT - 1);
+            addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT - 1, 0);
         } catch (IllegalArgumentException iae) {
             receivedException = true;
         }
@@ -807,7 +807,7 @@
     @Test
     public void testAppUsageLimitObserver_ConcurrentUsage() throws Exception {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         AppTimeLimitController.UsageGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
         startUsage(PKG_SOC1);
         // Add 10 mins
@@ -967,7 +967,7 @@
     /** Verify app usage limit observer added correctly reports its total usage limit */
     @Test
     public void testAppUsageLimitObserver_GetTotalUsageLimit() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
         assertNotNull("Observer wasn't added", group);
         assertEquals("Observer didn't correctly report total usage limit",
@@ -978,7 +978,7 @@
     @Test
     public void testAppUsageLimitObserver_GetUsageRemaining() {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         startUsage(PKG_SOC1);
         setTime(TIME_10_MIN);
         stopUsage(PKG_SOC1);
@@ -993,8 +993,8 @@
      */
     @Test
     public void testAppUsageLimitObserver_GetAppUsageLimit() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, 0);
         UsageStatsManagerInternal.AppUsageLimitData group = getAppUsageLimit(PKG_SOC1);
         assertEquals("Observer with the smallest usage limit remaining wasn't returned",
                 TIME_10_MIN, group.getTotalUsageLimit());
@@ -1006,8 +1006,8 @@
     @Test
     public void testAppUsageLimitObserver_GetAppUsageLimitUsed() {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, 0);
         startUsage(PKG_GAME1);
         setTime(TIME_10_MIN * 2 + TIME_1_MIN);
         stopUsage(PKG_GAME1);
@@ -1024,8 +1024,8 @@
     @Test
     public void testAppUsageLimitObserver_GetAppUsageLimitAllUsed() {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, 0);
         startUsage(PKG_SOC1);
         setTime(TIME_10_MIN);
         stopUsage(PKG_SOC1);
@@ -1046,10 +1046,10 @@
         }
     }
 
-    /** Verify that a limit of 0 is allowed for the special case of re-registering an observer. */
+    /** Verify that timeUsed can be the same as timeLimit (for re-registering observers). */
     @Test
     public void testAppUsageLimitObserver_ZeroTimeRemainingIsAllowed() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_1_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_1_MIN, TIME_1_MIN);
         AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
         assertNotNull("Observer wasn't added", group);
         assertEquals("Usage remaining was not 0.", 0, group.getUsageRemaining());
@@ -1078,8 +1078,8 @@
     }
 
     private void addAppUsageLimitObserver(int observerId, String[] packages, long timeLimit,
-            long timeRemaining) {
-        mController.addAppUsageLimitObserver(UID, observerId, packages, timeLimit, timeRemaining,
+            long timeUsed) {
+        mController.addAppUsageLimitObserver(UID, observerId, packages, timeLimit, timeUsed,
                 null, USER_ID);
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 7df52b2..4626840 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -117,6 +117,7 @@
 import android.util.AtomicFile;
 
 import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.R;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -311,6 +312,9 @@
 
     @Before
     public void setUp() throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+                "android.permission.WRITE_DEVICE_CONFIG", "android.permission.READ_DEVICE_CONFIG");
+
         MockitoAnnotations.initMocks(this);
 
         LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
@@ -392,6 +396,8 @@
     public void tearDown() throws Exception {
         mFile.delete();
         clearDeviceConfig();
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation().dropShellPermissionIdentity();
     }
 
     public void waitForIdle() {
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 9f11472..e375195 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -19,6 +19,7 @@
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.service.notification.Adjustment.KEY_IMPORTANCE;
 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
@@ -423,6 +424,138 @@
                 (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS));
         assertEquals(record.getInterruptionMs(timestamp),
                 (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS));
+        // If no importance calculation has been run, no explanation is available.
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION));
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL));
+        assertNull(logMaker.getTaggedData(
+                MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION));
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST));
+    }
+
+    @Test
+    public void testLogMakerImportanceApp() {
+        long timestamp = 1000L;
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, null /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        record.calculateImportance();  // This importance calculation will yield 'app'
+        final LogMaker logMaker = record.getLogMaker(timestamp);
+        assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_APP,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION));
+        assertEquals(channel.getImportance(),
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE));
+        // The additional information is only populated if the initial importance is overridden.
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL));
+        assertNull(logMaker.getTaggedData(
+                MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION));
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST));
+    }
+
+    @Test
+    public void testLogMakerImportanceAsst() {
+        long timestamp = 1000L;
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, null /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        Bundle signals = new Bundle();
+        signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
+        record.addAdjustment(new Adjustment(PKG_O, KEY_IMPORTANCE, signals, "", uid));
+        record.applyAdjustments();
+        record.calculateImportance();  // This importance calculation will yield 'asst'
+        final LogMaker logMaker = record.getLogMaker(timestamp);
+        assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_ASST,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION));
+        // Therefore this is the assistant-set importance
+        assertEquals(IMPORTANCE_LOW,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE));
+        // Initial importance is populated so we know what it was, since it didn't get used.
+        assertEquals(channel.getImportance(),
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL));
+        assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_APP,
+                logMaker.getTaggedData(
+                        MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION));
+        // This field is only populated if the assistant was itself overridden by the system.
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST));
+    }
+
+    @Test
+    public void testLogMakerImportanceSystem() {
+        long timestamp = 1000L;
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, null /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        record.setSystemImportance(IMPORTANCE_HIGH);
+        record.calculateImportance();  // This importance calculation will yield 'system'
+        final LogMaker logMaker = record.getLogMaker(timestamp);
+        assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION));
+        // Therefore this is the system-set importance
+        assertEquals(IMPORTANCE_HIGH,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE));
+        // Initial importance is populated so we know what it was, since it didn't get used.
+        assertEquals(channel.getImportance(),
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL));
+        assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_APP,
+                logMaker.getTaggedData(
+                        MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION));
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST));
+    }
+
+    @Test
+    public void testLogMakerImportanceUser() {
+        long timestamp = 1000L;
+        channel.lockFields(channel.USER_LOCKED_IMPORTANCE);
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, null /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        record.calculateImportance();  // This importance calculation will yield 'user'
+        final LogMaker logMaker = record.getLogMaker(timestamp);
+        assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_USER,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION));
+        // Therefore this is the user-set importance
+        assertEquals(channel.getImportance(),
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE));
+        // The additional information is only populated if the initial importance is overridden.
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL));
+        assertNull(logMaker.getTaggedData(
+                MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION));
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST));
+    }
+
+    @Test
+    public void testLogMakerImportanceMulti() {
+        long timestamp = 1000L;
+        channel.lockFields(channel.USER_LOCKED_IMPORTANCE);
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, null /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        // Add all 3 ways of overriding the app-set importance of the notification
+        Bundle signals = new Bundle();
+        signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
+        record.addAdjustment(new Adjustment(PKG_O, KEY_IMPORTANCE, signals, "", uid));
+        record.applyAdjustments();
+        record.setSystemImportance(IMPORTANCE_HIGH);
+        record.calculateImportance();  // This importance calculation will yield 'system'
+        final LogMaker logMaker = record.getLogMaker(timestamp);
+        assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_SYSTEM,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_EXPLANATION));
+        // Therefore this is the system-set importance
+        assertEquals(IMPORTANCE_HIGH,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE));
+        // Initial importance is populated so we know what it was, since it didn't get used.
+        assertEquals(channel.getImportance(),
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL));
+        assertEquals(MetricsEvent.IMPORTANCE_EXPLANATION_USER, logMaker.getTaggedData(
+                MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_INITIAL_EXPLANATION));
+        // Assistant importance is populated so we know what it was, since it didn't get used.
+        assertEquals(IMPORTANCE_LOW, logMaker.getTaggedData(
+                MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST));
     }
 
     @Test
@@ -807,7 +940,7 @@
         assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
 
         Bundle bundle = new Bundle();
-        bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
+        bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
         Adjustment adjustment = new Adjustment(
                 PKG_O, record.getKey(), bundle, "", record.getUserId());
 
@@ -831,7 +964,7 @@
         assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
 
         Bundle bundle = new Bundle();
-        bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
+        bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
         Adjustment adjustment = new Adjustment(
                 PKG_O, record.getKey(), bundle, "", record.getUserId());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 83c0af9..c072d4e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -59,7 +59,7 @@
     public void setUpOnDisplay(DisplayContent dc) {
         mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(dc);
+        mToken = WindowTestUtils.createTestAppWindowToken(dc, false /* skipOnParentChanged */);
 
         mTask.addChild(mToken, 0);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index db04f11..a98a604 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -60,7 +60,7 @@
         MockitoAnnotations.initMocks(this);
 
         mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
-                ACTIVITY_TYPE_STANDARD);
+                ACTIVITY_TYPE_STANDARD, false /* skipOnParentChanged */);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 70c8c93..68b40b9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -81,7 +81,8 @@
     public void setUp() throws Exception {
         mStack = createTaskStackOnDisplay(mDisplayContent);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
+        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent,
+                false /* skipOnParentChanged */);
 
         mTask.addChild(mToken, 0);
     }
@@ -218,6 +219,9 @@
 
     @Test
     public void testSizeCompatBounds() {
+        // The real surface transaction is unnecessary.
+        mToken.setSkipPrepareSurfaces(true);
+
         final Rect fixedBounds = mToken.getRequestedOverrideConfiguration().windowConfiguration
                 .getBounds();
         fixedBounds.set(0, 0, 1200, 1600);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index aeda473..e4d3770 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -316,7 +316,7 @@
     public void testClearsRecordInMemoryOnPackageUninstalled() {
         mTarget.saveTask(mTestTask);
 
-        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName());
+        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName(), TEST_USER_ID);
 
         mTarget.getLaunchParams(mTestTask, null, mResult);
 
@@ -327,7 +327,7 @@
     public void testClearsWriteQueueItemOnPackageUninstalled() {
         mTarget.saveTask(mTestTask);
 
-        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName());
+        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName(), TEST_USER_ID);
 
         final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor,
                 mUserFolderGetter);
@@ -344,7 +344,7 @@
         mTarget.saveTask(mTestTask);
         mPersisterQueue.flush();
 
-        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName());
+        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName(), TEST_USER_ID);
 
         final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor,
                 mUserFolderGetter);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index a7a785d..0dec8ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -56,15 +56,24 @@
 
     static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) {
         synchronized (dc.mWmService.mGlobalLock) {
-            return new TestAppWindowToken(dc);
+            return new TestAppWindowToken(dc, true /* skipOnParentChanged */);
+        }
+    }
+
+    static TestAppWindowToken createTestAppWindowToken(DisplayContent dc,
+            boolean skipOnParentChanged) {
+        synchronized (dc.mWmService.mGlobalLock) {
+            return new TestAppWindowToken(dc, skipOnParentChanged);
         }
     }
 
     /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
     static class TestAppWindowToken extends AppWindowToken {
         boolean mOnTop = false;
+        private boolean mSkipPrepareSurfaces;
+        boolean mSkipOnParentChanged = true;
 
-        private TestAppWindowToken(DisplayContent dc) {
+        private TestAppWindowToken(DisplayContent dc, boolean skipOnParentChanged) {
             super(dc.mWmService, new IApplicationToken.Stub() {
                 @Override
                 public String getName() {
@@ -72,6 +81,7 @@
                 }
             }, new ComponentName("", ""), false, dc, true /* fillsParent */);
             mTargetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT;
+            mSkipOnParentChanged = skipOnParentChanged;
             mActivityRecord = mock(ActivityRecord.class);
             mActivityRecord.app = mock(WindowProcessController.class);
         }
@@ -93,10 +103,44 @@
         }
 
         @Override
+        void onParentChanged() {
+            if (!mSkipOnParentChanged) {
+                super.onParentChanged();
+            } else {
+                updateConfigurationFromParent(this);
+            }
+        }
+
+        @Override
         boolean isOnTop() {
             return mOnTop;
         }
 
+        @Override
+        void prepareSurfaces() {
+            if (!mSkipPrepareSurfaces) {
+                super.prepareSurfaces();
+            }
+        }
+
+        void setSkipPrepareSurfaces(boolean ignore) {
+            mSkipPrepareSurfaces = ignore;
+        }
+    }
+
+    /**
+     * Used when we don't want to perform surface related operation in
+     * {@link WindowContainer#onParentChanged} or the overridden method, but the configuration
+     * still needs to propagate from parent.
+     *
+     * @see ConfigurationContainer#onParentChanged
+     */
+    static void updateConfigurationFromParent(WindowContainer container) {
+        final WindowContainer parent = container.getParent();
+        if (parent != null) {
+            container.onConfigurationChanged(parent.getConfiguration());
+            container.onMergedOverrideConfigurationChanged();
+        }
     }
 
     static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
@@ -202,5 +246,10 @@
 
             mHasSurface = hadSurface;
         }
+
+        @Override
+        void onParentChanged() {
+            updateConfigurationFromParent(this);
+        }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index fb698d9..032eba1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -269,10 +269,16 @@
 
     WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
             windowingMode, int activityType) {
+        return createTestAppWindowToken(dc, windowingMode, activityType,
+                false /*skipOnParentChanged */);
+    }
+
+    WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
+            windowingMode, int activityType, boolean skipOnParentChanged) {
         final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
         final Task task = createTaskInStack(stack, 0 /* userId */);
         final WindowTestUtils.TestAppWindowToken appWindowToken =
-                WindowTestUtils.createTestAppWindowToken(dc);
+                WindowTestUtils.createTestAppWindowToken(dc, skipOnParentChanged);
         task.addChild(appWindowToken, 0);
         return appWindowToken;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 7d7c398..2fc6efa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -43,6 +43,7 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import org.junit.After;
@@ -211,6 +212,7 @@
         return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name);
     }
 
+    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForImeWithNoTarget() {
         mDisplayContent.mInputMethodTarget = null;
@@ -228,6 +230,7 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
+    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForImeWithAppTarget() {
         final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -247,6 +250,7 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
+    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
         final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -273,6 +277,7 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
+    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
         final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
@@ -296,6 +301,7 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
+    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForImeNonAppImeTarget() {
         final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
@@ -323,6 +329,7 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
+    @FlakyTest(bugId = 124088319)
     @Test
     public void testAssignWindowLayers_ForStatusBarImeTarget() {
         mDisplayContent.mInputMethodTarget = mStatusBarWindow;
@@ -337,6 +344,7 @@
         assertWindowHigher(mImeDialogWindow, mImeWindow);
     }
 
+    @FlakyTest(bugId = 124088319)
     @Test
     public void testStackLayers() {
         final WindowState anyWindow1 = createWindow("anyWindow");
@@ -424,6 +432,7 @@
         }
     }
 
+    @FlakyTest(bugId = 124088319)
     @Test
     public void testDockedDividerPosition() {
         final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index f3d6387..6861ad1 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -511,10 +511,10 @@
 
     class AppUsageLimitGroup extends UsageGroup {
         public AppUsageLimitGroup(UserData user, ObserverAppData observerApp, int observerId,
-                String[] observed, long timeLimitMs, long timeRemainingMs,
+                String[] observed, long timeLimitMs, long timeUsedMs,
                 PendingIntent limitReachedCallback) {
             super(user, observerApp, observerId, observed, timeLimitMs, limitReachedCallback);
-            mUsageTimeMs = timeLimitMs - timeRemainingMs;
+            mUsageTimeMs = timeUsedMs;
         }
 
         @Override
@@ -841,7 +841,7 @@
      * Existing app usage limit observer with the same observerId will be removed.
      */
     public void addAppUsageLimitObserver(int requestingUid, int observerId, String[] observed,
-            long timeLimit, long timeRemaining, PendingIntent callbackIntent,
+            long timeLimit, long timeUsed, PendingIntent callbackIntent,
             @UserIdInt int userId) {
         if (timeLimit < getMinTimeLimit()) {
             throw new IllegalArgumentException("Time limit must be >= " + getMinTimeLimit());
@@ -861,7 +861,7 @@
                         "Too many app usage observers added by uid " + requestingUid);
             }
             group = new AppUsageLimitGroup(user, observerApp, observerId, observed, timeLimit,
-                    timeRemaining, timeRemaining == 0L ? null : callbackIntent);
+                    timeUsed, timeUsed >= timeLimit ? null : callbackIntent);
             observerApp.appUsageLimitGroups.append(observerId, group);
 
             if (DEBUG) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 27fdbcb..1ec680f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1399,7 +1399,7 @@
 
         @Override
         public void registerAppUsageLimitObserver(int observerId, String[] packages,
-                long timeLimitMs, long timeRemainingMs, PendingIntent callbackIntent,
+                long timeLimitMs, long timeUsedMs, PendingIntent callbackIntent,
                 String callingPackage) {
             if (!hasPermissions(callingPackage,
                     Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) {
@@ -1410,11 +1410,7 @@
             if (packages == null || packages.length == 0) {
                 throw new IllegalArgumentException("Must specify at least one package");
             }
-            if (timeRemainingMs > timeLimitMs) {
-                throw new IllegalArgumentException(
-                        "Remaining time can't be greater than total time.");
-            }
-            if (callbackIntent == null && timeRemainingMs != 0L) {
+            if (callbackIntent == null && timeUsedMs < timeLimitMs) {
                 throw new NullPointerException("callbackIntent can't be null");
             }
             final int callingUid = Binder.getCallingUid();
@@ -1422,7 +1418,7 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 UsageStatsService.this.registerAppUsageLimitObserver(callingUid, observerId,
-                        packages, timeLimitMs, timeRemainingMs, callbackIntent, userId);
+                        packages, timeLimitMs, timeUsedMs, callbackIntent, userId);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1550,9 +1546,9 @@
     }
 
     void registerAppUsageLimitObserver(int callingUid, int observerId, String[] packages,
-            long timeLimitMs, long timeRemainingMs, PendingIntent callbackIntent, int userId) {
+            long timeLimitMs, long timeUsedMs, PendingIntent callbackIntent, int userId) {
         mAppTimeLimit.addAppUsageLimitObserver(callingUid, observerId, packages,
-                timeLimitMs, timeRemainingMs, callbackIntent, userId);
+                timeLimitMs, timeUsedMs, callbackIntent, userId);
     }
 
     void unregisterAppUsageLimitObserver(int callingUid, int observerId, int userId) {
diff --git a/telephony/java/android/telephony/DebugEventReporter.java b/telephony/java/android/telephony/AnomalyReporter.java
similarity index 82%
rename from telephony/java/android/telephony/DebugEventReporter.java
rename to telephony/java/android/telephony/AnomalyReporter.java
index 14b7dd6..9753d8b 100644
--- a/telephony/java/android/telephony/DebugEventReporter.java
+++ b/telephony/java/android/telephony/AnomalyReporter.java
@@ -29,7 +29,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
-import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
@@ -37,7 +36,7 @@
 /**
  * A Simple Surface for Telephony to notify a loosely-coupled debugger of particular issues.
  *
- * DebugEventReporter allows an optional external logging component to receive events detected by
+ * AnomalyReporter allows an optional external logging component to receive events detected by
  * the framework and take action. This log surface is designed to provide maximium flexibility
  * to the receiver of these events. Envisioned use cases of this include notifying a vendor
  * component of: an event that necessitates (timely) log collection on non-AOSP components;
@@ -49,8 +48,8 @@
  *
  * @hide
  */
-public final class DebugEventReporter {
-    private static final String TAG = "DebugEventReporter";
+public final class AnomalyReporter {
+    private static final String TAG = "AnomalyReporter";
 
     private static Context sContext = null;
 
@@ -63,12 +62,12 @@
      */
     private static String sDebugPackageName = null;
 
-    private DebugEventReporter() {};
+    private AnomalyReporter() {};
 
     /**
      * If enabled, build and send an intent to a Debug Service for logging.
      *
-     * This method sends the {@link TelephonyManager#DEBUG_EVENT DEBUG_EVENT} broadcast, which is
+     * This method sends the {@link TelephonyManager#ACTION_ANOMALY_REPORTED} broadcast, which is
      * system protected. Invoking this method unless you are the system will result in an error.
      *
      * @param eventId a fixed event ID that will be sent for each instance of the same event. This
@@ -77,9 +76,9 @@
      *        identification and discussion of this event. This description should ideally be
      *        static and must not contain any sensitive information (especially PII).
      */
-    public static void sendEvent(@NonNull UUID eventId, String description) {
+    public static void reportAnomaly(@NonNull UUID eventId, String description) {
         if (sContext == null) {
-            Rlog.w(TAG, "DebugEventReporter not yet initialized, dropping event=" + eventId);
+            Rlog.w(TAG, "AnomalyReporter not yet initialized, dropping event=" + eventId);
             return;
         }
 
@@ -94,28 +93,28 @@
         // so drop these events silently.
         if (sDebugPackageName == null) return;
 
-        Intent dbgIntent = new Intent(TelephonyManager.ACTION_DEBUG_EVENT);
-        dbgIntent.putExtra(TelephonyManager.EXTRA_DEBUG_EVENT_ID, new ParcelUuid(eventId));
+        Intent dbgIntent = new Intent(TelephonyManager.ACTION_ANOMALY_REPORTED);
+        dbgIntent.putExtra(TelephonyManager.EXTRA_ANOMALY_ID, new ParcelUuid(eventId));
         if (description != null) {
-            dbgIntent.putExtra(TelephonyManager.EXTRA_DEBUG_EVENT_DESCRIPTION, description);
+            dbgIntent.putExtra(TelephonyManager.EXTRA_ANOMALY_DESCRIPTION, description);
         }
         dbgIntent.setPackage(sDebugPackageName);
         sContext.sendBroadcast(dbgIntent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
     }
 
     /**
-     * Initialize the DebugEventReporter with the current context.
+     * Initialize the AnomalyReporter with the current context.
      *
-     * This method must be invoked before any calls to sendEvent() will succeed. This method should
-     * only be invoked at most once.
+     * This method must be invoked before any calls to reportAnomaly() will succeed. This method
+     * should only be invoked at most once.
      *
-     * @param context a Context object used to initialize this singleton DebugEventReporter in
+     * @param context a Context object used to initialize this singleton AnomalyReporter in
      *        the current process.
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public static void initialize(@NonNull Context context) {
         if (context == null) {
-            throw new IllegalArgumentException("DebugEventReporter needs a non-null context.");
+            throw new IllegalArgumentException("AnomalyReporter needs a non-null context.");
         }
 
         // Ensure that this context has sufficient permissions to send debug events.
@@ -129,13 +128,13 @@
         PackageManager pm = sContext.getPackageManager();
         if (pm == null) return;
         List<ResolveInfo> packages = pm.queryBroadcastReceivers(
-                new Intent(TelephonyManager.ACTION_DEBUG_EVENT),
+                new Intent(TelephonyManager.ACTION_ANOMALY_REPORTED),
                 PackageManager.MATCH_SYSTEM_ONLY
                         | PackageManager.MATCH_DIRECT_BOOT_AWARE
                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
         if (packages == null || packages.isEmpty()) return;
         if (packages.size() > 1) {
-            Rlog.e(TAG, "Multiple DebugEvent Receivers installed.");
+            Rlog.e(TAG, "Multiple Anomaly Receivers installed.");
         }
 
         for (ResolveInfo r : packages) {
@@ -156,14 +155,14 @@
         // Initialization may only be performed once.
     }
 
-    /** Dump the contents of the DebugEventReporter */
+    /** Dump the contents of the AnomalyReporter */
     public static void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
         if (sContext == null) return;
         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
         sContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP");
         pw.println("Initialized=" + (sContext != null ? "Yes" : "No"));
         pw.println("Debug Package=" + sDebugPackageName);
-        pw.println("Event Counts:");
+        pw.println("Anomaly Counts:");
         pw.increaseIndent();
         for (UUID event : sEvents.keySet()) {
             pw.println(event + ": " + sEvents.get(event));
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d79a168..524d080 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2520,6 +2520,18 @@
             "emergency_number_prefix_string_array";
 
     /**
+     * Indicates when a carrier has a primary subscription and an opportunistic subscription active,
+     * and when Internet data is switched to opportunistic network, whether to still show
+     * signal bar of primary network. By default it will be false, meaning whenever data
+     * is going over opportunistic network, signal bar will reflect signal strength and rat
+     * icon of that network.
+     *
+     * @hide
+     */
+    public static final String KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN =
+            "always_show_primary_signal_bar_in_opportunistic_network_boolean";
+
+    /**
      * GPS configs. See android.hardware.gnss@1.0 IGnssConfiguration.
      * @hide
      */
@@ -3052,6 +3064,8 @@
         sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]);
         sDefaults.putBoolean(KEY_USE_USIM_BOOL, false);
         sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false);
+        sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN,
+                false);
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 6c835dc..e5aadad 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -86,7 +86,7 @@
         }
 
         if ((mMccStr != null && mMncStr == null) || (mMccStr == null && mMncStr != null)) {
-            DebugEventReporter.sendEvent(
+            AnomalyReporter.reportAnomaly(
                     UUID.fromString("a3ab0b9d-f2aa-4baf-911d-7096c0d4645a"),
                     "CellIdentity Missing Half of PLMN ID");
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 16dafd6..0c6bc48 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1383,41 +1383,42 @@
      * in the application manifest. For performance reasons, if no application to receive these
      * events is detected at boot, then these events will not be sent.
      *
-     * <p>Each event will include an {@link EXTRA_DEBUG_EVENT_ID} that will uniquely identify the
+     * <p>Each event will include an {@link EXTRA_ANOMALY_ID} that will uniquely identify the
      * event that has occurred. Each event will be sent to the diagnostic monitor only once per
      * boot cycle (as another optimization).
      *
-     * @see #EXTRA_DEBUG_EVENT_ID
-     * @see #EXTRA_DEBUG_EVENT_DESCRIPTION
+     * @see #EXTRA_ANOMALY_ID
+     * @see #EXTRA_ANOMALY_DESCRIPTION
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public static final String ACTION_DEBUG_EVENT = "android.telephony.action.DEBUG_EVENT";
+    public static final String ACTION_ANOMALY_REPORTED =
+            "android.telephony.action.ANOMALY_REPORTED";
 
     /**
      * An arbitrary ParcelUuid which should be consistent for each occurrence of a DebugEvent.
      *
-     * This field must be included in all {@link ACTION_DEBUG_EVENT} events.
+     * This field must be included in all {@link ACTION_ANOMALY_REPORTED} events.
      *
-     * @see #ACTION_DEBUG_EVENT
+     * @see #ACTION_ANOMALY_REPORTED
      * @hide
      */
     @SystemApi
-    public static final String EXTRA_DEBUG_EVENT_ID = "android.telephony.extra.DEBUG_EVENT_ID";
+    public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
 
     /**
-     * A freeform string description of the DebugEvent.
+     * A freeform string description of the Anomaly.
      *
-     * This field is optional for all {@link ACTION_DEBUG_EVENT}s, as a guideline should not
+     * This field is optional for all {@link ACTION_ANOMALY_REPORTED}s, as a guideline should not
      * exceed 80 characters, and should be as short as possible to convey the essence of the event.
      *
-     * @see #ACTION_DEBUG_EVENT
+     * @see #ACTION_ANOMALY_REPORTED
      * @hide
      */
     @SystemApi
-    public static final String EXTRA_DEBUG_EVENT_DESCRIPTION =
-            "android.telephony.extra.DEBUG_EVENT_DESCRIPTION";
+    public static final String EXTRA_ANOMALY_DESCRIPTION =
+            "android.telephony.extra.ANOMALY_DESCRIPTION";
 
     //
     //
@@ -5188,6 +5189,40 @@
     }
 
     /**
+     * Opens a logical channel to the ICC card using the physical slot index.
+     *
+     * Use this method when no subscriptions are available on the SIM and the operation must be
+     * performed using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHO command.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
+     * @param slotIndex the physical slot index of the ICC card
+     * @param aid Application id. See ETSI 102.221 and 101.220.
+     * @param p2 P2 parameter (described in ISO 7816-4).
+     * @return an IccOpenLogicalChannelResponse object.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
+    @Nullable
+    public IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int slotIndex,
+            @Nullable String aid, int p2) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.iccOpenLogicalChannelBySlot(slotIndex, getOpPackageName(), aid,
+                        p2);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return null;
+    }
+
+    /**
      * Opens a logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
@@ -5231,6 +5266,38 @@
     }
 
     /**
+     * Closes a previously opened logical channel to the ICC card using the physical slot index.
+     *
+     * Use this method when no subscriptions are available on the SIM and the operation must be
+     * performed using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHC command.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
+     * @param slotIndex the physical slot index of the ICC card
+     * @param channel is the channel id to be closed as returned by a successful
+     *            iccOpenLogicalChannel.
+     * @return true if the channel was closed successfully.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
+    @Nullable
+    public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.iccCloseLogicalChannelBySlot(slotIndex, channel);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return false;
+    }
+
+    /**
      * Closes a previously opened logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
@@ -5239,7 +5306,7 @@
      * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
      * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
-     * @param channel is the channel id to be closed as retruned by a successful
+     * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      */
@@ -5257,7 +5324,7 @@
      * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription to use.
-     * @param channel is the channel id to be closed as retruned by a successful
+     * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      * @hide
@@ -5274,6 +5341,48 @@
     }
 
     /**
+     * Transmit an APDU to the ICC card over a logical channel using the physical slot index.
+     *
+     * Use this method when no subscriptions are available on the SIM and the operation must be
+     * performed using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CGLA command.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
+     * @param slotIndex the physical slot index of the ICC card
+     * @param channel is the channel id to be closed as returned by a successful
+     *            iccOpenLogicalChannel.
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
+    @Nullable
+    public String iccTransmitApduLogicalChannelBySlot(int slotIndex, int channel, int cla,
+            int instruction, int p1, int p2, int p3, @Nullable String data) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.iccTransmitApduLogicalChannelBySlot(slotIndex, channel, cla,
+                        instruction, p1, p2, p3, data);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return null;
+    }
+
+    /**
      * Transmit an APDU to the ICC card over a logical channel.
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
@@ -5337,6 +5446,46 @@
     }
 
     /**
+     * Transmit an APDU to the ICC card over the basic channel using the physical slot index.
+     *
+     * Use this method when no subscriptions are available on the SIM and the operation must be
+     * performed using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CSIM command.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
+     * @param slotIndex the physical slot index of the ICC card to target
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
+    @NonNull
+    public String iccTransmitApduBasicChannelBySlot(int slotIndex, int cla, int instruction, int p1,
+            int p2, int p3, @Nullable String data) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.iccTransmitApduBasicChannelBySlot(slotIndex, getOpPackageName(),
+                        cla, instruction, p1, p2, p3, data);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return null;
+    }
+
+    /**
      * Transmit an APDU to the ICC card over the basic channel.
      *
      * Input parameters equivalent to TS 27.007 AT+CSIM command.
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 0b1d1fb..d0b52c9 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1641,6 +1641,7 @@
          *
          * @param entryName the entry name to set for the APN
          */
+        @NonNull
         public Builder setEntryName(String entryName) {
             this.mEntryName = entryName;
             return this;
@@ -1651,6 +1652,7 @@
          *
          * @param apnName the name to set for the APN
          */
+        @NonNull
         public Builder setApnName(String apnName) {
             this.mApnName = apnName;
             return this;
@@ -1681,6 +1683,7 @@
          *
          * @param proxy the proxy address to set for the APN
          */
+        @NonNull
         public Builder setProxyAddress(String proxy) {
             this.mProxyAddress = proxy;
             return this;
@@ -1691,6 +1694,7 @@
          *
          * @param port the proxy port to set for the APN
          */
+        @NonNull
         public Builder setProxyPort(int port) {
             this.mProxyPort = port;
             return this;
@@ -1701,6 +1705,7 @@
          *
          * @param mmsc the MMSC Uri to set for the APN
          */
+        @NonNull
         public Builder setMmsc(Uri mmsc) {
             this.mMmsc = mmsc;
             return this;
@@ -1732,6 +1737,7 @@
          *
          * @param mmsProxy the MMS proxy address to set for the APN
          */
+        @NonNull
         public Builder setMmsProxyAddress(String mmsProxy) {
             this.mMmsProxyAddress = mmsProxy;
             return this;
@@ -1742,6 +1748,7 @@
          *
          * @param mmsPort the MMS proxy port to set for the APN
          */
+        @NonNull
         public Builder setMmsProxyPort(int mmsPort) {
             this.mMmsProxyPort = mmsPort;
             return this;
@@ -1752,6 +1759,7 @@
          *
          * @param user the APN username to set for the APN
          */
+        @NonNull
         public Builder setUser(String user) {
             this.mUser = user;
             return this;
@@ -1763,6 +1771,7 @@
          * @see android.provider.Telephony.Carriers#PASSWORD
          * @param password the APN password to set for the APN
          */
+        @NonNull
         public Builder setPassword(String password) {
             this.mPassword = password;
             return this;
@@ -1773,6 +1782,7 @@
          *
          * @param authType the authentication type to set for the APN
          */
+        @NonNull
         public Builder setAuthType(@AuthType int authType) {
             this.mAuthType = authType;
             return this;
@@ -1789,6 +1799,7 @@
          *
          * @param apnTypeBitmask a bitmask describing the types of the APN
          */
+        @NonNull
         public Builder setApnTypeBitmask(@ApnType int apnTypeBitmask) {
             this.mApnTypeBitmask = apnTypeBitmask;
             return this;
@@ -1801,6 +1812,7 @@
          *
          * @param operatorNumeric the numeric operator ID to set for this entry
          */
+        @NonNull
         public Builder setOperatorNumeric(String operatorNumeric) {
             this.mOperatorNumeric = operatorNumeric;
             return this;
@@ -1813,6 +1825,7 @@
          *
          * @param protocol the protocol to set to use to connect to this APN
          */
+        @NonNull
         public Builder setProtocol(@ProtocolType int protocol) {
             this.mProtocol = protocol;
             return this;
@@ -1825,6 +1838,7 @@
          *
          * @param roamingProtocol the protocol to set to use to connect to this APN when roaming
          */
+        @NonNull
         public Builder setRoamingProtocol(@ProtocolType  int roamingProtocol) {
             this.mRoamingProtocol = roamingProtocol;
             return this;
@@ -1835,6 +1849,7 @@
          *
          * @param carrierEnabled the current status to set for this APN
          */
+        @NonNull
         public Builder setCarrierEnabled(boolean carrierEnabled) {
             this.mCarrierEnabled = carrierEnabled;
             return this;
@@ -1845,6 +1860,7 @@
          *
          * @param networkTypeBitmask the Radio Technology (Network Type) info
          */
+        @NonNull
         public Builder setNetworkTypeBitmask(int networkTypeBitmask) {
             this.mNetworkTypeBitmask = networkTypeBitmask;
             return this;
@@ -1855,6 +1871,7 @@
          *
          * @param mvnoType the MVNO match type to set for this APN
          */
+        @NonNull
         public Builder setMvnoType(@MvnoType int mvnoType) {
             this.mMvnoType = mvnoType;
             return this;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java
index 1fb8798..bcadc80 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java
@@ -17,6 +17,7 @@
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.net.Uri;
 import android.os.Parcel;
@@ -42,7 +43,7 @@
                 new RcsParticipant(mOriginatingParticipantId), mNewIcon);
     }
 
-    public static final @android.annotation.NonNull Creator<RcsGroupThreadIconChangedEventDescriptor> CREATOR =
+    public static final @NonNull Creator<RcsGroupThreadIconChangedEventDescriptor> CREATOR =
             new Creator<RcsGroupThreadIconChangedEventDescriptor>() {
                 @Override
                 public RcsGroupThreadIconChangedEventDescriptor createFromParcel(Parcel in) {
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java
index 980aba2..597fa0a 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java
@@ -17,6 +17,7 @@
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 
@@ -44,7 +45,7 @@
                 mNewName);
     }
 
-    public static final @android.annotation.NonNull Creator<RcsGroupThreadNameChangedEventDescriptor> CREATOR =
+    public static final @NonNull Creator<RcsGroupThreadNameChangedEventDescriptor> CREATOR =
             new Creator<RcsGroupThreadNameChangedEventDescriptor>() {
                 @Override
                 public RcsGroupThreadNameChangedEventDescriptor createFromParcel(Parcel in) {
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java
index e899e1c..abea10a 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java
@@ -17,6 +17,7 @@
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -43,7 +44,7 @@
                 new RcsParticipant(mJoinedParticipantId));
     }
 
-    public static final @android.annotation.NonNull Creator<RcsGroupThreadParticipantJoinedEventDescriptor> CREATOR =
+    public static final @NonNull Creator<RcsGroupThreadParticipantJoinedEventDescriptor> CREATOR =
             new Creator<RcsGroupThreadParticipantJoinedEventDescriptor>() {
                 @Override
                 public RcsGroupThreadParticipantJoinedEventDescriptor createFromParcel(Parcel in) {
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java
index 8eefb4b..f287db1 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java
@@ -17,6 +17,7 @@
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -44,7 +45,8 @@
                 new RcsParticipant(mLeavingParticipantId));
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<RcsGroupThreadParticipantLeftEventDescriptor> CREATOR =
+    @NonNull
+    public static final Parcelable.Creator<RcsGroupThreadParticipantLeftEventDescriptor> CREATOR =
             new Creator<RcsGroupThreadParticipantLeftEventDescriptor>() {
                 @Override
                 public RcsGroupThreadParticipantLeftEventDescriptor createFromParcel(Parcel in) {
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
index 955f263..d95dc4f 100644
--- a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
@@ -17,6 +17,7 @@
 package android.telephony.ims;
 
 import android.annotation.CheckResult;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -152,7 +153,7 @@
         return mSenderParticipantId;
     }
 
-    public static final @android.annotation.NonNull Creator<RcsIncomingMessageCreationParams> CREATOR =
+    public static final @NonNull Creator<RcsIncomingMessageCreationParams> CREATOR =
             new Creator<RcsIncomingMessageCreationParams>() {
                 @Override
                 public RcsIncomingMessageCreationParams createFromParcel(Parcel in) {
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java
index 22fd8a5..c001ffb 100644
--- a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java
@@ -16,6 +16,7 @@
 
 package android.telephony.ims;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -64,7 +65,7 @@
         super(in);
     }
 
-    public static final @android.annotation.NonNull Creator<RcsOutgoingMessageCreationParams> CREATOR =
+    public static final @NonNull Creator<RcsOutgoingMessageCreationParams> CREATOR =
             new Creator<RcsOutgoingMessageCreationParams>() {
                 @Override
                 public RcsOutgoingMessageCreationParams createFromParcel(Parcel in) {
diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java
index aad9fb3..b29896c 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java
@@ -17,6 +17,7 @@
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 
@@ -45,7 +46,7 @@
                 mTimestamp, new RcsParticipant(mParticipantId), mNewAlias);
     }
 
-    public static final @android.annotation.NonNull Creator<RcsParticipantAliasChangedEventDescriptor> CREATOR =
+    public static final @NonNull Creator<RcsParticipantAliasChangedEventDescriptor> CREATOR =
             new Creator<RcsParticipantAliasChangedEventDescriptor>() {
                 @Override
                 public RcsParticipantAliasChangedEventDescriptor createFromParcel(Parcel in) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 122747a65..62b92fd 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -553,6 +553,20 @@
     void setCellInfoListRate(int rateInMillis);
 
     /**
+     * Opens a logical channel to the ICC card using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHO command.
+     *
+     * @param slotIndex The physical slot index of the target ICC card
+     * @param callingPackage the name of the package making the call.
+     * @param AID Application id. See ETSI 102.221 and 101.220.
+     * @param p2 P2 parameter (described in ISO 7816-4).
+     * @return an IccOpenLogicalChannelResponse object.
+     */
+    IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(
+            int slotIndex, String callingPackage, String AID, int p2);
+
+    /**
      * Opens a logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
@@ -567,12 +581,24 @@
             int subId, String callingPackage, String AID, int p2);
 
     /**
+     * Closes a previously opened logical channel to the ICC card using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHC command.
+     *
+     * @param slotIndex The physical slot index of the target ICC card
+     * @param channel is the channel id to be closed as returned by a
+     *            successful iccOpenLogicalChannel.
+     * @return true if the channel was closed successfully.
+     */
+    boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel);
+
+    /**
      * Closes a previously opened logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
      *
      * @param subId The subscription to use.
-     * @param channel is the channel id to be closed as retruned by a
+     * @param channel is the channel id to be closed as returned by a
      *            successful iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      */
@@ -580,12 +606,33 @@
     boolean iccCloseLogicalChannel(int subId, int channel);
 
     /**
+     * Transmit an APDU to the ICC card over a logical channel using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CGLA command.
+     *
+     * @param slotIndex The physical slot index of the target ICC card
+     * @param channel is the channel id to be closed as returned by a
+     *            successful iccOpenLogicalChannel.
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     */
+    String iccTransmitApduLogicalChannelBySlot(int slotIndex, int channel, int cla, int instruction,
+            int p1, int p2, int p3, String data);
+
+    /**
      * Transmit an APDU to the ICC card over a logical channel.
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
      * @param subId The subscription to use.
-     * @param channel is the channel id to be closed as retruned by a
+     * @param channel is the channel id to be closed as returned by a
      *            successful iccOpenLogicalChannel.
      * @param cla Class of the APDU command.
      * @param instruction Instruction of the APDU command.
@@ -602,6 +649,26 @@
             int p1, int p2, int p3, String data);
 
     /**
+     * Transmit an APDU to the ICC card over the basic channel using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CSIM command.
+     *
+     * @param slotIndex The physical slot index of the target ICC card
+     * @param callingPackage the name of the package making the call.
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     */
+    String iccTransmitApduBasicChannelBySlot(int slotIndex, String callingPackage, int cla,
+            int instruction, int p1, int p2, int p3, String data);
+
+    /**
      * Transmit an APDU to the ICC card over the basic channel.
      *
      * Input parameters equivalent to TS 27.007 AT+CSIM command.
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 8be721a..dfc3b6e 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -118,7 +118,7 @@
         ":com.android.tests.rollback.testapex.RollbackTestApexV2",
     ],
     test_config: "RollbackTest.xml",
-    sdk_version: "system_current",
+    sdk_version: "test_current",
 }
 
 java_test_host {
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index a03fae0..9aed074 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -340,16 +340,26 @@
     }
 
     /**
-     * Asserts that the given RollbackInfo has a single package with expected
-     * package name and versions.
+     * Asserts that the given RollbackInfo has the given packages with expected
+     * package names and all are rolled to and from the same given versions.
      */
-    static void assertRollbackInfoEquals(String packageName,
+    static void assertRollbackInfoEquals(String[] packageNames,
             long versionRolledBackFrom, long versionRolledBackTo,
             RollbackInfo info, VersionedPackage... causePackages) {
         assertNotNull(info);
-        assertEquals(1, info.getPackages().size());
-        assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, versionRolledBackTo,
-                info.getPackages().get(0));
+        assertEquals(packageNames.length, info.getPackages().size());
+        int foundPackages = 0;
+        for (String packageName : packageNames) {
+            for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
+                if (packageName.equals(pkgRollbackInfo.getPackageName())) {
+                    foundPackages++;
+                    assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom,
+                            versionRolledBackTo, pkgRollbackInfo);
+                    break;
+                }
+            }
+        }
+        assertEquals(packageNames.length, foundPackages);
         assertEquals(causePackages.length, info.getCausePackages().size());
         for (int i = 0; i < causePackages.length; ++i) {
             assertEquals(causePackages[i].getPackageName(),
@@ -360,6 +370,18 @@
     }
 
     /**
+     * Asserts that the given RollbackInfo has a single package with expected
+     * package name and versions.
+     */
+    static void assertRollbackInfoEquals(String packageName,
+            long versionRolledBackFrom, long versionRolledBackTo,
+            RollbackInfo info, VersionedPackage... causePackages) {
+        String[] packageNames = {packageName};
+        assertRollbackInfoEquals(packageNames, versionRolledBackFrom, versionRolledBackTo, info,
+                causePackages);
+    }
+
+    /**
      * Waits for the given session to be marked as ready.
      * Throws an assertion if the session fails.
      */
@@ -453,4 +475,17 @@
             fail(result);
         }
     }
+
+    /**
+     * Return the rollback info for a recently committed rollback, by matching the rollback id, or
+     * return null if no matching rollback is found.
+     */
+    static RollbackInfo getRecentlyCommittedRollbackInfoById(int getRollbackId) {
+        for (RollbackInfo info : getRollbackManager().getRecentlyCommittedRollbacks()) {
+            if (info.getRollbackId() == getRollbackId) {
+                return info;
+            }
+        }
+        return null;
+    }
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 59ae8d9..047451b 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -17,6 +17,7 @@
 package com.android.tests.rollback;
 
 import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals;
+import static com.android.tests.rollback.RollbackTestUtils.getRecentlyCommittedRollbackInfoById;
 import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage;
 
 import android.Manifest;
@@ -25,7 +26,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.After;
@@ -47,6 +47,8 @@
 
     private static final String TAG = "RollbackTest";
     private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
+    private static final String TEST_APP_A_V1 = "RollbackTestAppAv1.apk";
+    private static final String TEST_APP_A_V2 = "RollbackTestAppAv2.apk";
     private static final String TEST_APEX_PKG = "com.android.tests.rollback.testapex";
     private static final String TEST_APEX_V1 =
             "com.android.tests.rollback.testapex.RollbackTestApexV1.apex";
@@ -82,11 +84,11 @@
         RollbackTestUtils.uninstall(TEST_APP_A);
         assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
-        RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+        RollbackTestUtils.install(TEST_APP_A_V1, false);
         assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
         RollbackTestUtils.processUserData(TEST_APP_A);
 
-        RollbackTestUtils.installStaged(true, "RollbackTestAppAv2.apk");
+        RollbackTestUtils.installStaged(true, TEST_APP_A_V2);
 
         // At this point, the host test driver will reboot the device and run
         // testApkOnlyCommitRollback().
@@ -142,6 +144,86 @@
     }
 
     /**
+     * Test rollbacks of staged installs an apk and an apex.
+     * Prepare apex (and apk) phase.
+     */
+    @Test
+    public void testApkAndApexPrepare() throws Exception {
+        RollbackTestUtils.uninstall(TEST_APP_A);
+        assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        // Note: can't uninstall the apex. See note in #testApexOnlyPrepareApex().
+        RollbackTestUtils.installStaged(false, TEST_APP_A_V1, TEST_APEX_V1);
+
+        // At this point, the host test driver will reboot the device and run
+        // testApkAndApexEnableRollback().
+    }
+
+    /**
+     * Test rollbacks of staged installs an apk and an apex.
+     * Enable rollback phase.
+     */
+    @Test
+    public void testApkAndApexEnableRollback() throws Exception {
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        RollbackTestUtils.installStaged(true, TEST_APP_A_V2, TEST_APEX_V2);
+
+        // At this point, the host test driver will reboot the device and run
+        // testApkAndApexCommitRollback().
+    }
+
+    /**
+     * Test rollbacks of staged installs an apk and an apex.
+     * Commit rollback phase.
+     */
+    @Test
+    public void testApkAndApexCommitRollback() throws Exception {
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        RollbackTestUtils.processUserData(TEST_APP_A);
+
+        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+        RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                rm.getAvailableRollbacks(), TEST_APP_A);
+        String[] packagesNames = {TEST_APEX_PKG, TEST_APP_A};
+        assertRollbackInfoEquals(packagesNames, 2, 1, rollback);
+        assertTrue(rollback.isStaged());
+
+        RollbackTestUtils.rollback(rollback.getRollbackId());
+
+        RollbackInfo committed = getRecentlyCommittedRollbackInfoById(rollback.getRollbackId());
+
+        assertRollbackInfoEquals(packagesNames, 2, 1, committed);
+        assertTrue(committed.isStaged());
+        assertNotEquals(-1, committed.getCommittedSessionId());
+
+        RollbackTestUtils.waitForSessionReady(committed.getCommittedSessionId());
+
+        // The apex and apk should not be rolled back until after reboot.
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        // At this point, the host test driver will reboot the device and run
+        // testApkAndApexConfirmRollback().
+    }
+
+    /**
+     * Test rollbacks of staged installs an apk and an apex.
+     * Confirm rollback phase.
+     */
+    @Test
+    public void testApkAndApexConfirmRollback() throws Exception {
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        RollbackTestUtils.processUserData(TEST_APP_A);
+    }
+
+    /**
      * Test rollbacks of staged installs involving only apex.
      * Prepare apex phase.
      */
@@ -171,7 +253,7 @@
     }
 
     /**
-     * Test rollbacks of staged installs involving only apks.
+     * Test rollbacks of staged installs involving only apex.
      * Commit rollback phase.
      */
     @Test
@@ -186,18 +268,8 @@
 
         RollbackTestUtils.rollback(rollback.getRollbackId());
 
-        // Note: We can't use getUniqueRollbackInfoForPackage for the apex,
-        // because we can't uninstall the apex (b/123667725), which means
-        // there's no way to clear info about rollbacks from previous tests
-        // run on the device. Look up the info by rollback id instead.
-        RollbackInfo committed = null;
-        for (RollbackInfo info : rm.getRecentlyCommittedRollbacks()) {
-            if (info.getRollbackId() == rollback.getRollbackId()) {
-                assertNull(committed);
-                committed = info;
-                break;
-            }
-        }
+        RollbackInfo committed = getRecentlyCommittedRollbackInfoById(rollback.getRollbackId());
+
         assertRollbackInfoEquals(TEST_APEX_PKG, 2, 1, committed);
         assertTrue(committed.isStaged());
         assertNotEquals(-1, committed.getCommittedSessionId());
@@ -212,7 +284,7 @@
     }
 
     /**
-     * Test rollbacks of staged installs involving only apks.
+     * Test rollbacks of staged installs involving only apex.
      * Confirm rollback phase.
      */
     @Test
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 24a51dc..ac7f634 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -67,4 +67,18 @@
         getDevice().reboot();
         runPhase("testApexOnlyConfirmRollback");
     }
+
+    /**
+     * Tests staged rollbacks involving apk and apex.
+     */
+    @Test
+    public void testApkAndApex() throws Exception {
+        runPhase("testApkAndApexPrepare");
+        getDevice().reboot();
+        runPhase("testApkAndApexEnableRollback");
+        getDevice().reboot();
+        runPhase("testApkAndApexCommitRollback");
+        getDevice().reboot();
+        runPhase("testApkAndApexConfirmRollback");
+    }
 }
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
index adcd11a..bb985d7 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
@@ -197,7 +197,7 @@
                     intent.setPackage(getPackageName());
                     intent.putExtra(EXTRA_KEY_TIMEOUT, true);
                     mUsageStatsManager.registerAppUsageLimitObserver(1, packages,
-                            Duration.ofSeconds(60), Duration.ofSeconds(60),
+                            Duration.ofSeconds(60), Duration.ofSeconds(0),
                             PendingIntent.getActivity(UsageStatsActivity.this, 1, intent, 0));
                 }
             }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 985d667..dc11bf3 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -190,6 +190,8 @@
 
 import java.net.Inet4Address;
 import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -206,6 +208,7 @@
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 /**
@@ -2549,7 +2552,8 @@
         verifyActiveNetwork(TRANSPORT_CELLULAR);
     }
 
-    @Test
+    // TODO: deflake and re-enable
+    // @Test
     public void testPartialConnectivity() {
         // Register network callback.
         NetworkRequest request = new NetworkRequest.Builder()
@@ -4018,17 +4022,24 @@
         callback3.expectStopped();
     }
 
-    @Test
-    public void testNattSocketKeepalives_SingleThreadExecutor() throws Exception {
+    // Helper method to prepare the executor and run test
+    private void runTestWithSerialExecutors(Consumer<Executor> functor) {
         final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor();
-        doTestNattSocketKeepalivesWithExecutor(executorSingleThread);
+        final Executor executorInline = (Runnable r) -> r.run();
+        functor.accept(executorSingleThread);
         executorSingleThread.shutdown();
+        functor.accept(executorInline);
     }
 
     @Test
-    public void testNattSocketKeepalives_InlineExecutor() throws Exception {
-        final Executor executorInline = (Runnable r) -> r.run();
-        doTestNattSocketKeepalivesWithExecutor(executorInline);
+    public void testNattSocketKeepalives() {
+        runTestWithSerialExecutors(executor -> {
+            try {
+                doTestNattSocketKeepalivesWithExecutor(executor);
+            } catch (Exception e) {
+                fail(e.getMessage());
+            }
+        });
     }
 
     private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception {
@@ -4169,6 +4180,81 @@
 
         mWiFiNetworkAgent.disconnect();
         waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent = null;
+    }
+
+    @Test
+    public void testTcpSocketKeepalives() {
+        runTestWithSerialExecutors(executor -> {
+            try {
+                doTestTcpSocketKeepalivesWithExecutor(executor);
+            } catch (Exception e) {
+                fail(e.getMessage());
+            }
+        });
+    }
+
+    private void doTestTcpSocketKeepalivesWithExecutor(Executor executor) throws Exception {
+        final int srcPortV4 = 12345;
+        final int srcPortV6 = 23456;
+        final InetAddress myIPv4 = InetAddress.getByName("127.0.0.1");
+        final InetAddress myIPv6 = InetAddress.getByName("::1");
+
+        final int validKaInterval = 15;
+        final int invalidKaInterval = 9;
+
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName("wlan12");
+        lp.addLinkAddress(new LinkAddress(myIPv6, 64));
+        lp.addLinkAddress(new LinkAddress(myIPv4, 25));
+        lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
+        lp.addRoute(new RouteInfo(InetAddress.getByName("127.0.0.254")));
+
+        final Network notMyNet = new Network(61234);
+        final Network myNet = connectKeepaliveNetwork(lp);
+
+        final Socket testSocketV4 = new Socket();
+        final Socket testSocketV6 = new Socket();
+
+        TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
+        SocketKeepalive ka;
+
+        // Attempt to start Tcp keepalives with invalid parameters and check for errors.
+        // Invalid network.
+        ka = mCm.createSocketKeepalive(notMyNet, testSocketV4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
+
+        // Invalid Socket (socket is not bound with IPv4 address).
+        ka = mCm.createSocketKeepalive(myNet, testSocketV4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
+
+        // Invalid Socket (socket is not bound with IPv6 address).
+        ka = mCm.createSocketKeepalive(myNet, testSocketV6, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
+
+        // Bind the socket address
+        testSocketV4.bind(new InetSocketAddress(myIPv4, srcPortV4));
+        testSocketV6.bind(new InetSocketAddress(myIPv6, srcPortV6));
+
+        // Invalid Socket (socket is bound with IPv4 address).
+        ka = mCm.createSocketKeepalive(myNet, testSocketV4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
+
+        // Invalid Socket (socket is bound with IPv6 address).
+        ka = mCm.createSocketKeepalive(myNet, testSocketV6, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
+
+        testSocketV4.close();
+        testSocketV6.close();
+
+        mWiFiNetworkAgent.disconnect();
+        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent = null;
     }
 
     @Test
diff --git a/wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl b/wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl
similarity index 92%
rename from wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl
rename to wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl
index 284ffaa..4687f30 100644
--- a/wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl
+++ b/wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl
@@ -23,7 +23,7 @@
  *
  * @hide
  */
-oneway interface IWifiUsabilityStatsListener
+oneway interface IOnWifiUsabilityStatsListener
 {
     /**
      * Service to manager callback providing current Wi-Fi usability stats.
@@ -36,6 +36,6 @@
      *                           Wi-Fi usability stats.
      * @param stats The updated Wi-Fi usability statistics.
      */
-    void onStatsUpdated(int seqNum, boolean isSameBssidAndFreq,
+    void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
             in WifiUsabilityStatsEntry stats);
 }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 17948e7..62ea9af 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -28,7 +28,7 @@
 import android.net.wifi.INetworkRequestMatchCallback;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ITrafficStateCallback;
-import android.net.wifi.IWifiUsabilityStatsListener;
+import android.net.wifi.IOnWifiUsabilityStatsListener;
 import android.net.wifi.PasspointManagementObjectDefinition;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiActivityEnergyInfo;
@@ -190,9 +190,9 @@
 
     void unregisterSoftApCallback(int callbackIdentifier);
 
-    void addWifiUsabilityStatsListener(in IBinder binder, in IWifiUsabilityStatsListener listener, int listenerIdentifier);
+    void addOnWifiUsabilityStatsListener(in IBinder binder, in IOnWifiUsabilityStatsListener listener, int listenerIdentifier);
 
-    void removeWifiUsabilityStatsListener(int listenerIdentifier);
+    void removeOnWifiUsabilityStatsListener(int listenerIdentifier);
 
     void registerTrafficStateCallback(in IBinder binder, in ITrafficStateCallback callback, int callbackIdentifier);
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 4fd00f7..869f665 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -65,6 +65,7 @@
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -511,7 +512,7 @@
     /**
      * The look up key for an int that indicates why softAP started failed
      * currently support general and no_channel
-     * @see #SAP_START_FAILURE_GENERIC
+     * @see #SAP_START_FAILURE_GENERAL
      * @see #SAP_START_FAILURE_NO_CHANNEL
      *
      * @hide
@@ -615,15 +616,15 @@
     public @interface SapStartFailure {}
 
     /**
-     *  If WIFI AP start failed, this reason code means there is no legal channel exists on
-     *  user selected band by regulatory
+     *  All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL}.
      *
      *  @hide
      */
     public static final int SAP_START_FAILURE_GENERAL= 0;
 
     /**
-     *  All other reason for AP start failed besides SAP_START_FAILURE_GENERAL
+     *  If Wi-Fi AP start failed, this reason code means that no legal channel exists on user
+     *  selected band due to regulatory constraints.
      *
      *  @hide
      */
@@ -1272,7 +1273,10 @@
     })
     @NonNull
     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
-            List<ScanResult> scanResults) {
+            @Nullable List<ScanResult> scanResults) {
+        if (scanResults == null) {
+            return new HashMap<>();
+        }
         try {
             return mService.getMatchingOsuProviders(scanResults);
         } catch (RemoteException e) {
@@ -4785,13 +4789,13 @@
 
     /**
      * Interface for Wi-Fi usability statistics listener. Should be implemented by applications and
-     * set when calling {@link WifiManager#addWifiUsabilityStatsListener(Executor,
-     * WifiUsabilityStatsListener)}.
+     * set when calling {@link WifiManager#addOnWifiUsabilityStatsListener(Executor,
+     * OnWifiUsabilityStatsListener)}.
      *
      * @hide
      */
     @SystemApi
-    public interface WifiUsabilityStatsListener {
+    public interface OnWifiUsabilityStatsListener {
         /**
          * Called when Wi-Fi usability statistics is updated.
          *
@@ -4803,15 +4807,15 @@
          *                           Wi-Fi usability stats.
          * @param stats The updated Wi-Fi usability statistics.
          */
-        void onStatsUpdated(int seqNum, boolean isSameBssidAndFreq,
-                WifiUsabilityStatsEntry stats);
+        void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
+                @NonNull WifiUsabilityStatsEntry stats);
     }
 
     /**
-     * Adds a listener for Wi-Fi usability statistics. See {@link WifiUsabilityStatsListener}.
+     * Adds a listener for Wi-Fi usability statistics. See {@link OnWifiUsabilityStatsListener}.
      * Multiple listeners can be added. Callers will be invoked periodically by framework to
      * inform clients about the current Wi-Fi usability statistics. Callers can remove a previously
-     * added listener using {@link removeWifiUsabilityStatsListener}.
+     * added listener using {@link removeOnWifiUsabilityStatsListener}.
      *
      * @param executor The executor on which callback will be invoked.
      * @param listener Listener for Wifi usability statistics.
@@ -4820,25 +4824,25 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
-    public void addWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor,
-            @NonNull WifiUsabilityStatsListener listener) {
+    public void addOnWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull OnWifiUsabilityStatsListener listener) {
         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
         if (mVerboseLoggingEnabled) {
-            Log.v(TAG, "addWifiUsabilityStatsListener: listener=" + listener);
+            Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener);
         }
         try {
-            mService.addWifiUsabilityStatsListener(new Binder(),
-                    new IWifiUsabilityStatsListener.Stub() {
+            mService.addOnWifiUsabilityStatsListener(new Binder(),
+                    new IOnWifiUsabilityStatsListener.Stub() {
                         @Override
-                        public void onStatsUpdated(int seqNum, boolean isSameBssidAndFreq,
+                        public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
                                 WifiUsabilityStatsEntry stats) {
                             if (mVerboseLoggingEnabled) {
-                                Log.v(TAG, "WifiUsabilityStatsListener: onStatsUpdated: seqNum="
-                                        + seqNum);
+                                Log.v(TAG, "OnWifiUsabilityStatsListener: "
+                                        + "onWifiUsabilityStats: seqNum=" + seqNum);
                             }
                             Binder.withCleanCallingIdentity(() ->
-                                    executor.execute(() -> listener.onStatsUpdated(seqNum,
+                                    executor.execute(() -> listener.onWifiUsabilityStats(seqNum,
                                             isSameBssidAndFreq, stats)));
                         }
                     },
@@ -4859,13 +4863,13 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
-    public void removeWifiUsabilityStatsListener(@NonNull WifiUsabilityStatsListener listener) {
+    public void removeOnWifiUsabilityStatsListener(@NonNull OnWifiUsabilityStatsListener listener) {
         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
         if (mVerboseLoggingEnabled) {
-            Log.v(TAG, "removeWifiUsabilityStatsListener: listener=" + listener);
+            Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener);
         }
         try {
-            mService.removeWifiUsabilityStatsListener(listener.hashCode());
+            mService.removeOnWifiUsabilityStatsListener(listener.hashCode());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4879,7 +4883,8 @@
      *
      * @param seqNum Sequence number of the Wi-Fi usability score.
      * @param score The Wi-Fi usability score.
-     * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score.
+     * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second,
+     *                             expected range: [0, 100].
      *
      * @hide
      */
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
index 2dee971..51aa93a 100644
--- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
@@ -51,87 +51,88 @@
     public static final int PROBE_STATUS_FAILURE = 3;
 
     /** Absolute milliseconds from device boot when these stats were sampled */
-    public final long timeStampMs;
+    private final long mTimeStampMillis;
     /** The RSSI (in dBm) at the sample time */
-    public final int rssi;
+    private final int mRssi;
     /** Link speed at the sample time in Mbps */
-    public final int linkSpeedMbps;
+    private final int mLinkSpeedMbps;
     /** The total number of tx success counted from the last radio chip reset */
-    public final long totalTxSuccess;
+    private final long mTotalTxSuccess;
     /** The total number of MPDU data packet retries counted from the last radio chip reset */
-    public final long totalTxRetries;
+    private final long mTotalTxRetries;
     /** The total number of tx bad counted from the last radio chip reset */
-    public final long totalTxBad;
+    private final long mTotalTxBad;
     /** The total number of rx success counted from the last radio chip reset */
-    public final long totalRxSuccess;
+    private final long mTotalRxSuccess;
     /** The total time the wifi radio is on in ms counted from the last radio chip reset */
-    public final long totalRadioOnTimeMs;
+    private final long mTotalRadioOnTimeMillis;
     /** The total time the wifi radio is doing tx in ms counted from the last radio chip reset */
-    public final long totalRadioTxTimeMs;
+    private final long mTotalRadioTxTimeMillis;
     /** The total time the wifi radio is doing rx in ms counted from the last radio chip reset */
-    public final long totalRadioRxTimeMs;
+    private final long mTotalRadioRxTimeMillis;
     /** The total time spent on all types of scans in ms counted from the last radio chip reset */
-    public final long totalScanTimeMs;
+    private final long mTotalScanTimeMillis;
     /** The total time spent on nan scans in ms counted from the last radio chip reset */
-    public final long totalNanScanTimeMs;
+    private final long mTotalNanScanTimeMillis;
     /** The total time spent on background scans in ms counted from the last radio chip reset */
-    public final long totalBackgroundScanTimeMs;
+    private final long mTotalBackgroundScanTimeMillis;
     /** The total time spent on roam scans in ms counted from the last radio chip reset */
-    public final long totalRoamScanTimeMs;
+    private final long mTotalRoamScanTimeMillis;
     /** The total time spent on pno scans in ms counted from the last radio chip reset */
-    public final long totalPnoScanTimeMs;
+    private final long mTotalPnoScanTimeMillis;
     /** The total time spent on hotspot2.0 scans and GAS exchange in ms counted from the last radio
      * chip reset */
-    public final long totalHotspot2ScanTimeMs;
+    private final long mTotalHotspot2ScanTimeMillis;
     /** The total time CCA is on busy status on the current frequency in ms counted from the last
      * radio chip reset */
-    public final long totalCcaBusyFreqTimeMs;
-    /** The total radio on time of the current frequency from the last radio chip reset */
-    public final long totalRadioOnFreqTimeMs;
+    private final long mTotalCcaBusyFreqTimeMillis;
+    /** The total radio on time on the current frequency from the last radio chip reset */
+    private final long mTotalRadioOnFreqTimeMillis;
     /** The total number of beacons received from the last radio chip reset */
-    public final long totalBeaconRx;
+    private final long mTotalBeaconRx;
     /** The status of link probe since last stats update */
-    public final int probeStatusSinceLastUpdate;
+    @ProbeStatus private final int mProbeStatusSinceLastUpdate;
     /** The elapsed time of the most recent link probe since last stats update */
-    public final int probeElapsedTimeMsSinceLastUpdate;
+    private final int mProbeElapsedTimeSinceLastUpdateMillis;
     /** The MCS rate of the most recent link probe since last stats update */
-    public final int probeMcsRateSinceLastUpdate;
+    private final int mProbeMcsRateSinceLastUpdate;
     /** Rx link speed at the sample time in Mbps */
-    public final int rxLinkSpeedMbps;
+    private final int mRxLinkSpeedMbps;
 
     /** Constructor function {@hide} */
-    public WifiUsabilityStatsEntry(long timeStampMs, int rssi,
-            int linkSpeedMbps, long totalTxSuccess, long totalTxRetries,
-            long totalTxBad, long totalRxSuccess, long totalRadioOnTimeMs,
-            long totalRadioTxTimeMs, long totalRadioRxTimeMs, long totalScanTimeMs,
-            long totalNanScanTimeMs, long totalBackgroundScanTimeMs, long totalRoamScanTimeMs,
-            long totalPnoScanTimeMs, long totalHotspot2ScanTimeMs, long totalCcaBusyFreqTimeMs,
-            long totalRadioOnFreqTimeMs, long totalBeaconRx,
-            @ProbeStatus int probeStatusSinceLastUpdate, int probeElapsedTimeMsSinceLastUpdate,
+    public WifiUsabilityStatsEntry(long timeStampMillis, int rssi, int linkSpeedMbps,
+            long totalTxSuccess, long totalTxRetries, long totalTxBad, long totalRxSuccess,
+            long totalRadioOnTimeMillis, long totalRadioTxTimeMillis, long totalRadioRxTimeMillis,
+            long totalScanTimeMillis, long totalNanScanTimeMillis,
+            long totalBackgroundScanTimeMillis,
+            long totalRoamScanTimeMillis, long totalPnoScanTimeMillis,
+            long totalHotspot2ScanTimeMillis,
+            long totalCcaBusyFreqTimeMillis, long totalRadioOnFreqTimeMillis, long totalBeaconRx,
+            @ProbeStatus int probeStatusSinceLastUpdate, int probeElapsedTimeSinceLastUpdateMillis,
             int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps) {
-        this.timeStampMs = timeStampMs;
-        this.rssi = rssi;
-        this.linkSpeedMbps = linkSpeedMbps;
-        this.totalTxSuccess = totalTxSuccess;
-        this.totalTxRetries = totalTxRetries;
-        this.totalTxBad = totalTxBad;
-        this.totalRxSuccess = totalRxSuccess;
-        this.totalRadioOnTimeMs = totalRadioOnTimeMs;
-        this.totalRadioTxTimeMs = totalRadioTxTimeMs;
-        this.totalRadioRxTimeMs = totalRadioRxTimeMs;
-        this.totalScanTimeMs = totalScanTimeMs;
-        this.totalNanScanTimeMs = totalNanScanTimeMs;
-        this.totalBackgroundScanTimeMs = totalBackgroundScanTimeMs;
-        this.totalRoamScanTimeMs = totalRoamScanTimeMs;
-        this.totalPnoScanTimeMs = totalPnoScanTimeMs;
-        this.totalHotspot2ScanTimeMs = totalHotspot2ScanTimeMs;
-        this.totalCcaBusyFreqTimeMs = totalCcaBusyFreqTimeMs;
-        this.totalRadioOnFreqTimeMs = totalRadioOnFreqTimeMs;
-        this.totalBeaconRx = totalBeaconRx;
-        this.probeStatusSinceLastUpdate = probeStatusSinceLastUpdate;
-        this.probeElapsedTimeMsSinceLastUpdate = probeElapsedTimeMsSinceLastUpdate;
-        this.probeMcsRateSinceLastUpdate = probeMcsRateSinceLastUpdate;
-        this.rxLinkSpeedMbps = rxLinkSpeedMbps;
+        mTimeStampMillis = timeStampMillis;
+        mRssi = rssi;
+        mLinkSpeedMbps = linkSpeedMbps;
+        mTotalTxSuccess = totalTxSuccess;
+        mTotalTxRetries = totalTxRetries;
+        mTotalTxBad = totalTxBad;
+        mTotalRxSuccess = totalRxSuccess;
+        mTotalRadioOnTimeMillis = totalRadioOnTimeMillis;
+        mTotalRadioTxTimeMillis = totalRadioTxTimeMillis;
+        mTotalRadioRxTimeMillis = totalRadioRxTimeMillis;
+        mTotalScanTimeMillis = totalScanTimeMillis;
+        mTotalNanScanTimeMillis = totalNanScanTimeMillis;
+        mTotalBackgroundScanTimeMillis = totalBackgroundScanTimeMillis;
+        mTotalRoamScanTimeMillis = totalRoamScanTimeMillis;
+        mTotalPnoScanTimeMillis = totalPnoScanTimeMillis;
+        mTotalHotspot2ScanTimeMillis = totalHotspot2ScanTimeMillis;
+        mTotalCcaBusyFreqTimeMillis = totalCcaBusyFreqTimeMillis;
+        mTotalRadioOnFreqTimeMillis = totalRadioOnFreqTimeMillis;
+        mTotalBeaconRx = totalBeaconRx;
+        mProbeStatusSinceLastUpdate = probeStatusSinceLastUpdate;
+        mProbeElapsedTimeSinceLastUpdateMillis = probeElapsedTimeSinceLastUpdateMillis;
+        mProbeMcsRateSinceLastUpdate = probeMcsRateSinceLastUpdate;
+        mRxLinkSpeedMbps = rxLinkSpeedMbps;
     }
 
     /** Implement the Parcelable interface */
@@ -141,29 +142,29 @@
 
     /** Implement the Parcelable interface */
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeLong(timeStampMs);
-        dest.writeInt(rssi);
-        dest.writeInt(linkSpeedMbps);
-        dest.writeLong(totalTxSuccess);
-        dest.writeLong(totalTxRetries);
-        dest.writeLong(totalTxBad);
-        dest.writeLong(totalRxSuccess);
-        dest.writeLong(totalRadioOnTimeMs);
-        dest.writeLong(totalRadioTxTimeMs);
-        dest.writeLong(totalRadioRxTimeMs);
-        dest.writeLong(totalScanTimeMs);
-        dest.writeLong(totalNanScanTimeMs);
-        dest.writeLong(totalBackgroundScanTimeMs);
-        dest.writeLong(totalRoamScanTimeMs);
-        dest.writeLong(totalPnoScanTimeMs);
-        dest.writeLong(totalHotspot2ScanTimeMs);
-        dest.writeLong(totalCcaBusyFreqTimeMs);
-        dest.writeLong(totalRadioOnFreqTimeMs);
-        dest.writeLong(totalBeaconRx);
-        dest.writeInt(probeStatusSinceLastUpdate);
-        dest.writeInt(probeElapsedTimeMsSinceLastUpdate);
-        dest.writeInt(probeMcsRateSinceLastUpdate);
-        dest.writeInt(rxLinkSpeedMbps);
+        dest.writeLong(mTimeStampMillis);
+        dest.writeInt(mRssi);
+        dest.writeInt(mLinkSpeedMbps);
+        dest.writeLong(mTotalTxSuccess);
+        dest.writeLong(mTotalTxRetries);
+        dest.writeLong(mTotalTxBad);
+        dest.writeLong(mTotalRxSuccess);
+        dest.writeLong(mTotalRadioOnTimeMillis);
+        dest.writeLong(mTotalRadioTxTimeMillis);
+        dest.writeLong(mTotalRadioRxTimeMillis);
+        dest.writeLong(mTotalScanTimeMillis);
+        dest.writeLong(mTotalNanScanTimeMillis);
+        dest.writeLong(mTotalBackgroundScanTimeMillis);
+        dest.writeLong(mTotalRoamScanTimeMillis);
+        dest.writeLong(mTotalPnoScanTimeMillis);
+        dest.writeLong(mTotalHotspot2ScanTimeMillis);
+        dest.writeLong(mTotalCcaBusyFreqTimeMillis);
+        dest.writeLong(mTotalRadioOnFreqTimeMillis);
+        dest.writeLong(mTotalBeaconRx);
+        dest.writeInt(mProbeStatusSinceLastUpdate);
+        dest.writeInt(mProbeElapsedTimeSinceLastUpdateMillis);
+        dest.writeInt(mProbeMcsRateSinceLastUpdate);
+        dest.writeInt(mRxLinkSpeedMbps);
     }
 
     /** Implement the Parcelable interface */
@@ -186,4 +187,121 @@
             return new WifiUsabilityStatsEntry[size];
         }
     };
+
+    /** Absolute milliseconds from device boot when these stats were sampled */
+    public long getTimeStampMillis() {
+        return mTimeStampMillis;
+    }
+
+    /** The RSSI (in dBm) at the sample time */
+    public int getRssi() {
+        return mRssi;
+    }
+
+    /** Link speed at the sample time in Mbps */
+    public int getLinkSpeedMbps() {
+        return mLinkSpeedMbps;
+    }
+
+    /** The total number of tx success counted from the last radio chip reset */
+    public long getTotalTxSuccess() {
+        return mTotalTxSuccess;
+    }
+
+    /** The total number of MPDU data packet retries counted from the last radio chip reset */
+    public long getTotalTxRetries() {
+        return mTotalTxRetries;
+    }
+
+    /** The total number of tx bad counted from the last radio chip reset */
+    public long getTotalTxBad() {
+        return mTotalTxBad;
+    }
+
+    /** The total number of rx success counted from the last radio chip reset */
+    public long getTotalRxSuccess() {
+        return mTotalRxSuccess;
+    }
+
+    /** The total time the wifi radio is on in ms counted from the last radio chip reset */
+    public long getTotalRadioOnTimeMillis() {
+        return mTotalRadioOnTimeMillis;
+    }
+
+    /** The total time the wifi radio is doing tx in ms counted from the last radio chip reset */
+    public long getTotalRadioTxTimeMillis() {
+        return mTotalRadioTxTimeMillis;
+    }
+
+    /** The total time the wifi radio is doing rx in ms counted from the last radio chip reset */
+    public long getTotalRadioRxTimeMillis() {
+        return mTotalRadioRxTimeMillis;
+    }
+
+    /** The total time spent on all types of scans in ms counted from the last radio chip reset */
+    public long getTotalScanTimeMillis() {
+        return mTotalScanTimeMillis;
+    }
+
+    /** The total time spent on nan scans in ms counted from the last radio chip reset */
+    public long getTotalNanScanTimeMillis() {
+        return mTotalNanScanTimeMillis;
+    }
+
+    /** The total time spent on background scans in ms counted from the last radio chip reset */
+    public long getTotalBackgroundScanTimeMillis() {
+        return mTotalBackgroundScanTimeMillis;
+    }
+
+    /** The total time spent on roam scans in ms counted from the last radio chip reset */
+    public long getTotalRoamScanTimeMillis() {
+        return mTotalRoamScanTimeMillis;
+    }
+
+    /** The total time spent on pno scans in ms counted from the last radio chip reset */
+    public long getTotalPnoScanTimeMillis() {
+        return mTotalPnoScanTimeMillis;
+    }
+
+    /** The total time spent on hotspot2.0 scans and GAS exchange in ms counted from the last radio
+     * chip reset */
+    public long getTotalHotspot2ScanTimeMillis() {
+        return mTotalHotspot2ScanTimeMillis;
+    }
+
+    /** The total time CCA is on busy status on the current frequency in ms counted from the last
+     * radio chip reset */
+    public long getTotalCcaBusyFreqTimeMillis() {
+        return mTotalCcaBusyFreqTimeMillis;
+    }
+
+    /** The total radio on time on the current frequency from the last radio chip reset */
+    public long getTotalRadioOnFreqTimeMillis() {
+        return mTotalRadioOnFreqTimeMillis;
+    }
+
+    /** The total number of beacons received from the last radio chip reset */
+    public long getTotalBeaconRx() {
+        return mTotalBeaconRx;
+    }
+
+    /** The status of link probe since last stats update */
+    @ProbeStatus public int getProbeStatusSinceLastUpdate() {
+        return mProbeStatusSinceLastUpdate;
+    }
+
+    /** The elapsed time of the most recent link probe since last stats update */
+    public int getProbeElapsedTimeSinceLastUpdateMillis() {
+        return mProbeElapsedTimeSinceLastUpdateMillis;
+    }
+
+    /** The MCS rate of the most recent link probe since last stats update */
+    public int getProbeMcsRateSinceLastUpdate() {
+        return mProbeMcsRateSinceLastUpdate;
+    }
+
+    /** Rx link speed at the sample time in Mbps */
+    public int getRxLinkSpeedMbps() {
+        return mRxLinkSpeedMbps;
+    }
 }
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index c236c7a..842d78d 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -23,10 +23,10 @@
 import android.net.Network;
 import android.net.wifi.IDppCallback;
 import android.net.wifi.INetworkRequestMatchCallback;
+import android.net.wifi.IOnWifiUsabilityStatsListener;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ITrafficStateCallback;
 import android.net.wifi.IWifiManager;
-import android.net.wifi.IWifiUsabilityStatsListener;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.wifi.WifiConfiguration;
@@ -467,13 +467,13 @@
     }
 
     @Override
-    public void addWifiUsabilityStatsListener(
-            IBinder binder, IWifiUsabilityStatsListener listener, int listenerIdentifier) {
+    public void addOnWifiUsabilityStatsListener(
+            IBinder binder, IOnWifiUsabilityStatsListener listener, int listenerIdentifier) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public void removeWifiUsabilityStatsListener(int listenerIdentifier) {
+    public void removeOnWifiUsabilityStatsListener(int listenerIdentifier) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 5c2f626..600abc9 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -59,9 +59,9 @@
 import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription;
 import android.net.wifi.WifiManager.NetworkRequestMatchCallback;
 import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
+import android.net.wifi.WifiManager.OnWifiUsabilityStatsListener;
 import android.net.wifi.WifiManager.SoftApCallback;
 import android.net.wifi.WifiManager.TrafficStateCallback;
-import android.net.wifi.WifiManager.WifiUsabilityStatsListener;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -105,7 +105,7 @@
     @Mock SoftApCallback mSoftApCallback;
     @Mock TrafficStateCallback mTrafficStateCallback;
     @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback;
-    @Mock WifiUsabilityStatsListener mWifiUsabilityStatsListener;
+    @Mock OnWifiUsabilityStatsListener mOnWifiUsabilityStatsListener;
 
     private Executor mExecutor;
     private Handler mHandler;
@@ -1348,29 +1348,29 @@
     }
 
     /**
-     * Verify the call to addWifiUsabilityStatsListener goes to WifiServiceImpl.
+     * Verify the call to addOnWifiUsabilityStatsListener goes to WifiServiceImpl.
      */
     @Test
-    public void addWifiUsabilityStatsListeneroesToWifiServiceImpl() throws Exception {
+    public void addOnWifiUsabilityStatsListeneroesToWifiServiceImpl() throws Exception {
         mExecutor = new SynchronousExecutor();
-        mWifiManager.addWifiUsabilityStatsListener(mExecutor, mWifiUsabilityStatsListener);
-        verify(mWifiService).addWifiUsabilityStatsListener(any(IBinder.class),
-                any(IWifiUsabilityStatsListener.Stub.class), anyInt());
+        mWifiManager.addOnWifiUsabilityStatsListener(mExecutor, mOnWifiUsabilityStatsListener);
+        verify(mWifiService).addOnWifiUsabilityStatsListener(any(IBinder.class),
+                any(IOnWifiUsabilityStatsListener.Stub.class), anyInt());
     }
 
     /**
-     * Verify the call to removeWifiUsabilityStatsListener goes to WifiServiceImpl.
+     * Verify the call to removeOnWifiUsabilityStatsListener goes to WifiServiceImpl.
      */
     @Test
-    public void removeWifiUsabilityListenerGoesToWifiServiceImpl() throws Exception {
+    public void removeOnWifiUsabilityListenerGoesToWifiServiceImpl() throws Exception {
         ArgumentCaptor<Integer> listenerIdentifier = ArgumentCaptor.forClass(Integer.class);
         mExecutor = new SynchronousExecutor();
-        mWifiManager.addWifiUsabilityStatsListener(mExecutor, mWifiUsabilityStatsListener);
-        verify(mWifiService).addWifiUsabilityStatsListener(any(IBinder.class),
-                any(IWifiUsabilityStatsListener.Stub.class), listenerIdentifier.capture());
+        mWifiManager.addOnWifiUsabilityStatsListener(mExecutor, mOnWifiUsabilityStatsListener);
+        verify(mWifiService).addOnWifiUsabilityStatsListener(any(IBinder.class),
+                any(IOnWifiUsabilityStatsListener.Stub.class), listenerIdentifier.capture());
 
-        mWifiManager.removeWifiUsabilityStatsListener(mWifiUsabilityStatsListener);
-        verify(mWifiService).removeWifiUsabilityStatsListener(
+        mWifiManager.removeOnWifiUsabilityStatsListener(mOnWifiUsabilityStatsListener);
+        verify(mWifiService).removeOnWifiUsabilityStatsListener(
                 eq((int) listenerIdentifier.getValue()));
     }
 
diff --git a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
index a22f8ce..8e37113 100644
--- a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
@@ -81,29 +81,35 @@
     private static void assertWifiUsabilityStatsEntryEquals(
             WifiUsabilityStatsEntry expected,
             WifiUsabilityStatsEntry actual) {
-        assertEquals(expected.timeStampMs, actual.timeStampMs);
-        assertEquals(expected.rssi, actual.rssi);
-        assertEquals(expected.linkSpeedMbps, actual.linkSpeedMbps);
-        assertEquals(expected.totalTxSuccess, actual.totalTxSuccess);
-        assertEquals(expected.totalTxRetries, actual.totalTxRetries);
-        assertEquals(expected.totalTxBad, actual.totalTxBad);
-        assertEquals(expected.totalRxSuccess, actual.totalRxSuccess);
-        assertEquals(expected.totalRadioOnTimeMs, actual.totalRadioOnTimeMs);
-        assertEquals(expected.totalRadioTxTimeMs, actual.totalRadioTxTimeMs);
-        assertEquals(expected.totalRadioRxTimeMs, actual.totalRadioRxTimeMs);
-        assertEquals(expected.totalScanTimeMs, actual.totalScanTimeMs);
-        assertEquals(expected.totalNanScanTimeMs, actual.totalNanScanTimeMs);
-        assertEquals(expected.totalBackgroundScanTimeMs, actual.totalBackgroundScanTimeMs);
-        assertEquals(expected.totalRoamScanTimeMs, actual.totalRoamScanTimeMs);
-        assertEquals(expected.totalPnoScanTimeMs, actual.totalPnoScanTimeMs);
-        assertEquals(expected.totalHotspot2ScanTimeMs, actual.totalHotspot2ScanTimeMs);
-        assertEquals(expected.totalCcaBusyFreqTimeMs, actual.totalCcaBusyFreqTimeMs);
-        assertEquals(expected.totalRadioOnFreqTimeMs, actual.totalRadioOnFreqTimeMs);
-        assertEquals(expected.totalBeaconRx, actual.totalBeaconRx);
-        assertEquals(expected.probeStatusSinceLastUpdate, actual.probeStatusSinceLastUpdate);
-        assertEquals(expected.probeElapsedTimeMsSinceLastUpdate,
-                actual.probeElapsedTimeMsSinceLastUpdate);
-        assertEquals(expected.probeMcsRateSinceLastUpdate, actual.probeMcsRateSinceLastUpdate);
-        assertEquals(expected.rxLinkSpeedMbps, actual.rxLinkSpeedMbps);
+        assertEquals(expected.getTimeStampMillis(), actual.getTimeStampMillis());
+        assertEquals(expected.getRssi(), actual.getRssi());
+        assertEquals(expected.getLinkSpeedMbps(), actual.getLinkSpeedMbps());
+        assertEquals(expected.getTotalTxSuccess(), actual.getTotalTxSuccess());
+        assertEquals(expected.getTotalTxRetries(), actual.getTotalTxRetries());
+        assertEquals(expected.getTotalTxBad(), actual.getTotalTxBad());
+        assertEquals(expected.getTotalRxSuccess(), actual.getTotalRxSuccess());
+        assertEquals(expected.getTotalRadioOnTimeMillis(), actual.getTotalRadioOnTimeMillis());
+        assertEquals(expected.getTotalRadioTxTimeMillis(), actual.getTotalRadioTxTimeMillis());
+        assertEquals(expected.getTotalRadioRxTimeMillis(), actual.getTotalRadioRxTimeMillis());
+        assertEquals(expected.getTotalScanTimeMillis(), actual.getTotalScanTimeMillis());
+        assertEquals(expected.getTotalNanScanTimeMillis(), actual.getTotalNanScanTimeMillis());
+        assertEquals(expected.getTotalBackgroundScanTimeMillis(),
+                actual.getTotalBackgroundScanTimeMillis());
+        assertEquals(expected.getTotalRoamScanTimeMillis(), actual.getTotalRoamScanTimeMillis());
+        assertEquals(expected.getTotalPnoScanTimeMillis(), actual.getTotalPnoScanTimeMillis());
+        assertEquals(expected.getTotalHotspot2ScanTimeMillis(),
+                actual.getTotalHotspot2ScanTimeMillis());
+        assertEquals(expected.getTotalCcaBusyFreqTimeMillis(),
+                actual.getTotalCcaBusyFreqTimeMillis());
+        assertEquals(expected.getTotalRadioOnFreqTimeMillis(),
+                actual.getTotalRadioOnFreqTimeMillis());
+        assertEquals(expected.getTotalBeaconRx(), actual.getTotalBeaconRx());
+        assertEquals(expected.getProbeStatusSinceLastUpdate(),
+                actual.getProbeStatusSinceLastUpdate());
+        assertEquals(expected.getProbeElapsedTimeSinceLastUpdateMillis(),
+                actual.getProbeElapsedTimeSinceLastUpdateMillis());
+        assertEquals(expected.getProbeMcsRateSinceLastUpdate(),
+                actual.getProbeMcsRateSinceLastUpdate());
+        assertEquals(expected.getRxLinkSpeedMbps(), actual.getRxLinkSpeedMbps());
     }
 }