Merge "New ContentCapture constant: ActivityEvent.TYPE_ACTIVITY_DESTROYED"
diff --git a/Android.bp b/Android.bp
index 4219d36..05c7dbc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -772,7 +772,6 @@
         "android.hardware.vibrator-V1.3-java",
         "android.hardware.wifi-V1.0-java-constants",
         "networkstack-aidl-framework-java",
-        "netd_aidl_parcelables-java",
         "devicepolicyprotosnano",
     ],
 
@@ -912,6 +911,9 @@
         "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
         "core/java/android/net/ip/IIpClient.aidl",
         "core/java/android/net/ip/IIpClientCallbacks.aidl",
+        "core/java/android/net/IIpMemoryStore.aidl",
+        "core/java/android/net/IIpMemoryStoreCallbacks.aidl",
+        "core/java/android/net/ipmemorystore/**/*.aidl",
     ],
     backend: {
         ndk: {
@@ -925,12 +927,20 @@
 }
 
 aidl_interface {
+    name: "ipmemorystore-aidl-interfaces",
+    local_include_dir: "core/java",
+    srcs: [
+        "core/java/android/net/IIpMemoryStore.aidl",
+        "core/java/android/net/IIpMemoryStoreCallbacks.aidl",
+        "core/java/android/net/ipmemorystore/**/*.aidl",
+    ],
+}
+
+aidl_interface {
     name: "networkstack-aidl-framework",
     local_include_dir: "core/java",
     srcs: [
         "core/java/android/net/TcpKeepalivePacketDataParcelable.aidl",
-        "core/java/android/net/IIpMemoryStore.aidl",
-        "core/java/android/net/ipmemorystore/**/*.aidl",
     ],
     api_dir: "aidl/networkstack",
     backend: {
@@ -941,18 +951,25 @@
 }
 
 filegroup {
-    name: "framework-networkstack-shared-srcs",
+    name: "framework-annotations",
     srcs: [
-        // TODO: remove these annotations as soon as we can use andoid.support.annotations.*
         "core/java/android/annotation/NonNull.java",
         "core/java/android/annotation/Nullable.java",
         "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/IntRange.java",
         "core/java/android/annotation/UnsupportedAppUsage.java",
-        "core/java/android/net/DhcpResults.java",
-        "core/java/android/util/LocalLog.java",
         "core/java/com/android/internal/annotations/GuardedBy.java",
         "core/java/com/android/internal/annotations/VisibleForTesting.java",
+    ]
+}
+
+filegroup {
+    name: "framework-networkstack-shared-srcs",
+    srcs: [
+        // TODO: remove these annotations as soon as we can use andoid.support.annotations.*
+        ":framework-annotations",
+        "core/java/android/net/DhcpResults.java",
+        "core/java/android/util/LocalLog.java",
         "core/java/com/android/internal/util/HexDump.java",
         "core/java/com/android/internal/util/IndentingPrintWriter.java",
         "core/java/com/android/internal/util/IState.java",
@@ -1807,4 +1824,4 @@
     name: "framework-aidl-mappings",
     srcs: [":framework-defaults"],
     output: "framework-aidl-mappings.txt"
-}
\ No newline at end of file
+}
diff --git a/api/current.txt b/api/current.txt
index dcaa28b..8ff63c0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5429,7 +5429,7 @@
     method @NonNull public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput);
     method @NonNull public android.app.Notification.Action build();
     method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
-    method public android.os.Bundle getExtras();
+    method @NonNull public android.os.Bundle getExtras();
     method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean);
     method @NonNull public android.app.Notification.Action.Builder setContextual(boolean);
     method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int);
@@ -6623,7 +6623,7 @@
     method @Nullable public String[] getAccountTypesWithManagementDisabled();
     method @Nullable public java.util.List<android.content.ComponentName> getActiveAdmins();
     method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName);
-    method @Nullable public java.util.List<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
+    method @Nullable public java.util.Set<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
     method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
     method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
     method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
@@ -6736,7 +6736,7 @@
     method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
     method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
     method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.List<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.Set<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean);
     method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
     method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11676,7 +11676,6 @@
     field public static final String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
     field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
-    field public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable";
     field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
     field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
     field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
@@ -12016,7 +12015,7 @@
     method @NonNull public android.content.pm.ShortcutInfo.Builder setIntents(@NonNull android.content.Intent[]);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setLocusId(@NonNull android.content.LocusId);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLabel(@NonNull CharSequence);
-    method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived();
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived(boolean);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setPerson(@NonNull android.app.Person);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setPersons(@NonNull android.app.Person[]);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setRank(int);
@@ -23294,6 +23293,7 @@
     field public static final String ACTION_MICROPHONE_MUTE_CHANGED = "android.media.action.MICROPHONE_MUTE_CHANGED";
     field @Deprecated public static final String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
     field public static final String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
+    field public static final String ACTION_SPEAKERPHONE_STATE_CHANGED = "android.media.action.SPEAKERPHONE_STATE_CHANGED";
     field public static final int ADJUST_LOWER = -1; // 0xffffffff
     field public static final int ADJUST_MUTE = -100; // 0xffffff9c
     field public static final int ADJUST_RAISE = 1; // 0x1
@@ -25698,14 +25698,14 @@
   public static class MediaPlayer2.DrmEventCallback {
     ctor public MediaPlayer2.DrmEventCallback();
     method public void onDrmConfig(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm);
-    method public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo);
-    method public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
+    method @Nullable public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.DrmInfo);
+    method @NonNull public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
     method public void onDrmPrepared(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, @Nullable byte[]);
   }
 
   public static final class MediaPlayer2.DrmInfo {
-    method public java.util.Map<java.util.UUID,byte[]> getPssh();
-    method public java.util.List<java.util.UUID> getSupportedSchemes();
+    method @NonNull public java.util.Map<java.util.UUID,byte[]> getPssh();
+    method @NonNull public java.util.List<java.util.UUID> getSupportedSchemes();
   }
 
   public static final class MediaPlayer2.DrmPreparationInfo {
@@ -25713,13 +25713,13 @@
 
   public static final class MediaPlayer2.DrmPreparationInfo.Builder {
     ctor public MediaPlayer2.DrmPreparationInfo.Builder();
-    method public android.media.MediaPlayer2.DrmPreparationInfo build();
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]);
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]);
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String);
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>);
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo build();
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID);
   }
 
   public static class MediaPlayer2.EventCallback {
@@ -25750,7 +25750,7 @@
   }
 
   public static final class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException {
-    ctor public MediaPlayer2.NoDrmSchemeException(String);
+    ctor public MediaPlayer2.NoDrmSchemeException(@Nullable String);
   }
 
   public static class MediaPlayer2.TrackInfo {
@@ -28757,10 +28757,9 @@
   }
 
   public final class DnsResolver {
-    method public static android.net.DnsResolver getInstance();
-    method public void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException;
-    method public void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException;
-    method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.InetAddressAnswerListener) throws android.system.ErrnoException;
+    method @NonNull public static android.net.DnsResolver getInstance();
+    method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>);
+    method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>);
     field public static final int CLASS_IN = 1; // 0x1
     field public static final int FLAG_EMPTY = 0; // 0x0
     field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
@@ -28770,12 +28769,23 @@
     field public static final int TYPE_AAAA = 28; // 0x1c
   }
 
-  public static interface DnsResolver.InetAddressAnswerListener {
-    method public void onAnswer(@NonNull java.util.List<java.net.InetAddress>);
+  public abstract static class DnsResolver.AnswerCallback<T> {
+    ctor public DnsResolver.AnswerCallback(@NonNull android.net.DnsResolver.AnswerParser<T>);
+    method public abstract void onAnswer(@NonNull T);
+    method public abstract void onParseException(@NonNull android.net.ParseException);
+    method public abstract void onQueryException(@NonNull android.system.ErrnoException);
   }
 
-  public static interface DnsResolver.RawAnswerListener {
-    method public void onAnswer(@Nullable byte[]);
+  public static interface DnsResolver.AnswerParser<T> {
+    method @NonNull public T parse(@NonNull byte[]) throws android.net.ParseException;
+  }
+
+  public abstract static class DnsResolver.InetAddressAnswerCallback extends android.net.DnsResolver.AnswerCallback<java.util.List<java.net.InetAddress>> {
+    ctor public DnsResolver.InetAddressAnswerCallback();
+  }
+
+  public abstract static class DnsResolver.RawAnswerCallback extends android.net.DnsResolver.AnswerCallback<byte[]> {
+    ctor public DnsResolver.RawAnswerCallback();
   }
 
   public class InetAddresses {
@@ -29090,6 +29100,8 @@
   }
 
   public class ParseException extends java.lang.RuntimeException {
+    ctor public ParseException(@NonNull String);
+    ctor public ParseException(@NonNull String, @NonNull Throwable);
     field public String response;
   }
 
@@ -45049,7 +45061,6 @@
     method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean removeSubscriptionsFromGroup(@NonNull int[]);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setMetered(boolean, int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String setSubscriptionGroup(@NonNull int[]);
     method public void setSubscriptionOverrideCongested(int, boolean, long);
@@ -45287,7 +45298,7 @@
     field public static final int PHONE_TYPE_GSM = 1; // 0x1
     field public static final int PHONE_TYPE_NONE = 0; // 0x0
     field public static final int PHONE_TYPE_SIP = 3; // 0x3
-    field public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; // 0x2
+    field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2
     field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0
     field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1
     field public static final int SIM_STATE_ABSENT = 1; // 0x1
@@ -51944,6 +51955,7 @@
     method @NonNull public android.view.WindowInsets consumeStableInsets();
     method @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
     method @Nullable public android.view.DisplayCutout getDisplayCutout();
+    method @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
     method public int getStableInsetBottom();
     method public int getStableInsetLeft();
     method public int getStableInsetRight();
@@ -51955,6 +51967,7 @@
     method public int getSystemWindowInsetRight();
     method public int getSystemWindowInsetTop();
     method @NonNull public android.graphics.Insets getSystemWindowInsets();
+    method @NonNull public android.graphics.Insets getTappableElementInsets();
     method public boolean hasInsets();
     method public boolean hasStableInsets();
     method public boolean hasSystemWindowInsets();
@@ -51970,9 +51983,11 @@
     ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets);
     method @NonNull public android.view.WindowInsets build();
     method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
+    method @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets);
+    method @NonNull public android.view.WindowInsets.Builder setTappableElementInsets(@NonNull android.graphics.Insets);
   }
 
   public interface WindowManager extends android.view.ViewManager {
@@ -53017,7 +53032,7 @@
     method public int describeContents();
     method @NonNull public static android.view.contentcapture.ContentCaptureContext forLocusId(@NonNull String);
     method @Nullable public android.os.Bundle getExtras();
-    method @NonNull public android.content.LocusId getLocusId();
+    method @Nullable public android.content.LocusId getLocusId();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureContext> CREATOR;
   }
diff --git a/api/removed.txt b/api/removed.txt
index 4fe0ed9..fa07094 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -314,17 +314,11 @@
 package android.net {
 
   public class ConnectivityManager {
-    method @Deprecated public void getLatestTetheringEntitlementValue(int, boolean, @NonNull android.net.ConnectivityManager.TetheringEntitlementValueListener, @Nullable android.os.Handler);
     method @Deprecated public boolean requestRouteToHost(int, int);
     method @Deprecated public int startUsingNetworkFeature(int, String);
     method @Deprecated public int stopUsingNetworkFeature(int, String);
   }
 
-  @Deprecated public abstract static class ConnectivityManager.TetheringEntitlementValueListener {
-    ctor public ConnectivityManager.TetheringEntitlementValueListener();
-    method public void onEntitlementResult(int);
-  }
-
   @Deprecated public class NetworkBadging {
     method @NonNull public static android.graphics.drawable.Drawable getWifiIcon(@IntRange(from=0, to=4) int, int, @Nullable android.content.res.Resources.Theme);
     field public static final int BADGING_4K = 30; // 0x1e
diff --git a/api/system-current.txt b/api/system-current.txt
index 147ccd8..47e2b5b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -186,6 +186,7 @@
     field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
     field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
     field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
+    field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
     field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
     field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
     field public static final String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
@@ -665,7 +666,6 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
     method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
-    method @Nullable @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS, conditional=true) public android.content.ComponentName getProfileOwnerAsUser(@NonNull android.os.UserHandle);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState();
     method public boolean isDeviceManaged();
@@ -1837,9 +1837,9 @@
   }
 
   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) @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(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
     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
@@ -4282,11 +4282,14 @@
 
 package android.net.apf {
 
-  public class ApfCapabilities {
+  public final class ApfCapabilities implements android.os.Parcelable {
     ctor public ApfCapabilities(int, int, int);
+    method public int describeContents();
     method public static boolean getApfDrop8023Frames(android.content.Context);
     method public static int[] getApfEthTypeBlackList(android.content.Context);
     method public boolean hasDataAccess();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
     field public final int apfPacketFormat;
     field public final int apfVersionSupported;
     field public final int maximumApfProgramSize;
@@ -4484,16 +4487,16 @@
 
 package android.net.util {
 
-  public class SocketUtils {
+  public final class SocketUtils {
     method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException;
     method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
     method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException;
     method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
     method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
     method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
-    method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
-    method public static java.net.SocketAddress makePacketSocketAddress(short, int);
-    method public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
     method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
   }
 
@@ -4934,6 +4937,10 @@
 
   public final class WifiUsabilityStatsEntry implements android.os.Parcelable {
     method public int describeContents();
+    method public int getCellularDataNetworkType();
+    method public int getCellularSignalStrengthDb();
+    method public int getCellularSignalStrengthDbm();
+    method public boolean getIsSameRegisteredCell();
     method public int getLinkSpeedMbps();
     method public int getProbeElapsedTimeSinceLastUpdateMillis();
     method public int getProbeMcsRateSinceLastUpdate();
@@ -5616,6 +5623,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile(int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isPrimaryUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String);
@@ -5860,6 +5868,7 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
     field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
     field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot";
+    field public static final String NAMESPACE_APP_COMPAT = "app_compat";
     field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
@@ -5870,9 +5879,12 @@
     field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
     field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
     field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+    field public static final String NAMESPACE_ROLLBACK = "rollback";
+    field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
     field public static final String NAMESPACE_RUNTIME = "runtime";
     field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
     field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
+    field public static final String NAMESPACE_SCHEDULER = "scheduler";
     field public static final String NAMESPACE_SYSTEMUI = "systemui";
     field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
   }
@@ -5901,18 +5913,6 @@
     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 static interface DeviceConfig.Scheduler {
-    field public static final String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
-    field public static final String NAMESPACE = "scheduler";
-  }
-
   public static interface DeviceConfig.Storage {
     field public static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
     field public static final String NAMESPACE = "storage";
@@ -6055,6 +6055,7 @@
     field public static final String ACTION_ACCESSIBILITY_DETAILS_SETTINGS = "android.settings.ACCESSIBILITY_DETAILS_SETTINGS";
     field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
     field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS";
+    field public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
     field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
     field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
   }
@@ -7237,7 +7238,6 @@
     field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828
     field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c
     field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850
-    field public static final int ACCESS_PROBE_LIMIT_REACHED = 2079; // 0x81f
     field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30
     field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
     field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
@@ -7352,9 +7352,7 @@
     field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e
     field public static final int INVALID_SIM_STATE = 2224; // 0x8b0
     field public static final int INVALID_TRANSACTION_ID = 81; // 0x51
-    field public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 2052; // 0x804
     field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff
-    field public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 2053; // 0x805
     field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca
     field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77
     field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
@@ -7373,6 +7371,10 @@
     field public static final int MAC_FAILURE = 2183; // 0x887
     field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
     field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
+    field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
+    field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804
+    field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805
+    field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
     field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f
     field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61
     field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802
@@ -7481,7 +7483,6 @@
     field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5
     field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8
     field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9
-    field public static final int PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
     field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6
     field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7
     field public static final int PPP_TIMEOUT = 2228; // 0x8b4
@@ -7682,15 +7683,14 @@
     field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
   }
 
-  public class NetworkRegistrationInfo implements android.os.Parcelable {
-    ctor public NetworkRegistrationInfo(int, int, int, int, int, boolean, @NonNull int[], @Nullable android.telephony.CellIdentity);
+  public final class NetworkRegistrationInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getAccessNetworkTechnology();
-    method @NonNull public int[] getAvailableServices();
+    method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
     method @Nullable public android.telephony.CellIdentity getCellIdentity();
     method @Nullable public android.telephony.DataSpecificRegistrationStates getDataSpecificStates();
     method public int getDomain();
-    method public int getRegState();
+    method public int getRegistrationState();
     method public int getRejectCause();
     method public int getRoamingType();
     method public int getTransportType();
@@ -7700,31 +7700,30 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR;
     field public static final int DOMAIN_CS = 1; // 0x1
     field public static final int DOMAIN_PS = 2; // 0x2
-    field public static final int REG_STATE_DENIED = 3; // 0x3
-    field public static final int REG_STATE_HOME = 1; // 0x1
-    field public static final int REG_STATE_NOT_REG_NOT_SEARCHING = 0; // 0x0
-    field public static final int REG_STATE_NOT_REG_SEARCHING = 2; // 0x2
-    field public static final int REG_STATE_ROAMING = 5; // 0x5
-    field public static final int REG_STATE_UNKNOWN = 4; // 0x4
+    field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3
+    field public static final int REGISTRATION_STATE_HOME = 1; // 0x1
+    field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0
+    field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2
+    field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5
+    field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4
     field public static final int SERVICE_TYPE_DATA = 2; // 0x2
     field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5
     field public static final int SERVICE_TYPE_SMS = 3; // 0x3
+    field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0
     field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4
     field public static final int SERVICE_TYPE_VOICE = 1; // 0x1
   }
 
-  public static class NetworkRegistrationInfo.Builder {
+  public static final class NetworkRegistrationInfo.Builder {
     ctor public NetworkRegistrationInfo.Builder();
     method @NonNull public android.telephony.NetworkRegistrationInfo build();
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAccessNetworkTechnology(int);
-    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAvailableServices(@NonNull int[]);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAvailableServices(@NonNull java.util.List<java.lang.Integer>);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setCellIdentity(@Nullable android.telephony.CellIdentity);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setDomain(int);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setEmergencyOnly(boolean);
-    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setNrStatus(int);
-    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegState(int);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegistrationState(int);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRejectCause(int);
-    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRoamingType(int);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setTransportType(int);
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 4e3a984..0fcf727 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -14,6 +14,7 @@
     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 TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
     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";
@@ -720,13 +721,14 @@
   }
 
   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();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
+    method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+    method @RequiresPermission(android.Manifest.permission.TEST_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 String PROPERTY_ROLLBACK_LIFETIME_MILLIS = "rollback_lifetime_in_millis";
     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
@@ -1305,11 +1307,14 @@
 
 package android.net.apf {
 
-  public class ApfCapabilities {
+  public final class ApfCapabilities implements android.os.Parcelable {
     ctor public ApfCapabilities(int, int, int);
+    method public int describeContents();
     method public static boolean getApfDrop8023Frames(android.content.Context);
     method public static int[] getApfEthTypeBlackList(android.content.Context);
     method public boolean hasDataAccess();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
     field public final int apfPacketFormat;
     field public final int apfVersionSupported;
     field public final int maximumApfProgramSize;
@@ -1507,16 +1512,16 @@
 
 package android.net.util {
 
-  public class SocketUtils {
+  public final class SocketUtils {
     method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException;
     method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
     method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException;
     method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
     method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
     method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
-    method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
-    method public static java.net.SocketAddress makePacketSocketAddress(short, int);
-    method public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
     method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
   }
 
@@ -2067,6 +2072,8 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+    field public static final String NAMESPACE_ROLLBACK = "rollback";
+    field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
   }
 
   public static interface DeviceConfig.OnPropertiesChangedListener {
@@ -2092,13 +2099,6 @@
     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;
@@ -2549,7 +2549,8 @@
     method public int getCarrierIdListVersion();
     method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
-    method public void setCarrierTestOverride(String, String, String, String, String, String, String);
+    method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
+    method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String);
     field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
@@ -3176,19 +3177,19 @@
 
   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD}) public @interface InspectableProperty {
     method public abstract int attributeId() default android.content.res.Resources.ID_NULL;
-    method public abstract android.view.inspector.InspectableProperty.EnumMap[] enumMapping() default {};
-    method public abstract android.view.inspector.InspectableProperty.FlagMap[] flagMapping() default {};
+    method public abstract android.view.inspector.InspectableProperty.EnumEntry[] enumMapping() default {};
+    method public abstract android.view.inspector.InspectableProperty.FlagEntry[] flagMapping() default {};
     method public abstract boolean hasAttributeId() default true;
     method public abstract String name() default "";
     method public abstract android.view.inspector.InspectableProperty.ValueType valueType() default android.view.inspector.InspectableProperty.ValueType.INFERRED;
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.EnumMap {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.EnumEntry {
     method public abstract String name();
     method public abstract int value();
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.FlagMap {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.FlagEntry {
     method public abstract int mask() default 0;
     method public abstract String name();
     method public abstract int target();
@@ -3217,7 +3218,7 @@
   }
 
   public class DatePicker extends android.widget.FrameLayout {
-    method @android.view.inspector.InspectableProperty(name="datePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumMap(value=android.widget.DatePicker.MODE_SPINNER, name="spinner"), @android.view.inspector.InspectableProperty.EnumMap(value=android.widget.DatePicker.MODE_CALENDAR, name="calendar")}) public int getMode();
+    method @android.view.inspector.InspectableProperty(name="datePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumEntry(value=android.widget.DatePicker.MODE_SPINNER, name="spinner"), @android.view.inspector.InspectableProperty.EnumEntry(value=android.widget.DatePicker.MODE_CALENDAR, name="calendar")}) public int getMode();
     field public static final int MODE_CALENDAR = 2; // 0x2
     field public static final int MODE_SPINNER = 1; // 0x1
   }
@@ -3253,7 +3254,7 @@
     method public android.view.View getAmView();
     method public android.view.View getHourView();
     method public android.view.View getMinuteView();
-    method @android.view.inspector.InspectableProperty(name="timePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumMap(name="clock", value=android.widget.TimePicker.MODE_CLOCK), @android.view.inspector.InspectableProperty.EnumMap(name="spinner", value=android.widget.TimePicker.MODE_SPINNER)}) public int getMode();
+    method @android.view.inspector.InspectableProperty(name="timePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumEntry(name="clock", value=android.widget.TimePicker.MODE_CLOCK), @android.view.inspector.InspectableProperty.EnumEntry(name="spinner", value=android.widget.TimePicker.MODE_SPINNER)}) public int getMode();
     method public android.view.View getPmView();
     field public static final int MODE_CLOCK = 2; // 0x2
     field public static final int MODE_SPINNER = 1; // 0x1
diff --git a/cmds/idmap2/idmap2/Commands.h b/cmds/idmap2/idmap2/Commands.h
index dcc69b3..718e361 100644
--- a/cmds/idmap2/idmap2/Commands.h
+++ b/cmds/idmap2/idmap2/Commands.h
@@ -20,10 +20,12 @@
 #include <string>
 #include <vector>
 
-bool Create(const std::vector<std::string>& args, std::ostream& out_error);
-bool Dump(const std::vector<std::string>& args, std::ostream& out_error);
-bool Lookup(const std::vector<std::string>& args, std::ostream& out_error);
-bool Scan(const std::vector<std::string>& args, std::ostream& out_error);
-bool Verify(const std::vector<std::string>& args, std::ostream& out_error);
+#include "idmap2/Result.h"
+
+android::idmap2::Result<android::idmap2::Unit> Create(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Verify(const std::vector<std::string>& args);
 
 #endif  // IDMAP2_IDMAP2_COMMANDS_H_
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index c416fa1..fdbb210 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -33,14 +33,17 @@
 using android::ApkAssets;
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
 using android::idmap2::Idmap;
 using android::idmap2::PoliciesToBitmask;
 using android::idmap2::PolicyBitmask;
 using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
+using android::idmap2::Unit;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 using android::idmap2::utils::UidHasWriteAccessToPath;
 
-bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Create(const std::vector<std::string>& args) {
   SYSTRACE << "Create " << args;
   std::string target_apk_path;
   std::string overlay_apk_path;
@@ -63,15 +66,14 @@
                           &policies)
           .OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks",
                         &ignore_overlayable);
-  if (!opts.Parse(args, out_error)) {
-    return false;
+  const auto opts_ok = opts.Parse(args);
+  if (!opts_ok) {
+    return opts_ok.GetError();
   }
 
   const uid_t uid = getuid();
   if (!UidHasWriteAccessToPath(uid, idmap_path)) {
-    out_error << "error: uid " << uid << " does not have write access to " << idmap_path
-              << std::endl;
-    return false;
+    return Error("uid %d does not have write access to %s", uid, idmap_path.c_str());
   }
 
   PolicyBitmask fulfilled_policies = 0;
@@ -79,8 +81,7 @@
   if (conv_result) {
     fulfilled_policies |= *conv_result;
   } else {
-    out_error << "error: " << conv_result.GetErrorMessage() << std::endl;
-    return false;
+    return conv_result.GetError();
   }
 
   if (fulfilled_policies == 0) {
@@ -89,36 +90,33 @@
 
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
   if (!target_apk) {
-    out_error << "error: failed to load apk " << target_apk_path << std::endl;
-    return false;
+    return Error("failed to load apk %s", target_apk_path.c_str());
   }
 
   const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   if (!overlay_apk) {
-    out_error << "error: failed to load apk " << overlay_apk_path << std::endl;
-    return false;
+    return Error("failed to load apk %s", overlay_apk_path.c_str());
   }
 
+  std::stringstream stream;
   const std::unique_ptr<const Idmap> idmap =
       Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           fulfilled_policies, !ignore_overlayable, out_error);
+                           fulfilled_policies, !ignore_overlayable, stream);
   if (!idmap) {
-    return false;
+    return Error("failed to create idmap: %s", stream.str().c_str());
   }
 
   umask(kIdmapFilePermissionMask);
   std::ofstream fout(idmap_path);
   if (fout.fail()) {
-    out_error << "failed to open idmap path " << idmap_path << std::endl;
-    return false;
+    return Error("failed to open idmap path %s", idmap_path.c_str());
   }
   BinaryStreamVisitor visitor(fout);
   idmap->accept(&visitor);
   fout.close();
   if (fout.fail()) {
-    out_error << "failed to write to idmap path " << idmap_path << std::endl;
-    return false;
+    return Error("failed to write to idmap path %s", idmap_path.c_str());
   }
 
-  return true;
+  return Unit{};
 }
diff --git a/cmds/idmap2/idmap2/Dump.cpp b/cmds/idmap2/idmap2/Dump.cpp
index 3947703..fd58222 100644
--- a/cmds/idmap2/idmap2/Dump.cpp
+++ b/cmds/idmap2/idmap2/Dump.cpp
@@ -17,6 +17,7 @@
 #include <fstream>
 #include <iostream>
 #include <memory>
+#include <sstream>
 #include <string>
 #include <vector>
 
@@ -24,14 +25,18 @@
 #include "idmap2/Idmap.h"
 #include "idmap2/PrettyPrintVisitor.h"
 #include "idmap2/RawPrintVisitor.h"
+#include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
 
 using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
 using android::idmap2::Idmap;
 using android::idmap2::PrettyPrintVisitor;
 using android::idmap2::RawPrintVisitor;
+using android::idmap2::Result;
+using android::idmap2::Unit;
 
-bool Dump(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Dump(const std::vector<std::string>& args) {
   SYSTRACE << "Dump " << args;
   std::string idmap_path;
   bool verbose;
@@ -40,14 +45,16 @@
       CommandLineOptions("idmap2 dump")
           .MandatoryOption("--idmap-path", "input: path to idmap file to pretty-print", &idmap_path)
           .OptionalFlag("--verbose", "annotate every byte of the idmap", &verbose);
-  if (!opts.Parse(args, out_error)) {
-    return false;
+  const auto opts_ok = opts.Parse(args);
+  if (!opts_ok) {
+    return opts_ok.GetError();
   }
+  std::stringstream stream;
   std::ifstream fin(idmap_path);
-  const std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(fin, out_error);
+  const std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(fin, stream);
   fin.close();
   if (!idmap) {
-    return false;
+    return Error("failed to load idmap: %s", stream.str().c_str());
   }
 
   if (verbose) {
@@ -58,5 +65,5 @@
     idmap->accept(&visitor);
   }
 
-  return true;
+  return Unit{};
 }
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index 83a40ef..677c6fa 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -57,6 +57,7 @@
 using android::idmap2::IdmapHeader;
 using android::idmap2::ResourceId;
 using android::idmap2::Result;
+using android::idmap2::Unit;
 using android::idmap2::Xml;
 using android::idmap2::ZipFile;
 using android::util::Utf16ToUtf8;
@@ -157,7 +158,7 @@
 }
 }  // namespace
 
-bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Lookup(const std::vector<std::string>& args) {
   SYSTRACE << "Lookup " << args;
   std::vector<std::string> idmap_paths;
   std::string config_str;
@@ -172,14 +173,14 @@
                            "'[package:]type/name') to look up",
                            &resid_str);
 
-  if (!opts.Parse(args, out_error)) {
-    return false;
+  const auto opts_ok = opts.Parse(args);
+  if (!opts_ok) {
+    return opts_ok.GetError();
   }
 
   ConfigDescription config;
   if (!ConfigDescription::Parse(config_str, &config)) {
-    out_error << "error: failed to parse config" << std::endl;
-    return false;
+    return Error("failed to parse config");
   }
 
   std::vector<std::unique_ptr<const ApkAssets>> apk_assets;
@@ -191,39 +192,33 @@
     auto idmap_header = IdmapHeader::FromBinaryStream(fin);
     fin.close();
     if (!idmap_header) {
-      out_error << "error: failed to read idmap from " << idmap_path << std::endl;
-      return false;
+      return Error("failed to read idmap from %s", idmap_path.c_str());
     }
 
     if (i == 0) {
       target_path = idmap_header->GetTargetPath().to_string();
       auto target_apk = ApkAssets::Load(target_path);
       if (!target_apk) {
-        out_error << "error: failed to read target apk from " << target_path << std::endl;
-        return false;
+        return Error("failed to read target apk from %s", target_path.c_str());
       }
       apk_assets.push_back(std::move(target_apk));
 
       const Result<std::string> package_name =
           GetTargetPackageNameFromManifest(idmap_header->GetOverlayPath().to_string());
       if (!package_name) {
-        out_error << "error: failed to parse android:targetPackage from overlay manifest"
-                  << std::endl;
-        return false;
+        return Error("failed to parse android:targetPackage from overlay manifest");
       }
       target_package_name = *package_name;
     } else if (target_path != idmap_header->GetTargetPath()) {
-      out_error << "error: different target APKs (expected target APK " << target_path << " but "
-                << idmap_path << " has target APK " << idmap_header->GetTargetPath() << ")"
-                << std::endl;
-      return false;
+      return Error("different target APKs (expected target APK %s but %s has target APK %s)",
+                   target_path.c_str(), idmap_path.c_str(),
+                   idmap_header->GetTargetPath().to_string().c_str());
     }
 
     auto overlay_apk = ApkAssets::LoadOverlay(idmap_path);
     if (!overlay_apk) {
-      out_error << "error: failed to read overlay apk from " << idmap_header->GetOverlayPath()
-                << std::endl;
-      return false;
+      return Error("failed to read overlay apk from %s",
+                   idmap_header->GetOverlayPath().to_string().c_str());
     }
     apk_assets.push_back(std::move(overlay_apk));
   }
@@ -238,16 +233,14 @@
 
   const Result<ResourceId> resid = ParseResReference(am, resid_str, target_package_name);
   if (!resid) {
-    out_error << "error: failed to parse resource ID" << std::endl;
-    return false;
+    return Error(resid.GetError(), "failed to parse resource ID");
   }
 
   const Result<std::string> value = GetValue(am, *resid);
   if (!value) {
-    out_error << StringPrintf("error: resource 0x%08x not found", *resid) << std::endl;
-    return false;
+    return Error(value.GetError(), "resource 0x%08x not found", *resid);
   }
   std::cout << *value << std::endl;
 
-  return true;
+  return Unit{};
 }
diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp
index a0ffccb..d8867fe 100644
--- a/cmds/idmap2/idmap2/Main.cpp
+++ b/cmds/idmap2/idmap2/Main.cpp
@@ -24,14 +24,17 @@
 #include <vector>
 
 #include "idmap2/CommandLineOptions.h"
+#include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
 
 #include "Commands.h"
 
 using android::idmap2::CommandLineOptions;
+using android::idmap2::Result;
+using android::idmap2::Unit;
 
 using NameToFunctionMap =
-    std::map<std::string, std::function<bool(const std::vector<std::string>&, std::ostream&)>>;
+    std::map<std::string, std::function<Result<Unit>(const std::vector<std::string>&)>>;
 
 namespace {
 
@@ -69,5 +72,10 @@
     PrintUsage(commands, std::cerr);
     return EXIT_FAILURE;
   }
-  return iter->second(*args, std::cerr) ? EXIT_SUCCESS : EXIT_FAILURE;
+  const auto result = iter->second(*args);
+  if (!result) {
+    std::cerr << "error: " << result.GetErrorMessage() << std::endl;
+    return EXIT_FAILURE;
+  }
+  return EXIT_SUCCESS;
 }
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index e85f132..24331af 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -30,6 +30,7 @@
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
 #include "idmap2/ResourceUtils.h"
+#include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
 #include "idmap2/Xml.h"
 #include "idmap2/ZipFile.h"
@@ -37,6 +38,7 @@
 #include "Commands.h"
 
 using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
 using android::idmap2::Idmap;
 using android::idmap2::kPolicyProduct;
 using android::idmap2::kPolicyPublic;
@@ -45,6 +47,7 @@
 using android::idmap2::PolicyBitmask;
 using android::idmap2::PolicyFlags;
 using android::idmap2::Result;
+using android::idmap2::Unit;
 using android::idmap2::utils::ExtractOverlayManifestInfo;
 using android::idmap2::utils::FindFiles;
 using android::idmap2::utils::OverlayManifestInfo;
@@ -69,8 +72,8 @@
   return version == "Q" || version == "q";
 }
 
-std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
-                                                       bool recursive, std::ostream& out_error) {
+Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector<std::string>& dirs,
+                                                               bool recursive) {
   SYSTRACE << "FindApkFiles " << dirs << " " << recursive;
   const auto predicate = [](unsigned char type, const std::string& path) -> bool {
     static constexpr size_t kExtLen = 4;  // strlen(".apk")
@@ -82,8 +85,7 @@
   for (const auto& dir : dirs) {
     const auto apk_paths = FindFiles(dir, recursive, predicate);
     if (!apk_paths) {
-      out_error << "error: failed to open directory " << dir << std::endl;
-      return nullptr;
+      return Error("failed to open directory %s", dir.c_str());
     }
     paths.insert(apk_paths->cbegin(), apk_paths->cend());
   }
@@ -110,7 +112,7 @@
 
 }  // namespace
 
-bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Scan(const std::vector<std::string>& args) {
   SYSTRACE << "Scan " << args;
   std::vector<std::string> input_directories;
   std::string target_package_name;
@@ -135,22 +137,22 @@
               "input: an overlayable policy this overlay fulfills "
               "(if none or supplied, the overlays will not have their policies overriden",
               &override_policies);
-  if (!opts.Parse(args, out_error)) {
-    return false;
+  const auto opts_ok = opts.Parse(args);
+  if (!opts_ok) {
+    return opts_ok.GetError();
   }
 
-  const auto apk_paths = FindApkFiles(input_directories, recursive, out_error);
+  const auto apk_paths = FindApkFiles(input_directories, recursive);
   if (!apk_paths) {
-    return false;
+    return Error(apk_paths.GetError(), "failed to find apk files");
   }
 
   std::vector<InputOverlay> interesting_apks;
-  for (const std::string& path : *apk_paths) {
+  for (const std::string& path : **apk_paths) {
     Result<OverlayManifestInfo> overlay_info =
         ExtractOverlayManifestInfo(path, /* assert_overlay */ false);
     if (!overlay_info) {
-      out_error << "error: " << overlay_info.GetErrorMessage() << std::endl;
-      return false;
+      return overlay_info.GetError();
     }
 
     if (!overlay_info->is_static) {
@@ -194,16 +196,13 @@
 
   std::stringstream stream;
   for (const auto& overlay : interesting_apks) {
-    // Create the idmap for the overlay if it currently does not exist or if it is not up to date.
-    std::stringstream dev_null;
-
     std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path};
     for (const std::string& policy : overlay.policies) {
       verify_args.emplace_back("--policy");
       verify_args.emplace_back(policy);
     }
 
-    if (!Verify(std::vector<std::string>(verify_args), dev_null)) {
+    if (!Verify(std::vector<std::string>(verify_args))) {
       std::vector<std::string> create_args = {"--target-apk-path",  target_apk_path,
                                               "--overlay-apk-path", overlay.apk_path,
                                               "--idmap-path",       overlay.idmap_path};
@@ -216,8 +215,9 @@
         create_args.emplace_back(policy);
       }
 
-      if (!Create(create_args, out_error)) {
-        return false;
+      const auto create_ok = Create(create_args);
+      if (!create_ok) {
+        return Error(create_ok.GetError(), "failed to create idmap");
       }
     }
 
@@ -226,5 +226,5 @@
 
   std::cout << stream.str();
 
-  return true;
+  return Unit{};
 }
diff --git a/cmds/idmap2/idmap2/Verify.cpp b/cmds/idmap2/idmap2/Verify.cpp
index d8fe7aa..9cb67b3 100644
--- a/cmds/idmap2/idmap2/Verify.cpp
+++ b/cmds/idmap2/idmap2/Verify.cpp
@@ -21,29 +21,39 @@
 
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/Idmap.h"
+#include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
 
 using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
 using android::idmap2::IdmapHeader;
+using android::idmap2::Result;
+using android::idmap2::Unit;
 
-bool Verify(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Verify(const std::vector<std::string>& args) {
   SYSTRACE << "Verify " << args;
   std::string idmap_path;
 
   const CommandLineOptions opts =
       CommandLineOptions("idmap2 verify")
           .MandatoryOption("--idmap-path", "input: path to idmap file to verify", &idmap_path);
-  if (!opts.Parse(args, out_error)) {
-    return false;
+
+  const auto opts_ok = opts.Parse(args);
+  if (!opts_ok) {
+    return opts_ok.GetError();
   }
 
   std::ifstream fin(idmap_path);
   const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
   fin.close();
   if (!header) {
-    out_error << "error: failed to parse idmap header" << std::endl;
-    return false;
+    return Error("failed to parse idmap header");
   }
 
-  return header->IsUpToDate(out_error);
+  const auto header_ok = header->IsUpToDate();
+  if (!header_ok) {
+    return Error(header_ok.GetError(), "idmap not up to date");
+  }
+
+  return Unit{};
 }
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index fa94414..e03a9cc 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -104,8 +104,7 @@
   std::ifstream fin(idmap_path);
   const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
   fin.close();
-  std::stringstream dev_null;
-  *_aidl_return = header && header->IsUpToDate(dev_null);
+  *_aidl_return = header && header->IsUpToDate();
 
   // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
 
diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h
index 6db6bf9..52ac818 100644
--- a/cmds/idmap2/include/idmap2/CommandLineOptions.h
+++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h
@@ -23,6 +23,8 @@
 #include <string>
 #include <vector>
 
+#include "idmap2/Result.h"
+
 namespace android::idmap2 {
 
 /*
@@ -46,7 +48,7 @@
                                      std::string* value);
   CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
                                      std::vector<std::string>* value);
-  bool Parse(const std::vector<std::string>& argv, std::ostream& outError) const;
+  Result<Unit> Parse(const std::vector<std::string>& argv) const;
   void Usage(std::ostream& out) const;
 
  private:
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 1666dc8..673d18d 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -115,7 +115,7 @@
   // Invariant: anytime the idmap data encoding is changed, the idmap version
   // field *must* be incremented. Because of this, we know that if the idmap
   // header is up-to-date the entire file is up-to-date.
-  bool IsUpToDate(std::ostream& out_error) const;
+  Result<Unit> IsUpToDate() const;
 
   void accept(Visitor* v) const;
 
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index a49a607..d5fd2ce 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -19,12 +19,14 @@
 #include <iostream>
 #include <memory>
 #include <set>
+#include <sstream>
 #include <string>
 #include <vector>
 
 #include "android-base/macros.h"
 
 #include "idmap2/CommandLineOptions.h"
+#include "idmap2/Result.h"
 
 namespace android::idmap2 {
 
@@ -77,7 +79,7 @@
   return *this;
 }
 
-bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const {
+Result<Unit> CommandLineOptions::Parse(const std::vector<std::string>& argv) const {
   const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) {
     return opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
   });
@@ -89,8 +91,9 @@
   for (size_t i = 0; i < argv_size; i++) {
     const std::string arg = argv[i];
     if ("--help" == arg || "-h" == arg) {
-      Usage(outError);
-      return false;
+      std::stringstream stream;
+      Usage(stream);
+      return Error("%s", stream.str().c_str());
     }
     bool match = false;
     for (const Option& opt : options_) {
@@ -100,9 +103,9 @@
         if (opt.argument) {
           i++;
           if (i >= argv_size) {
-            outError << "error: " << opt.name << ": missing argument" << std::endl;
-            Usage(outError);
-            return false;
+            std::stringstream stream;
+            Usage(stream);
+            return Error("%s: missing argument\n%s", opt.name.c_str(), stream.str().c_str());
           }
         }
         opt.action(argv[i]);
@@ -111,20 +114,27 @@
       }
     }
     if (!match) {
-      outError << "error: " << arg << ": unknown option" << std::endl;
-      Usage(outError);
-      return false;
+      std::stringstream stream;
+      Usage(stream);
+      return Error("%s: unknown option\n%s", arg.c_str(), stream.str().c_str());
     }
   }
 
   if (!mandatory_opts.empty()) {
+    std::stringstream stream;
+    bool separator = false;
     for (const auto& opt : mandatory_opts) {
-      outError << "error: " << opt << ": missing mandatory option" << std::endl;
+      if (separator) {
+        stream << ", ";
+      }
+      separator = true;
+      stream << opt << ": missing mandatory option";
     }
-    Usage(outError);
-    return false;
+    stream << std::endl;
+    Usage(stream);
+    return Error("%s", stream.str().c_str());
   }
-  return true;
+  return Unit{};
 }
 
 void CommandLineOptions::Usage(std::ostream& out) const {
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index a7d180c..2a39c2f 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -142,62 +142,46 @@
   return std::move(idmap_header);
 }
 
-bool IdmapHeader::IsUpToDate(std::ostream& out_error) const {
+Result<Unit> IdmapHeader::IsUpToDate() const {
   if (magic_ != kIdmapMagic) {
-    out_error << base::StringPrintf("error: bad magic: actual 0x%08x, expected 0x%08x", magic_,
-                                    kIdmapMagic)
-              << std::endl;
-    return false;
+    return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic);
   }
 
   if (version_ != kIdmapCurrentVersion) {
-    out_error << base::StringPrintf("error: bad version: actual 0x%08x, expected 0x%08x", version_,
-                                    kIdmapCurrentVersion)
-              << std::endl;
-    return false;
+    return Error("bad version: actual 0x%08x, expected 0x%08x", version_, kIdmapCurrentVersion);
   }
 
   const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path_);
   if (!target_zip) {
-    out_error << "error: failed to open target " << target_path_ << std::endl;
-    return false;
+    return Error("failed to open target %s", GetTargetPath().to_string().c_str());
   }
 
   Result<uint32_t> target_crc = GetCrc(*target_zip);
   if (!target_crc) {
-    out_error << "error: failed to get target crc" << std::endl;
-    return false;
+    return Error("failed to get target crc");
   }
 
   if (target_crc_ != *target_crc) {
-    out_error << base::StringPrintf(
-                     "error: bad target crc: idmap version 0x%08x, file system version 0x%08x",
-                     target_crc_, *target_crc)
-              << std::endl;
-    return false;
+    return Error("bad target crc: idmap version 0x%08x, file system version 0x%08x", target_crc_,
+                 *target_crc);
   }
 
   const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path_);
   if (!overlay_zip) {
-    out_error << "error: failed to open overlay " << overlay_path_ << std::endl;
-    return false;
+    return Error("failed to open overlay %s", GetOverlayPath().to_string().c_str());
   }
 
   Result<uint32_t> overlay_crc = GetCrc(*overlay_zip);
   if (!overlay_crc) {
-    out_error << "error: failed to get overlay crc" << std::endl;
-    return false;
+    return Error("failed to get overlay crc");
   }
 
   if (overlay_crc_ != *overlay_crc) {
-    out_error << base::StringPrintf(
-                     "error: bad overlay crc: idmap version 0x%08x, file system version 0x%08x",
-                     overlay_crc_, *overlay_crc)
-              << std::endl;
-    return false;
+    return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_,
+                 *overlay_crc);
   }
 
-  return true;
+  return Unit{};
 }
 
 std::unique_ptr<const IdmapData::Header> IdmapData::Header::FromBinaryStream(std::istream& stream) {
diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
index 39f18d3..d567af6 100644
--- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp
+++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
@@ -46,14 +46,13 @@
   CommandLineOptions opts =
       CommandLineOptions("test").OptionalFlag("--foo", "", &foo).OptionalFlag("--bar", "", &bar);
 
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "--bar"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "--bar"});
   ASSERT_TRUE(success);
   ASSERT_TRUE(foo);
   ASSERT_TRUE(bar);
 
   foo = bar = false;
-  success = opts.Parse({"--foo"}, fakeStdErr);
+  success = opts.Parse({"--foo"});
   ASSERT_TRUE(success);
   ASSERT_TRUE(foo);
   ASSERT_FALSE(bar);
@@ -65,21 +64,19 @@
   CommandLineOptions opts = CommandLineOptions("test")
                                 .MandatoryOption("--foo", "", &foo)
                                 .MandatoryOption("--bar", "", &bar);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo, "FOO");
   ASSERT_EQ(bar, "BAR");
 
-  success = opts.Parse({"--foo"}, fakeStdErr);
+  success = opts.Parse({"--foo"});
   ASSERT_FALSE(success);
 }
 
 TEST(CommandLineOptionsTests, MandatoryOptionMultipleArgsButExpectedOnce) {
   std::string foo;
   CommandLineOptions opts = CommandLineOptions("test").MandatoryOption("--foo", "", &foo);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "FIRST", "--foo", "SECOND"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "FIRST", "--foo", "SECOND"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo, "SECOND");
 }
@@ -87,8 +84,7 @@
 TEST(CommandLineOptionsTests, MandatoryOptionMultipleArgsAndExpectedOnceOrMore) {
   std::vector<std::string> args;
   CommandLineOptions opts = CommandLineOptions("test").MandatoryOption("--foo", "", &args);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "FOO", "--foo", "BAR"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "FOO", "--foo", "BAR"});
   ASSERT_TRUE(success);
   ASSERT_EQ(args.size(), 2U);
   ASSERT_EQ(args[0], "FOO");
@@ -101,23 +97,22 @@
   CommandLineOptions opts = CommandLineOptions("test")
                                 .OptionalOption("--foo", "", &foo)
                                 .OptionalOption("--bar", "", &bar);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo, "FOO");
   ASSERT_EQ(bar, "BAR");
 
-  success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
+  success = opts.Parse({"--foo", "BAZ"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo, "BAZ");
 
-  success = opts.Parse({"--foo"}, fakeStdErr);
+  success = opts.Parse({"--foo"});
   ASSERT_FALSE(success);
 
-  success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
+  success = opts.Parse({"--foo", "--bar", "BAR"});
   ASSERT_FALSE(success);
 
-  success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
+  success = opts.Parse({"--foo", "FOO", "--bar"});
   ASSERT_FALSE(success);
 }
 
@@ -127,8 +122,7 @@
   CommandLineOptions opts = CommandLineOptions("test")
                                 .OptionalOption("--foo", "", &foo)
                                 .OptionalOption("--bar", "", &bar);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo.size(), 1U);
   ASSERT_EQ(foo[0], "FOO");
@@ -137,7 +131,7 @@
 
   foo.clear();
   bar.clear();
-  success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
+  success = opts.Parse({"--foo", "BAZ"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo.size(), 1U);
   ASSERT_EQ(foo[0], "BAZ");
@@ -145,8 +139,7 @@
 
   foo.clear();
   bar.clear();
-  success =
-      opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}, fakeStdErr);
+  success = opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo.size(), 2U);
   ASSERT_EQ(foo[0], "BAZ");
@@ -157,17 +150,17 @@
 
   foo.clear();
   bar.clear();
-  success = opts.Parse({"--foo"}, fakeStdErr);
+  success = opts.Parse({"--foo"});
   ASSERT_FALSE(success);
 
   foo.clear();
   bar.clear();
-  success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
+  success = opts.Parse({"--foo", "--bar", "BAR"});
   ASSERT_FALSE(success);
 
   foo.clear();
   bar.clear();
-  success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
+  success = opts.Parse({"--foo", "FOO", "--bar"});
   ASSERT_FALSE(success);
 }
 
@@ -179,14 +172,13 @@
                                 .MandatoryOption("--foo", "", &foo)
                                 .OptionalFlag("--baz", "", &baz)
                                 .OptionalOption("--bar", "", &bar);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--unexpected"}, fakeStdErr);
+  auto success = opts.Parse({"--unexpected"});
   ASSERT_FALSE(success);
 
-  success = opts.Parse({"--bar", "BAR"}, fakeStdErr);
+  success = opts.Parse({"--bar", "BAR"});
   ASSERT_FALSE(success);
 
-  success = opts.Parse({"--baz", "--foo", "FOO"}, fakeStdErr);
+  success = opts.Parse({"--baz", "--foo", "FOO"});
   ASSERT_TRUE(success);
   ASSERT_TRUE(baz);
   ASSERT_EQ(foo, "FOO");
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 8d65428..c20ae7b 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -501,7 +501,7 @@
 
   std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
   ASSERT_THAT(header, NotNull());
-  ASSERT_TRUE(header->IsUpToDate(error)) << error.str();
+  ASSERT_TRUE(header->IsUpToDate());
 
   // magic: bytes (0x0, 0x03)
   std::string bad_magic_string(stream.str());
@@ -514,7 +514,7 @@
       IdmapHeader::FromBinaryStream(bad_magic_stream);
   ASSERT_THAT(bad_magic_header, NotNull());
   ASSERT_NE(header->GetMagic(), bad_magic_header->GetMagic());
-  ASSERT_FALSE(bad_magic_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_magic_header->IsUpToDate());
 
   // version: bytes (0x4, 0x07)
   std::string bad_version_string(stream.str());
@@ -527,7 +527,7 @@
       IdmapHeader::FromBinaryStream(bad_version_stream);
   ASSERT_THAT(bad_version_header, NotNull());
   ASSERT_NE(header->GetVersion(), bad_version_header->GetVersion());
-  ASSERT_FALSE(bad_version_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_version_header->IsUpToDate());
 
   // target crc: bytes (0x8, 0xb)
   std::string bad_target_crc_string(stream.str());
@@ -540,7 +540,7 @@
       IdmapHeader::FromBinaryStream(bad_target_crc_stream);
   ASSERT_THAT(bad_target_crc_header, NotNull());
   ASSERT_NE(header->GetTargetCrc(), bad_target_crc_header->GetTargetCrc());
-  ASSERT_FALSE(bad_target_crc_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_target_crc_header->IsUpToDate());
 
   // overlay crc: bytes (0xc, 0xf)
   std::string bad_overlay_crc_string(stream.str());
@@ -553,7 +553,7 @@
       IdmapHeader::FromBinaryStream(bad_overlay_crc_stream);
   ASSERT_THAT(bad_overlay_crc_header, NotNull());
   ASSERT_NE(header->GetOverlayCrc(), bad_overlay_crc_header->GetOverlayCrc());
-  ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate());
 
   // target path: bytes (0x10, 0x10f)
   std::string bad_target_path_string(stream.str());
@@ -563,7 +563,7 @@
       IdmapHeader::FromBinaryStream(bad_target_path_stream);
   ASSERT_THAT(bad_target_path_header, NotNull());
   ASSERT_NE(header->GetTargetPath(), bad_target_path_header->GetTargetPath());
-  ASSERT_FALSE(bad_target_path_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_target_path_header->IsUpToDate());
 
   // overlay path: bytes (0x110, 0x20f)
   std::string bad_overlay_path_string(stream.str());
@@ -573,7 +573,7 @@
       IdmapHeader::FromBinaryStream(bad_overlay_path_stream);
   ASSERT_THAT(bad_overlay_path_header, NotNull());
   ASSERT_NE(header->GetOverlayPath(), bad_overlay_path_header->GetOverlayPath());
-  ASSERT_FALSE(bad_overlay_path_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_overlay_path_header->IsUpToDate());
 }
 
 class TestVisitor : public Visitor {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 7a753aec..1dbbbc5 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -310,7 +310,7 @@
         DangerousPermissionState dangerous_permission_state = 10050;
         TrainInfo train_info = 10051;
         TimeZoneDataInfo time_zone_data_info = 10052;
-        SDCardInfo sdcard_info = 10053;
+        ExternalStorageInfo external_storage_info = 10053;
         GpuStatsGlobalInfo gpu_stats_global_info = 10054;
         GpuStatsAppInfo gpu_stats_app_info = 10055;
         SystemIonHeapSize system_ion_heap_size = 10056;
@@ -3311,25 +3311,27 @@
 }
 
 /**
- * Logs that an SD card is mounted and information about it, its type (public or private) and the
- * size in bytes.
+ * Logs that external storage is mounted and information about it, the storage type (sd card/usb/
+ * others), its type (public or private) and the size in bytes.
  * Pulled from:
  *   StatsCompanionService
  */
 
-message SDCardInfo {
+message ExternalStorageInfo {
 
-    enum Type {
+    enum VolumeType {
         UNKNOWN = 0;
-        TYPE_PUBLIC = 1;
-        TYPE_PRIVATE = 2;
-        OTHERS = 3;
+        PUBLIC = 1;
+        PRIVATE = 2;
+        OTHER = 3;
     }
 
-    // Type of the SD card: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
-    optional Type type = 1;
+    // The type of external storage.
+    optional android.stats.storage.ExternalStorageType storage_type = 1;
+    // Type of the volume: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
+    optional VolumeType volume_type = 2;
     // Total size of the sd card in bytes.
-    optional int64 size_bytes = 2;
+    optional int64 size_bytes = 3;
 }
 
 /*
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index c7ae656..2abfc24 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -242,9 +242,9 @@
         // TimeZoneDataInfo.
         {android::util::TIME_ZONE_DATA_INFO,
          {.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}},
-        // SDCardInfo
-        {android::util::SDCARD_INFO,
-         {.puller = new StatsCompanionServicePuller(android::util::SDCARD_INFO)}},
+        // ExternalStorageInfo
+        {android::util::EXTERNAL_STORAGE_INFO,
+         {.puller = new StatsCompanionServicePuller(android::util::EXTERNAL_STORAGE_INFO)}},
         // GpuStatsGlobalInfo
         {android::util::GPU_STATS_GLOBAL_INFO,
          {.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}},
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index f6cfe48..e8d3293 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -340,4 +340,21 @@
      * like persisting database etc.
      */
     public abstract void prepareForPossibleShutdown();
+
+    /**
+     * Returns {@code true} if {@code uid} is running a foreground service of a specific
+     * {@code foregroundServiceType}.
+     */
+    public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType);
+
+    /**
+     * Registers the specified {@code processObserver} to be notified of future changes to
+     * process state.
+     */
+    public abstract void registerProcessObserver(IProcessObserver processObserver);
+
+    /**
+     * Unregisters the specified {@code processObserver}.
+     */
+    public abstract void unregisterProcessObserver(IProcessObserver processObserver);
 }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a226062..7a0639e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3054,9 +3054,9 @@
     }
 
     @Override
-    public String getContentCaptureServicePackageName() {
+    public String getSystemCaptionsServicePackageName() {
         try {
-            return mPM.getContentCaptureServicePackageName();
+            return mPM.getSystemCaptionsServicePackageName();
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl
index b436aa2..7be3620 100644
--- a/core/java/android/app/IProcessObserver.aidl
+++ b/core/java/android/app/IProcessObserver.aidl
@@ -19,5 +19,6 @@
 /** {@hide} */
 oneway interface IProcessObserver {
     void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
+    void onForegroundServicesChanged(int pid, int uid, int serviceTypes);
     void onProcessDied(int pid, int uid);
 }
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 3ecb587..bcd43a2 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -440,7 +440,7 @@
      */
     public boolean isKeyguardSecure() {
         try {
-            return mWM.isKeyguardSecure();
+            return mWM.isKeyguardSecure(mContext.getUserId());
         } catch (RemoteException ex) {
             return false;
         }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index db8c905..41a9921 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -781,6 +781,16 @@
             isBundledApp = false;
         }
 
+        // Similar to vendor apks, we should add /product/lib for apks from product partition
+        // and not having /product/lib in the default search path
+        final boolean treatProductApkAsUnbundled = !defaultSearchPaths.contains("/product/lib");
+        if (mApplicationInfo.getCodePath() != null
+                && mApplicationInfo.isProduct() && treatProductApkAsUnbundled
+                // TODO(b/128557860): Change target SDK version when version code R is available.
+                && getTargetSdkVersion() == Build.VERSION_CODES.CUR_DEVELOPMENT) {
+            isBundledApp = false;
+        }
+
         makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
 
         String libraryPermittedPath = mDataDir;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 23f64b8..523b200 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1569,12 +1569,12 @@
          * Builder class for {@link Action} objects.
          */
         public static final class Builder {
-            private final Icon mIcon;
-            private final CharSequence mTitle;
-            private final PendingIntent mIntent;
+            @Nullable private final Icon mIcon;
+            @Nullable private final CharSequence mTitle;
+            @Nullable private final PendingIntent mIntent;
             private boolean mAllowGeneratedReplies = true;
-            private final Bundle mExtras;
-            private ArrayList<RemoteInput> mRemoteInputs;
+            @NonNull private final Bundle mExtras;
+            @Nullable private ArrayList<RemoteInput> mRemoteInputs;
             private @SemanticAction int mSemanticAction;
             private boolean mIsContextual;
 
@@ -1610,9 +1610,10 @@
                         action.getAllowGeneratedReplies(), action.getSemanticAction());
             }
 
-            private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
-                    RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
-                            @SemanticAction int semanticAction) {
+            private Builder(@Nullable Icon icon, @Nullable CharSequence title,
+                    @Nullable PendingIntent intent, @NonNull Bundle extras,
+                    @Nullable RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
+                    @SemanticAction int semanticAction) {
                 mIcon = icon;
                 mTitle = title;
                 mIntent = intent;
@@ -1645,6 +1646,7 @@
              *
              * <p>The returned Bundle is shared with this Builder.
              */
+            @NonNull
             public Bundle getExtras() {
                 return mExtras;
             }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 08e0880..4d280b7 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -101,11 +101,9 @@
 import android.net.EthernetManager;
 import android.net.IConnectivityManager;
 import android.net.IEthernetManager;
-import android.net.IIpMemoryStore;
 import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
 import android.net.ITestNetworkManager;
-import android.net.IpMemoryStore;
 import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
@@ -340,17 +338,6 @@
             }
         });
 
-        registerService(Context.IP_MEMORY_STORE_SERVICE, IpMemoryStore.class,
-                new CachedServiceFetcher<IpMemoryStore>() {
-                    @Override
-                    public IpMemoryStore createService(final ContextImpl ctx)
-                            throws ServiceNotFoundException {
-                        IBinder b = ServiceManager.getServiceOrThrow(
-                                Context.IP_MEMORY_STORE_SERVICE);
-                        IIpMemoryStore service = IIpMemoryStore.Stub.asInterface(b);
-                        return new IpMemoryStore(ctx, service);
-                    }});
-
         registerService(Context.IPSEC_SERVICE, IpSecManager.class,
                 new CachedServiceFetcher<IpSecManager>() {
             @Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9a4e215..20e85e6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -112,6 +112,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
@@ -5171,7 +5172,8 @@
      * </ul>
      * The call will fail if called with the package name of an unsupported VPN app.
      * <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure
-     * of the VPN provider could break networking for all apps.
+     * of the VPN provider could break networking for all apps. This method clears any lockdown
+     * whitelist set by {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)}.
      *
      * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to
      *        remove an existing always-on VPN configuration.
@@ -5181,11 +5183,11 @@
      * @throws NameNotFoundException if {@code vpnPackage} is not installed.
      * @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being
      *         set as always-on, or if always-on VPN is not available.
-     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List)
+     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
      */
     public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
             boolean lockdownEnabled) throws NameNotFoundException {
-        setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptyList());
+        setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptySet());
     }
 
     /**
@@ -5195,6 +5197,11 @@
      * System apps can always bypass VPN.
      * <p> Note that the system doesn't update the whitelist when packages are installed or
      * uninstalled, the admin app must call this method to keep the list up to date.
+     * <p> When {@code lockdownEnabled} is false {@code lockdownWhitelist} is ignored . When
+     * {@code lockdownEnabled} is {@code true} and {@code lockdownWhitelist} is {@code null} or
+     * empty, only system apps can bypass VPN.
+     * <p> Setting always-on VPN package to {@code null} or using
+     * {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)} clears lockdown whitelist.
      *
      * @param vpnPackage package name for an installed VPN app on the device, or {@code null}
      *         to remove an existing always-on VPN configuration
@@ -5211,13 +5218,13 @@
      *         available.
      */
     public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
-            boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist)
+            boolean lockdownEnabled, @Nullable Set<String> lockdownWhitelist)
             throws NameNotFoundException {
         throwIfParentInstance("setAlwaysOnVpnPackage");
         if (mService != null) {
             try {
-                mService.setAlwaysOnVpnPackage(
-                        admin, vpnPackage, lockdownEnabled, lockdownWhitelist);
+                mService.setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled,
+                        lockdownWhitelist == null ? null : new ArrayList<>(lockdownWhitelist));
             } catch (ServiceSpecificException e) {
                 switch (e.errorCode) {
                     case ERROR_VPN_PACKAGE_NOT_FOUND:
@@ -5255,7 +5262,7 @@
     }
 
     /**
-     * Called by device or profile owner to query the list of packages that are allowed to access
+     * Called by device or profile owner to query the set of packages that are allowed to access
      * the network directly when always-on VPN is in lockdown mode but not connected. Returns
      * {@code null} when always-on VPN is not active or not in lockdown mode.
      *
@@ -5263,13 +5270,15 @@
      *
      * @throws SecurityException if {@code admin} is not a device or a profile owner.
      *
-     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List)
+     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
      */
-    public @Nullable List<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) {
+    public @Nullable Set<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) {
         throwIfParentInstance("getAlwaysOnVpnLockdownWhitelist");
         if (mService != null) {
             try {
-                return mService.getAlwaysOnVpnLockdownWhitelist(admin);
+                final List<String> whitelist =
+                        mService.getAlwaysOnVpnLockdownWhitelist(admin);
+                return whitelist == null ? null : new HashSet<>(whitelist);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -6339,7 +6348,6 @@
      */
     @RequiresPermission(value = android.Manifest.permission.INTERACT_ACROSS_USERS,
             conditional = true)
-    @SystemApi
     public @Nullable ComponentName getProfileOwnerAsUser(@NonNull UserHandle user) {
         if (mService != null) {
             try {
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
index b6f37f6..298b003 100644
--- a/core/java/android/app/prediction/AppPredictionContext.java
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -26,7 +26,8 @@
 import android.os.Parcelable;
 
 /**
- * TODO(b/111701043): Add java docs
+ * Class that provides contextual information about the environment in which the app prediction is
+ * used, such as package name, UI in which the app targets are shown, and number of targets.
  *
  * @hide
  */
@@ -57,20 +58,32 @@
         mExtras = parcel.readBundle();
     }
 
+    /**
+     * Returns the UI surface of the prediction context.
+     */
     @NonNull
     public String getUiSurface() {
         return mUiSurface;
     }
 
+    /**
+     * Returns the predicted target count
+     */
     public @IntRange(from = 0) int getPredictedTargetCount() {
         return mPredictedTargetCount;
     }
 
+    /**
+     * Returns the package name of the prediction context.
+     */
     @NonNull
     public String getPackageName() {
         return mPackageName;
     }
 
+    /**
+     * Returns the extras of the prediction context.
+     */
     @Nullable
     public Bundle getExtras() {
         return mExtras;
@@ -100,9 +113,6 @@
         dest.writeBundle(mExtras);
     }
 
-    /**
-     * @see Parcelable.Creator
-     */
     public static final @android.annotation.NonNull Parcelable.Creator<AppPredictionContext> CREATOR =
             new Parcelable.Creator<AppPredictionContext>() {
                 public AppPredictionContext createFromParcel(Parcel parcel) {
@@ -132,7 +142,7 @@
         private Bundle mExtras;
 
         /**
-         * TODO(b/123591863): Add java docs
+         * @param context The {@link Context} of the prediction client.
          *
          * @hide
          */
diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java
index 45825cf..cb5b7e7 100644
--- a/core/java/android/app/prediction/AppPredictionManager.java
+++ b/core/java/android/app/prediction/AppPredictionManager.java
@@ -23,7 +23,8 @@
 import com.android.internal.util.Preconditions;
 
 /**
- * TODO (b/111701043) : Add java doc
+ * Class that provides methods to create prediction clients.
+ *
  * @hide
  */
 @SystemApi
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.java b/core/java/android/app/prediction/AppPredictionSessionId.java
index 1c5d8b4..281a16f 100644
--- a/core/java/android/app/prediction/AppPredictionSessionId.java
+++ b/core/java/android/app/prediction/AppPredictionSessionId.java
@@ -22,7 +22,7 @@
 import android.os.Parcelable;
 
 /**
- * TODO (b/111701043) : Add java doc
+ * The id for an app prediction session. See {@link AppPredictor}.
  *
  * @hide
  */
@@ -33,6 +33,8 @@
     private final String mId;
 
     /**
+     * Creates a new id for a prediction session.
+     *
      * @hide
      */
     public AppPredictionSessionId(@NonNull String id) {
@@ -58,7 +60,6 @@
 
     @Override
     public int hashCode() {
-        // Ensure that the id has a consistent hash
         return mId.hashCode();
     }
 
@@ -72,9 +73,6 @@
         dest.writeString(mId);
     }
 
-    /**
-     * @see Parcelable.Creator
-     */
     public static final @android.annotation.NonNull Parcelable.Creator<AppPredictionSessionId> CREATOR =
             new Parcelable.Creator<AppPredictionSessionId>() {
                 public AppPredictionSessionId createFromParcel(Parcel parcel) {
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index 284327d..3e4e8dc 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -39,7 +39,7 @@
 import java.util.function.Consumer;
 
 /**
- * TODO (b/111701043) : Add java doc
+ * Class that represents an App Prediction client.
  *
  * <p>
  * Usage: <pre> {@code
@@ -49,14 +49,20 @@
  *
  *    void onCreate() {
  *         mClient = new AppPredictor(...)
+ *         mClient.registerPredictionUpdates(...)
  *    }
  *
  *    void onStart() {
- *        mClient.requestPredictionUpdate();
+ *        mClient.requestPredictionUpdate()
+ *    }
+ *
+ *    void onClick(...) {
+ *        mClient.notifyAppTargetEvent(...)
  *    }
  *
  *    void onDestroy() {
- *        mClient.close();
+ *        mClient.unregisterPredictionUpdates()
+ *        mClient.close()
  *    }
  *
  * }</pre>
@@ -83,7 +89,8 @@
      * The caller should call {@link AppPredictor#destroy()} to dispose the client once it
      * no longer used.
      *
-     * @param predictionContext The prediction context
+     * @param context The {@link Context} of the user of this {@link AppPredictor}.
+     * @param predictionContext The prediction context.
      */
     AppPredictor(@NonNull Context context, @NonNull AppPredictionContext predictionContext) {
         IBinder b = ServiceManager.getService(Context.APP_PREDICTION_SERVICE);
@@ -102,6 +109,8 @@
 
     /**
      * Notifies the prediction service of an app target event.
+     *
+     * @param event The {@link AppTargetEvent} that represents the app target event.
      */
     public void notifyAppTargetEvent(@NonNull AppTargetEvent event) {
         if (mIsClosed.get()) {
@@ -118,6 +127,9 @@
 
     /**
      * Notifies the prediction service when the targets in a launch location are shown to the user.
+     *
+     * @param launchLocation The launch location where the targets are shown to the user.
+     * @param targetIds List of {@link AppTargetId}s that are shown to the user.
      */
     public void notifyLocationShown(@NonNull String launchLocation,
             @NonNull List<AppTargetId> targetIds) {
@@ -138,7 +150,10 @@
      * Requests the prediction service provide continuous updates of App predictions via the
      * provided callback, until the given callback is unregistered.
      *
-     * @see Callback#onTargetsAvailable(List)
+     * @see Callback#onTargetsAvailable(List).
+     *
+     * @param callbackExecutor The callback executor to use when calling the callback.
+     * @param callback The Callback to be called when updates of App predictions are available.
      */
     public void registerPredictionUpdates(@NonNull @CallbackExecutor Executor callbackExecutor,
             @NonNull AppPredictor.Callback callback) {
@@ -164,6 +179,10 @@
     /**
      * Requests the prediction service to stop providing continuous updates to the provided
      * callback until the callback is re-registered.
+     *
+     * @see {@link AppPredictor#registerPredictionUpdates(Executor, Callback)}.
+     *
+     * @param callback The callback to be unregistered.
      */
     public void unregisterPredictionUpdates(@NonNull AppPredictor.Callback callback) {
         if (mIsClosed.get()) {
@@ -187,7 +206,7 @@
      * Requests the prediction service to dispatch a new set of App predictions via the provided
      * callback.
      *
-     * @see Callback#onTargetsAvailable(List)
+     * @see Callback#onTargetsAvailable(List).
      */
     public void requestPredictionUpdate() {
         if (mIsClosed.get()) {
@@ -205,6 +224,10 @@
     /**
      * Returns a new list of AppTargets sorted based on prediction rank or {@code null} if the
      * ranker is not available.
+     *
+     * @param targets List of app targets to be sorted.
+     * @param callbackExecutor The callback executor to use when calling the callback.
+     * @param callback The callback to return the sorted list of app targets.
      */
     @Nullable
     public void sortTargets(@NonNull List<AppTarget> targets,
@@ -255,7 +278,7 @@
     }
 
     /**
-     * TODO(b/123591863): Add java docs
+     * Returns the id of this prediction session.
      *
      * @hide
      */
@@ -271,7 +294,7 @@
 
         /**
          * Called when a new set of predicted app targets are available.
-         * @param targets Sorted list of predicted targets
+         * @param targets Sorted list of predicted targets.
          */
         void onTargetsAvailable(@NonNull List<AppTarget> targets);
     }
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index 6f09d34..bb1b96c 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -29,6 +29,7 @@
 
 /**
  * A representation of a launchable target.
+ *
  * @hide
  */
 @SystemApi
@@ -45,7 +46,12 @@
     private int mRank;
 
     /**
-     * TODO(b/123591863): Add java docs
+     * Creates an instance of AppTarget that represent a launchable component.
+     *
+     * @param id A unique id for this launchable target.
+     * @param packageName Package name of the target.
+     * @param className Class name of the target.
+     * @param user The UserHandle of the user which this target belongs to.
      *
      * @hide
      */
@@ -62,7 +68,11 @@
     }
 
     /**
-     * TODO(b/123591863): Add java docs
+     * Creates an instance of AppTarget that represent a launchable shortcut.
+     *
+     * @param id A unique id for this launchable target.
+     * @param shortcutInfo The {@link ShortcutInfo} that is represented with this target.
+     * @param className Class name fo the target.
      *
      * @hide
      */
@@ -186,9 +196,6 @@
         dest.writeInt(mRank);
     }
 
-    /**
-     * @see Parcelable.Creator
-     */
     public static final @android.annotation.NonNull Parcelable.Creator<AppTarget> CREATOR =
             new Parcelable.Creator<AppTarget>() {
                 public AppTarget createFromParcel(Parcel parcel) {
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index f6964f3..54b9563 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -28,6 +28,7 @@
 
 /**
  * A representation of an app target event.
+ *
  * @hide
  */
 @SystemApi
@@ -118,9 +119,6 @@
         dest.writeInt(mAction);
     }
 
-    /**
-     * @see Creator
-     */
     public static final @android.annotation.NonNull Creator<AppTargetEvent> CREATOR =
             new Creator<AppTargetEvent>() {
                 public AppTargetEvent createFromParcel(Parcel parcel) {
@@ -134,6 +132,7 @@
 
     /**
      * A builder for app target events.
+     *
      * @hide
      */
     @SystemApi
@@ -143,6 +142,10 @@
         private String mLocation;
         private @ActionType int mAction;
 
+        /**
+         * @param target The app target that is associated with this event.
+         * @param actionType The event type, which is one of the values in {@link ActionType}.
+         */
         public Builder(@Nullable AppTarget target, @ActionType int actionType) {
             mTarget = target;
             mAction = actionType;
diff --git a/core/java/android/app/prediction/AppTargetId.java b/core/java/android/app/prediction/AppTargetId.java
index aa2ec1f..3603f5f 100644
--- a/core/java/android/app/prediction/AppTargetId.java
+++ b/core/java/android/app/prediction/AppTargetId.java
@@ -22,7 +22,8 @@
 import android.os.Parcelable;
 
 /**
- * The id for a prediction target.
+ * The id for a prediction target. See {@link AppTarget}.
+ *
  * @hide
  */
 @SystemApi
@@ -33,7 +34,7 @@
     private final String mId;
 
     /**
-     * TODO(b/123591863): Add java docs
+     * Creates a new id for a prediction target.
      *
      * @hide
      */
@@ -49,6 +50,7 @@
 
     /**
      * Returns the id.
+     *
      * @hide
      */
     @NonNull
@@ -66,7 +68,6 @@
 
     @Override
     public int hashCode() {
-        // Ensure that the id has a consistent hash
         return mId.hashCode();
     }
 
@@ -80,9 +81,6 @@
         dest.writeString(mId);
     }
 
-    /**
-     * @see Creator
-     */
     public static final @android.annotation.NonNull Creator<AppTargetId> CREATOR =
             new Creator<AppTargetId>() {
                 public AppTargetId createFromParcel(Parcel parcel) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 49a29f0a..fb933b1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3703,14 +3703,6 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
-     * {@link android.net.IpMemoryStore} to store and read information about
-     * known networks.
-     * @hide
-     */
-    public static final String IP_MEMORY_STORE_SERVICE = "ipmemorystore";
-
-    /**
-     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
      * IPSec.
      *
@@ -4016,6 +4008,16 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link com.android.server.attention.AttentionManagerService} for attention services.
+     *
+     * @see #getSystemService(String)
+     * @see android.server.attention.AttentionManagerService
+     * @hide
+     */
+    public static final String ATTENTION_SERVICE = "attention";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.view.inputmethod.InputMethodManager} for accessing input
      * methods.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a2d3f6a..efd9990 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1997,7 +1997,8 @@
     public static final String EXTRA_LAUNCHER_EXTRAS = "android.intent.extra.LAUNCHER_EXTRAS";
 
     /**
-     * Intent extra: ID of the shortcut used to send the share intent.
+     * Intent extra: ID of the shortcut used to send the share intent. Will be sent with
+     * {@link #ACTION_SEND}.
      *
      * @see ShortcutInfo#getId()
      *
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index fd3529b..464e866 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -742,7 +742,7 @@
 
     String getAppPredictionServicePackageName();
 
-    String getContentCaptureServicePackageName();
+    String getSystemCaptionsServicePackageName();
 
     String getIncidentReportApproverPackageName();
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 99324ba..2f99879 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2589,14 +2589,6 @@
     public static final String FEATURE_PC = "android.hardware.type.pc";
 
     /**
-     * Feature for {@link #getSystemAvailableFeatures} and
-     * {@link #hasSystemFeature}: This is a foldable device. Properties such as
-     * the display size may change in response to being folded.
-     */
-    @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable";
-
-    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * The device supports printing.
      */
@@ -6863,9 +6855,9 @@
      *
      * @hide
      */
-    public String getContentCaptureServicePackageName() {
+    public String getSystemCaptionsServicePackageName() {
         throw new UnsupportedOperationException(
-                "getContentCaptureServicePackageName not implemented in subclass");
+                "getSystemCaptionsServicePackageName not implemented in subclass");
     }
 
     /**
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 7b61807..1f82fa6 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1270,8 +1270,8 @@
          * system services even after it has been unpublished as a dynamic shortcut.
          */
         @NonNull
-        public Builder setLongLived() {
-            mIsLongLived = true;
+        public Builder setLongLived(boolean londLived) {
+            mIsLongLived = londLived;
             return this;
         }
 
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 9038b03..d54a6fe 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -24,6 +24,7 @@
 import android.annotation.TestApi;
 import android.content.Context;
 import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.VersionedPackage;
 import android.os.RemoteException;
@@ -48,6 +49,24 @@
     private final String mCallerPackageName;
     private final IRollbackManager mBinder;
 
+    /**
+     * Lifetime duration of rollback packages in millis. A rollback will be available for
+     * at most that duration of time after a package is installed with
+     * {@link PackageInstaller.SessionParams#setEnableRollback()}.
+     *
+     * <p>If flag value is negative, the default value will be assigned.
+     *
+     * @see RollbackManager
+     *
+     * Flag type: {@code long}
+     * Namespace: NAMESPACE_ROLLBACK_BOOT
+     *
+     * @hide
+     */
+    @TestApi
+    public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS =
+            "rollback_lifetime_in_millis";
+
     /** {@hide} */
     public RollbackManager(Context context, IRollbackManager binder) {
         mCallerPackageName = context.getPackageName();
@@ -57,10 +76,12 @@
     /**
      * Returns a list of all currently available rollbacks.
      *
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
+     * @throws SecurityException if the caller does not have appropriate permissions.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_ROLLBACKS,
+            android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+    })
     @NonNull
     public List<RollbackInfo> getAvailableRollbacks() {
         try {
@@ -85,10 +106,12 @@
      * rolled back from.
      *
      * @return the recently committed rollbacks
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
+     * @throws SecurityException if the caller does not have appropriate permissions.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_ROLLBACKS,
+            android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+    })
     public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() {
         try {
             return mBinder.getRecentlyExecutedRollbacks().getList();
@@ -171,10 +194,12 @@
      * @param statusReceiver where to deliver the results. Intents sent to
      *                       this receiver contain {@link #EXTRA_STATUS}
      *                       and {@link #EXTRA_STATUS_MESSAGE}.
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
+     * @throws SecurityException if the caller does not have appropriate permissions.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_ROLLBACKS,
+            android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+    })
     public void commitRollback(int rollbackId, @NonNull List<VersionedPackage> causePackages,
             @NonNull IntentSender statusReceiver) {
         try {
@@ -191,12 +216,11 @@
      * across device reboot, by simulating what happens on reboot without
      * actually rebooting the device.
      *
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
+     * @throws SecurityException if the caller does not have appropriate permissions.
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS)
     @TestApi
     public void reloadPersistedData() {
         try {
@@ -213,12 +237,11 @@
      * recently committed rollbacks that contain the given package.
      *
      * @param packageName the name of the package to expire data for.
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
+     * @throws SecurityException if the caller does not have appropriate permissions.
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS)
     @TestApi
     public void expireRollbackForPackage(@NonNull String packageName) {
         try {
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 6ea35f0..bae0fd3 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -315,7 +315,7 @@
     /**
      * The sensor is dirty. The user should be informed to clean the sensor.
      */
-    public static final int SENSOR_DIRTY = 21;
+    public static final int FACE_ACQUIRED_SENSOR_DIRTY = 21;
 
     /**
      * Hardware vendors may extend this list if there are conditions that do not fall under one of
diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java
index 7fa1cfb..21fcc63 100644
--- a/core/java/android/hardware/display/BrightnessChangeEvent.java
+++ b/core/java/android/hardware/display/BrightnessChangeEvent.java
@@ -80,15 +80,23 @@
      * Histogram counting how many times a pixel of a given value was displayed onscreen for the
      * Value component of HSV if the device supports color sampling, if the device does not support
      * color sampling the value will be null.
+     *
      * The buckets of the histogram are evenly weighted, the number of buckets is device specific.
-     * For example if we had {10, 6, 4, 1} this means that 10 pixels were in the range
-     * [0x00,0x3f], 6 pixels were in the range [0x40,0x7f] etc.
+     * The units are in pixels * milliseconds, with 1 pixel millisecond being 1 pixel displayed
+     * for 1 millisecond.
+     * For example if we had {100, 50, 30, 20}, value component was onscreen for 100 pixel
+     * milliseconds in range 0x00->0x3F, 30 pixel milliseconds in range 0x40->0x7F, etc.
+     *
+     * {@see #colorSampleDuration}
      */
     @Nullable
     public final long[] colorValueBuckets;
 
     /**
-     * How many milliseconds of data are contained in the colorValueBuckets.
+     * How many milliseconds of data are contained in the colorValueBuckets, if the device does
+     * not support color sampling the value will be 0L.
+     *
+     * {@see #colorValueBuckets}
      */
     public final long colorSampleDuration;
 
@@ -283,7 +291,8 @@
             return this;
         }
 
-        /** {@see BrightnessChangeEvent#valueBuckets} */
+        /** {@see BrightnessChangeEvent#colorValueBuckets}
+         *  {@see BrightnessChangeEvent#colorSampleDuration} */
         public Builder setColorValues(@NonNull long[] colorValueBuckets, long colorSampleDuration) {
             Objects.requireNonNull(colorValueBuckets);
             mColorValueBuckets = colorValueBuckets;
diff --git a/core/java/android/hardware/display/DisplayedContentSample.java b/core/java/android/hardware/display/DisplayedContentSample.java
index 0610377..4a429bb 100644
--- a/core/java/android/hardware/display/DisplayedContentSample.java
+++ b/core/java/android/hardware/display/DisplayedContentSample.java
@@ -30,12 +30,14 @@
      * Construct an object representing a color histogram of pixels that were displayed on screen.
      *
      * @param numFrames The number of frames represented by this sample.
-     * @param mSamplesComponent0 is a histogram counting how many times a pixel of a given value
-     * was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the histogram are evenly
-     * weighted, the number of buckets is device specific.
-     * eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that 10 red pixels were
-     * displayed onscreen in range 0x00->0x3F, 6 red pixels were displayed onscreen in range
-     * 0x40->0x7F, etc.
+     * @param mSamplesComponent0 is a histogram counting how many times and for how long a pixel
+     * of a given value was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the
+     * histogram are evenly weighted, the number of buckets is device specific.
+     * The units are in pixels * milliseconds, with 1 pixel millisecond being 1 pixel displayed
+     * onscreen for 1ms.
+     * eg, for RGBA_8888, if sampleComponent0 is {100, 50, 30, 20},  then red component was
+     * onscreen for 100 pixel milliseconds in range 0x00->0x3F, 30 pixel milliseconds in
+     * range 0x40->0x7F, etc.
      * @param mSamplesComponent1 is the same sample definition as sampleComponent0, but for the
      * second component of format.
      * @param mSamplesComponent2 is the same sample definition as sampleComponent0, but for the
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 139a5ee..3e8c334 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -634,6 +634,8 @@
                 return context.getString(R.string.face_acquired_obscured);
             case FACE_ACQUIRED_START:
                 return null;
+            case FACE_ACQUIRED_SENSOR_DIRTY:
+                return context.getString(R.string.face_acquired_sensor_dirty);
             case FACE_ACQUIRED_VENDOR: {
                 String[] msgArray = context.getResources().getStringArray(
                         R.array.face_acquired_vendor);
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index f208724..7873fc0 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -29,15 +29,33 @@
  * {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} activity.
  */
 public class CaptivePortal implements Parcelable {
-    /** @hide */
+    /**
+     * Response code from the captive portal application, indicating that the portal was dismissed
+     * and the network should be re-validated.
+     * @see ICaptivePortal#appResponse(int)
+     * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+     * @hide
+     */
     @SystemApi
     @TestApi
     public static final int APP_RETURN_DISMISSED    = 0;
-    /** @hide */
+    /**
+     * Response code from the captive portal application, indicating that the user did not login and
+     * does not want to use the captive portal network.
+     * @see ICaptivePortal#appResponse(int)
+     * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+     * @hide
+     */
     @SystemApi
     @TestApi
     public static final int APP_RETURN_UNWANTED     = 1;
-    /** @hide */
+    /**
+     * Response code from the captive portal application, indicating that the user does not wish to
+     * login but wants to use the captive portal network as-is.
+     * @see ICaptivePortal#appResponse(int)
+     * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+     * @hide
+     */
     @SystemApi
     @TestApi
     public static final int APP_RETURN_WANTED_AS_IS = 2;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d08379f..e5802c2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2816,23 +2816,6 @@
     }
 
     /**
-     * @removed
-     * @deprecated This API would be removed when all of caller has been updated.
-     * */
-    @Deprecated
-    public abstract static class TetheringEntitlementValueListener  {
-        /**
-         * Called to notify entitlement result.
-         *
-         * @param resultCode a int value of entitlement result. It may be one of
-         *         {@link #TETHER_ERROR_NO_ERROR},
-         *         {@link #TETHER_ERROR_PROVISION_FAILED}, or
-         *         {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}.
-         */
-        public void onEntitlementResult(int resultCode) {}
-    }
-
-    /**
      * Get the last value of the entitlement check on this downstream. If the cached value is
      * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the
      * cached value. Otherwise, a UI-based entitlement check would be performed. It is not
@@ -2878,31 +2861,6 @@
     }
 
     /**
-     * @removed
-     * @deprecated This API would be removed when all of caller has been updated.
-     * */
-    @Deprecated
-    public void getLatestTetheringEntitlementValue(int type, boolean showEntitlementUi,
-            @NonNull final TetheringEntitlementValueListener listener, @Nullable Handler handler) {
-        Preconditions.checkNotNull(listener, "TetheringEntitlementValueListener cannot be null.");
-        ResultReceiver wrappedListener = new ResultReceiver(handler) {
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                listener.onEntitlementResult(resultCode);
-            }
-        };
-
-        try {
-            String pkgName = mContext.getOpPackageName();
-            Log.i(TAG, "getLatestTetheringEntitlementValue:" + pkgName);
-            mService.getLatestTetheringEntitlementResult(type, wrappedListener,
-                    showEntitlementUi, pkgName);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Report network connectivity status.  This is currently used only
      * to alter status bar UI.
      * <p>This method requires the caller to hold the permission
diff --git a/core/java/android/net/DnsPacket.java b/core/java/android/net/DnsPacket.java
index 0ac02b1..83e57e0 100644
--- a/core/java/android/net/DnsPacket.java
+++ b/core/java/android/net/DnsPacket.java
@@ -71,7 +71,7 @@
     }
 
     /**
-     * It's used both for DNS questions and DNS resource records.
+     * Superclass for DNS questions and DNS resource records.
      *
      * DNS questions (No TTL/RDATA)
      * DNS resource records (With TTL/RDATA)
@@ -96,12 +96,13 @@
         /**
          * Create a new DnsRecord from a positioned ByteBuffer.
          *
-         * @param ByteBuffer input of record, must be in network byte order
-         *         (which is the default).
          * Reads the passed ByteBuffer from its current position and decodes a DNS record.
          * When this constructor returns, the reading position of the ByteBuffer has been
          * advanced to the end of the DNS header record.
          * This is meant to chain with other methods reading a DNS response in sequence.
+         *
+         * @param ByteBuffer input of record, must be in network byte order
+         *         (which is the default).
          */
         DnsRecord(int recordType, @NonNull ByteBuffer buf)
                 throws BufferUnderflowException, ParseException {
@@ -205,16 +206,6 @@
     protected final DnsHeader mHeader;
     protected final List<DnsRecord>[] mRecords;
 
-    public static class ParseException extends Exception {
-        public ParseException(String msg) {
-            super(msg);
-        }
-
-        public ParseException(String msg, Throwable cause) {
-            super(msg, cause);
-        }
-    }
-
     protected DnsPacket(@NonNull byte[] data) throws ParseException {
         if (null == data) throw new ParseException("Parse header failed, null input data");
         final ByteBuffer buffer;
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index d3bc3e6..93b8cf8 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -22,11 +22,11 @@
 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Handler;
-import android.os.MessageQueue;
+import android.os.Looper;
 import android.system.ErrnoException;
 import android.util.Log;
 
@@ -37,8 +37,7 @@
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.function.Consumer;
-
+import java.util.concurrent.Executor;
 
 /**
  * Dns resolver class for asynchronous dns querying
@@ -81,66 +80,137 @@
     public static final int FLAG_NO_CACHE_STORE = 1 << 1;
     public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2;
 
-    private static final int DNS_RAW_RESPONSE = 1;
-
     private static final int NETID_UNSET = 0;
 
     private static final DnsResolver sInstance = new DnsResolver();
 
     /**
-     * listener for receiving raw answers
-     */
-    public interface RawAnswerListener {
-        /**
-         * {@code byte[]} is {@code null} if query timed out
-         */
-        void onAnswer(@Nullable byte[] answer);
-    }
-
-    /**
-     * listener for receiving parsed answers
-     */
-    public interface InetAddressAnswerListener {
-        /**
-         * Will be called exactly once with all the answers to the query.
-         * size of addresses will be zero if no available answer could be parsed.
-         */
-        void onAnswer(@NonNull List<InetAddress> addresses);
-    }
-
-    /**
      * Get instance for DnsResolver
      */
-    public static DnsResolver getInstance() {
+    public static @NonNull DnsResolver getInstance() {
         return sInstance;
     }
 
     private DnsResolver() {}
 
     /**
-     * Pass in a blob and corresponding setting,
-     * get a blob back asynchronously with the entire raw answer.
+     * Answer parser for parsing raw answers
+     *
+     * @param <T> The type of the parsed answer
+     */
+    public interface AnswerParser<T> {
+        /**
+         * Creates a <T> answer by parsing the given raw answer.
+         *
+         * @param rawAnswer the raw answer to be parsed
+         * @return a parsed <T> answer
+         * @throws ParseException if parsing failed
+         */
+        @NonNull T parse(@NonNull byte[] rawAnswer) throws ParseException;
+    }
+
+    /**
+     * Base class for answer callbacks
+     *
+     * @param <T> The type of the parsed answer
+     */
+    public abstract static class AnswerCallback<T> {
+        /** @hide */
+        public final AnswerParser<T> parser;
+
+        public AnswerCallback(@NonNull AnswerParser<T> parser) {
+            this.parser = parser;
+        };
+
+        /**
+         * Success response to
+         * {@link android.net.DnsResolver#query query()}.
+         *
+         * Invoked when the answer to a query was successfully parsed.
+         *
+         * @param answer parsed answer to the query.
+         *
+         * {@see android.net.DnsResolver#query query()}
+         */
+        public abstract void onAnswer(@NonNull T answer);
+
+        /**
+         * Error response to
+         * {@link android.net.DnsResolver#query query()}.
+         *
+         * Invoked when there is no valid answer to
+         * {@link android.net.DnsResolver#query query()}
+         *
+         * @param exception a {@link ParseException} object with additional
+         *    detail regarding the failure
+         */
+        public abstract void onParseException(@NonNull ParseException exception);
+
+        /**
+         * Error response to
+         * {@link android.net.DnsResolver#query query()}.
+         *
+         * Invoked if an error happens when
+         * issuing the DNS query or receiving the result.
+         * {@link android.net.DnsResolver#query query()}
+         *
+         * @param exception an {@link ErrnoException} object with additional detail
+         *    regarding the failure
+         */
+        public abstract void onQueryException(@NonNull ErrnoException exception);
+    }
+
+    /**
+     * Callback for receiving raw answers
+     */
+    public abstract static class RawAnswerCallback extends AnswerCallback<byte[]> {
+        public RawAnswerCallback() {
+            super(rawAnswer -> rawAnswer);
+        }
+    }
+
+    /**
+     * Callback for receiving parsed {@link InetAddress} answers
+     *
+     * Note that if the answer does not contain any IP addresses,
+     * onAnswer will be called with an empty list.
+     */
+    public abstract static class InetAddressAnswerCallback
+            extends AnswerCallback<List<InetAddress>> {
+        public InetAddressAnswerCallback() {
+            super(rawAnswer -> new DnsAddressAnswer(rawAnswer).getAddresses());
+        }
+    }
+
+    /**
+     * Send a raw DNS query.
+     * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
      *
      * @param network {@link Network} specifying which network for querying.
      *         {@code null} for query on default network.
      * @param query blob message
      * @param flags flags as a combination of the FLAGS_* constants
-     * @param handler {@link Handler} to specify the thread
-     *         upon which the {@link RawAnswerListener} will be invoked.
-     * @param listener a {@link RawAnswerListener} which will be called to notify the caller
+     * @param executor The {@link Executor} that the callback should be executed on.
+     * @param callback an {@link AnswerCallback} which will be called to notify the caller
      *         of the result of dns query.
      */
-    public void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
-            @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException {
-        final FileDescriptor queryfd = resNetworkSend((network != null
+    public <T> void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
+            @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) {
+        final FileDescriptor queryfd;
+        try {
+            queryfd = resNetworkSend((network != null
                 ? network.netId : NETID_UNSET), query, query.length, flags);
-        registerFDListener(handler.getLooper().getQueue(), queryfd,
-                answerbuf -> listener.onAnswer(answerbuf));
+        } catch (ErrnoException e) {
+            callback.onQueryException(e);
+            return;
+        }
+
+        registerFDListener(executor, queryfd, callback);
     }
 
     /**
-     * Pass in a domain name and corresponding setting,
-     * get a blob back asynchronously with the entire raw answer.
+     * Send a DNS query with the specified name, class and query type.
+     * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
      *
      * @param network {@link Network} specifying which network for querying.
      *         {@code null} for query on default network.
@@ -148,74 +218,53 @@
      * @param nsClass dns class as one of the CLASS_* constants
      * @param nsType dns resource record (RR) type as one of the TYPE_* constants
      * @param flags flags as a combination of the FLAGS_* constants
-     * @param handler {@link Handler} to specify the thread
-     *         upon which the {@link RawAnswerListener} will be invoked.
-     * @param listener a {@link RawAnswerListener} which will be called to notify the caller
+     * @param executor The {@link Executor} that the callback should be executed on.
+     * @param callback an {@link AnswerCallback} which will be called to notify the caller
      *         of the result of dns query.
      */
-    public void query(@Nullable Network network, @NonNull String domain, @QueryClass int nsClass,
-            @QueryType int nsType, @QueryFlag int flags,
-            @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException {
-        final FileDescriptor queryfd = resNetworkQuery((network != null
-                ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
-        registerFDListener(handler.getLooper().getQueue(), queryfd,
-                answerbuf -> listener.onAnswer(answerbuf));
+    public <T> void query(@Nullable Network network, @NonNull String domain,
+            @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags,
+            @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) {
+        final FileDescriptor queryfd;
+        try {
+            queryfd = resNetworkQuery((network != null
+                    ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
+        } catch (ErrnoException e) {
+            callback.onQueryException(e);
+            return;
+        }
+        registerFDListener(executor, queryfd, callback);
     }
 
-    /**
-     * Pass in a domain name and corresponding setting,
-     * get back a set of InetAddresses asynchronously.
-     *
-     * @param network {@link Network} specifying which network for querying.
-     *         {@code null} for query on default network.
-     * @param domain domain name for querying
-     * @param flags flags as a combination of the FLAGS_* constants
-     * @param handler {@link Handler} to specify the thread
-     *         upon which the {@link InetAddressAnswerListener} will be invoked.
-     * @param listener an {@link InetAddressAnswerListener} which will be called to
-     *         notify the caller of the result of dns query.
-     *
-     */
-    public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
-            @NonNull Handler handler, @NonNull InetAddressAnswerListener listener)
-            throws ErrnoException {
-        final FileDescriptor v4fd = resNetworkQuery((network != null
-                ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
-        final FileDescriptor v6fd = resNetworkQuery((network != null
-                ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
-
-        final InetAddressAnswerAccumulator accmulator =
-                new InetAddressAnswerAccumulator(2, listener);
-        final Consumer<byte[]> consumer = answerbuf ->
-                accmulator.accumulate(parseAnswers(answerbuf));
-
-        registerFDListener(handler.getLooper().getQueue(), v4fd, consumer);
-        registerFDListener(handler.getLooper().getQueue(), v6fd, consumer);
-    }
-
-    private void registerFDListener(@NonNull MessageQueue queue,
-            @NonNull FileDescriptor queryfd, @NonNull Consumer<byte[]> answerConsumer) {
-        queue.addOnFileDescriptorEventListener(
+    private <T> void registerFDListener(@NonNull Executor executor,
+            @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback) {
+        Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
                 queryfd,
                 FD_EVENTS,
                 (fd, events) -> {
-                    byte[] answerbuf = null;
-                    try {
-                    // TODO: Implement result function in Java side instead of using JNI
-                    //       Because JNI method close fd prior than unregistering fd on
-                    //       event listener.
-                        answerbuf = resNetworkResult(fd);
-                    } catch (ErrnoException e) {
-                        Log.e(TAG, "resNetworkResult:" + e.toString());
-                    }
-                    answerConsumer.accept(answerbuf);
+                    executor.execute(() -> {
+                        byte[] answerbuf = null;
+                        try {
+                            answerbuf = resNetworkResult(fd);
+                        } catch (ErrnoException e) {
+                            Log.e(TAG, "resNetworkResult:" + e.toString());
+                            answerCallback.onQueryException(e);
+                            return;
+                        }
 
+                        try {
+                            answerCallback.onAnswer(
+                                    answerCallback.parser.parse(answerbuf));
+                        } catch (ParseException e) {
+                            answerCallback.onParseException(e);
+                        }
+                    });
                     // Unregister this fd listener
                     return 0;
                 });
     }
 
-    private class DnsAddressAnswer extends DnsPacket {
+    private static class DnsAddressAnswer extends DnsPacket {
         private static final String TAG = "DnsResolver.DnsAddressAnswer";
         private static final boolean DBG = false;
 
@@ -226,12 +275,6 @@
             if ((mHeader.flags & (1 << 15)) == 0) {
                 throw new ParseException("Not an answer packet");
             }
-            if (mHeader.rcode != 0) {
-                throw new ParseException("Response error, rcode:" + mHeader.rcode);
-            }
-            if (mHeader.getRecordCount(ANSECTION) == 0) {
-                throw new ParseException("No available answer");
-            }
             if (mHeader.getRecordCount(QDSECTION) == 0) {
                 throw new ParseException("No question found");
             }
@@ -241,6 +284,8 @@
 
         public @NonNull List<InetAddress> getAddresses() {
             final List<InetAddress> results = new ArrayList<InetAddress>();
+            if (mHeader.getRecordCount(ANSECTION) == 0) return results;
+
             for (final DnsRecord ansSec : mRecords[ANSECTION]) {
                 // Only support A and AAAA, also ignore answers if query type != answer type.
                 int nsType = ansSec.nsType;
@@ -259,34 +304,4 @@
         }
     }
 
-    private @Nullable List<InetAddress> parseAnswers(@Nullable byte[] data) {
-        try {
-            return (data == null) ? null : new DnsAddressAnswer(data).getAddresses();
-        } catch (DnsPacket.ParseException e) {
-            Log.e(TAG, "Parse answer fail " + e.getMessage());
-            return null;
-        }
-    }
-
-    private class InetAddressAnswerAccumulator {
-        private final List<InetAddress> mAllAnswers;
-        private final InetAddressAnswerListener mAnswerListener;
-        private final int mTargetAnswerCount;
-        private int mReceivedAnswerCount = 0;
-
-        InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerListener listener) {
-            mTargetAnswerCount = size;
-            mAllAnswers = new ArrayList<>();
-            mAnswerListener = listener;
-        }
-
-        public void accumulate(@Nullable List<InetAddress> answer) {
-            if (null != answer) {
-                mAllAnswers.addAll(answer);
-            }
-            if (++mReceivedAnswerCount == mTargetAnswerCount) {
-                mAnswerListener.onAnswer(mAllAnswers);
-            }
-        }
-    }
 }
diff --git a/media/java/android/media/session/SessionLink.aidl b/core/java/android/net/IIpMemoryStoreCallbacks.aidl
similarity index 69%
rename from media/java/android/media/session/SessionLink.aidl
rename to core/java/android/net/IIpMemoryStoreCallbacks.aidl
index c3be23e..53108db 100644
--- a/media/java/android/media/session/SessionLink.aidl
+++ b/core/java/android/net/IIpMemoryStoreCallbacks.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The Android Open Source Project
+ * 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.
@@ -14,6 +14,11 @@
  * limitations under the License.
  */
 
-package android.media.session;
+package android.net;
 
-parcelable SessionLink;
+import android.net.IIpMemoryStore;
+
+/** {@hide} */
+oneway interface IIpMemoryStoreCallbacks {
+    void onIpMemoryStoreFetched(in IIpMemoryStore ipMemoryStore);
+}
diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl
index edb9df6..3751c36 100644
--- a/core/java/android/net/INetworkStackConnector.aidl
+++ b/core/java/android/net/INetworkStackConnector.aidl
@@ -15,6 +15,7 @@
  */
 package android.net;
 
+import android.net.IIpMemoryStoreCallbacks;
 import android.net.INetworkMonitorCallbacks;
 import android.net.Network;
 import android.net.dhcp.DhcpServingParamsParcel;
@@ -27,4 +28,5 @@
         in IDhcpServerCallbacks cb);
     void makeNetworkMonitor(in Network network, String name, in INetworkMonitorCallbacks cb);
     void makeIpClient(in String ifName, in IIpClientCallbacks callbacks);
-}
\ No newline at end of file
+    void fetchIpMemoryStore(in IIpMemoryStoreCallbacks cb);
+}
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index c638491..c97b37b 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -19,11 +19,9 @@
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
 
 import com.google.android.collect.Sets;
 
-import java.net.InetAddress;
 import java.util.HashSet;
 
 /**
@@ -117,40 +115,6 @@
     }
 
     /**
-     * Construct InterfaceConfiguration from InterfaceConfigurationParcel.
-     */
-    public static InterfaceConfiguration fromParcel(InterfaceConfigurationParcel p) {
-        InterfaceConfiguration cfg = new InterfaceConfiguration();
-        cfg.setHardwareAddress(p.hwAddr);
-
-        final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr);
-        cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength));
-        for (String flag : p.flags) {
-            cfg.setFlag(flag);
-        }
-
-        return cfg;
-    }
-
-    /**
-     * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname.
-     */
-    public InterfaceConfigurationParcel toParcel(String iface) {
-        InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel();
-        cfgParcel.ifName = iface;
-        if (!TextUtils.isEmpty(mHwAddr)) {
-            cfgParcel.hwAddr = mHwAddr;
-        } else {
-            cfgParcel.hwAddr = "";
-        }
-        cfgParcel.ipv4Addr = mAddr.getAddress().getHostAddress();
-        cfgParcel.prefixLength = mAddr.getPrefixLength();
-        cfgParcel.flags = mFlags.toArray(EMPTY_STRING_ARRAY);
-
-        return cfgParcel;
-    }
-
-    /**
      * This function determines if the interface is up and has a valid IP
      * configuration (IP address has a non zero octet).
      *
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index d42fce3..ae421a4 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -40,6 +40,7 @@
 import android.util.BackupUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
 import java.io.ByteArrayOutputStream;
@@ -89,10 +90,22 @@
 
     private static boolean sForceAllNetworkTypes = false;
 
+    /**
+     * Results in matching against all mobile network types.
+     *
+     * <p>See {@link #matchesMobile} and {@link matchesMobileWildcard}.
+     */
+    @VisibleForTesting
     public static void forceAllNetworkTypes() {
         sForceAllNetworkTypes = true;
     }
 
+    /** Resets the affect of {@link #forceAllNetworkTypes}. */
+    @VisibleForTesting
+    public static void resetForceAllNetworkTypes() {
+        sForceAllNetworkTypes = false;
+    }
+
     /**
      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
      * the given IMSI.
diff --git a/core/java/android/net/ParseException.java b/core/java/android/net/ParseException.java
index 2380e86..9d4727a 100644
--- a/core/java/android/net/ParseException.java
+++ b/core/java/android/net/ParseException.java
@@ -16,15 +16,22 @@
 
 package android.net;
 
+import android.annotation.NonNull;
+
 /**
- * Thrown when parsing a URL fails.
+ * Thrown when parsing failed.
  */
 // See non-public class {@link WebAddress}.
 public class ParseException extends RuntimeException {
     public String response;
 
-    ParseException(String response) {
+    public ParseException(@NonNull String response) {
         super(response);
         this.response = response;
     }
+
+    public ParseException(@NonNull String response, @NonNull Throwable cause) {
+        super(response, cause);
+        this.response = response;
+    }
 }
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index d4a4cf4..e56f059 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -19,14 +19,17 @@
 import static android.os.UserHandle.PER_USER_RANGE;
 
 import android.os.Parcel;
+import android.os.Parcelable;
 
 /**
  * An inclusive range of UIDs.
  *
  * @hide
  */
-public final class UidRange extends UidRangeParcel {
-    private UidRange() {}
+public final class UidRange implements Parcelable {
+    public final int start;
+    public final int stop;
+
     public UidRange(int startUid, int stopUid) {
         if (startUid < 0) throw new IllegalArgumentException("Invalid start UID.");
         if (stopUid < 0) throw new IllegalArgumentException("Invalid stop UID.");
@@ -86,18 +89,28 @@
         return start + "-" + stop;
     }
 
-    /**
-     * DO NOT override "writeToParcel" and "readFromParcel" in this class.
-     * The parceling code is autogenerated by the superclass.
-     */
+    // Implement the Parcelable interface
+    // TODO: Consider making this class no longer parcelable, since all users are likely in the
+    // system server.
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(start);
+        dest.writeInt(stop);
+    }
 
     public static final @android.annotation.NonNull Creator<UidRange> CREATOR =
         new Creator<UidRange>() {
             @Override
             public UidRange createFromParcel(Parcel in) {
-                UidRange obj = new UidRange();
-                obj.readFromParcel(in);
-                return obj;
+                int start = in.readInt();
+                int stop = in.readInt();
+
+                return new UidRange(start, stop);
             }
             @Override
             public UidRange[] newArray(int size) {
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 870d8b1..ea245a4 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -27,6 +27,8 @@
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.app.Service;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
@@ -48,6 +50,7 @@
 import java.net.Socket;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 /**
  * VpnService is a base class for applications to extend and build their
@@ -138,7 +141,7 @@
      * provides users with the ability to set it as always-on, so that VPN connection is
      * persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device
      * owner and profile owner apps through
-     * {@link android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage}.
+     * {@link DevicePolicyManager#setAlwaysOnVpnPackage}.
      *
      * <p>VPN apps not supporting this feature should opt out by adding this meta-data field to the
      * {@code VpnService} component of {@code AndroidManifest.xml}. In case there is more than one
@@ -370,7 +373,10 @@
     }
 
     /**
-     * Returns whether the service is running in always-on VPN mode.
+     * Returns whether the service is running in always-on VPN mode. In this mode the system ensures
+     * that the service is always running by restarting it when necessary, e.g. after reboot.
+     *
+     * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
      */
     public final boolean isAlwaysOn() {
         try {
@@ -381,8 +387,11 @@
     }
 
     /**
-     * Returns whether the service is running in always-on VPN mode blocking connections without
-     * VPN.
+     * Returns whether the service is running in always-on VPN lockdown mode. In this mode the
+     * system ensures that the service is always running and that the apps aren't allowed to bypass
+     * the VPN.
+     *
+     * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
      */
     public final boolean isLockdownEnabled() {
         try {
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index e09fa8f..d6023d7 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -19,17 +19,20 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
 
 import com.android.internal.R;
 
 /**
  * APF program support capabilities.
  *
+ * This class is immutable.
  * @hide
  */
 @SystemApi
 @TestApi
-public class ApfCapabilities {
+public final class ApfCapabilities implements Parcelable {
     /**
      * Version of APF instruction set supported for packet filtering. 0 indicates no support for
      * packet filtering using APF programs.
@@ -53,6 +56,37 @@
         this.apfPacketFormat = apfPacketFormat;
     }
 
+    private ApfCapabilities(Parcel in) {
+        apfVersionSupported = in.readInt();
+        maximumApfProgramSize = in.readInt();
+        apfPacketFormat = in.readInt();
+    }
+
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(apfVersionSupported);
+        dest.writeInt(maximumApfProgramSize);
+        dest.writeInt(apfPacketFormat);
+    }
+
+    public static final Creator<ApfCapabilities> CREATOR = new Creator<ApfCapabilities>() {
+        @Override
+        public ApfCapabilities createFromParcel(Parcel in) {
+            return new ApfCapabilities(in);
+        }
+
+        @Override
+        public ApfCapabilities[] newArray(int size) {
+            return new ApfCapabilities[size];
+        }
+    };
+
     @Override
     public String toString() {
         return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
index 5827f9e..6f8aece 100644
--- a/core/java/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -45,7 +45,7 @@
  */
 @SystemApi
 @TestApi
-public class SocketUtils {
+public final class SocketUtils {
     /**
      * Create a raw datagram socket that is bound to an interface.
      *
@@ -63,6 +63,7 @@
     /**
      * Make a socket address to communicate with netlink.
      */
+    @NonNull
     public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) {
         return new NetlinkSocketAddress(portId, groupsMask);
     }
@@ -70,13 +71,15 @@
     /**
      * Make socket address that packet sockets can bind to.
      */
-    public static SocketAddress makePacketSocketAddress(short protocol, int ifIndex) {
-        return new PacketSocketAddress(protocol, ifIndex);
+    @NonNull
+    public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex) {
+        return new PacketSocketAddress((short) protocol, ifIndex);
     }
 
     /**
      * Make a socket address that packet socket can send packets to.
      */
+    @NonNull
     public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) {
         return new PacketSocketAddress(ifIndex, hwAddr);
     }
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 6432c24..b82e517 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -935,12 +935,16 @@
     }
 
     /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
+     * Returns the value associated with the given key, or {@code null} if
+     * no mapping of the desired type exists for the given key or a {@code null}
      * value is explicitly associated with the key.
      *
-     * @param key a String, or null
-     * @return a Parcelable value, or null
+     * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+     * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+     * Otherwise, this method might throw an exception or return {@code null}.
+     *
+     * @param key a String, or {@code null}
+     * @return a Parcelable value, or {@code null}
      */
     @Nullable
     public <T extends Parcelable> T getParcelable(@Nullable String key) {
@@ -958,12 +962,16 @@
     }
 
     /**
-     * Returns the value associated with the given key, or null if
+     * Returns the value associated with the given key, or {@code null} if
      * no mapping of the desired type exists for the given key or a null
      * value is explicitly associated with the key.
      *
-     * @param key a String, or null
-     * @return a Parcelable[] value, or null
+     * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+     * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+     * Otherwise, this method might throw an exception or return {@code null}.
+     *
+     * @param key a String, or {@code null}
+     * @return a Parcelable[] value, or {@code null}
      */
     @Nullable
     public Parcelable[] getParcelableArray(@Nullable String key) {
@@ -981,12 +989,16 @@
     }
 
     /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
+     * Returns the value associated with the given key, or {@code null} if
+     * no mapping of the desired type exists for the given key or a {@code null}
      * value is explicitly associated with the key.
      *
-     * @param key a String, or null
-     * @return an ArrayList<T> value, or null
+     * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+     * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+     * Otherwise, this method might throw an exception or return {@code null}.
+     *
+     * @param key a String, or {@code null}
+     * @return an ArrayList<T> value, or {@code null}
      */
     @Nullable
     public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) {
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 39e9138..707a404 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -82,12 +82,18 @@
     public void setup(Context context, Bundle coreSettings) {
         final PackageManager pm = context.getPackageManager();
         final String packageName = context.getPackageName();
+        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
         setupGpuLayers(context, coreSettings, pm, packageName);
+        Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle");
         setupAngle(context, coreSettings, pm, packageName);
+        Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "chooseDriver");
         if (!chooseDriver(context, coreSettings, pm, packageName)) {
             setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
                     SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName);
         }
+        Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
     }
 
     /**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 790bb27..9c9829f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1470,6 +1470,24 @@
     }
 
     /**
+     * Check if a user is a restricted profile. Restricted profiles may have a reduced number of
+     * available apps, app restrictions, and account restrictions.
+     *
+     * @param user the user to check
+     * @return whether the user is a restricted profile.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public boolean isRestrictedProfile(@NonNull UserHandle user) {
+        try {
+            return mService.getUserInfo(user.getIdentifier()).isRestricted();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Checks if specified user can have restricted profile.
      * @hide
      */
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 6d32f8c..7bd0fe2 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -78,6 +78,15 @@
             "activity_manager_native_boot";
 
     /**
+     * Namespace for all app compat related features.  These features will be applied
+     * immediately upon change.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_APP_COMPAT = "app_compat";
+
+    /**
      * Namespace for AttentionManagerService related features.
      *
      * @hide
@@ -163,6 +172,22 @@
     public static final String NAMESPACE_NETD_NATIVE = "netd_native";
 
     /**
+     * Namespace for Rollback flags that are applied immediately.
+     *
+     * @hide
+     */
+    @SystemApi @TestApi
+    public static final String NAMESPACE_ROLLBACK = "rollback";
+
+    /**
+     * Namespace for Rollback flags that are applied after a reboot.
+     *
+     * @hide
+     */
+    @SystemApi @TestApi
+    public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
+
+    /**
      * Namespace for all runtime related features that don't require a reboot to become active.
      * There are no feature flags using NAMESPACE_RUNTIME.
      *
@@ -191,6 +216,15 @@
     public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
 
     /**
+     * Namespace for system scheduler related features. These features will be applied
+     * immediately upon change.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_SCHEDULER = "scheduler";
+
+    /**
      * Namespace for System UI related features.
      *
      * @hide
@@ -261,50 +295,6 @@
     }
 
     /**
-     * Namespace for Rollback.
-     *
-     * @hide
-     */
-    @SystemApi @TestApi
-    public interface Rollback {
-
-        /**
-         * Namespace for flags that can be changed immediately after becoming available on device.
-         */
-        String NAMESPACE = "rollback";
-
-        /**
-         * Namespace for flags that can be changed only after reboot.
-         */
-        String BOOT_NAMESPACE = "rollback_boot";
-
-        /**
-         * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
-         * rollback within that period, the install will proceed without rollback enabled.
-         *
-         * <p>If flag value is negative, the default value will be assigned.
-         *
-         * Flag type: {@code long}
-         * Namespace: Rollback.NAMESPACE
-         */
-        String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
-
-        /**
-         * Lifetime duration of rollback packages in millis. A rollback will be available for
-         * at most that duration of time after a package is installed with
-         * {@link PackageInstaller.SessionParams#setEnableRollback()}.
-         *
-         * <p>If flag value is negative, the default value will be assigned.
-         *
-         * @see RollbackManager
-         *
-         * Flag type: {@code long}
-         * Namespace: Rollback.BOOT_NAMESPACE
-         */
-        String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
-    }
-
-    /**
      * Namespace for storage-related features.
      *
      * @hide
@@ -321,25 +311,6 @@
         String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
     }
 
-    /**
-     * Namespace for system scheduler related features. These features will be applied
-     * immediately upon change.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface Scheduler {
-        String NAMESPACE = "scheduler";
-
-        /**
-         * Flag for enabling fast metrics collection in system scheduler.
-         * A flag value of '' or '0' means the fast metrics collection is not
-         * enabled. Otherwise fast metrics collection is enabled and flag value
-         * is the order id.
-         */
-        String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
-    }
-
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners =
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 1549c45..d505f02 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -25,6 +25,7 @@
 import android.content.pm.ProviderInfo;
 import android.database.Cursor;
 import android.net.Uri;
+import android.util.Log;
 
 /**
  * Base class for a search indexable provider. Such provider offers data to be indexed either
@@ -112,19 +113,26 @@
     @Override
     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                         String sortOrder) {
-        switch (mMatcher.match(uri)) {
-            case MATCH_RES_CODE:
-                return queryXmlResources(null);
-            case MATCH_RAW_CODE:
-                return queryRawData(null);
-            case MATCH_NON_INDEXABLE_KEYS_CODE:
-                return queryNonIndexableKeys(null);
-            case MATCH_SITE_MAP_PAIRS_CODE:
-                return querySiteMapPairs();
-            case MATCH_SLICE_URI_PAIRS_CODE:
-                return querySliceUriPairs();
-            default:
-                throw new UnsupportedOperationException("Unknown Uri " + uri);
+        try {
+            switch (mMatcher.match(uri)) {
+                case MATCH_RES_CODE:
+                    return queryXmlResources(null);
+                case MATCH_RAW_CODE:
+                    return queryRawData(null);
+                case MATCH_NON_INDEXABLE_KEYS_CODE:
+                    return queryNonIndexableKeys(null);
+                case MATCH_SITE_MAP_PAIRS_CODE:
+                    return querySiteMapPairs();
+                case MATCH_SLICE_URI_PAIRS_CODE:
+                    return querySliceUriPairs();
+                default:
+                    throw new UnsupportedOperationException("Unknown Uri " + uri);
+            }
+        } catch (UnsupportedOperationException e) {
+            throw e;
+        } catch (Exception e) {
+            Log.e(TAG, "Provider querying exception:", e);
+            return null;
         }
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 313384d..b8174e6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1696,6 +1696,19 @@
     public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE =
             "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
 
+    /**
+     * Activity Action: Show screen that let user manage how Android handles URL resolution.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
+
     // End of Intent actions for Settings
 
     /**
@@ -12585,8 +12598,9 @@
 
         /**
          * Battery level [1-100] at which low power mode automatically turns on.
-         * Pre-Q If 0, it will not automatically turn on. Q and newer it will only automatically
-         * turn on if the {@link #AUTOMATIC_POWER_SAVER_MODE} setting is also set to
+         * If 0, it will not automatically turn on. For Q and newer, it will only automatically
+         * turn on if the value is greater than 0 and the {@link #AUTOMATIC_POWER_SAVER_MODE}
+         * setting is also set to
          * {@link android.os.PowerManager.AutoPowerSaverMode#POWER_SAVER_MODE_PERCENTAGE}.
          *
          * @see #AUTOMATIC_POWER_SAVER_MODE
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 19e216a..34ced17 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -30,6 +30,7 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -201,18 +202,26 @@
         if (mAutofillProxies == null) {
             mAutofillProxies = new SparseArray<>();
         }
+
+        final ICancellationSignal transport = CancellationSignal.createTransport();
+        final CancellationSignal cancellationSignal = CancellationSignal.fromTransport(transport);
         AutofillProxy proxy = mAutofillProxies.get(sessionId);
         if (proxy == null) {
             proxy = new AutofillProxy(sessionId, client, taskId, componentName, focusedId,
-                    focusedValue, requestTime, callback);
+                    focusedValue, requestTime, callback, cancellationSignal);
             mAutofillProxies.put(sessionId,  proxy);
         } else {
             // TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging
             if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId);
             proxy.update(focusedId, focusedValue, callback);
         }
-        // TODO(b/123101711): set cancellation signal
-        final CancellationSignal cancellationSignal = null;
+
+        try {
+            callback.onCancellable(transport);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+
         onFillRequest(new FillRequest(proxy), cancellationSignal, new FillController(proxy),
                 new FillCallback(proxy));
     }
@@ -329,18 +338,21 @@
         @GuardedBy("mLock")
         private FillWindow mFillWindow;
 
+        private CancellationSignal mCancellationSignal;
+
         private AutofillProxy(int sessionId, @NonNull IBinder client, int taskId,
                 @NonNull ComponentName componentName, @NonNull AutofillId focusedId,
                 @Nullable AutofillValue focusedValue, long requestTime,
-                @NonNull IFillCallback callback) {
+                @NonNull IFillCallback callback, @NonNull CancellationSignal cancellationSignal) {
             mSessionId = sessionId;
             mClient = IAugmentedAutofillManagerClient.Stub.asInterface(client);
             mCallback = callback;
             this.taskId = taskId;
             this.componentName = componentName;
-            this.mFocusedId = focusedId;
-            this.mFocusedValue = focusedValue;
-            this.mFirstRequestTime = requestTime;
+            mFocusedId = focusedId;
+            mFocusedValue = focusedValue;
+            mFirstRequestTime = requestTime;
+            mCancellationSignal = cancellationSignal;
             // TODO(b/123099468): linkToDeath
         }
 
@@ -394,6 +406,12 @@
 
         public void requestShowFillUi(int width, int height, Rect anchorBounds,
                 IAutofillWindowPresenter presenter) throws RemoteException {
+            if (mCancellationSignal.isCanceled()) {
+                if (VERBOSE) {
+                    Log.v(TAG, "requestShowFillUi() not showing because request is cancelled");
+                }
+                return;
+            }
             mClient.requestShowFillUi(mSessionId, mFocusedId, width, height, anchorBounds,
                     presenter);
         }
@@ -408,8 +426,13 @@
                 mFocusedId = focusedId;
                 mFocusedValue = focusedValue;
                 if (mCallback != null) {
-                    // TODO(b/123101711): we need to check whether the previous request was
-                    //  completed or not, and if not, cancel it first.
+                    try {
+                        if (mCallback.isCompleted()) {
+                            mCallback.cancel();
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "failed to check current pending request status", e);
+                    }
                     Slog.d(TAG, "mCallback is updated.");
                 }
                 mCallback = callback;
diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl
index 2b072664..88baa87 100644
--- a/core/java/android/service/autofill/augmented/IFillCallback.aidl
+++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl
@@ -24,7 +24,8 @@
  * @hide
  */
 interface IFillCallback {
-    // TODO(b/123101711): add cancellation (after we have CTS tests, so we can test it)
-//    void onCancellable(in ICancellationSignal cancellation);
+    void onCancellable(in ICancellationSignal cancellation);
     void onSuccess();
+    boolean isCompleted();
+    void cancel();
 }
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index cc74e1a..8512a0b 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -292,9 +292,9 @@
         return uid;
     }
 
-    /** The package that posted the notification.
-     *<p>
-     * Might be different from {@link #getPackageName()} if the app owning the notification has
+    /**
+     * The package that posted the notification.
+     * <p> Might be different from {@link #getPackageName()} if the app owning the notification has
      * a {@link NotificationManager#setNotificationDelegate(String) notification delegate}.
      */
     public @NonNull String getOpPkg() {
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 83f14d1..100774c 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -536,7 +536,7 @@
          * or playing back a file. The value should be one of the STREAM_ constants
          * defined in {@link AudioManager}.
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
         public static final String KEY_PARAM_STREAM = "streamType";
@@ -546,7 +546,7 @@
          * speaking text or playing back a file. The value should be set
          * using {@link TextToSpeech#setAudioAttributes(AudioAttributes)}.
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          * @hide
          */
@@ -557,7 +557,7 @@
          * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
          * spoken, a file has been played back or a silence duration has elapsed.
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          * @see TextToSpeech#synthesizeToFile(String, HashMap, String)
          */
@@ -568,7 +568,7 @@
          * volume used when speaking text. Volume is specified as a float ranging from 0 to 1
          * where 0 is silence, and 1 is the maximum volume (the default behavior).
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
         public static final String KEY_PARAM_VOLUME = "volume";
@@ -578,7 +578,7 @@
          * Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan,
          * 0 to center (the default behavior), and +1 to hard-right.
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
         public static final String KEY_PARAM_PAN = "pan";
@@ -589,7 +589,7 @@
          * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must
          * use network based synthesis.
          *
-         * @see TextToSpeech#speak(String, int, java.util.HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
          * @see TextToSpeech#getFeatures(java.util.Locale)
          *
@@ -607,7 +607,7 @@
          * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize
          * text on-device (without making network requests).
          *
-         * @see TextToSpeech#speak(String, int, java.util.HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
          * @see TextToSpeech#getFeatures(java.util.Locale)
 
@@ -625,7 +625,7 @@
          * output. It can be used to associate one of the {@link android.media.audiofx.AudioEffect}
          * objects with the synthesis (or earcon) output.
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
         public static final String KEY_PARAM_SESSION_ID = "sessionId";
@@ -881,7 +881,7 @@
     /**
      * Adds a mapping between a string of text and a sound resource in a
      * package. After a call to this method, subsequent calls to
-     * {@link #speak(String, int, HashMap)} will play the specified sound resource
+     * {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound resource
      * if it is available, or synthesize the text it is missing.
      *
      * @param text
@@ -915,7 +915,7 @@
     /**
      * Adds a mapping between a CharSequence (may be spanned with TtsSpans) of text
      * and a sound resource in a package. After a call to this method, subsequent calls to
-     * {@link #speak(String, int, HashMap)} will play the specified sound resource
+     * {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound resource
      * if it is available, or synthesize the text it is missing.
      *
      * @param text
@@ -947,11 +947,10 @@
     }
 
     /**
-     * Adds a mapping between a string of text and a sound file. Using this, it
-     * is possible to add custom pronounciations for a string of text.
-     * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
-     * will play the specified sound resource if it is available, or synthesize the text it is
-     * missing.
+     * Adds a mapping between a string of text and a sound file. Using this, it is possible to
+     * add custom pronounciations for a string of text. After a call to this method, subsequent
+     * calls to {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound
+     * resource if it is available, or synthesize the text it is missing.
      *
      * @param text
      *            The string of text. Example: <code>"south_south_east"</code>
@@ -970,8 +969,8 @@
 
     /**
      * Adds a mapping between a CharSequence (may be spanned with TtsSpans and a sound file.
-     * Using this, it is possible to add custom pronounciations for a string of text.
-     * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
+     * Using this, it is possible to add custom pronounciations for a string of text. After a call
+     * to this method, subsequent calls to {@link #speak(CharSequence, int, Bundle, String)}
      * will play the specified sound resource if it is available, or synthesize the text it is
      * missing.
      *
diff --git a/core/java/android/text/style/LineBackgroundSpan.java b/core/java/android/text/style/LineBackgroundSpan.java
index e43fd83..7cb9147 100644
--- a/core/java/android/text/style/LineBackgroundSpan.java
+++ b/core/java/android/text/style/LineBackgroundSpan.java
@@ -53,6 +53,15 @@
     /**
      * Default implementation of the {@link LineBackgroundSpan}, which changes the background
      * color of the lines to which the span is attached.
+     * <p>
+     * For example, an <code>LineBackgroundSpan</code> can be used like this:
+     * <pre>
+     * String text = "This is a multiline text. LineBackgroundSpan is applied here. This is a multiline text.";
+     * SpannableString string = new SpannableString(text);
+     * string.setSpan(new LineBackgroundSpan.Standard(Color.YELLOW), 26, 61, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+     * </pre>
+     * <img src="{@docRoot}reference/android/images/text/style/linebackgroundspan.png" />
+     * <figcaption>Text with <code>LineBackgroundSpan</code></figcaption>
      */
     class Standard implements LineBackgroundSpan, ParcelableSpan {
 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e32c4e1..9ee6585 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -129,7 +129,7 @@
     @UnsupportedAppUsage
     boolean isKeyguardLocked();
     @UnsupportedAppUsage
-    boolean isKeyguardSecure();
+    boolean isKeyguardSecure(int userId);
     void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message);
 
     // Requires INTERACT_ACROSS_USERS_FULL permission
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 2d7e179..6129b38 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -145,7 +145,14 @@
 
             // TODO: set system gesture insets based on actual system gesture area.
             typeInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets);
-            typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets);
+            typeInsetsMap[Type.indexOf(Type.mandatorySystemGestures())] =
+                    Insets.of(legacyContentInsets);
+            typeInsetsMap[Type.indexOf(Type.tappableElement())] = Insets.of(legacyContentInsets);
+
+            typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyStableInsets);
+            typeMaxInsetsMap[Type.indexOf(Type.mandatorySystemGestures())] =
+                    Insets.of(legacyStableInsets);
+            typeMaxInsetsMap[Type.indexOf(Type.tappableElement())] = Insets.of(legacyStableInsets);
         }
         for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
             InsetsSource source = mSources.get(type);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 49eb78d..ab2cc66 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -130,8 +130,8 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
-import android.view.inspector.InspectableProperty.FlagMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
+import android.view.inspector.InspectableProperty.FlagEntry;
 import android.widget.Checkable;
 import android.widget.FrameLayout;
 import android.widget.ScrollBarDrawable;
@@ -6902,13 +6902,13 @@
      * @return a bitmask representing the enabled scroll indicators
      */
     @InspectableProperty(flagMapping = {
-            @FlagMap(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"),
-            @FlagMap(target = SCROLL_INDICATOR_TOP, name = "top"),
-            @FlagMap(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"),
-            @FlagMap(target = SCROLL_INDICATOR_LEFT, name = "left"),
-            @FlagMap(target = SCROLL_INDICATOR_RIGHT, name = "right"),
-            @FlagMap(target = SCROLL_INDICATOR_START, name = "start"),
-            @FlagMap(target = SCROLL_INDICATOR_END, name = "end")
+            @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"),
+            @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"),
+            @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"),
+            @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"),
+            @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"),
+            @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"),
+            @FlagEntry(target = SCROLL_INDICATOR_END, name = "end")
     })
     @ScrollIndicators
     public int getScrollIndicators() {
@@ -9037,12 +9037,12 @@
             @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
                 to = "noExcludeDescendants")})
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"),
-            @EnumMap(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"),
-            @EnumMap(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"),
-            @EnumMap(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
+            @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"),
+            @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"),
+            @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"),
+            @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
                     name = "yesExcludeDescendants"),
-            @EnumMap(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
+            @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
                     name = "noExcludeDescendants"),
     })
     public @AutofillImportance int getImportantForAutofill() {
@@ -9230,12 +9230,12 @@
             @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
                 to = "noExcludeDescendants")})
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"),
-            @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"),
-            @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"),
-            @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS,
+            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"),
+            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"),
+            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"),
+            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS,
                     name = "yesExcludeDescendants"),
-            @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
+            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
                     name = "noExcludeDescendants"),
     })
     public @ContentCaptureImportance int getImportantForContentCapture() {
@@ -10539,9 +10539,9 @@
     @Deprecated
     @DrawingCacheQuality
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = DRAWING_CACHE_QUALITY_LOW, name = "low"),
-            @EnumMap(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"),
-            @EnumMap(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto")
+            @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"),
+            @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"),
+            @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto")
     })
     public int getDrawingCacheQuality() {
         return mViewFlags & DRAWING_CACHE_QUALITY_MASK;
@@ -11281,9 +11281,9 @@
         @ViewDebug.IntToString(from = GONE,      to = "GONE")
     })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = VISIBLE, name = "visible"),
-            @EnumMap(value = INVISIBLE, name = "invisible"),
-            @EnumMap(value = GONE, name = "gone")
+            @EnumEntry(value = VISIBLE, name = "visible"),
+            @EnumEntry(value = INVISIBLE, name = "invisible"),
+            @EnumEntry(value = GONE, name = "gone")
     })
     @Visibility
     public int getVisibility() {
@@ -11532,10 +11532,10 @@
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE,  to = "LOCALE")
     })
     @InspectableProperty(hasAttributeId = false, enumMapping = {
-            @EnumMap(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
-            @EnumMap(value = LAYOUT_DIRECTION_RTL, name = "rtl"),
-            @EnumMap(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"),
-            @EnumMap(value = LAYOUT_DIRECTION_LOCALE, name = "locale")
+            @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
+            @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"),
+            @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"),
+            @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale")
     })
     @LayoutDir
     public int getRawLayoutDirection() {
@@ -11591,8 +11591,8 @@
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL")
     })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
-            @EnumMap(value = LAYOUT_DIRECTION_RTL, name = "rtl")
+            @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
+            @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl")
     })
     @ResolvedLayoutDir
     public int getLayoutDirection() {
@@ -12077,9 +12077,9 @@
             @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO")
             }, category = "focus")
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = NOT_FOCUSABLE, name = "false"),
-            @EnumMap(value = FOCUSABLE, name = "true"),
-            @EnumMap(value = FOCUSABLE_AUTO, name = "auto")
+            @EnumEntry(value = NOT_FOCUSABLE, name = "false"),
+            @EnumEntry(value = FOCUSABLE, name = "true"),
+            @EnumEntry(value = FOCUSABLE_AUTO, name = "auto")
     })
     @Focusable
     public int getFocusable() {
@@ -12962,10 +12962,10 @@
                     to = "noHideDescendants")
         })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"),
-            @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"),
-            @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"),
-            @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
+            @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"),
+            @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"),
+            @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"),
+            @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
                     name = "noHideDescendants"),
     })
     public int getImportantForAccessibility() {
@@ -13021,9 +13021,9 @@
      * @see #setAccessibilityLiveRegion(int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"),
-            @EnumMap(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"),
-            @EnumMap(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive")
+            @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"),
+            @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"),
+            @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive")
     })
     public int getAccessibilityLiveRegion() {
         return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK)
@@ -18651,9 +18651,9 @@
      * @hide
      */
     @InspectableProperty(name = "requiresFadingEdge", flagMapping = {
-            @FlagMap(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"),
-            @FlagMap(target = FADING_EDGE_VERTICAL, name = "vertical"),
-            @FlagMap(target = FADING_EDGE_HORIZONTAL, name = "horizontal")
+            @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"),
+            @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"),
+            @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal")
     })
     public int getFadingEdge() {
         return mViewFlags & FADING_EDGE_MASK;
@@ -18948,10 +18948,10 @@
             @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET")
     })
     @InspectableProperty(name = "scrollbarStyle", enumMapping = {
-            @EnumMap(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"),
-            @EnumMap(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"),
-            @EnumMap(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"),
-            @EnumMap(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset")
+            @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"),
+            @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"),
+            @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"),
+            @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset")
     })
     @ScrollBarStyle
     public int getScrollBarStyle() {
@@ -20504,9 +20504,9 @@
      * @see #LAYER_TYPE_HARDWARE
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = LAYER_TYPE_NONE, name = "none"),
-            @EnumMap(value = LAYER_TYPE_SOFTWARE, name = "software"),
-            @EnumMap(value = LAYER_TYPE_HARDWARE, name = "hardware")
+            @EnumEntry(value = LAYER_TYPE_NONE, name = "none"),
+            @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"),
+            @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware")
     })
     @LayerType
     public int getLayerType() {
@@ -26187,9 +26187,9 @@
      * @return This view's over-scroll mode.
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = OVER_SCROLL_ALWAYS, name = "always"),
-            @EnumMap(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"),
-            @EnumMap(value = OVER_SCROLL_NEVER, name = "never")
+            @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"),
+            @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"),
+            @EnumEntry(value = OVER_SCROLL_NEVER, name = "never")
     })
     public int getOverScrollMode() {
         return mOverScrollMode;
@@ -26580,14 +26580,14 @@
             @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
     })
     @InspectableProperty(hasAttributeId = false, enumMapping = {
-            @EnumMap(value = TEXT_DIRECTION_INHERIT, name = "inherit"),
-            @EnumMap(value = TEXT_DIRECTION_LOCALE, name = "locale"),
-            @EnumMap(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
-            @EnumMap(value = TEXT_DIRECTION_LTR, name = "ltr"),
-            @EnumMap(value = TEXT_DIRECTION_RTL, name = "rtl"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
+            @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"),
+            @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"),
+            @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
+            @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"),
+            @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
     })
     @UnsupportedAppUsage
     public int getRawTextDirection() {
@@ -26657,13 +26657,13 @@
             @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
     })
     @InspectableProperty(hasAttributeId = false, enumMapping = {
-            @EnumMap(value = TEXT_DIRECTION_LOCALE, name = "locale"),
-            @EnumMap(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
-            @EnumMap(value = TEXT_DIRECTION_LTR, name = "ltr"),
-            @EnumMap(value = TEXT_DIRECTION_RTL, name = "rtl"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
+            @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"),
+            @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
+            @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"),
+            @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
     })
     public int getTextDirection() {
         return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
@@ -26837,13 +26837,13 @@
             @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
     })
     @InspectableProperty(hasAttributeId = false, enumMapping = {
-            @EnumMap(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"),
-            @EnumMap(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
-            @EnumMap(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
-            @EnumMap(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
-            @EnumMap(value = TEXT_ALIGNMENT_CENTER, name = "center"),
-            @EnumMap(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
-            @EnumMap(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
+            @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"),
+            @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
+            @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
+            @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
+            @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"),
+            @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
+            @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
     })
     @TextAlignment
     @UnsupportedAppUsage
@@ -26912,12 +26912,12 @@
             @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
     })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
-            @EnumMap(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
-            @EnumMap(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
-            @EnumMap(value = TEXT_ALIGNMENT_CENTER, name = "center"),
-            @EnumMap(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
-            @EnumMap(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
+            @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
+            @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
+            @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
+            @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"),
+            @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
+            @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
     })
     @TextAlignment
     public int getTextAlignment() {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4964ee1..a4d80dc 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -61,7 +61,7 @@
 import android.view.animation.Transformation;
 import android.view.autofill.Helper;
 import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
 
 import com.android.internal.R;
 
@@ -778,9 +778,9 @@
         @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
     })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = FOCUS_BEFORE_DESCENDANTS, name = "beforeDescendants"),
-            @EnumMap(value = FOCUS_AFTER_DESCENDANTS, name = "afterDescendants"),
-            @EnumMap(value = FOCUS_BLOCK_DESCENDANTS, name = "blocksDescendants")
+            @EnumEntry(value = FOCUS_BEFORE_DESCENDANTS, name = "beforeDescendants"),
+            @EnumEntry(value = FOCUS_AFTER_DESCENDANTS, name = "afterDescendants"),
+            @EnumEntry(value = FOCUS_BLOCK_DESCENDANTS, name = "blocksDescendants")
     })
     public int getDescendantFocusability() {
         return mGroupFlags & FLAG_MASK_FOCUSABILITY;
@@ -6574,10 +6574,10 @@
         @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
     })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = PERSISTENT_NO_CACHE, name = "none"),
-            @EnumMap(value = PERSISTENT_ANIMATION_CACHE, name = "animation"),
-            @EnumMap(value = PERSISTENT_SCROLLING_CACHE, name = "scrolling"),
-            @EnumMap(value = PERSISTENT_ALL_CACHES, name = "all"),
+            @EnumEntry(value = PERSISTENT_NO_CACHE, name = "none"),
+            @EnumEntry(value = PERSISTENT_ANIMATION_CACHE, name = "animation"),
+            @EnumEntry(value = PERSISTENT_SCROLLING_CACHE, name = "scrolling"),
+            @EnumEntry(value = PERSISTENT_ALL_CACHES, name = "all"),
     })
     public int getPersistentDrawingCache() {
         return mPersistentDrawingCache;
@@ -6657,8 +6657,8 @@
      * @see #setLayoutMode(int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = LAYOUT_MODE_CLIP_BOUNDS, name = "clipBounds"),
-            @EnumMap(value = LAYOUT_MODE_OPTICAL_BOUNDS, name = "opticalBounds")
+            @EnumEntry(value = LAYOUT_MODE_CLIP_BOUNDS, name = "clipBounds"),
+            @EnumEntry(value = LAYOUT_MODE_OPTICAL_BOUNDS, name = "opticalBounds")
     })
     public int getLayoutMode() {
         if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
@@ -7849,8 +7849,8 @@
             @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
         })
         @InspectableProperty(name = "layout_width", enumMapping = {
-                @InspectableProperty.EnumMap(name = "match_parent", value = MATCH_PARENT),
-                @InspectableProperty.EnumMap(name = "wrap_content", value = WRAP_CONTENT)
+                @EnumEntry(name = "match_parent", value = MATCH_PARENT),
+                @EnumEntry(name = "wrap_content", value = WRAP_CONTENT)
         })
         public int width;
 
@@ -7864,8 +7864,8 @@
             @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
         })
         @InspectableProperty(name = "layout_height", enumMapping = {
-                @InspectableProperty.EnumMap(name = "match_parent", value = MATCH_PARENT),
-                @InspectableProperty.EnumMap(name = "wrap_content", value = WRAP_CONTENT)
+                @EnumEntry(name = "match_parent", value = MATCH_PARENT),
+                @EnumEntry(name = "wrap_content", value = WRAP_CONTENT)
         })
         public int height;
 
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index f1a992c..aac0e34 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -20,14 +20,18 @@
 import static android.view.WindowInsets.Type.FIRST;
 import static android.view.WindowInsets.Type.IME;
 import static android.view.WindowInsets.Type.LAST;
+import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
 import static android.view.WindowInsets.Type.SIDE_BARS;
 import static android.view.WindowInsets.Type.SIZE;
 import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
+import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
 import static android.view.WindowInsets.Type.TOP_BAR;
 import static android.view.WindowInsets.Type.all;
 import static android.view.WindowInsets.Type.compatSystemInsets;
 import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.mandatorySystemGestures;
 import static android.view.WindowInsets.Type.systemGestures;
+import static android.view.WindowInsets.Type.tappableElement;
 
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -223,6 +227,8 @@
         assignCompatInsets(typeInsetMap, insets);
         // TODO: set system gesture insets based on actual system gesture area.
         typeInsetMap[indexOf(systemGestures())] = Insets.of(insets);
+        typeInsetMap[indexOf(mandatorySystemGestures())] = Insets.of(insets);
+        typeInsetMap[indexOf(tappableElement())] = Insets.of(insets);
         return typeInsetMap;
     }
 
@@ -639,15 +645,22 @@
      * priority and may consume some or all touch input, e.g. due to the a system bar
      * occupying it, or it being reserved for touch-only gestures.
      *
+     * <p>An app can declare priority over system gestures with
+     * {@link View#setSystemGestureExclusionRects} outside of the
+     * {@link #getMandatorySystemGestureInsets() mandatory system gesture insets}.
+     *
      * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
-     * as long as they are outside the {@link #getSystemWindowInsets() system window insets}.
+     * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
      *
      * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
      * even when the system gestures are inactive due to
      * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
      * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
      *
-     * <p>This inset does not affect the result of {@link #isConsumed()} and cannot be consumed.
+     * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
+     * system window insets} by {@link #consumeSystemWindowInsets()}.
+     *
+     * @see #getMandatorySystemGestureInsets
      */
     @NonNull
     public Insets getSystemGestureInsets() {
@@ -655,6 +668,60 @@
     }
 
     /**
+     * Returns the mandatory system gesture insets.
+     *
+     * <p>The mandatory system gesture insets represent the area of a window where mandatory system
+     * gestures have priority and may consume some or all touch input, e.g. due to the a system bar
+     * occupying it, or it being reserved for touch-only gestures.
+     *
+     * <p>In contrast to {@link #getSystemGestureInsets regular system gestures}, <b>mandatory</b>
+     * system gestures cannot be overriden by {@link View#setSystemGestureExclusionRects}.
+     *
+     * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
+     * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
+     *
+     * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
+     * even when the system gestures are inactive due to
+     * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
+     * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+     *
+     * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
+     * system window insets} by {@link #consumeSystemWindowInsets()}.
+     *
+     * @see #getSystemGestureInsets
+     */
+    @NonNull
+    public Insets getMandatorySystemGestureInsets() {
+        return getInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES);
+    }
+
+    /**
+     * Returns the tappable element insets.
+     *
+     * <p>The tappable element insets represent how much tappable elements <b>must at least</b> be
+     * inset to remain both tappable and visually unobstructed by persistent system windows.
+     *
+     * <p>This may be smaller than {@link #getSystemWindowInsets()} if the system window is
+     * largely transparent and lets through simple taps (but not necessarily more complex gestures).
+     *
+     * <p>Note that generally, tappable elements <strong>should</strong> be aligned with the
+     * {@link #getSystemWindowInsets() system window insets} instead to avoid overlapping with the
+     * system bars.
+     *
+     * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
+     * even when the area covered by the inset would be tappable due to
+     * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
+     * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+     *
+     * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
+     * system window insets} by {@link #consumeSystemWindowInsets()}.
+     */
+    @NonNull
+    public Insets getTappableElementInsets() {
+        return getInsets(mTypeInsetsMap, TAPPABLE_ELEMENT);
+    }
+
+    /**
      * Returns a copy of this WindowInsets with the stable insets fully consumed.
      *
      * @return A modified copy of this WindowInsets
@@ -895,6 +962,41 @@
         }
 
         /**
+         * Sets mandatory system gesture insets in pixels.
+         *
+         * <p>The mandatory system gesture insets represent the area of a window where mandatory
+         * system gestures have priority and may consume some or all touch input, e.g. due to the a
+         * system bar occupying it, or it being reserved for touch-only gestures.
+         *
+         * <p>In contrast to {@link #setSystemGestureInsets regular system gestures},
+         * <b>mandatory</b> system gestures cannot be overriden by
+         * {@link View#setSystemGestureExclusionRects}.
+         *
+         * @see #getMandatorySystemGestureInsets()
+         * @return itself
+         */
+        @NonNull
+        public Builder setMandatorySystemGestureInsets(@NonNull Insets insets) {
+            WindowInsets.setInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES, insets);
+            return this;
+        }
+
+        /**
+         * Sets tappable element insets in pixels.
+         *
+         * <p>The tappable element insets represent how much tappable elements <b>must at least</b>
+         * be inset to remain both tappable and visually unobstructed by persistent system windows.
+         *
+         * @see #getTappableElementInsets()
+         * @return itself
+         */
+        @NonNull
+        public Builder setTappableElementInsets(@NonNull Insets insets) {
+            WindowInsets.setInsets(mTypeInsetsMap, TAPPABLE_ELEMENT, insets);
+            return this;
+        }
+
+        /**
          * Sets the insets of a specific window type in pixels.
          *
          * <p>The insets represents the area of a a window that is partially or fully obscured by
@@ -1041,16 +1143,18 @@
      */
     public static final class Type {
 
-        static final int FIRST = 0x1;
+        static final int FIRST = 1 << 0;
         static final int TOP_BAR = FIRST;
 
-        static final int IME = 0x2;
-        static final int SIDE_BARS = 0x4;
+        static final int IME = 1 << 1;
+        static final int SIDE_BARS = 1 << 2;
 
-        static final int SYSTEM_GESTURES = 0x8;
+        static final int SYSTEM_GESTURES = 1 << 3;
+        static final int MANDATORY_SYSTEM_GESTURES = 1 << 4;
+        static final int TAPPABLE_ELEMENT = 1 << 5;
 
-        static final int LAST = 0x10;
-        static final int SIZE = 5;
+        static final int LAST = 1 << 6;
+        static final int SIZE = 7;
         static final int WINDOW_DECOR = LAST;
 
         static int indexOf(@InsetType int type) {
@@ -1063,8 +1167,12 @@
                     return 2;
                 case SYSTEM_GESTURES:
                     return 3;
-                case WINDOW_DECOR:
+                case MANDATORY_SYSTEM_GESTURES:
                     return 4;
+                case TAPPABLE_ELEMENT:
+                    return 5;
+                case WINDOW_DECOR:
+                    return 6;
                 default:
                     throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
                             + " type=" + type);
@@ -1076,7 +1184,8 @@
 
         /** @hide */
         @Retention(RetentionPolicy.SOURCE)
-        @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES })
+        @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES,
+                MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT})
         public @interface InsetType {
         }
 
@@ -1131,6 +1240,20 @@
         }
 
         /**
+         * @see #getMandatorySystemGestureInsets
+         */
+        public static @InsetType int mandatorySystemGestures() {
+            return MANDATORY_SYSTEM_GESTURES;
+        }
+
+        /**
+         * @see #getTappableElementInsets
+         */
+        public static @InsetType int tappableElement() {
+            return TAPPABLE_ELEMENT;
+        }
+
+        /**
          * @return All system bars. Includes {@link #topBar()} as well as {@link #sideBars()}, but
          *         not {@link #ime()}.
          */
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 604cce5..8f1896d 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -3146,6 +3146,10 @@
             if (afm == null) return null;
 
             final View view = afm.getClient().autofillClientFindViewByAutofillIdTraversal(id);
+            if (view == null) {
+                Log.w(TAG, "getViewCoordinates(" + id + "): could not find view");
+                return null;
+            }
             final Rect windowVisibleDisplayFrame = new Rect();
             view.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
             final int[] location = new int[2];
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 019ebff..5a27e94 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -161,7 +161,7 @@
     /**
      * Gets the context id.
      */
-    @NonNull
+    @Nullable
     public LocusId getLocusId() {
         return mId;
     }
diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java
index 97ede86..03f1ec5 100644
--- a/core/java/android/view/inspector/InspectableProperty.java
+++ b/core/java/android/view/inspector/InspectableProperty.java
@@ -87,21 +87,21 @@
      *
      * Note that {@link #enumMapping()} cannot be used simultaneously with {@link #flagMapping()}.
      *
-     * @return An array of {@link EnumMap}, empty if not applicable
+     * @return An array of {@link EnumEntry}, empty if not applicable
      * @see android.annotation.IntDef
      */
-    EnumMap[] enumMapping() default {};
+    EnumEntry[] enumMapping() default {};
 
     /**
      * For flags packed into primitive {int} properties, model the string names of the flags.
      *
      * Note that {@link #flagMapping()} cannot be used simultaneously with {@link #enumMapping()}.
      *
-     * @return An array of {@link FlagMap}, empty if not applicable
+     * @return An array of {@link FlagEntry}, empty if not applicable
      * @see android.annotation.IntDef
      * @see IntFlagMapping
      */
-    FlagMap[] flagMapping() default {};
+    FlagEntry[] flagMapping() default {};
 
 
     /**
@@ -113,7 +113,7 @@
     @Target({TYPE})
     @Retention(SOURCE)
     @TestApi
-    @interface EnumMap {
+    @interface EnumEntry {
         /**
          * The string name of this enumeration value.
          *
@@ -138,7 +138,7 @@
     @Target({TYPE})
     @Retention(SOURCE)
     @TestApi
-    @interface FlagMap {
+    @interface FlagEntry {
         /**
          * The string name of this flag.
          *
@@ -195,7 +195,7 @@
          *
          * This is inferred if {@link #enumMapping()} is specified.
          *
-         * @see EnumMap
+         * @see EnumEntry
          * @hide
          */
         @TestApi
@@ -206,7 +206,7 @@
          *
          * This is inferred if {@link #flagMapping()} is specified.
          *
-         * @see FlagMap
+         * @see FlagEntry
          * @hide
          */
         @TestApi
@@ -227,7 +227,7 @@
         /**
          * Value packs gravity information.
          *
-         * This type is not inferred, and is non-trivial to represent using {@link FlagMap}.
+         * This type is not inferred, and is non-trivial to represent using {@link FlagEntry}.
          *
          * @see android.view.Gravity
          * @hide
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 034cabd..26dba45 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2292,9 +2292,9 @@
      * @return the requested renderer priority policy.
      */
     @InspectableProperty(hasAttributeId = false, enumMapping = {
-            @InspectableProperty.EnumMap(name = "waived", value = RENDERER_PRIORITY_WAIVED),
-            @InspectableProperty.EnumMap(name = "bound", value = RENDERER_PRIORITY_BOUND),
-            @InspectableProperty.EnumMap(name = "important", value = RENDERER_PRIORITY_IMPORTANT)
+            @InspectableProperty.EnumEntry(name = "waived", value = RENDERER_PRIORITY_WAIVED),
+            @InspectableProperty.EnumEntry(name = "bound", value = RENDERER_PRIORITY_BOUND),
+            @InspectableProperty.EnumEntry(name = "important", value = RENDERER_PRIORITY_IMPORTANT)
     })
     @RendererPriority
     public int getRendererRequestedPriority() {
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 6d88530..4413585 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -448,8 +448,9 @@
 
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
             try {
-                initialApplication.getAssets().addAssetPathAsSharedLibrary(
-                        webViewContext.getApplicationInfo().sourceDir);
+                for (String newAssetPath : webViewContext.getApplicationInfo().getAllApkPaths()) {
+                    initialApplication.getAssets().addAssetPathAsSharedLibrary(newAssetPath);
+                }
                 ClassLoader clazzLoader = webViewContext.getClassLoader();
 
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 24f1fb5..4cb552d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -83,7 +83,7 @@
 import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
 import android.widget.RemoteViews.OnClickHandler;
 
 import com.android.internal.R;
@@ -1221,10 +1221,10 @@
      * @return The current choice mode
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = CHOICE_MODE_NONE, name = "none"),
-            @EnumMap(value = CHOICE_MODE_SINGLE, name = "singleChoice"),
-            @EnumMap(value = CHOICE_MODE_MULTIPLE, name = "multipleChoice"),
-            @EnumMap(value = CHOICE_MODE_MULTIPLE_MODAL, name = "multipleChoiceModal")
+            @EnumEntry(value = CHOICE_MODE_NONE, name = "none"),
+            @EnumEntry(value = CHOICE_MODE_SINGLE, name = "singleChoice"),
+            @InspectableProperty.EnumEntry(value = CHOICE_MODE_MULTIPLE, name = "multipleChoice"),
+            @EnumEntry(value = CHOICE_MODE_MULTIPLE_MODAL, name = "multipleChoiceModal")
     })
     public int getChoiceMode() {
         return mChoiceMode;
@@ -6293,9 +6293,9 @@
      *         {@link #TRANSCRIPT_MODE_ALWAYS_SCROLL}
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = TRANSCRIPT_MODE_DISABLED, name = "disabled"),
-            @EnumMap(value = TRANSCRIPT_MODE_NORMAL, name = "normal"),
-            @EnumMap(value = TRANSCRIPT_MODE_ALWAYS_SCROLL, name = "alwaysScroll")
+            @EnumEntry(value = TRANSCRIPT_MODE_DISABLED, name = "disabled"),
+            @EnumEntry(value = TRANSCRIPT_MODE_NORMAL, name = "normal"),
+            @EnumEntry(value = TRANSCRIPT_MODE_ALWAYS_SCROLL, name = "alwaysScroll")
     })
     public int getTranscriptMode() {
         return mTranscriptMode;
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index ecb846b..0c593be 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -216,8 +216,8 @@
      * @hide Visible for testing only.
      */
     @InspectableProperty(name = "datePickerMode", enumMapping = {
-            @InspectableProperty.EnumMap(value = MODE_SPINNER, name = "spinner"),
-            @InspectableProperty.EnumMap(value = MODE_CALENDAR, name = "calendar")
+            @InspectableProperty.EnumEntry(value = MODE_SPINNER, name = "spinner"),
+            @InspectableProperty.EnumEntry(value = MODE_CALENDAR, name = "calendar")
     })
     @DatePickerMode
     @TestApi
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 1c8bb04..8cda47d 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -331,8 +331,8 @@
      */
     @Orientation
     @InspectableProperty(enumMapping = {
-            @InspectableProperty.EnumMap(value = HORIZONTAL, name = "horizontal"),
-            @InspectableProperty.EnumMap(value = VERTICAL, name = "vertical")
+            @InspectableProperty.EnumEntry(value = HORIZONTAL, name = "horizontal"),
+            @InspectableProperty.EnumEntry(value = VERTICAL, name = "vertical")
     })
     public int getOrientation() {
         return mOrientation;
@@ -510,8 +510,8 @@
      */
     @AlignmentMode
     @InspectableProperty(enumMapping = {
-            @InspectableProperty.EnumMap(value = ALIGN_BOUNDS, name = "alignBounds"),
-            @InspectableProperty.EnumMap(value = ALIGN_MARGINS, name = "alignMargins"),
+            @InspectableProperty.EnumEntry(value = ALIGN_BOUNDS, name = "alignBounds"),
+            @InspectableProperty.EnumEntry(value = ALIGN_MARGINS, name = "alignMargins"),
     })
     public int getAlignmentMode() {
         return mAlignmentMode;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index f44c331..4e39a55 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -2174,11 +2174,11 @@
 
     @StretchMode
     @InspectableProperty(enumMapping = {
-            @InspectableProperty.EnumMap(value = NO_STRETCH, name = "none"),
-            @InspectableProperty.EnumMap(value = STRETCH_SPACING, name = "spacingWidth"),
-            @InspectableProperty.EnumMap(
+            @InspectableProperty.EnumEntry(value = NO_STRETCH, name = "none"),
+            @InspectableProperty.EnumEntry(value = STRETCH_SPACING, name = "spacingWidth"),
+            @InspectableProperty.EnumEntry(
                     value = STRETCH_SPACING_UNIFORM, name = "spacingWidthUniform"),
-            @InspectableProperty.EnumMap(value = STRETCH_COLUMN_WIDTH, name = "columnWidth"),
+            @InspectableProperty.EnumEntry(value = STRETCH_COLUMN_WIDTH, name = "columnWidth"),
     })
     public int getStretchMode() {
         return mStretchMode;
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index bdde435..a83e826 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1850,8 +1850,8 @@
      */
     @OrientationMode
     @InspectableProperty(enumMapping = {
-            @InspectableProperty.EnumMap(value = HORIZONTAL, name = "horizontal"),
-            @InspectableProperty.EnumMap(value = VERTICAL, name = "vertical")
+            @InspectableProperty.EnumEntry(value = HORIZONTAL, name = "horizontal"),
+            @InspectableProperty.EnumEntry(value = VERTICAL, name = "vertical")
     })
     public int getOrientation() {
         return mOrientation;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 04bcb14..a5a1a80c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -173,8 +173,8 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
-import android.view.inspector.InspectableProperty.FlagMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
+import android.view.inspector.InspectableProperty.FlagEntry;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationContext;
 import android.view.textclassifier.TextClassificationManager;
@@ -1900,8 +1900,8 @@
      * @see #setAutoSizeTextTypeUniformWithPresetSizes(int[], int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(name = "none", value = AUTO_SIZE_TEXT_TYPE_NONE),
-            @EnumMap(name = "uniform", value = AUTO_SIZE_TEXT_TYPE_UNIFORM)
+            @EnumEntry(name = "none", value = AUTO_SIZE_TEXT_TYPE_NONE),
+            @EnumEntry(name = "uniform", value = AUTO_SIZE_TEXT_TYPE_UNIFORM)
     })
     @AutoSizeTextType
     public int getAutoSizeTextType() {
@@ -3527,10 +3527,10 @@
      * @attr ref android.R.styleable#TextView_autoLink
      */
     @InspectableProperty(name = "autoLink", flagMapping = {
-            @FlagMap(name = "web", target = Linkify.WEB_URLS),
-            @FlagMap(name = "email", target = Linkify.EMAIL_ADDRESSES),
-            @FlagMap(name = "phone", target = Linkify.PHONE_NUMBERS),
-            @FlagMap(name = "map", target = Linkify.MAP_ADDRESSES)
+            @FlagEntry(name = "web", target = Linkify.WEB_URLS),
+            @FlagEntry(name = "email", target = Linkify.EMAIL_ADDRESSES),
+            @FlagEntry(name = "phone", target = Linkify.PHONE_NUMBERS),
+            @FlagEntry(name = "map", target = Linkify.MAP_ADDRESSES)
     })
     public final int getAutoLinkMask() {
         return mAutoLinkMask;
@@ -4515,9 +4515,9 @@
      * @see #setBreakStrategy(int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(name = "simple", value = Layout.BREAK_STRATEGY_SIMPLE),
-            @EnumMap(name = "high_quality", value = Layout.BREAK_STRATEGY_HIGH_QUALITY),
-            @EnumMap(name = "balanced", value = Layout.BREAK_STRATEGY_BALANCED)
+            @EnumEntry(name = "simple", value = Layout.BREAK_STRATEGY_SIMPLE),
+            @EnumEntry(name = "high_quality", value = Layout.BREAK_STRATEGY_HIGH_QUALITY),
+            @EnumEntry(name = "balanced", value = Layout.BREAK_STRATEGY_BALANCED)
     })
     @Layout.BreakStrategy
     public int getBreakStrategy() {
@@ -4566,9 +4566,9 @@
      * @see #setHyphenationFrequency(int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(name = "none", value = Layout.HYPHENATION_FREQUENCY_NONE),
-            @EnumMap(name = "normal", value = Layout.HYPHENATION_FREQUENCY_NORMAL),
-            @EnumMap(name = "full", value = Layout.HYPHENATION_FREQUENCY_FULL)
+            @EnumEntry(name = "none", value = Layout.HYPHENATION_FREQUENCY_NONE),
+            @EnumEntry(name = "normal", value = Layout.HYPHENATION_FREQUENCY_NORMAL),
+            @EnumEntry(name = "full", value = Layout.HYPHENATION_FREQUENCY_FULL)
     })
     @Layout.HyphenationFrequency
     public int getHyphenationFrequency() {
@@ -4628,8 +4628,8 @@
      * @see #setJustificationMode(int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(name = "none", value = Layout.JUSTIFICATION_MODE_NONE),
-            @EnumMap(name = "inter_word", value = Layout.JUSTIFICATION_MODE_INTER_WORD)
+            @EnumEntry(name = "none", value = Layout.JUSTIFICATION_MODE_NONE),
+            @EnumEntry(name = "inter_word", value = Layout.JUSTIFICATION_MODE_INTER_WORD)
     })
     public @Layout.JustificationMode int getJustificationMode() {
         return mJustificationMode;
@@ -6667,142 +6667,142 @@
      * @see android.text.InputType
      */
     @InspectableProperty(flagMapping = {
-            @FlagMap(name = "none", mask = 0xffffffff, target = InputType.TYPE_NULL),
-            @FlagMap(
+            @FlagEntry(name = "none", mask = 0xffffffff, target = InputType.TYPE_NULL),
+            @FlagEntry(
                     name = "text",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL),
-            @FlagMap(
+            @FlagEntry(
                     name = "textUri",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI),
-            @FlagMap(
+            @FlagEntry(
                     name = "textEmailAddress",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS),
-            @FlagMap(
+            @FlagEntry(
                     name = "textEmailSubject",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT),
-            @FlagMap(
+            @FlagEntry(
                     name = "textShortMessage",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE),
-            @FlagMap(
+            @FlagEntry(
                     name = "textLongMessage",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE),
-            @FlagMap(
+            @FlagEntry(
                     name = "textPersonName",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_PERSON_NAME),
-            @FlagMap(
+            @FlagEntry(
                     name = "textPostalAddress",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS),
-            @FlagMap(
+            @FlagEntry(
                     name = "textPassword",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD),
-            @FlagMap(
+            @FlagEntry(
                     name = "textVisiblePassword",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD),
-            @FlagMap(
+            @FlagEntry(
                     name = "textWebEditText",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT),
-            @FlagMap(
+            @FlagEntry(
                     name = "textFilter",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_FILTER),
-            @FlagMap(
+            @FlagEntry(
                     name = "textPhonetic",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PHONETIC),
-            @FlagMap(
+            @FlagEntry(
                     name = "textWebEmailAddress",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS),
-            @FlagMap(
+            @FlagEntry(
                     name = "textWebPassword",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD),
-            @FlagMap(
+            @FlagEntry(
                     name = "number",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL),
-            @FlagMap(
+            @FlagEntry(
                     name = "numberPassword",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_NUMBER
                             | InputType.TYPE_NUMBER_VARIATION_PASSWORD),
-            @FlagMap(
+            @FlagEntry(
                     name = "phone",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_PHONE),
-            @FlagMap(
+            @FlagEntry(
                     name = "datetime",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_DATETIME
                             | InputType.TYPE_DATETIME_VARIATION_NORMAL),
-            @FlagMap(
+            @FlagEntry(
                     name = "date",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_DATETIME
                             | InputType.TYPE_DATETIME_VARIATION_DATE),
-            @FlagMap(
+            @FlagEntry(
                     name = "time",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_DATETIME
                             | InputType.TYPE_DATETIME_VARIATION_TIME),
-            @FlagMap(
+            @FlagEntry(
                     name = "textCapCharacters",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS),
-            @FlagMap(
+            @FlagEntry(
                     name = "textCapWords",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_WORDS),
-            @FlagMap(
+            @FlagEntry(
                     name = "textCapSentences",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES),
-            @FlagMap(
+            @FlagEntry(
                     name = "textAutoCorrect",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT),
-            @FlagMap(
+            @FlagEntry(
                     name = "textAutoComplete",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE),
-            @FlagMap(
+            @FlagEntry(
                     name = "textMultiLine",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE),
-            @FlagMap(
+            @FlagEntry(
                     name = "textImeMultiLine",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE),
-            @FlagMap(
+            @FlagEntry(
                     name = "textNoSuggestions",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS),
-            @FlagMap(
+            @FlagEntry(
                     name = "numberSigned",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED),
-            @FlagMap(
+            @FlagEntry(
                     name = "numberDecimal",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL),
@@ -6832,49 +6832,51 @@
      * @see EditorInfo
      */
     @InspectableProperty(flagMapping = {
-            @FlagMap(name = "normal", mask = 0xffffffff, target = EditorInfo.IME_NULL),
-            @FlagMap(
+            @FlagEntry(name = "normal", mask = 0xffffffff, target = EditorInfo.IME_NULL),
+            @FlagEntry(
                     name = "actionUnspecified",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_UNSPECIFIED),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionNone",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_NONE),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionGo",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_GO),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionSearch",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_SEARCH),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionSend",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_SEND),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionNext",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_NEXT),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionDone",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_DONE),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionPrevious",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_PREVIOUS),
-            @FlagMap(name = "flagForceAscii", target = EditorInfo.IME_FLAG_FORCE_ASCII),
-            @FlagMap(name = "flagNavigateNext", target = EditorInfo.IME_FLAG_NAVIGATE_NEXT),
-            @FlagMap(name = "flagNavigatePrevious", target = EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS),
-            @FlagMap(
+            @FlagEntry(name = "flagForceAscii", target = EditorInfo.IME_FLAG_FORCE_ASCII),
+            @FlagEntry(name = "flagNavigateNext", target = EditorInfo.IME_FLAG_NAVIGATE_NEXT),
+            @FlagEntry(
+                    name = "flagNavigatePrevious",
+                    target = EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS),
+            @FlagEntry(
                     name = "flagNoAccessoryAction",
                     target = EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION),
-            @FlagMap(name = "flagNoEnterAction", target = EditorInfo.IME_FLAG_NO_ENTER_ACTION),
-            @FlagMap(name = "flagNoExtractUi", target = EditorInfo.IME_FLAG_NO_EXTRACT_UI),
-            @FlagMap(name = "flagNoFullscreen", target = EditorInfo.IME_FLAG_NO_FULLSCREEN),
-            @FlagMap(
+            @FlagEntry(name = "flagNoEnterAction", target = EditorInfo.IME_FLAG_NO_ENTER_ACTION),
+            @FlagEntry(name = "flagNoExtractUi", target = EditorInfo.IME_FLAG_NO_EXTRACT_UI),
+            @FlagEntry(name = "flagNoFullscreen", target = EditorInfo.IME_FLAG_NO_FULLSCREEN),
+            @FlagEntry(
                     name = "flagNoPersonalizedLearning",
                     target = EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING),
     })
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index c7a2980..8a5d531 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -169,8 +169,8 @@
     @TimePickerMode
     @TestApi
     @InspectableProperty(name = "timePickerMode", enumMapping = {
-            @InspectableProperty.EnumMap(name = "clock", value = MODE_CLOCK),
-            @InspectableProperty.EnumMap(name = "spinner", value = MODE_SPINNER)
+            @InspectableProperty.EnumEntry(name = "clock", value = MODE_CLOCK),
+            @InspectableProperty.EnumEntry(name = "spinner", value = MODE_SPINNER)
     })
     public int getMode() {
         return mMode;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index f250666..faf0c7d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -680,7 +680,7 @@
                             & DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
                 }
             }
-        } catch (SecurityException e) {
+        } catch (SecurityException | NullPointerException e) {
             Log.w(TAG, "Error loading file preview", e);
         }
 
@@ -918,6 +918,8 @@
         if (isSendAction(in)) {
             in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
                     Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+
+            in.fixUris(getUserId());
         }
     }
 
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index eb881de..5c144d3 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -577,6 +577,12 @@
         protected boolean isFinal() {
             return false;
         }
+
+        protected boolean isRequestCompleted() {
+            synchronized (mLock) {
+                return mCompleted;
+            }
+        }
     }
 
     /**
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 7ad9223..f037407 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2305,4 +2305,8 @@
 
     // Open: Settings > Special App Access > Do not disturb control for app
     ZEN_ACCESS_DETAIL = 1692;
+
+    // OPEN: Settings > Face > Remove face
+    // OS: Q
+    DIALOG_FACE_REMOVE = 1693;
 }
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 8fce94e..9bf1825 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -318,6 +318,16 @@
     // Whether battery saver is enabled.
     optional bool enabled = 1;
 
+    enum StateEnum {
+        STATE_UNKNOWN = 0;
+        STATE_OFF = 1;
+        STATE_MANUAL_ON = 2;
+        STATE_AUTOMATIC_ON = 3;
+        STATE_OFF_AUTOMATIC_SNOOZED = 4;
+        STATE_PENDING_STICKY_ON = 5;
+    }
+    optional StateEnum state = 18;
+
     // Whether full battery saver is enabled.
     optional bool is_full_enabled = 14;
 
@@ -337,8 +347,7 @@
     // Whether battery status has been set at least once.
     optional bool battery_status_set = 4;
 
-    // Whether automatic battery saver has been canceled by the user.
-    optional bool battery_saver_snoozing = 5;
+    reserved 5; // battery_saver_snoozing
 
     // Whether the device is connected to any power source.
     optional bool is_powered = 6;
@@ -373,5 +382,5 @@
     // using elapsed realtime as the timebase.
     optional int64 last_adaptive_battery_saver_changed_externally_elapsed = 17;
 
-    // Next tag: 18
+    // Next tag: 19
 }
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index c08d7ca..4ef26dd5 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -66,6 +66,10 @@
     optional bool can_show_light = 8;
     optional string group_key = 9 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional sint32 importance = 10;
+    // The package the notification was posted for.
+    optional string package = 11;
+    // The package that posted the notification. It might not be the same as package.
+    optional string delegate_package = 12;
 }
 
 message ListenersDisablingEffectsProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c7417bf..efc6ad0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3929,6 +3929,10 @@
     <permission android:name="android.permission.MANAGE_ROLLBACKS"
         android:protectionLevel="signature|verifier" />
 
+    <!-- @SystemApi @TestApi @hide Allows testing apk level rollbacks. -->
+    <permission android:name="android.permission.TEST_MANAGE_ROLLBACKS"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi @hide Allows an application to mark other applications as harmful -->
     <permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS"
         android:protectionLevel="signature|verifier" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dbea13e..fe2c665 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -118,8 +118,11 @@
     <attr name="manageSpaceActivity" format="string" />
 
     <!-- Option to let applications specify that user data can/cannot be
-         cleared by the user in Settings. This flag is turned on by default.
-         <em>This attribute is usable only by applications
+         cleared. This flag is turned on by default.
+         <p>Starting from API level 29 this flag only controls if the user can
+         clear app data from Settings. To control clearing the data after a
+         failed restore use allowClearUserDataOnFailedRestore flag.
+         <p><em>This attribute is usable only by applications
          included in the system image. Third-party apps cannot use it.</em> -->
     <attr name="allowClearUserData" format="boolean" />
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2b13c4e..74970e8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1538,43 +1538,45 @@
     <string name="permdesc_useFaceAuthentication">Allows the app to use face authentication hardware for authentication</string>
 
     <!-- Message shown during face acquisition when the face cannot be recognized [CHAR LIMIT=50] -->
-    <string name="face_acquired_insufficient">Couldn\u2019t process face. Please try again.</string>
+    <string name="face_acquired_insufficient">Couldn\u2019t capture accurate face data. Try again.</string>
     <!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_bright">Face is too bright. Please try in lower light.</string>
+    <string name="face_acquired_too_bright">Too bright. Try gentler lighting.</string>
     <!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_dark">Face is too dark. Please uncover light source.</string>
+    <string name="face_acquired_too_dark">Too dark. Try brighter lighting.</string>
     <!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_close">Please move sensor farther from face.</string>
+    <string name="face_acquired_too_close">Move phone farther away.</string>
     <!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_far">Please bring sensor closer to face.</string>
+    <string name="face_acquired_too_far">Move phone closer.</string>
     <!-- Message shown during face acquisition when the user is too high relatively to sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_high">Please move sensor higher.</string>
+    <string name="face_acquired_too_high">Move phone higher.</string>
     <!-- Message shown during face acquisition when the user is too low relatively to sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_low">Please move sensor lower.</string>
+    <string name="face_acquired_too_low">Move phone lower.</string>
     <!-- Message shown during face acquisition when the user is too right relatively to sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_right">Please move sensor to the right.</string>
+    <string name="face_acquired_too_right">Move phone to the right.</string>
     <!-- Message shown during face acquisition when the user is too left relatively to sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_left">Please move sensor to the left.</string>
+    <string name="face_acquired_too_left">Move phone to the left.</string>
     <!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_poor_gaze">Please look at the sensor.</string>
+    <string name="face_acquired_poor_gaze">Look at the screen with your eyes open.</string>
     <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] -->
-    <string name="face_acquired_not_detected">No face detected.</string>
+    <string name="face_acquired_not_detected">Can\u2019t see your face. Look at the phone.</string>
     <!-- Message shown during face acquisition when the device is not steady [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_much_motion">Too much motion.</string>
+    <string name="face_acquired_too_much_motion">Too much motion. Hold phone steady.</string>
     <!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] -->
     <string name="face_acquired_recalibrate">Please re-enroll your face.</string>
     <!-- Message shown during face enrollment when a different person's face is detected [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_different">Different face detected.</string>
+    <string name="face_acquired_too_different">No longer able to recognize face. Try again.</string>
     <!-- Message shown during face enrollment when the face is too similar to a previous acquisition [CHAR LIMIT=50] -->
     <string name="face_acquired_too_similar">Too similar, please change your pose.</string>
     <!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] -->
-    <string name="face_acquired_pan_too_extreme">Please look more directly at the camera.</string>
+    <string name="face_acquired_pan_too_extreme">Please look more directly at the screen.</string>
     <!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] -->
-    <string name="face_acquired_tilt_too_extreme">Please look more directly at the camera.</string>
+    <string name="face_acquired_tilt_too_extreme">Please look more directly at the screen.</string>
     <!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] -->
     <string name="face_acquired_roll_too_extreme">Please straighten your head vertically.</string>
     <!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] -->
-    <string name="face_acquired_obscured">Please uncover your face.</string>
+    <string name="face_acquired_obscured">Clear the space between your head and the phone.</string>
+    <!-- Message shown during acquisition when the sensor is dirty [CHAR LIMIT=50] -->
+    <string name="face_acquired_sensor_dirty">Please clean the camera.</string>
     <!-- Array containing custom messages shown during face acquisition from vendor.  Vendor is expected to add and translate these strings -->
     <string-array name="face_acquired_vendor">
     </string-array>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e5fc104..17ccc31 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2546,6 +2546,7 @@
   <java-symbol type="string" name="face_acquired_tilt_too_extreme" />
   <java-symbol type="string" name="face_acquired_roll_too_extreme" />
   <java-symbol type="string" name="face_acquired_obscured" />
+  <java-symbol type="string" name="face_acquired_sensor_dirty" />
   <java-symbol type="array" name="face_acquired_vendor" />
   <java-symbol type="string" name="face_name_template" />
   <java-symbol type="string" name="face_authenticated_no_confirmation_required" />
diff --git a/docs/html/reference/images/text/style/linebackgroundspan.png b/docs/html/reference/images/text/style/linebackgroundspan.png
new file mode 100644
index 0000000..37d5253
--- /dev/null
+++ b/docs/html/reference/images/text/style/linebackgroundspan.png
Binary files differ
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 105af6e8..51c4252 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -16,7 +16,6 @@
 
 package android.security.keystore;
 
-import libcore.util.EmptyArray;
 import android.security.Credentials;
 import android.security.GateKeeper;
 import android.security.KeyStore;
@@ -31,6 +30,8 @@
 import android.security.keystore.WrappedKeyEntry;
 import android.util.Log;
 
+import libcore.util.EmptyArray;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -123,7 +124,14 @@
 
         final Certificate[] caList;
 
-        final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
+        // Suppress the key not found warning for this call. It seems that this error is exclusively
+        // being thrown when there is a self signed certificate chain, so when the keystore service
+        // attempts to query for the CA details, it obviously fails to find them and returns a
+        // key not found exception. This is WAI, and throwing a stack trace here can be very
+        // misleading since the trace is not clear.
+        final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias,
+                                             mUid,
+                                             true /* suppressKeyNotFoundWarning */);
         if (caBytes != null) {
             final Collection<X509Certificate> caChain = toCertificates(caBytes);
 
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index c512a6b..9a95fdf 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -292,8 +292,10 @@
 
     pAsset = new _FileAsset;
     result = pAsset->openChunk(dataMap);
-    if (result != NO_ERROR)
+    if (result != NO_ERROR) {
+        delete pAsset;
         return NULL;
+    }
 
     pAsset->mAccessMode = mode;
     return pAsset;
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index aeeb32c..8f7e814 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -18,6 +18,7 @@
 
 #include "hwui/Bitmap.h"
 #include "renderthread/EglManager.h"
+#include "renderthread/VulkanManager.h"
 #include "thread/ThreadBase.h"
 #include "utils/TimeUtils.h"
 
@@ -25,7 +26,9 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
+#include <GrContext.h>
 #include <SkCanvas.h>
+#include <SkImage.h>
 #include <utils/GLUtils.h>
 #include <utils/Trace.h>
 #include <utils/TraceUtils.h>
@@ -33,58 +36,247 @@
 
 namespace android::uirenderer {
 
-static std::mutex sLock{};
-static sp<ThreadBase> sUploadThread = nullptr;
-static renderthread::EglManager sEglManager;
-static int sPendingUploads = 0;
-static nsecs_t sLastUpload = 0;
+class AHBUploader;
+// This helper uploader classes allows us to upload using either EGL or Vulkan using the same
+// interface.
+static sp<AHBUploader> sUploader = nullptr;
 
-static bool shouldTimeOutLocked() {
-    nsecs_t durationSince = systemTime() - sLastUpload;
-    return durationSince > 2000_ms;
-}
+struct FormatInfo {
+    PixelFormat pixelFormat;
+    GLint format, type;
+    VkFormat vkFormat;
+    bool isSupported = false;
+    bool valid = true;
+};
 
-static void checkIdleTimeout() {
-    std::lock_guard _lock{sLock};
-    if (sPendingUploads == 0 && shouldTimeOutLocked()) {
-        sEglManager.destroy();
-    } else {
-        sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout);
-    }
-}
+class AHBUploader : public RefBase {
+public:
+    virtual ~AHBUploader() {}
 
-static void beginUpload() {
-    std::lock_guard _lock{sLock};
-    sPendingUploads++;
-
-    if (!sUploadThread) {
-        sUploadThread = new ThreadBase{};
+    // Called to start creation of the Vulkan and EGL contexts on another thread before we actually
+    // need to do an upload.
+    void initialize() {
+        onInitialize();
     }
 
-    if (!sUploadThread->isRunning()) {
-        sUploadThread->start("GrallocUploadThread");
+    void destroy() {
+        std::lock_guard _lock{mLock};
+        LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
+        if (mUploadThread) {
+            mUploadThread->requestExit();
+            mUploadThread->join();
+            mUploadThread = nullptr;
+        }
+        onDestroy();
     }
 
-    if (!sEglManager.hasEglContext()) {
-        sUploadThread->queue().runSync([]() {
-            sEglManager.initialize();
-            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+                              sp<GraphicBuffer> graphicBuffer) {
+        ATRACE_CALL();
+        beginUpload();
+        bool result = onUploadHardwareBitmap(bitmap, format, graphicBuffer);
+        endUpload();
+        return result;
+    }
+
+    void postIdleTimeoutCheck() {
+        mUploadThread->queue().postDelayed(5000_ms, [this](){ this->idleTimeoutCheck(); });
+    }
+
+protected:
+    std::mutex mLock;
+    sp<ThreadBase> mUploadThread = nullptr;
+
+private:
+    virtual void onInitialize() = 0;
+    virtual void onIdle() = 0;
+    virtual void onDestroy() = 0;
+
+    virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+                                        sp<GraphicBuffer> graphicBuffer) = 0;
+    virtual void onBeginUpload() = 0;
+
+    bool shouldTimeOutLocked() {
+        nsecs_t durationSince = systemTime() - mLastUpload;
+        return durationSince > 2000_ms;
+    }
+
+    void idleTimeoutCheck() {
+        std::lock_guard _lock{mLock};
+        if (mPendingUploads == 0 && shouldTimeOutLocked()) {
+            onIdle();
+        } else {
+            this->postIdleTimeoutCheck();
+        }
+    }
+
+    void beginUpload() {
+        std::lock_guard _lock{mLock};
+        mPendingUploads++;
+
+        if (!mUploadThread) {
+            mUploadThread = new ThreadBase{};
+        }
+        if (!mUploadThread->isRunning()) {
+            mUploadThread->start("GrallocUploadThread");
+        }
+
+        onBeginUpload();
+    }
+
+    void endUpload() {
+        std::lock_guard _lock{mLock};
+        mPendingUploads--;
+        mLastUpload = systemTime();
+    }
+
+    int mPendingUploads = 0;
+    nsecs_t mLastUpload = 0;
+};
+
+#define FENCE_TIMEOUT 2000000000
+
+class EGLUploader : public AHBUploader {
+private:
+    void onInitialize() override {}
+    void onDestroy() override {
+        mEglManager.destroy();
+    }
+    void onIdle() override {
+        mEglManager.destroy();
+    }
+
+    void onBeginUpload() override {
+        if (!mEglManager.hasEglContext()) {
+            mUploadThread->queue().runSync([this]() {
+                this->mEglManager.initialize();
+                glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+            });
+
+            this->postIdleTimeoutCheck();
+        }
+    }
+
+
+    EGLDisplay getUploadEglDisplay() {
+        std::lock_guard _lock{mLock};
+        LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?");
+        return mEglManager.eglDisplay();
+    }
+
+    bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+                                sp<GraphicBuffer> graphicBuffer) override {
+        ATRACE_CALL();
+
+        EGLDisplay display = getUploadEglDisplay();
+
+        LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+                            uirenderer::renderthread::EglManager::eglErrorString());
+        // We use an EGLImage to access the content of the GraphicBuffer
+        // The EGL image is later bound to a 2D texture
+        EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+        AutoEglImage autoImage(display, clientBuffer);
+        if (autoImage.image == EGL_NO_IMAGE_KHR) {
+            ALOGW("Could not create EGL image, err =%s",
+                  uirenderer::renderthread::EglManager::eglErrorString());
+            return false;
+        }
+
+        {
+            ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
+            EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
+                AutoSkiaGlTexture glTexture;
+                glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
+                GL_CHECKPOINT(MODERATE);
+
+                // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
+                // provide.
+                // But asynchronous in sense that driver may upload texture onto hardware buffer
+                // when we first use it in drawing
+                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
+                                format.format, format.type, bitmap.getPixels());
+                GL_CHECKPOINT(MODERATE);
+
+                EGLSyncKHR uploadFence =
+                        eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
+                LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR,
+                                    "Could not create sync fence %#x", eglGetError());
+                glFlush();
+                return uploadFence;
+            });
+
+            EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
+            LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
+                                "Failed to wait for the fence %#x", eglGetError());
+
+            eglDestroySyncKHR(display, fence);
+        }
+        return true;
+    }
+
+    renderthread::EglManager mEglManager;
+};
+
+class VkUploader : public AHBUploader {
+private:
+    void onInitialize() override {
+        std::lock_guard _lock{mLock};
+        if (!mUploadThread) {
+            mUploadThread = new ThreadBase{};
+        }
+        if (!mUploadThread->isRunning()) {
+            mUploadThread->start("GrallocUploadThread");
+        }
+
+        mUploadThread->queue().post([this]() {
+            std::lock_guard _lock{mVkLock};
+            if (!mVulkanManager.hasVkContext()) {
+                mVulkanManager.initialize();
+            }
         });
-        sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout);
     }
-}
+    void onDestroy() override {
+        mGrContext.reset();
+        mVulkanManager.destroy();
+    }
+    void onIdle() override {
+        mGrContext.reset();
+    }
 
-static void endUpload() {
-    std::lock_guard _lock{sLock};
-    sPendingUploads--;
-    sLastUpload = systemTime();
-}
+    void onBeginUpload() override {
+        {
+            std::lock_guard _lock{mVkLock};
+            if (!mVulkanManager.hasVkContext()) {
+                LOG_ALWAYS_FATAL_IF(mGrContext,
+                    "GrContext exists with no VulkanManager for vulkan uploads");
+                mUploadThread->queue().runSync([this]() {
+                    mVulkanManager.initialize();
+                });
+            }
+        }
+        if (!mGrContext) {
+            GrContextOptions options;
+            mGrContext = mVulkanManager.createContext(options);
+            LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
+            this->postIdleTimeoutCheck();
+        }
+    }
 
-static EGLDisplay getUploadEglDisplay() {
-    std::lock_guard _lock{sLock};
-    LOG_ALWAYS_FATAL_IF(!sEglManager.hasEglContext(), "Forgot to begin an upload?");
-    return sEglManager.eglDisplay();
-}
+    bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+                                sp<GraphicBuffer> graphicBuffer) override {
+        ATRACE_CALL();
+
+        std::lock_guard _lock{mLock};
+
+        sk_sp<SkImage> image = SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(),
+            bitmap.pixmap(), reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()));
+        return (image.get() != nullptr);
+    }
+
+    sk_sp<GrContext> mGrContext;
+    renderthread::VulkanManager mVulkanManager;
+    std::mutex mVkLock;
+};
 
 bool HardwareBitmapUploader::hasFP16Support() {
     static std::once_flag sOnce;
@@ -105,16 +297,7 @@
     return hasFP16Support;
 }
 
-#define FENCE_TIMEOUT 2000000000
-
-struct FormatInfo {
-    PixelFormat pixelFormat;
-    GLint format, type;
-    bool isSupported = false;
-    bool valid = true;
-};
-
-static FormatInfo determineFormat(const SkBitmap& skBitmap) {
+static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
     FormatInfo formatInfo;
     switch (skBitmap.info().colorType()) {
         case kRGBA_8888_SkColorType:
@@ -124,15 +307,18 @@
             formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
             formatInfo.format = GL_RGBA;
             formatInfo.type = GL_UNSIGNED_BYTE;
+            formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
             break;
         case kRGBA_F16_SkColorType:
             formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
             if (formatInfo.isSupported) {
                 formatInfo.type = GL_HALF_FLOAT;
                 formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16;
+                formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
             } else {
                 formatInfo.type = GL_UNSIGNED_BYTE;
                 formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
+                formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
             }
             formatInfo.format = GL_RGBA;
             break;
@@ -141,12 +327,14 @@
             formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565;
             formatInfo.format = GL_RGB;
             formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
+            formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
             break;
         case kGray_8_SkColorType:
-            formatInfo.isSupported = true;
+            formatInfo.isSupported = usingGL;
             formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
             formatInfo.format = GL_LUMINANCE;
             formatInfo.type = GL_UNSIGNED_BYTE;
+            formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
             break;
         default:
             ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
@@ -172,29 +360,37 @@
     }
 }
 
-class ScopedUploadRequest {
-public:
-    ScopedUploadRequest() { beginUpload(); }
-    ~ScopedUploadRequest() { endUpload(); }
-};
+
+static void createUploader(bool usingGL) {
+    static std::mutex lock;
+    std::lock_guard _lock{lock};
+    if (!sUploader.get()) {
+        if (usingGL) {
+            sUploader = new EGLUploader();
+        } else {
+            sUploader = new VkUploader();
+        }
+    }
+}
 
 sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) {
     ATRACE_CALL();
 
-    FormatInfo format = determineFormat(sourceBitmap);
+    bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
+            uirenderer::RenderPipelineType::SkiaGL;
+
+    FormatInfo format = determineFormat(sourceBitmap, usingGL);
     if (!format.valid) {
         return nullptr;
     }
 
-    ScopedUploadRequest _uploadRequest{};
-
     SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
     sp<GraphicBuffer> buffer = new GraphicBuffer(
             static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()),
             format.pixelFormat,
             GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
                     GraphicBuffer::USAGE_SW_READ_NEVER,
-            std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) +
+            std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) +
                     "]");
 
     status_t error = buffer->initCheck();
@@ -203,64 +399,24 @@
         return nullptr;
     }
 
-    EGLDisplay display = getUploadEglDisplay();
+    createUploader(usingGL);
 
-    LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
-                        uirenderer::renderthread::EglManager::eglErrorString());
-    // We use an EGLImage to access the content of the GraphicBuffer
-    // The EGL image is later bound to a 2D texture
-    EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();
-    AutoEglImage autoImage(display, clientBuffer);
-    if (autoImage.image == EGL_NO_IMAGE_KHR) {
-        ALOGW("Could not create EGL image, err =%s",
-              uirenderer::renderthread::EglManager::eglErrorString());
+    if (!sUploader->uploadHardwareBitmap(bitmap, format, buffer)) {
         return nullptr;
     }
-
-    {
-        ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
-        EGLSyncKHR fence = sUploadThread->queue().runSync([&]() -> EGLSyncKHR {
-            AutoSkiaGlTexture glTexture;
-            glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
-            GL_CHECKPOINT(MODERATE);
-
-            // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
-            // provide.
-            // But asynchronous in sense that driver may upload texture onto hardware buffer when we
-            // first
-            // use it in drawing
-            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format,
-                            format.type, bitmap.getPixels());
-            GL_CHECKPOINT(MODERATE);
-
-            EGLSyncKHR uploadFence =
-                    eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
-            LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x",
-                                eglGetError());
-            glFlush();
-            return uploadFence;
-        });
-
-        EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
-        LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
-                            "Failed to wait for the fence %#x", eglGetError());
-
-        eglDestroySyncKHR(display, fence);
-    }
-
-    return Bitmap::createFrom(buffer.get(), bitmap.colorType(), bitmap.refColorSpace(),
+    return Bitmap::createFrom(buffer, bitmap.colorType(), bitmap.refColorSpace(),
                               bitmap.alphaType(), Bitmap::computePalette(bitmap));
 }
 
+void HardwareBitmapUploader::initialize() {
+    bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
+            uirenderer::RenderPipelineType::SkiaGL;
+    createUploader(usingGL);
+    sUploader->initialize();
+}
+
 void HardwareBitmapUploader::terminate() {
-    std::lock_guard _lock{sLock};
-    LOG_ALWAYS_FATAL_IF(sPendingUploads, "terminate called while uploads in progress");
-    if (sUploadThread) {
-        sUploadThread->requestExit();
-        sUploadThread->join();
-        sUploadThread = nullptr;
-    }
-    sEglManager.destroy();
+    sUploader->destroy();
 }
 
 }  // namespace android::uirenderer
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 6f41e6d..c300593 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -22,9 +22,11 @@
 
 class ANDROID_API HardwareBitmapUploader {
 public:
-    static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+    static void initialize();
     static void terminate();
 
+    static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+
     static bool hasFP16Support();
 };
 
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index def805a..6cce319 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -29,6 +29,7 @@
 #include "utils/FatVector.h"
 #include "utils/TimeUtils.h"
 #include "utils/TraceUtils.h"
+#include "../HardwareBitmapUploader.h"
 
 #ifdef HWUI_GLES_WRAP_ENABLED
 #include "debug/GlesDriver.h"
@@ -415,6 +416,7 @@
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
         requireVkContext();
     }
+    HardwareBitmapUploader::initialize();
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 9298be6..5f43b48 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -41,6 +41,7 @@
 namespace android {
 
 class Bitmap;
+class AutoBackendTextureRelease;
 
 namespace uirenderer {
 
@@ -135,6 +136,7 @@
     friend class DispatchFrameCallbacks;
     friend class RenderProxy;
     friend class DummyVsyncSource;
+    friend class android::AutoBackendTextureRelease;
     friend class android::uirenderer::TestUtils;
     friend class android::uirenderer::WebViewFunctor;
     friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp
index 077a8f7..65d95ad 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.cpp
+++ b/libs/hwui/surfacetexture/ImageConsumer.cpp
@@ -24,13 +24,17 @@
 #include "renderthread/VulkanManager.h"
 #include "utils/Color.h"
 #include <GrAHardwareBufferUtils.h>
+#include <GrBackendSurface.h>
 
 // Macro for including the SurfaceTexture name in log messages
 #define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
 
+using namespace android::uirenderer::renderthread;
+
 namespace android {
 
 void ImageConsumer::onFreeBufferLocked(int slotIndex) {
+    // This callback may be invoked on any thread.
     mImageSlots[slotIndex].clear();
 }
 
@@ -46,55 +50,141 @@
     mImageSlots[buf].eglFence() = EGL_NO_SYNC_KHR;
 }
 
+/**
+ * AutoBackendTextureRelease manages EglImage/VkImage lifetime. It is a ref-counted object
+ * that keeps GPU resources alive until the last SKImage object using them is destroyed.
+ */
+class AutoBackendTextureRelease {
+public:
+    static void releaseProc(SkImage::ReleaseContext releaseContext);
+
+    AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer);
+
+    const GrBackendTexture& getTexture() const { return mBackendTexture; }
+
+    void ref() { mUsageCount++; }
+
+    void unref(bool releaseImage);
+
+    inline sk_sp<SkImage> getImage() { return mImage; }
+
+    void makeImage(sp<GraphicBuffer>& graphicBuffer, android_dataspace dataspace,
+                   GrContext* context);
+
+private:
+    // The only way to invoke dtor is with unref, when mUsageCount is 0.
+    ~AutoBackendTextureRelease() {}
+
+    GrBackendTexture mBackendTexture;
+    GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
+    GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
+
+    // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs
+    // are held by SkImages.
+    int mUsageCount = 1;
+
+    // mImage is the SkImage created from mBackendTexture.
+    sk_sp<SkImage> mImage;
+};
+
+AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer) {
+    bool createProtectedImage =
+        0 != (buffer->getUsage() & GraphicBuffer::USAGE_PROTECTED);
+    GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(
+        context,
+        reinterpret_cast<AHardwareBuffer*>(buffer),
+        buffer->getPixelFormat(),
+        false);
+    mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
+        context,
+        reinterpret_cast<AHardwareBuffer*>(buffer),
+        buffer->getWidth(),
+        buffer->getHeight(),
+        &mDeleteProc,
+        &mDeleteCtx,
+        createProtectedImage,
+        backendFormat,
+        false);
+}
+
+void AutoBackendTextureRelease::unref(bool releaseImage) {
+    if (!RenderThread::isCurrent()) {
+        // EGLImage needs to be destroyed on RenderThread to prevent memory leak.
+        // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not
+        // thread safe.
+        RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); });
+        return;
+    }
+
+    if (releaseImage) {
+        mImage.reset();
+    }
+
+    mUsageCount--;
+    if (mUsageCount <= 0) {
+        if (mBackendTexture.isValid()) {
+            mDeleteProc(mDeleteCtx);
+            mBackendTexture = {};
+        }
+        delete this;
+    }
+}
+
+void AutoBackendTextureRelease::releaseProc(SkImage::ReleaseContext releaseContext) {
+    AutoBackendTextureRelease* textureRelease =
+        reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
+    textureRelease->unref(false);
+}
+
+void AutoBackendTextureRelease::makeImage(sp<GraphicBuffer>& graphicBuffer,
+                                          android_dataspace dataspace, GrContext* context) {
+    SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(
+        graphicBuffer->getPixelFormat());
+    mImage = SkImage::MakeFromTexture(context,
+        mBackendTexture,
+        kTopLeft_GrSurfaceOrigin,
+        colorType,
+        kPremul_SkAlphaType,
+        uirenderer::DataSpaceToColorSpace(dataspace),
+        releaseProc,
+        this);
+    if (mImage.get()) {
+        // The following ref will be counteracted by releaseProc, when SkImage is discarded.
+        ref();
+    }
+}
+
 void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer,
                                               android_dataspace dataspace, bool forceCreate,
                                               GrContext* context) {
-    if (!mImage.get() || dataspace != mDataspace || forceCreate) {
+    if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace
+            || forceCreate) {
         if (!graphicBuffer.get()) {
             clear();
             return;
         }
 
-        if (!mBackendTexture.isValid()) {
-            clear();
-            bool createProtectedImage =
-                0 != (graphicBuffer->getUsage() & GraphicBuffer::USAGE_PROTECTED);
-            GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(
-                context,
-                reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
-                graphicBuffer->getPixelFormat(),
-                false);
-            mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
-                context,
-                reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
-                graphicBuffer->getWidth(),
-                graphicBuffer->getHeight(),
-                &mDeleteProc,
-                &mDeleteCtx,
-                createProtectedImage,
-                backendFormat,
-                false);
+        if (!mTextureRelease) {
+            mTextureRelease = new AutoBackendTextureRelease(context, graphicBuffer.get());
         }
+
         mDataspace = dataspace;
-        SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(
-            graphicBuffer->getPixelFormat());
-        mImage = SkImage::MakeFromTexture(context,
-            mBackendTexture,
-            kTopLeft_GrSurfaceOrigin,
-            colorType,
-            kPremul_SkAlphaType,
-            uirenderer::DataSpaceToColorSpace(dataspace));
+        mTextureRelease->makeImage(graphicBuffer, dataspace, context);
     }
 }
 
 void ImageConsumer::ImageSlot::clear() {
-    mImage.reset();
-    if (mBackendTexture.isValid()) {
-        mDeleteProc(mDeleteCtx);
-        mBackendTexture = {};
+    if (mTextureRelease) {
+        // The following unref counteracts the initial mUsageCount of 1, set by default initializer.
+        mTextureRelease->unref(true);
+        mTextureRelease = nullptr;
     }
 }
 
+sk_sp<SkImage> ImageConsumer::ImageSlot::getImage() {
+    return mTextureRelease ? mTextureRelease->getImage() : nullptr;
+}
+
 sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
                                            uirenderer::RenderState& renderState) {
     BufferItem item;
diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h
index eee0a0a..2fdece9 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.h
+++ b/libs/hwui/surfacetexture/ImageConsumer.h
@@ -25,7 +25,6 @@
 #include <cutils/compiler.h>
 #include <gui/BufferItem.h>
 #include <system/graphics.h>
-#include <GrBackendSurface.h>
 
 namespace GrAHardwareBufferUtils {
 typedef void* DeleteImageCtx;
@@ -38,6 +37,7 @@
 class RenderState;
 }
 
+class AutoBackendTextureRelease;
 class SurfaceTexture;
 
 /*
@@ -81,16 +81,14 @@
 
         void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace,
                             bool forceCreate, GrContext* context);
+
         void clear();
 
         inline EGLSyncKHR& eglFence() { return mEglFence; }
 
-        inline sk_sp<SkImage> getImage() { return mImage; }
+        sk_sp<SkImage> getImage();
 
     private:
-        // mImage is the SkImage created from mGraphicBuffer.
-        sk_sp<SkImage> mImage;
-
         // the dataspace associated with the current image
         android_dataspace mDataspace;
 
@@ -100,11 +98,11 @@
          */
         EGLSyncKHR mEglFence;
 
-        GrBackendTexture mBackendTexture;
-
-        GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
-
-        GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
+        /**
+         * mTextureRelease may outlive ImageConsumer, if the last ref is held by an SkImage.
+         * ImageConsumer holds one ref to mTextureRelease, which is decremented by "clear".
+         */
+        AutoBackendTextureRelease* mTextureRelease = nullptr;
     };
 
     /**
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 050b2ec..01f1798 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -167,9 +167,9 @@
 
     /**
      * Broadcast intent action when the set of enabled location providers changes. To check the
-     * status of a provider, use {@link #isProviderEnabled(String)}. Depending on API level, may
+     * status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will
      * include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider
-     * whose state has changed. See {@link #EXTRA_PROVIDER_NAME} for the supported API level.
+     * whose state has changed.
      *
      * @see #EXTRA_PROVIDER_NAME
      */
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index 5cd3621..fbe184b 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -3463,7 +3463,7 @@
              * @param uuid of selected crypto scheme
              * @return this
              */
-            public Builder setUuid(@NonNull UUID uuid) {
+            public @NonNull Builder setUuid(@NonNull UUID uuid) {
                 this.mUUID = uuid;
                 return this;
             }
@@ -3480,7 +3480,7 @@
              * @param keySetId identifier of a persisted offline key
              * @return this
              */
-            public Builder setKeySetId(@Nullable byte[] keySetId) {
+            public @NonNull Builder setKeySetId(@Nullable byte[] keySetId) {
                 this.mKeySetId = keySetId;
                 return this;
             }
@@ -3494,7 +3494,7 @@
              * @param initData container-specific DRM initialization data
              * @return this
              */
-            public Builder setInitData(@Nullable byte[] initData) {
+            public @NonNull Builder setInitData(@Nullable byte[] initData) {
                 this.mInitData = initData;
                 return this;
             }
@@ -3505,7 +3505,7 @@
              * @param mimeType mime type to the content
              * @return this
              */
-            public Builder setMimeType(@Nullable String mimeType) {
+            public @NonNull Builder setMimeType(@Nullable String mimeType) {
                 this.mMimeType = mimeType;
                 return this;
             }
@@ -3519,7 +3519,7 @@
              * @param keyType type of the key request
              * @return this
              */
-            public Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
+            public @NonNull Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
                 this.mKeyType = keyType;
                 return this;
             }
@@ -3531,7 +3531,8 @@
              * @param optionalParameters optional parameters to be included in a key request
              * @return this
              */
-            public Builder setOptionalParameters(@Nullable Map<String, String> optionalParameters) {
+            public @NonNull Builder setOptionalParameters(
+                    @Nullable Map<String, String> optionalParameters) {
                 this.mOptionalParameters = optionalParameters;
                 return this;
             }
@@ -3540,7 +3541,7 @@
              * @return an immutable {@link MediaPlayer2.DrmPreparationInfo} representing the
              *         settings of this builder
              */
-            public MediaPlayer2.DrmPreparationInfo build() {
+            public @NonNull MediaPlayer2.DrmPreparationInfo build() {
                 return new MediaPlayer2.DrmPreparationInfo(mUUID, mKeySetId, mInitData, mMimeType,
                         mKeyType, mOptionalParameters);
             }
@@ -3597,7 +3598,8 @@
          * @return a {@link DrmPreparationInfo} object to initialize DRM playback, or null to skip
          *         DRM initialization
          */
-        public DrmPreparationInfo onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) {
+        public @Nullable DrmPreparationInfo onDrmInfo(@NonNull MediaPlayer2 mp,
+                @NonNull DataSourceDesc dsd, @NonNull DrmInfo drmInfo) {
             return null;
         }
 
@@ -3630,11 +3632,13 @@
          * @param request a {@link MediaDrm.KeyRequest} prepared using the
          *        {@link DrmPreparationInfo} returned from
          *        {@link #onDrmInfo(MediaPlayer2, DataSourceDesc, DrmInfo)}
-         * @return the response to {@code request} (from license server)
+         * @return the response to {@code request} (from license server); returning {@code null} or
+         *         throwing an {@link RuntimeException} from this callback would trigger an
+         *         {@link EventCallback#onError}.
          */
-        public byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
-                @NonNull MediaDrm.KeyRequest request) {
-            return null;
+        public @NonNull byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp,
+                @NonNull DataSourceDesc dsd, @NonNull MediaDrm.KeyRequest request) {
+            return new byte[0];
         }
 
         /**
@@ -4144,7 +4148,7 @@
         /**
          * Returns the PSSH info of the data source for each supported DRM scheme.
          */
-        public Map<UUID, byte[]> getPssh() {
+        public @NonNull Map<UUID, byte[]> getPssh() {
             return mMapPssh;
         }
 
@@ -4153,7 +4157,7 @@
          * It effectively identifies the subset of the source's DRM schemes which
          * are supported by the device too.
          */
-        public List<UUID> getSupportedSchemes() {
+        public @NonNull List<UUID> getSupportedSchemes() {
             return Arrays.asList(mSupportedSchemes);
         }
 
@@ -4276,7 +4280,7 @@
      * Extends MediaDrm.MediaDrmException
      */
     public static final class NoDrmSchemeException extends MediaDrmException {
-        public NoDrmSchemeException(String detailMessage) {
+        public NoDrmSchemeException(@Nullable String detailMessage) {
             super(detailMessage);
         }
     }
diff --git a/media/apex/java/android/media/Session2Command.java b/media/apex/java/android/media/Session2Command.java
index 20d6391..6822ea5 100644
--- a/media/apex/java/android/media/Session2Command.java
+++ b/media/apex/java/android/media/Session2Command.java
@@ -32,6 +32,10 @@
  * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
  * {@link #getCustomCommand()} shouldn't be {@code null}.
  * <p>
+ * Refer to the
+ * <a href="{@docRoot}reference/androidx/media2/SessionCommand2.html">AndroidX SessionCommand</a>
+ * class for the list of valid commands.
+ * <p>
  * This API is not generally intended for third party application developers.
  * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
  * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 6a595d2..f9080a7 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1820,6 +1820,21 @@
             "android.media.action.MICROPHONE_MUTE_CHANGED";
 
     /**
+     * Broadcast Action: speakerphone state changed.
+     *
+     * You <em>cannot</em> receive this through components declared
+     * in manifests, only by explicitly registering for it with
+     * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
+     * Context.registerReceiver()}.
+     *
+     * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
+     * speakerphone functionality is enabled or not.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
+            "android.media.action.SPEAKERPHONE_STATE_CHANGED";
+
+    /**
      * Sets the audio mode.
      * <p>
      * The audio mode encompasses audio routing AND the behavior of
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index d724762..3838a999 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -37,6 +37,7 @@
 import java.net.UnknownServiceException;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 
 /** @hide */
 public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
@@ -46,27 +47,23 @@
     // connection timeout - 30 sec
     private static final int CONNECT_TIMEOUT_MS = 30 * 1000;
 
-    @UnsupportedAppUsage
-    private long mCurrentOffset = -1;
-    @UnsupportedAppUsage
-    private URL mURL = null;
-    @UnsupportedAppUsage
-    private Map<String, String> mHeaders = null;
-    @UnsupportedAppUsage
-    private HttpURLConnection mConnection = null;
-    @UnsupportedAppUsage
-    private long mTotalSize = -1;
-    private InputStream mInputStream = null;
-
-    @UnsupportedAppUsage
-    private boolean mAllowCrossDomainRedirect = true;
-    @UnsupportedAppUsage
-    private boolean mAllowCrossProtocolRedirect = true;
-
     // from com.squareup.okhttp.internal.http
     private final static int HTTP_TEMP_REDIRECT = 307;
     private final static int MAX_REDIRECTS = 20;
 
+    class ConnectionState {
+        public HttpURLConnection mConnection = null;
+        public InputStream mInputStream = null;
+        public long mCurrentOffset = -1;
+        public Map<String, String> mHeaders = null;
+        public URL mURL = null;
+        public long mTotalSize = -1;
+        public boolean mAllowCrossDomainRedirect = true;
+        public boolean mAllowCrossProtocolRedirect = true;
+    }
+    private final AtomicReference<ConnectionState> mConnectionStateHolder =
+            new AtomicReference<ConnectionState>();
+
     @UnsupportedAppUsage
     public MediaHTTPConnection() {
         CookieHandler cookieHandler = CookieHandler.getDefault();
@@ -84,13 +81,23 @@
             Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers);
         }
 
+        ConnectionState connectionState = mConnectionStateHolder.get();
+        synchronized (this) {
+            if (connectionState == null) {
+                connectionState = new ConnectionState();
+                mConnectionStateHolder.set(connectionState);
+            }
+        }
+
         try {
             disconnect();
-            mAllowCrossDomainRedirect = true;
-            mURL = new URL(uri);
-            mHeaders = convertHeaderStringToMap(headers);
+            connectionState.mAllowCrossDomainRedirect = true;
+            connectionState.mURL = new URL(uri);
+            connectionState.mHeaders = convertHeaderStringToMap(headers, connectionState);
         } catch (MalformedURLException e) {
             return null;
+        } finally {
+            mConnectionStateHolder.set(connectionState);
         }
 
         return native_getIMemory();
@@ -106,18 +113,21 @@
     }
 
     /* returns true iff header is internal */
-    private boolean filterOutInternalHeaders(String key, String val) {
+    private boolean filterOutInternalHeaders(
+            String key, String val, ConnectionState connectionState) {
         if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
-            mAllowCrossDomainRedirect = parseBoolean(val);
+            connectionState.mAllowCrossDomainRedirect = parseBoolean(val);
             // cross-protocol redirects are also controlled by this flag
-            mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect;
+            connectionState.mAllowCrossProtocolRedirect =
+                    connectionState.mAllowCrossDomainRedirect;
         } else {
             return false;
         }
         return true;
     }
 
-    private Map<String, String> convertHeaderStringToMap(String headers) {
+    private Map<String, String> convertHeaderStringToMap(String headers,
+            ConnectionState connectionState) {
         HashMap<String, String> map = new HashMap<String, String>();
 
         String[] pairs = headers.split("\r\n");
@@ -127,7 +137,7 @@
                 String key = pair.substring(0, colonPos);
                 String val = pair.substring(colonPos + 1);
 
-                if (!filterOutInternalHeaders(key, val)) {
+                if (!filterOutInternalHeaders(key, val, connectionState)) {
                     map.put(key, val);
                 }
             }
@@ -139,25 +149,28 @@
     @Override
     @UnsupportedAppUsage
     public void disconnect() {
-        teardownConnection();
-        mHeaders = null;
-        mURL = null;
+        ConnectionState connectionState = mConnectionStateHolder.getAndSet(null);
+        if (connectionState != null) {
+            teardownConnection(connectionState);
+            connectionState.mHeaders = null;
+            connectionState.mURL = null;
+        }
     }
 
-    private void teardownConnection() {
-        if (mConnection != null) {
-            if (mInputStream != null) {
+    private void teardownConnection(ConnectionState connectionState) {
+        if (connectionState.mConnection != null) {
+            if (connectionState.mInputStream != null) {
                 try {
-                    mInputStream.close();
+                    connectionState.mInputStream.close();
                 } catch (IOException e) {
                 }
-                mInputStream = null;
+                connectionState.mInputStream = null;
             }
 
-            mConnection.disconnect();
-            mConnection = null;
+            connectionState.mConnection.disconnect();
+            connectionState.mConnection = null;
 
-            mCurrentOffset = -1;
+            connectionState.mCurrentOffset = -1;
         }
     }
 
@@ -184,42 +197,44 @@
         return false;
     }
 
-    private void seekTo(long offset) throws IOException {
-        teardownConnection();
+    private void seekTo(long offset, ConnectionState connectionState) throws IOException {
+        teardownConnection(connectionState);
 
         try {
             int response;
             int redirectCount = 0;
 
-            URL url = mURL;
+            URL url = connectionState.mURL;
 
             // do not use any proxy for localhost (127.0.0.1)
             boolean noProxy = isLocalHost(url);
 
             while (true) {
                 if (noProxy) {
-                    mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
+                    connectionState.mConnection =
+                            (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
                 } else {
-                    mConnection = (HttpURLConnection)url.openConnection();
+                    connectionState.mConnection = (HttpURLConnection) url.openConnection();
                 }
-                mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
+                connectionState.mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
 
                 // handle redirects ourselves if we do not allow cross-domain redirect
-                mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect);
+                connectionState.mConnection.setInstanceFollowRedirects(
+                        connectionState.mAllowCrossDomainRedirect);
 
-                if (mHeaders != null) {
-                    for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
-                        mConnection.setRequestProperty(
+                if (connectionState.mHeaders != null) {
+                    for (Map.Entry<String, String> entry : connectionState.mHeaders.entrySet()) {
+                        connectionState.mConnection.setRequestProperty(
                                 entry.getKey(), entry.getValue());
                     }
                 }
 
                 if (offset > 0) {
-                    mConnection.setRequestProperty(
+                    connectionState.mConnection.setRequestProperty(
                             "Range", "bytes=" + offset + "-");
                 }
 
-                response = mConnection.getResponseCode();
+                response = connectionState.mConnection.getResponseCode();
                 if (response != HttpURLConnection.HTTP_MULT_CHOICE &&
                         response != HttpURLConnection.HTTP_MOVED_PERM &&
                         response != HttpURLConnection.HTTP_MOVED_TEMP &&
@@ -233,7 +248,7 @@
                     throw new NoRouteToHostException("Too many redirects: " + redirectCount);
                 }
 
-                String method = mConnection.getRequestMethod();
+                String method = connectionState.mConnection.getRequestMethod();
                 if (response == HTTP_TEMP_REDIRECT &&
                         !method.equals("GET") && !method.equals("HEAD")) {
                     // "If the 307 status code is received in response to a
@@ -241,34 +256,35 @@
                     // automatically redirect the request"
                     throw new NoRouteToHostException("Invalid redirect");
                 }
-                String location = mConnection.getHeaderField("Location");
+                String location = connectionState.mConnection.getHeaderField("Location");
                 if (location == null) {
                     throw new NoRouteToHostException("Invalid redirect");
                 }
-                url = new URL(mURL /* TRICKY: don't use url! */, location);
+                url = new URL(connectionState.mURL /* TRICKY: don't use url! */, location);
                 if (!url.getProtocol().equals("https") &&
                         !url.getProtocol().equals("http")) {
                     throw new NoRouteToHostException("Unsupported protocol redirect");
                 }
-                boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol());
-                if (!mAllowCrossProtocolRedirect && !sameProtocol) {
+                boolean sameProtocol =
+                        connectionState.mURL.getProtocol().equals(url.getProtocol());
+                if (!connectionState.mAllowCrossProtocolRedirect && !sameProtocol) {
                     throw new NoRouteToHostException("Cross-protocol redirects are disallowed");
                 }
-                boolean sameHost = mURL.getHost().equals(url.getHost());
-                if (!mAllowCrossDomainRedirect && !sameHost) {
+                boolean sameHost = connectionState.mURL.getHost().equals(url.getHost());
+                if (!connectionState.mAllowCrossDomainRedirect && !sameHost) {
                     throw new NoRouteToHostException("Cross-domain redirects are disallowed");
                 }
 
                 if (response != HTTP_TEMP_REDIRECT) {
                     // update effective URL, unless it is a Temporary Redirect
-                    mURL = url;
+                    connectionState.mURL = url;
                 }
             }
 
-            if (mAllowCrossDomainRedirect) {
+            if (connectionState.mAllowCrossDomainRedirect) {
                 // remember the current, potentially redirected URL if redirects
                 // were handled by HttpURLConnection
-                mURL = mConnection.getURL();
+                connectionState.mURL = connectionState.mConnection.getURL();
             }
 
             if (response == HttpURLConnection.HTTP_PARTIAL) {
@@ -276,10 +292,9 @@
                 // because what we want is not just the length of the range
                 // returned but the size of the full content if available.
 
-                String contentRange =
-                    mConnection.getHeaderField("Content-Range");
+                String contentRange = connectionState.mConnection.getHeaderField("Content-Range");
 
-                mTotalSize = -1;
+                connectionState.mTotalSize = -1;
                 if (contentRange != null) {
                     // format is "bytes xxx-yyy/zzz
                     // where "zzz" is the total number of bytes of the
@@ -291,7 +306,7 @@
                             contentRange.substring(lastSlashPos + 1);
 
                         try {
-                            mTotalSize = Long.parseLong(total);
+                            connectionState.mTotalSize = Long.parseLong(total);
                         } catch (NumberFormatException e) {
                         }
                     }
@@ -299,7 +314,7 @@
             } else if (response != HttpURLConnection.HTTP_OK) {
                 throw new IOException();
             } else {
-                mTotalSize = mConnection.getContentLength();
+                connectionState.mTotalSize = connectionState.mConnection.getContentLength();
             }
 
             if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) {
@@ -308,14 +323,14 @@
                 throw new ProtocolException();
             }
 
-            mInputStream =
-                new BufferedInputStream(mConnection.getInputStream());
+            connectionState.mInputStream =
+                new BufferedInputStream(connectionState.mConnection.getInputStream());
 
-            mCurrentOffset = offset;
+            connectionState.mCurrentOffset = offset;
         } catch (IOException e) {
-            mTotalSize = -1;
-            teardownConnection();
-            mCurrentOffset = -1;
+            connectionState.mTotalSize = -1;
+            teardownConnection(connectionState);
+            connectionState.mCurrentOffset = -1;
 
             throw e;
         }
@@ -324,10 +339,14 @@
     @Override
     @UnsupportedAppUsage
     public int readAt(long offset, int size) {
-        return native_readAt(offset, size);
+        ConnectionState connectionState = mConnectionStateHolder.get();
+        if (connectionState != null) {
+            return native_readAt(offset, size, connectionState);
+        }
+        return -1;
     }
 
-    private int readAt(long offset, byte[] data, int size) {
+    private int readAt(long offset, byte[] data, int size, ConnectionState connectionState) {
         StrictMode.ThreadPolicy policy =
             new StrictMode.ThreadPolicy.Builder().permitAll().build();
 
@@ -335,12 +354,12 @@
 
         try {
             synchronized(this) {
-                if (offset != mCurrentOffset) {
-                    seekTo(offset);
+                if (offset != connectionState.mCurrentOffset) {
+                    seekTo(offset, connectionState);
                 }
             }
 
-            int n = mInputStream.read(data, 0, size);
+            int n = connectionState.mInputStream.read(data, 0, size);
 
             if (n == -1) {
                 // InputStream signals EOS using a -1 result, our semantics
@@ -348,7 +367,7 @@
                 n = 0;
             }
 
-            mCurrentOffset += n;
+            connectionState.mCurrentOffset += n;
 
             if (VERBOSE) {
                 Log.d(TAG, "readAt " + offset + " / " + size + " => " + n);
@@ -380,35 +399,47 @@
 
     @Override
     public synchronized long getSize() {
-        if (mConnection == null) {
-            try {
-                seekTo(0);
-            } catch (IOException e) {
-                return -1;
+        ConnectionState connectionState = mConnectionStateHolder.get();
+        if (connectionState != null) {
+            if (connectionState.mConnection == null) {
+                try {
+                    seekTo(0, connectionState);
+                } catch (IOException e) {
+                    return -1;
+                }
             }
+            return connectionState.mTotalSize;
         }
 
-        return mTotalSize;
+        return -1;
     }
 
     @Override
     @UnsupportedAppUsage
     public synchronized String getMIMEType() {
-        if (mConnection == null) {
-            try {
-                seekTo(0);
-            } catch (IOException e) {
-                return "application/octet-stream";
+        ConnectionState connectionState = mConnectionStateHolder.get();
+        if (connectionState != null) {
+            if (connectionState.mConnection == null) {
+                try {
+                    seekTo(0, connectionState);
+                } catch (IOException e) {
+                    return "application/octet-stream";
+                }
             }
+            return connectionState.mConnection.getContentType();
         }
 
-        return mConnection.getContentType();
+        return null;
     }
 
     @Override
     @UnsupportedAppUsage
     public String getUri() {
-        return mURL.toString();
+        ConnectionState connectionState = mConnectionStateHolder.get();
+        if (connectionState != null) {
+            return connectionState.mURL.toString();
+        }
+        return null;
     }
 
     @Override
@@ -421,7 +452,7 @@
     private native final void native_finalize();
 
     private native final IBinder native_getIMemory();
-    private native final int native_readAt(long offset, int size);
+    private native int native_readAt(long offset, int size, ConnectionState connectionState);
 
     static {
         System.loadLibrary("media_jni");
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index cfcc294..02348476 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -22,10 +22,10 @@
 import android.media.session.ICallback;
 import android.media.session.IOnMediaKeyListener;
 import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession;
 import android.media.session.ISession2TokensListener;
 import android.media.session.MediaSession;
 import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
 import android.os.Bundle;
 import android.view.KeyEvent;
 
@@ -34,7 +34,7 @@
  * @hide
  */
 interface ISessionManager {
-    SessionLink createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
+    ISession createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
             in Bundle sessionInfo, int userId);
     void notifySession2Created(in Session2Token sessionToken);
     List<MediaSession.Token> getSessions(in ComponentName compName, int userId);
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 4fc436c..cbc6c9d 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -36,6 +36,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
@@ -163,11 +164,11 @@
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         try {
             SessionCallbackLink cbLink = new SessionCallbackLink(context);
-            SessionLink sessionLink = manager.createSession(cbLink, tag, sessionInfo);
-            mImpl = new MediaSessionEngine(context, sessionLink, cbLink);
+            ISession binder = manager.createSession(cbLink, tag, sessionInfo);
+            mImpl = new MediaSessionEngine(context, binder, cbLink);
             mMaxBitmapSize = context.getResources().getDimensionPixelSize(
                     com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
-        } catch (RuntimeException e) {
+        } catch (RemoteException e) {
             throw new RuntimeException("Remote error creating session.", e);
         }
     }
diff --git a/media/java/android/media/session/MediaSessionEngine.java b/media/java/android/media/session/MediaSessionEngine.java
index 266bf32..7c5243a 100644
--- a/media/java/android/media/session/MediaSessionEngine.java
+++ b/media/java/android/media/session/MediaSessionEngine.java
@@ -25,6 +25,7 @@
 import android.media.AudioAttributes;
 import android.media.MediaDescription;
 import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
 import android.media.Rating;
 import android.media.VolumeProvider;
 import android.media.session.MediaSessionManager.RemoteUserInfo;
@@ -34,6 +35,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
@@ -55,7 +57,7 @@
 
     private final MediaSession.Token mSessionToken;
     private final MediaController mController;
-    private final SessionLink mSessionLink;
+    private final ISession mBinder;
 
     private CallbackMessageHandler mCallbackHandler;
     private VolumeProvider mVolumeProvider;
@@ -70,14 +72,14 @@
      * finished with the session.
      *
      * @param context The context to use to create the session.
-     * @param sessionLink A session link for the binder of MediaSessionRecord
+     * @param binder A session binder
      */
-    public MediaSessionEngine(@NonNull Context context, @NonNull SessionLink sessionLink,
-            @NonNull SessionCallbackLink cbLink) {
-        mSessionLink = sessionLink;
+    public MediaSessionEngine(@NonNull Context context, @NonNull ISession binder,
+            @NonNull SessionCallbackLink cbLink) throws RemoteException {
+        mBinder = binder;
 
         cbLink.setSessionEngine(this);
-        mSessionToken = new MediaSession.Token(mSessionLink.getController());
+        mSessionToken = new MediaSession.Token(mBinder.getController());
         mController = new MediaController(context, mSessionToken);
     }
 
@@ -134,8 +136,8 @@
      */
     public void setSessionActivity(@Nullable PendingIntent pi) {
         try {
-            mSessionLink.setLaunchPendingIntent(pi);
-        } catch (RuntimeException e) {
+            mBinder.setLaunchPendingIntent(pi);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
         }
     }
@@ -150,8 +152,8 @@
      */
     public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
         try {
-            mSessionLink.setMediaButtonReceiver(mbr);
-        } catch (RuntimeException e) {
+            mBinder.setMediaButtonReceiver(mbr);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
         }
     }
@@ -163,8 +165,8 @@
      */
     public void setFlags(int flags) {
         try {
-            mSessionLink.setFlags(flags);
-        } catch (RuntimeException e) {
+            mBinder.setFlags(flags);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setFlags.", e);
         }
     }
@@ -185,8 +187,8 @@
             throw new IllegalArgumentException("Attributes cannot be null for local playback.");
         }
         try {
-            mSessionLink.setPlaybackToLocal(attributes);
-        } catch (RuntimeException e) {
+            mBinder.setPlaybackToLocal(attributes);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
         }
     }
@@ -217,10 +219,10 @@
         });
 
         try {
-            mSessionLink.setPlaybackToRemote(volumeProvider.getVolumeControl(),
+            mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
                     volumeProvider.getMaxVolume());
-            mSessionLink.setCurrentVolume(volumeProvider.getCurrentVolume());
-        } catch (RuntimeException e) {
+            mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
         }
     }
@@ -238,9 +240,9 @@
             return;
         }
         try {
-            mSessionLink.setActive(active);
+            mBinder.setActive(active);
             mActive = active;
-        } catch (RuntimeException e) {
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setActive.", e);
         }
     }
@@ -267,8 +269,8 @@
             throw new IllegalArgumentException("event cannot be null or empty");
         }
         try {
-            mSessionLink.sendEvent(event, extras);
-        } catch (RuntimeException e) {
+            mBinder.sendEvent(event, extras);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Error sending event", e);
         }
     }
@@ -280,8 +282,8 @@
      */
     public void close() {
         try {
-            mSessionLink.destroySession();
-        } catch (RuntimeException e) {
+            mBinder.destroySession();
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Error releasing session: ", e);
         }
     }
@@ -316,8 +318,8 @@
     public void setPlaybackState(@Nullable PlaybackState state) {
         mPlaybackState = state;
         try {
-            mSessionLink.setPlaybackState(state);
-        } catch (RuntimeException e) {
+            mBinder.setPlaybackState(state);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Dead object in setPlaybackState.", e);
         }
     }
@@ -344,8 +346,8 @@
         String metadataDescription = "size=" + fields + ", description=" + description;
 
         try {
-            mSessionLink.setMetadata(metadata, duration, metadataDescription);
-        } catch (RuntimeException e) {
+            mBinder.setMetadata(metadata, duration, metadataDescription);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Dead object in setPlaybackState.", e);
         }
     }
@@ -363,8 +365,8 @@
      */
     public void setQueue(@Nullable List<MediaSession.QueueItem> queue) {
         try {
-            mSessionLink.setQueue(queue);
-        } catch (RuntimeException e) {
+            mBinder.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
+        } catch (RemoteException e) {
             Log.wtf("Dead object in setQueue.", e);
         }
     }
@@ -378,8 +380,8 @@
      */
     public void setQueueTitle(@Nullable CharSequence title) {
         try {
-            mSessionLink.setQueueTitle(title);
-        } catch (RuntimeException e) {
+            mBinder.setQueueTitle(title);
+        } catch (RemoteException e) {
             Log.wtf("Dead object in setQueueTitle.", e);
         }
     }
@@ -399,8 +401,8 @@
      */
     public void setRatingType(int type) {
         try {
-            mSessionLink.setRatingType(type);
-        } catch (RuntimeException e) {
+            mBinder.setRatingType(type);
+        } catch (RemoteException e) {
             Log.e(TAG, "Error in setRatingType.", e);
         }
     }
@@ -414,8 +416,8 @@
      */
     public void setExtras(@Nullable Bundle extras) {
         try {
-            mSessionLink.setExtras(extras);
-        } catch (RuntimeException e) {
+            mBinder.setExtras(extras);
+        } catch (RemoteException e) {
             Log.wtf("Dead object in setExtras.", e);
         }
     }
@@ -464,8 +466,8 @@
             }
         }
         try {
-            mSessionLink.setCurrentVolume(provider.getCurrentVolume());
-        } catch (RuntimeException e) {
+            mBinder.setCurrentVolume(provider.getCurrentVolume());
+        } catch (RemoteException e) {
             Log.e(TAG, "Error in notifyVolumeChanged", e);
         }
     }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index f530442..7ca5c93 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -107,7 +107,7 @@
      * @hide
      */
     @NonNull
-    public SessionLink createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag,
+    public ISession createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag,
             @Nullable Bundle sessionInfo) {
         try {
             return mService.createSession(mContext.getPackageName(), cbStub, tag, sessionInfo,
diff --git a/media/java/android/media/session/SessionLink.java b/media/java/android/media/session/SessionLink.java
deleted file mode 100644
index a47c262..0000000
--- a/media/java/android/media/session/SessionLink.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * 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.
- */
-
-package android.media.session;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.media.AudioAttributes;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.session.MediaSession.QueueItem;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-
-import java.util.List;
-
-/**
- * Handles incoming commands from {@link MediaSession}.
- * @hide
- */
-public final class SessionLink implements Parcelable {
-    public static final @android.annotation.NonNull Parcelable.Creator<SessionLink> CREATOR =
-            new Parcelable.Creator<SessionLink>() {
-                @Override
-                public SessionLink createFromParcel(Parcel in) {
-                    return new SessionLink(in.readStrongBinder());
-                }
-
-                @Override
-                public SessionLink[] newArray(int size) {
-                    return new SessionLink[size];
-                }
-            };
-
-    final SessionStub mSessionStub;
-    final ISession mISession;
-
-    /**
-     * Constructor for stub (Callee)
-     */
-    public SessionLink(@NonNull SessionStub sessionStub) {
-        mSessionStub = sessionStub;
-        mISession = new StubProxy();
-    }
-
-    /**
-     * Constructor for interface (Caller)
-     */
-    public SessionLink(IBinder binder) {
-        mSessionStub = null;
-        mISession = ISession.Stub.asInterface(binder);
-    }
-
-    /**
-     * Tell system that the session sends an event to all the connected controllers.
-     *
-     * @param event the name of the event
-     * @param extras the extras included with the event
-     */
-    void sendEvent(@NonNull String event, @Nullable Bundle extras) {
-        try {
-            mISession.sendEvent(event, extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Gets the controller binder from the system.
-     */
-    @NonNull
-    ISessionController getController() {
-        try {
-            return mISession.getController();
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the flags.
-     *
-     * @param flags the new session flags
-     */
-    void setFlags(int flags) {
-        try {
-            mISession.setFlags(flags);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session is (in)active.
-     *
-     * @param active the new activeness state
-     */
-    void setActive(boolean active) {
-        try {
-            mISession.setActive(active);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the media button receiver.
-     *
-     * @param mbr the pending intent for media button receiver
-     */
-    void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
-        try {
-            mISession.setMediaButtonReceiver(mbr);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the pending intent for launching UI.
-     *
-     * @param pi the pending intent for launching UI
-     */
-    void setLaunchPendingIntent(@Nullable PendingIntent pi) {
-        try {
-            mISession.setLaunchPendingIntent(pi);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session is destroyed.
-     */
-    void destroySession() {
-        try {
-            mISession.destroySession();
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new metadata.
-     *
-     * @param metadata the new metadata
-     * @param duration the duration of the media in milliseconds
-     * @param metadataDescription the description of the metadata
-     */
-    void setMetadata(@Nullable MediaMetadata metadata, long duration,
-            @Nullable String metadataDescription) {
-        try {
-            mISession.setMetadata(metadata, duration, metadataDescription);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new playback state.
-     *
-     * @param state the new playback state
-     */
-    void setPlaybackState(@Nullable PlaybackState state) {
-        try {
-            mISession.setPlaybackState(state);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new queue.
-     *
-     * @param queue the new queue
-     */
-    void setQueue(@Nullable List<QueueItem> queue) {
-        try {
-            mISession.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new queue title.
-     *
-     * @param title the new queue title
-     */
-    void setQueueTitle(@Nullable CharSequence title) {
-        try {
-            mISession.setQueueTitle(title);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new extras.
-     *
-     * @param extras the new extras
-     */
-    void setExtras(@Nullable Bundle extras) {
-        try {
-            mISession.setExtras(extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new rating type of the current media.
-     *
-     * @param type the rating type.
-     */
-    void setRatingType(int type) {
-        try {
-            mISession.setRatingType(type);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session represents a local playback.
-     *
-     * @param attributes the audio attributes of the local playback.
-     */
-    void setPlaybackToLocal(@NonNull AudioAttributes attributes) {
-        try {
-            mISession.setPlaybackToLocal(attributes);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session represents a remote playback.
-     *
-     * @param control the volume control type
-     * @param max the max volume
-     */
-    void setPlaybackToRemote(int control, int max) {
-        try {
-            mISession.setPlaybackToRemote(control, max);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new current volume.
-     *
-     * @param currentVolume the new current volume
-     */
-    void setCurrentVolume(int currentVolume) {
-        try {
-            mISession.setCurrentVolume(currentVolume);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Gets the binder */
-    @NonNull
-    public IBinder getBinder() {
-        return mISession.asBinder();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mISession.asBinder());
-    }
-
-    /**
-     * Class for Stub implementation
-     */
-    public abstract static class SessionStub {
-        /** Stub method for ISession.sendEvent */
-        public void sendEvent(@NonNull String event, @Nullable Bundle data) {
-        }
-
-        /** Stub method for ISession.getController */
-        @NonNull
-        public ISessionController getController() {
-            return null;
-        }
-
-        /** Stub method for ISession.setFlags */
-        public void setFlags(int flags) {
-        }
-
-        /** Stub method for ISession.setActive */
-        public void setActive(boolean active) {
-        }
-
-        /** Stub method for ISession.setMediaButtonReceiver */
-        public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
-        }
-
-        /** Stub method for ISession.setLaunchPendingIntent */
-        public void setLaunchPendingIntent(@Nullable PendingIntent pi) {
-        }
-
-        /** Stub method for ISession.destroySession */
-        public void destroySession() {
-        }
-
-        /** Stub method for ISession.setMetadata */
-        public void setMetadata(@Nullable MediaMetadata metadata, long duration,
-                @Nullable String metadataDescription) {
-        }
-
-        /** Stub method for ISession.setPlaybackState */
-        public void setPlaybackState(@Nullable PlaybackState state) {
-        }
-
-        /** Stub method for ISession.setQueue */
-        public void setQueue(@Nullable List<QueueItem> queue) {
-        }
-
-        /** Stub method for ISession.setQueueTitle */
-        public void setQueueTitle(@Nullable CharSequence title) {
-        }
-
-        /** Stub method for ISession.setExtras */
-        public void setExtras(@Nullable Bundle extras) {
-        }
-
-        /** Stub method for ISession.setRatingType */
-        public void setRatingType(int type) {
-        }
-
-        /** Stub method for ISession.setPlaybackToLocal */
-        public void setPlaybackToLocal(@NonNull AudioAttributes attributes) {
-        }
-
-        /** Stub method for ISession.setPlaybackToRemote */
-        public void setPlaybackToRemote(int control, int max) {
-        }
-
-        /** Stub method for ISession.setCurrentVolume */
-        public void setCurrentVolume(int currentVolume) {
-        }
-    }
-
-    private class StubProxy extends ISession.Stub {
-        @Override
-        public void sendEvent(String event, Bundle data) {
-            mSessionStub.sendEvent(event, data);
-        }
-
-        @Override
-        public ISessionController getController() {
-            return mSessionStub.getController();
-        }
-
-        @Override
-        public void setFlags(int flags) {
-            mSessionStub.setFlags(flags);
-        }
-
-        @Override
-        public void setActive(boolean active) {
-            mSessionStub.setActive(active);
-        }
-
-        @Override
-        public void setMediaButtonReceiver(PendingIntent mbr) {
-            mSessionStub.setMediaButtonReceiver(mbr);
-        }
-
-        @Override
-        public void setLaunchPendingIntent(PendingIntent pi) {
-            mSessionStub.setLaunchPendingIntent(pi);
-        }
-
-        @Override
-        public void destroySession() {
-            mSessionStub.destroySession();
-        }
-
-        @Override
-        public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) {
-            mSessionStub.setMetadata(metadata, duration, metadataDescription);
-        }
-
-        @Override
-        public void setPlaybackState(PlaybackState state) {
-            mSessionStub.setPlaybackState(state);
-        }
-
-        @Override
-        public void setQueue(MediaParceledListSlice queue) {
-            mSessionStub.setQueue(queue == null ? null : queue.getList());
-        }
-
-        @Override
-        public void setQueueTitle(CharSequence title) {
-            mSessionStub.setQueueTitle(title);
-        }
-
-        @Override
-        public void setExtras(Bundle extras) {
-            mSessionStub.setExtras(extras);
-        }
-
-        @Override
-        public void setRatingType(int type) {
-            mSessionStub.setRatingType(type);
-        }
-
-        @Override
-        public void setPlaybackToLocal(AudioAttributes attributes) {
-            mSessionStub.setPlaybackToLocal(attributes);
-        }
-
-        @Override
-        public void setPlaybackToRemote(int control, int max) {
-            mSessionStub.setPlaybackToRemote(control, max);
-        }
-
-        @Override
-        public void setCurrentVolume(int currentVolume) {
-            mSessionStub.setCurrentVolume(currentVolume);
-        }
-    }
-}
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
index 365e045..d28c15c 100644
--- a/media/jni/android_media_MediaHTTPConnection.cpp
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -109,7 +109,8 @@
     gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
     CHECK(gFields.context != NULL);
 
-    gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I");
+    gFields.readAtMethodID = env->GetMethodID(
+            clazz.get(), "readAt", "(J[BILandroid/media/MediaHTTPConnection$ConnectionState;)I");
 }
 
 static void android_media_MediaHTTPConnection_native_setup(
@@ -132,7 +133,7 @@
 }
 
 static jint android_media_MediaHTTPConnection_native_readAt(
-        JNIEnv *env, jobject thiz, jlong offset, jint size) {
+        JNIEnv *env, jobject thiz, jlong offset, jint size, jobject connectionState) {
     sp<JMediaHTTPConnection> conn = getObject(env, thiz);
     if (size > JMediaHTTPConnection::kBufferSize) {
         size = JMediaHTTPConnection::kBufferSize;
@@ -141,7 +142,7 @@
     jbyteArray byteArrayObj = conn->getByteArrayObj();
 
     jint n = env->CallIntMethod(
-            thiz, gFields.readAtMethodID, offset, byteArrayObj, size);
+            thiz, gFields.readAtMethodID, offset, byteArrayObj, size, connectionState);
 
     if (n > 0) {
         env->GetByteArrayRegion(
@@ -158,7 +159,7 @@
     { "native_getIMemory", "()Landroid/os/IBinder;",
       (void *)android_media_MediaHTTPConnection_native_getIMemory },
 
-    { "native_readAt", "(JI)I",
+    { "native_readAt", "(JILandroid/media/MediaHTTPConnection$ConnectionState;)I",
       (void *)android_media_MediaHTTPConnection_native_readAt },
 
     { "native_init", "()V",
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index a288d010..bda5743 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -52,6 +52,7 @@
 import android.webkit.CookieManager;
 import android.webkit.SslErrorHandler;
 import android.webkit.WebChromeClient;
+import android.webkit.WebResourceRequest;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
@@ -409,8 +410,7 @@
                     TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
                     getResources().getDisplayMetrics());
         private int mPagesLoaded;
-        // the host of the page that this webview is currently loading. Can be null when undefined.
-        private String mHostname;
+        private String mMainFrameUrl;
 
         // If we haven't finished cleaning up the history, don't allow going back.
         public boolean allowBack() {
@@ -436,7 +436,6 @@
             }
             final URL url = makeURL(urlString);
             Log.d(TAG, "onPageStarted: " + sanitizeURL(url));
-            mHostname = host(url);
             // For internally generated pages, leave URL bar listing prior URL as this is the URL
             // the page refers to.
             if (!urlString.startsWith(INTERNAL_ASSETS)) {
@@ -480,17 +479,28 @@
             return Integer.toString((int)dp) + "px";
         }
 
+        // Check if webview is trying to load the main frame and record its url.
+        @Override
+        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+            if (request.isForMainFrame()) {
+                mMainFrameUrl = request.getUrl().toString();
+            }
+            return false;
+        }
+
         // A web page consisting of a large broken lock icon to indicate SSL failure.
 
         @Override
         public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
-            final URL url = makeURL(error.getUrl());
-            final String host = host(url);
+            final URL errorUrl = makeURL(error.getUrl());
+            final URL mainFrameUrl = makeURL(mMainFrameUrl);
             Log.d(TAG, String.format("SSL error: %s, url: %s, certificate: %s",
-                    sslErrorName(error), sanitizeURL(url), error.getCertificate()));
-            if (url == null || !Objects.equals(host, mHostname)) {
-                // Ignore ssl errors for resources coming from a different hostname than the page
-                // that we are currently loading, and only cancel the request.
+                    sslErrorName(error), sanitizeURL(errorUrl), error.getCertificate()));
+            if (errorUrl == null
+                    // Ignore SSL errors from resources by comparing the main frame url with SSL
+                    // error url.
+                    || !errorUrl.equals(mainFrameUrl)) {
+                Log.d(TAG, "onReceivedSslError: mMainFrameUrl = " + mMainFrameUrl);
                 handler.cancel();
                 return;
             }
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 9064ebe..4c9629d 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -58,8 +58,8 @@
 
     manifest: "AndroidManifest.xml",
 
-    owner: "google",
     platform_apis: true,
+    product_specific: true,
     certificate: "platform",
     privileged: true,
 
@@ -82,4 +82,6 @@
     ],
 
     plugins: ["dagger2-compiler-2.19"],
+
+    required: ["privapp_whitelist_com.android.systemui"],
 }
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 190247a..8872147 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -25,6 +25,7 @@
         ":services-networkstack-shared-srcs",
     ],
     static_libs: [
+        "ipmemorystore-client",
         "netd_aidl_interface-java",
         "networkstack-aidl-interfaces-java",
         "datastallprotosnano",
diff --git a/packages/NetworkStack/jarjar-rules-shared.txt b/packages/NetworkStack/jarjar-rules-shared.txt
index a8c712a..7346b1a 100644
--- a/packages/NetworkStack/jarjar-rules-shared.txt
+++ b/packages/NetworkStack/jarjar-rules-shared.txt
@@ -8,12 +8,3 @@
 rule android.net.DhcpResultsParcelable* @0
 rule android.net.DhcpResults* android.net.networkstack.DhcpResults@1
 rule android.net.LocalLog* android.net.networkstack.LocalLog@1
-
-# TODO: remove from framework dependencies, then remove here
-rule android.net.InterfaceConfigurationParcel* android.net.networkstack.InterfaceConfigurationParcel@1
-rule android.net.TetherStatsParcel* android.net.networkstack.TetherStatsParcel@1
-
-# Used by UidRange, which is used by framework classes such as NetworkCapabilities.
-rule android.net.UidRangeParcel* android.net.networkstack.UidRangeParcel@1
-# TODO: move TcpKeepalivePacketData to services.net and delete
-rule android.net.TcpKeepalivePacketDataParcelable* android.net.networkstack.TcpKeepalivePacketDataParcelable@1
\ No newline at end of file
diff --git a/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java
new file mode 100644
index 0000000..475f826
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java
@@ -0,0 +1,42 @@
+/*
+ * 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 android.net;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+/**
+ * service used to communicate with the ip memory store service in network stack,
+ * which is running in the same module.
+ * @see com.android.server.connectivity.ipmemorystore.IpMemoryStoreService
+ * @hide
+ */
+public class NetworkStackIpMemoryStore extends IpMemoryStoreClient {
+    @NonNull private final IIpMemoryStore mService;
+
+    public NetworkStackIpMemoryStore(@NonNull final Context context,
+            @NonNull final IIpMemoryStore service) {
+        super(context);
+        mService = service;
+    }
+
+    @Override
+    @NonNull
+    protected IIpMemoryStore getService() {
+        return mService;
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 7c7cdbd..b68fe23 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -29,6 +29,7 @@
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
+import android.net.NetworkStackIpMemoryStore;
 import android.net.ProvisioningConfigurationParcelable;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
@@ -61,6 +62,7 @@
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.WakeupMessage;
 import com.android.server.NetworkObserverRegistry;
+import com.android.server.NetworkStackService.NetworkStackServiceManager;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -100,6 +102,7 @@
     // One holds StateMachine logs and the other connectivity packet logs.
     private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
     private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
+    private final NetworkStackIpMemoryStore mIpMemoryStore;
 
     /**
      * Dump all state machine and connectivity packet logs to the specified writer.
@@ -388,13 +391,14 @@
     }
 
     public IpClient(Context context, String ifName, IIpClientCallbacks callback,
-            NetworkObserverRegistry observerRegistry) {
-        this(context, ifName, callback, observerRegistry, new Dependencies());
+            NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager) {
+        this(context, ifName, callback, observerRegistry, nssManager, new Dependencies());
     }
 
     @VisibleForTesting
     IpClient(Context context, String ifName, IIpClientCallbacks callback,
-            NetworkObserverRegistry observerRegistry, Dependencies deps) {
+            NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager,
+            Dependencies deps) {
         super(IpClient.class.getSimpleName() + "." + ifName);
         Preconditions.checkNotNull(ifName);
         Preconditions.checkNotNull(callback);
@@ -408,6 +412,8 @@
         mShutdownLatch = new CountDownLatch(1);
         mCm = mContext.getSystemService(ConnectivityManager.class);
         mObserverRegistry = observerRegistry;
+        mIpMemoryStore =
+                new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
 
         sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
         mLog = sSmLogs.get(mInterfaceName);
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index e7c8e85..335d951 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -29,6 +29,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
+import android.net.IIpMemoryStore;
+import android.net.IIpMemoryStoreCallbacks;
 import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
@@ -49,6 +51,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -86,7 +89,19 @@
         return makeConnector(this);
     }
 
-    private static class NetworkStackConnector extends INetworkStackConnector.Stub {
+    /**
+     * An interface for internal clients of the network stack service that can return
+     * or create inline instances of the service it manages.
+     */
+    public interface NetworkStackServiceManager {
+        /**
+         * Get an instance of the IpMemoryStoreService.
+         */
+        IIpMemoryStore getIpMemoryStoreService();
+    }
+
+    private static class NetworkStackConnector extends INetworkStackConnector.Stub
+            implements NetworkStackServiceManager {
         private static final int NUM_VALIDATION_LOG_LINES = 20;
         private final Context mContext;
         private final INetd mNetd;
@@ -94,6 +109,7 @@
         private final ConnectivityManager mCm;
         @GuardedBy("mIpClients")
         private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>();
+        private final IpMemoryStoreService mIpMemoryStoreService;
 
         private static final int MAX_VALIDATION_LOGS = 10;
         @GuardedBy("mValidationLogs")
@@ -116,6 +132,7 @@
                     (IBinder) context.getSystemService(Context.NETD_SERVICE));
             mObserverRegistry = new NetworkObserverRegistry();
             mCm = context.getSystemService(ConnectivityManager.class);
+            mIpMemoryStoreService = new IpMemoryStoreService(context);
 
             try {
                 mObserverRegistry.register(mNetd);
@@ -159,7 +176,7 @@
 
         @Override
         public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException {
-            final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry);
+            final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry, this);
 
             synchronized (mIpClients) {
                 final Iterator<WeakReference<IpClient>> it = mIpClients.iterator();
@@ -176,6 +193,17 @@
         }
 
         @Override
+        public IIpMemoryStore getIpMemoryStoreService() {
+            return mIpMemoryStoreService;
+        }
+
+        @Override
+        public void fetchIpMemoryStore(@NonNull final IIpMemoryStoreCallbacks cb)
+                throws RemoteException {
+            cb.onIpMemoryStoreFetched(mIpMemoryStoreService);
+        }
+
+        @Override
         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
                 @Nullable String[] args) {
             checkDumpPermission();
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index b238ae4..9d91487 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -1615,12 +1615,12 @@
                 return;
             }
             // See if the data sub is registered for PS services on cell.
-            final NetworkRegistrationInfo nrs = dataSs.getNetworkRegistrationInfo(
+            final NetworkRegistrationInfo nri = dataSs.getNetworkRegistrationInfo(
                     NetworkRegistrationInfo.DOMAIN_PS,
                     AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
             latencyBroadcast.putExtra(
                     NetworkMonitorUtils.EXTRA_CELL_ID,
-                    nrs == null ? null : nrs.getCellIdentity());
+                    nri == null ? null : nri.getCellIdentity());
             latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_MOBILE);
         } else {
             return;
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
similarity index 99%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
index bbecc63..4d4ceed 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
 import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
similarity index 98%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
index d43dc6a..f801b35 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import static android.net.ipmemorystore.Status.ERROR_DATABASE_CANNOT_BE_OPENED;
 import static android.net.ipmemorystore.Status.ERROR_GENERIC;
 import static android.net.ipmemorystore.Status.ERROR_ILLEGAL_ARGUMENT;
 import static android.net.ipmemorystore.Status.SUCCESS;
 
-import static com.android.server.net.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
+import static com.android.server.connectivity.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -40,7 +40,6 @@
 import android.net.ipmemorystore.SameL3NetworkResponse;
 import android.net.ipmemorystore.Status;
 import android.net.ipmemorystore.StatusParcelable;
-import android.net.ipmemorystore.Utils;
 import android.os.RemoteException;
 import android.util.Log;
 
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
similarity index 99%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
index aa45400..38d5544 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import com.android.internal.annotations.VisibleForTesting;
 
diff --git a/core/java/android/net/ipmemorystore/Utils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
similarity index 94%
rename from core/java/android/net/ipmemorystore/Utils.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
index b361aca..9cbf490 100644
--- a/core/java/android/net/ipmemorystore/Utils.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package android.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.ipmemorystore.Blob;
 
 /** {@hide} */
 public class Utils {
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
index 4536c47..eee12d6 100644
--- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -51,6 +51,7 @@
 import com.android.internal.R;
 import com.android.server.NetworkObserver;
 import com.android.server.NetworkObserverRegistry;
+import com.android.server.NetworkStackService;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -90,6 +91,7 @@
     @Mock private AlarmManager mAlarm;
     @Mock private IpClient.Dependencies mDependencies;
     @Mock private ContentResolver mContentResolver;
+    @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
 
     private NetworkObserver mObserver;
     private InterfaceParams mIfParams;
@@ -118,7 +120,8 @@
 
     private IpClient makeIpClient(String ifname) throws Exception {
         setTestInterfaceParams(ifname);
-        final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry, mDependencies);
+        final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry,
+                mNetworkStackServiceManager, mDependencies);
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
         ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class);
@@ -142,8 +145,8 @@
     public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
         setTestInterfaceParams(null);
         try {
-            final IpClient ipc = new IpClient(
-                    mContext, null, mCb, mObserverRegistry, mDependencies);
+            final IpClient ipc = new IpClient(mContext, null, mCb, mObserverRegistry,
+                    mNetworkStackServiceManager, mDependencies);
             ipc.shutdown();
             fail();
         } catch (NullPointerException npe) {
@@ -156,8 +159,8 @@
         final String ifname = "lo";
         setTestInterfaceParams(ifname);
         try {
-            final IpClient ipc = new IpClient(
-                    mContext, ifname, null, mObserverRegistry, mDependencies);
+            final IpClient ipc = new IpClient(mContext, ifname, null, mObserverRegistry,
+                    mNetworkStackServiceManager, mDependencies);
             ipc.shutdown();
             fail();
         } catch (NullPointerException npe) {
@@ -168,16 +171,16 @@
     @Test
     public void testInvalidInterfaceDoesNotThrow() throws Exception {
         setTestInterfaceParams(TEST_IFNAME);
-        final IpClient ipc = new IpClient(
-                mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
+        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
+                mNetworkStackServiceManager, mDependencies);
         ipc.shutdown();
     }
 
     @Test
     public void testInterfaceNotFoundFailsImmediately() throws Exception {
         setTestInterfaceParams(null);
-        final IpClient ipc = new IpClient(
-                mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
+        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
+                mNetworkStackServiceManager, mDependencies);
         ipc.startProvisioning(new ProvisioningConfiguration());
         verify(mCb, times(1)).onProvisioningFailure(any());
         ipc.shutdown();
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
similarity index 99%
rename from tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
rename to packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index be10680..d0e58b8 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
similarity index 97%
rename from tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
rename to packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
index 7413b914..3d3aabc 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
-import static com.android.server.net.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
+import static com.android.server.connectivity.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 591cf70..a69b412 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -93,6 +93,7 @@
 
         <activity android:name=".UninstallerActivity"
                 android:configChanges="orientation|keyboardHidden|screenSize"
+                android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
                 android:excludeFromRecents="true"
                 android:noHistory="true">
             <intent-filter android:priority="1">
diff --git a/packages/PackageInstaller/res/values/themes.xml b/packages/PackageInstaller/res/values/themes.xml
index 6c8e4c5..b11d28b 100644
--- a/packages/PackageInstaller/res/values/themes.xml
+++ b/packages/PackageInstaller/res/values/themes.xml
@@ -24,4 +24,9 @@
     <style name="Theme.AlertDialogActivity"
             parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
 
+    <style name="Theme.AlertDialogActivity.NoActionBar">
+        <item name="android:windowActionBar">false</item>
+        <item name="android:windowNoTitle">true</item>
+    </style>
+
 </resources>
diff --git a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
index e27ae7d..da575db 100644
--- a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
+++ b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
@@ -21,6 +21,8 @@
     style="@style/EntityHeader"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:orientation="horizontal">
 
     <LinearLayout
diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index 8529e3e..87b5b57 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -47,7 +48,16 @@
         if (dpm == null) {
             return null;
         }
-        ComponentName adminComponent = dpm.getProfileOwnerAsUser(user);
+
+        Context userContext;
+        try {
+            userContext = context.createPackageContextAsUser(context.getPackageName(), 0, user);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalStateException(e);
+        }
+
+        ComponentName adminComponent = userContext.getSystemService(
+                DevicePolicyManager.class).getProfileOwner();
         if (adminComponent != null) {
             return new EnforcedAdmin(adminComponent, enforcedRestriction, user);
         }
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index bf97d77..d3dde92 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -185,8 +185,12 @@
 
     <!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_active_battery_level">Active, <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level for untethered headset. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_active_battery_level_untethered">Active, L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
     <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_battery_level"><xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for untethered headset. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_battery_level_untethered">L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
     <!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_active_no_battery_level">Active</string>
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index c9fbc7b..d4d0519 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -128,12 +128,12 @@
     // to protect access to these.
     final ArrayList<Session> mSessions = new ArrayList<Session>();
     final ArrayList<Session> mRebuildingSessions = new ArrayList<Session>();
-    final InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
+    private InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
     // Map: userid => (Map: package name => AppEntry)
     final SparseArray<HashMap<String, AppEntry>> mEntriesMap =
             new SparseArray<HashMap<String, AppEntry>>();
     final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>();
-    List<ApplicationInfo> mApplications = new ArrayList<ApplicationInfo>();
+    List<ApplicationInfo> mApplications = new ArrayList<>();
     long mCurId = 1;
     UUID mCurComputingSizeUuid;
     String mCurComputingSizePkg;
@@ -166,7 +166,7 @@
     /**
      * Flags to configure the session to request various types of info.
      */
-    @IntDef(prefix = { "FLAG_SESSION_" }, value = {
+    @IntDef(prefix = {"FLAG_SESSION_"}, value = {
             FLAG_SESSION_REQUEST_HOME_APP,
             FLAG_SESSION_REQUEST_ICONS,
             FLAG_SESSION_REQUEST_SIZES,
@@ -174,7 +174,13 @@
             FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface SessionFlags {}
+    public @interface SessionFlags {
+    }
+
+    @VisibleForTesting
+    void setInterestingConfigChanges(InterestingConfigChanges interestingConfigChanges) {
+        mInterestingConfigChanges = interestingConfigChanges;
+    }
 
     public static final @SessionFlags int DEFAULT_SESSION_FLAGS =
             FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS |
@@ -190,6 +196,7 @@
         for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) {
             mEntriesMap.put(userId, new HashMap<String, AppEntry>());
         }
+
         mThread = new HandlerThread("ApplicationsState.Loader",
                 Process.THREAD_PRIORITY_BACKGROUND);
         mThread.start();
@@ -256,12 +263,14 @@
             mPackageIntentReceiver = new PackageIntentReceiver();
             mPackageIntentReceiver.registerReceiver();
         }
-        mApplications = new ArrayList<ApplicationInfo>();
+
+        final List<ApplicationInfo> prevApplications = mApplications;
+        mApplications = new ArrayList<>();
         for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) {
             try {
                 // If this user is new, it needs a map created.
                 if (mEntriesMap.indexOfKey(user.id) < 0) {
-                    mEntriesMap.put(user.id, new HashMap<String, AppEntry>());
+                    mEntriesMap.put(user.id, new HashMap<>());
                 }
                 @SuppressWarnings("unchecked")
                 ParceledListSlice<ApplicationInfo> list =
@@ -279,14 +288,14 @@
             // should completely reload the app entries.
             clearEntries();
         } else {
-            for (int i=0; i<mAppEntries.size(); i++) {
+            for (int i = 0; i < mAppEntries.size(); i++) {
                 mAppEntries.get(i).sizeStale = true;
             }
         }
 
         mHaveDisabledApps = false;
         mHaveInstantApps = false;
-        for (int i=0; i<mApplications.size(); i++) {
+        for (int i = 0; i < mApplications.size(); i++) {
             final ApplicationInfo info = mApplications.get(i);
             // Need to trim out any applications that are disabled by
             // something different than the user.
@@ -312,8 +321,9 @@
                 entry.info = info;
             }
         }
-        if (mAppEntries.size() > mApplications.size()) {
-            // There are less apps now, some must have been uninstalled.
+
+        if (anyAppIsRemoved(prevApplications, mApplications)) {
+            // some apps have been uninstalled.
             clearEntries();
         }
         mCurComputingSizePkg = null;
@@ -322,6 +332,82 @@
         }
     }
 
+    /* The original design is mAppEntries.size() > mApplications.size().
+       It's correct if there is only the owner user and only one app is removed.
+       Problem 1:
+       If there is a user profile, the size of mAppEntries < mApplications is normal because
+       the number of app entries on UI (mAppEntries) should be equal to the number of apps got
+       from PMS (mApplications).
+
+       owner only case:
+       mApplications: user 0: 191
+       mAppEntries  : user 0: 191
+       total mAppEntries: 191, mApplications: 191
+       If an app is removed, cached mAppEntries: 191 , mApplications: 191 -> 190, it is detected
+       as the number of apps becomes less.
+
+       If there is a work profile, mAppEntries removes some apps that are not installed for the
+       owner user.
+
+       For example, in the following case, 6 apps are removed from mAppEntries for the owner.
+       mApplications: user 0: 197, user 10: 189 => total 386
+       mAppEntries  : user 0: 191, user 10: 189 => total 380
+       If an app is removed, cached mAppEntries: 380 , mApplications: 386 -> 385, the size of
+       mAppEntries is still not larger than mApplications, then does not clear mAppEntries.
+
+       Problem 2:
+       If remove an app and add another app outside Settings (e.g. Play Store) and back to
+       Settings, the amount of apps are not changed, it causes the entries keep the removed app.
+
+       Another case, if adding more apps than removing apps (e.g. add 2 apps and remove 1 app),
+       the final number of apps (mApplications) is even increased,
+
+       Therefore, should not only count on number of apps to determine any app is removed.
+       Compare the change of applications instead.
+    */
+    private static boolean anyAppIsRemoved(List<ApplicationInfo> prevApplications,
+            List<ApplicationInfo> applications) {
+
+        // No cache
+        if (prevApplications.size() == 0) {
+            return false;
+        }
+
+        if (applications.size() < prevApplications.size()) {
+            return true;
+        }
+
+        // build package sets of all applications <userId, HashSet of packages>
+        final HashMap<String, HashSet<String>> packageMap = new HashMap<>();
+        for (ApplicationInfo application : applications) {
+            final String userId = String.valueOf(UserHandle.getUserId(application.uid));
+
+            HashSet<String> appPackages = packageMap.get(userId);
+            if (appPackages == null) {
+                appPackages = new HashSet<>();
+                packageMap.put(userId, appPackages);
+            }
+            if (hasFlag(application.flags, ApplicationInfo.FLAG_INSTALLED)) {
+                appPackages.add(application.packageName);
+            }
+        }
+
+        // detect any previous app is removed
+        for (ApplicationInfo prevApplication : prevApplications) {
+            if (!hasFlag(prevApplication.flags, ApplicationInfo.FLAG_INSTALLED)) {
+                continue;
+            }
+            final String userId = String.valueOf(UserHandle.getUserId(prevApplication.uid));
+
+            final HashSet<String> packagesSet = packageMap.get(userId);
+            if (packagesSet == null || !packagesSet.remove(prevApplication.packageName)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     @VisibleForTesting
     void clearEntries() {
         for (int i = 0; i < mEntriesMap.size(); i++) {
@@ -346,7 +432,7 @@
         if (!mResumed) {
             return;
         }
-        for (int i=0; i<mSessions.size(); i++) {
+        for (int i = 0; i < mSessions.size(); i++) {
             if (mSessions.get(i).mResumed) {
                 return;
             }
@@ -449,7 +535,7 @@
         if (DEBUG_LOCKING) Log.v(TAG, "sumCacheSizes about to acquire lock...");
         synchronized (mEntriesMap) {
             if (DEBUG_LOCKING) Log.v(TAG, "-> sumCacheSizes now has lock");
-            for (int i=mAppEntries.size()-1; i>=0; i--) {
+            for (int i = mAppEntries.size() - 1; i >= 0; i--) {
                 sum += mAppEntries.get(i).cacheSize;
             }
             if (DEBUG_LOCKING) Log.v(TAG, "...sumCacheSizes releasing lock");
@@ -458,7 +544,7 @@
     }
 
     int indexOfApplicationInfoLocked(String pkgName, int userId) {
-        for (int i=mApplications.size()-1; i>=0; i--) {
+        for (int i = mApplications.size() - 1; i >= 0; i--) {
             ApplicationInfo appInfo = mApplications.get(i);
             if (appInfo.packageName.equals(pkgName)
                     && UserHandle.getUserId(appInfo.uid) == userId) {
@@ -642,7 +728,7 @@
                 return;
             }
             mActiveSessions.clear();
-            for (int i=0; i<mSessions.size(); i++) {
+            for (int i = 0; i < mSessions.size(); i++) {
                 Session s = mSessions.get(i);
                 if (s.mResumed) {
                     mActiveSessions.add(new WeakReference<>(s));
@@ -784,7 +870,7 @@
 
             ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>();
             if (DEBUG) Log.i(TAG, "Rebuilding...");
-            for (int i=0; i<apps.size(); i++) {
+            for (int i = 0; i < apps.size(); i++) {
                 AppEntry entry = apps.get(i);
                 if (entry != null && (filter == null || filter.filterApp(entry))) {
                     synchronized (mEntriesMap) {
@@ -954,7 +1040,7 @@
                 }
             }
             if (rebuildingSessions != null) {
-                for (int i=0; i<rebuildingSessions.size(); i++) {
+                for (int i = 0; i < rebuildingSessions.size(); i++) {
                     rebuildingSessions.get(i).handleRebuildList();
                 }
             }
@@ -1047,9 +1133,9 @@
                             // If we do not specify MATCH_DIRECT_BOOT_AWARE or
                             // MATCH_DIRECT_BOOT_UNAWARE, system will derive and update the flags
                             // according to the user's lock state. When the user is locked,
-                            // components
-                            // with ComponentInfo#directBootAware == false will be filtered. We should
-                            // explicitly include both direct boot aware and unaware components here.
+                            // components with ComponentInfo#directBootAware == false will be
+                            // filtered. W should explicitly include both direct boot aware and
+                            // unaware component here.
                             List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
                                     launchIntent,
                                     PackageManager.MATCH_DISABLED_COMPONENTS
@@ -1128,8 +1214,10 @@
                         synchronized (mEntriesMap) {
                             if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES acquired lock");
                             if (mCurComputingSizePkg != null) {
-                                if (DEBUG_LOCKING) Log.v(TAG,
-                                        "MSG_LOAD_SIZES releasing: currently computing");
+                                if (DEBUG_LOCKING) {
+                                    Log.v(TAG,
+                                            "MSG_LOAD_SIZES releasing: currently computing");
+                                }
                                 return;
                             }
 
@@ -1181,8 +1269,10 @@
 
                                         });
                                     }
-                                    if (DEBUG_LOCKING) Log.v(TAG,
-                                            "MSG_LOAD_SIZES releasing: now computing");
+                                    if (DEBUG_LOCKING) {
+                                        Log.v(TAG,
+                                                "MSG_LOAD_SIZES releasing: now computing");
+                                    }
                                     return;
                                 }
                             }
@@ -1255,8 +1345,10 @@
                                 entry.internalSizeStr = getSizeStr(entry.internalSize);
                                 entry.externalSize = getTotalExternalSize(stats);
                                 entry.externalSizeStr = getSizeStr(entry.externalSize);
-                                if (DEBUG) Log.i(TAG, "Set size of " + entry.label + " " + entry
-                                        + ": " + entry.sizeStr);
+                                if (DEBUG) {
+                                    Log.i(TAG, "Set size of " + entry.label + " " + entry
+                                            + ": " + entry.sizeStr);
+                                }
                                 sizeChanged = true;
                             }
                         }
@@ -1299,9 +1391,11 @@
             userFilter.addAction(Intent.ACTION_USER_REMOVED);
             mContext.registerReceiver(this, userFilter);
         }
+
         void unregisterReceiver() {
             mContext.unregisterReceiver(this);
         }
+
         @Override
         public void onReceive(Context context, Intent intent) {
             String actionStr = intent.getAction();
@@ -1354,12 +1448,19 @@
 
     public interface Callbacks {
         void onRunningStateChanged(boolean running);
+
         void onPackageListChanged();
+
         void onRebuildComplete(ArrayList<AppEntry> apps);
+
         void onPackageIconChanged();
+
         void onPackageSizeChanged(String packageName);
+
         void onAllSizesComputed();
+
         void onLauncherInfoChanged();
+
         void onLoadEntriesCompleted();
     }
 
@@ -1491,6 +1592,7 @@
      */
     public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
         private final Collator sCollator = Collator.getInstance();
+
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
             int compareResult = sCollator.compare(object1.label, object2.label);
@@ -1504,6 +1606,7 @@
                     return compareResult;
                 }
             }
+
             return object1.info.uid - object2.info.uid;
         }
     };
@@ -1540,9 +1643,11 @@
 
     public interface AppFilter {
         void init();
+
         default void init(Context context) {
             init();
         }
+
         boolean filterApp(AppEntry info);
     }
 
@@ -1697,7 +1802,8 @@
         @Override
         public boolean filterApp(AppEntry entry) {
             return !AppUtils.isInstant(entry.info)
-                && hasFlag(entry.info.privateFlags, ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS);
+                    && hasFlag(entry.info.privateFlags,
+                    ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS);
         }
     };
 
@@ -1707,7 +1813,7 @@
         @Override
         public void init(Context context) {
             mHidePackageNames = context.getResources()
-                .getStringArray(R.array.config_hideWhenDisabled_packageNames);
+                    .getStringArray(R.array.config_hideWhenDisabled_packageNames);
         }
 
         @Override
@@ -1720,7 +1826,7 @@
                 if (!entry.info.enabled) {
                     return false;
                 } else if (entry.info.enabledSetting ==
-                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+                        PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
                     return false;
                 }
             }
@@ -1798,7 +1904,7 @@
         @Override
         public boolean filterApp(AppEntry entry) {
             boolean isMusicApp;
-            synchronized(entry) {
+            synchronized (entry) {
                 isMusicApp = entry.info.category == ApplicationInfo.CATEGORY_AUDIO;
             }
             return isMusicApp;
@@ -1813,7 +1919,7 @@
         @Override
         public boolean filterApp(AppEntry entry) {
             boolean isMovieApp;
-            synchronized(entry) {
+            synchronized (entry) {
                 isMovieApp = entry.info.category == ApplicationInfo.CATEGORY_VIDEO;
             }
             return isMovieApp;
@@ -1823,7 +1929,8 @@
     public static final AppFilter FILTER_PHOTOS =
             new AppFilter() {
                 @Override
-                public void init() {}
+                public void init() {
+                }
 
                 @Override
                 public boolean filterApp(AppEntry entry) {
@@ -1838,7 +1945,8 @@
     public static final AppFilter FILTER_OTHER_APPS =
             new AppFilter() {
                 @Override
-                public void init() {}
+                public void init() {
+                }
 
                 @Override
                 public boolean filterApp(AppEntry entry) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index ab95910..2405666 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -32,6 +32,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settingslib.R;
+import com.android.settingslib.Utils;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -830,6 +831,8 @@
         boolean a2dpConnected = true;        // A2DP is connected
         boolean hfpConnected = true;         // HFP is connected
         boolean hearingAidConnected = true;  // Hearing Aid is connected
+        int leftBattery = -1;
+        int rightBattery = -1;
 
         synchronized (mProfileLock) {
             for (LocalBluetoothProfile profile : getProfiles()) {
@@ -877,8 +880,23 @@
         int stringRes = R.string.bluetooth_pairing;
         //when profile is connected, information would be available
         if (profileConnected) {
+            // Update Meta data for connected device
+            if (Boolean.parseBoolean(
+                    mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))) {
+                try {
+                    leftBattery = Integer.parseInt(
+                            mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY));
+                    rightBattery = Integer.parseInt(mDevice.getMetadata(
+                                    BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY));
+                } catch (NumberFormatException e) {
+                    Log.d(TAG, "Parse error for unthethered battery level.");
+                }
+            }
+
             // Set default string with battery level in device connected situation.
-            if (batteryLevelPercentageString != null) {
+            if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+                stringRes = R.string.bluetooth_battery_level_untethered;
+            } else if (batteryLevelPercentageString != null) {
                 stringRes = R.string.bluetooth_battery_level;
             }
 
@@ -887,22 +905,36 @@
             //    2. Headset device active with in-calling state.
             //    3. A2DP device active without in-calling state.
             if (a2dpConnected || hfpConnected || hearingAidConnected) {
-                final boolean isOnCall =
-                        com.android.settingslib.Utils.isAudioModeOngoingCall(mContext);
+                final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext);
                 if ((mIsActiveDeviceHearingAid)
                         || (mIsActiveDeviceHeadset && isOnCall)
                         || (mIsActiveDeviceA2dp && !isOnCall)) {
-                    stringRes = (batteryLevelPercentageString != null)
-                            ? R.string.bluetooth_active_battery_level
-                            : R.string.bluetooth_active_no_battery_level;
+                    if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+                        stringRes = R.string.bluetooth_active_battery_level_untethered;
+                    } else if (batteryLevelPercentageString != null) {
+                        stringRes = R.string.bluetooth_active_battery_level;
+                    } else {
+                        stringRes = R.string.bluetooth_active_no_battery_level;
+                    }
                 }
             }
         }
 
-        return (stringRes != R.string.bluetooth_pairing
-                || getBondState() == BluetoothDevice.BOND_BONDING)
-                ? mContext.getString(stringRes, batteryLevelPercentageString)
-                : null;
+        if (stringRes != R.string.bluetooth_pairing
+                || getBondState() == BluetoothDevice.BOND_BONDING) {
+            if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+                return mContext.getString(stringRes, Utils.formatPercentage(leftBattery),
+                        Utils.formatPercentage(rightBattery));
+            } else {
+                return mContext.getString(stringRes, batteryLevelPercentageString);
+            }
+        } else {
+            return null;
+        }
+    }
+
+    private boolean isTwsBatteryAvailable(int leftBattery, int rightBattery) {
+        return leftBattery >= 0 && rightBattery >= 0;
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
index bee1b3c..d28b00a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
@@ -276,6 +276,12 @@
             return null;
         }
         ensureMetadataNotStale(context);
+        final ActivityInfo activityInfo = getActivityInfo(context);
+        if (activityInfo == null) {
+            Log.w(TAG, "Cannot find ActivityInfo for " + getDescription());
+            return null;
+        }
+
         int iconResId = mMetaData.getInt(META_DATA_PREFERENCE_ICON);
         // Set the icon
         if (iconResId == 0) {
@@ -283,11 +289,11 @@
             // ICON_URI should be loaded in app UI when need the icon object. Handling IPC at this
             // level is too complex because we don't have a strong threading contract for this class
             if (!mMetaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
-                iconResId = getActivityInfo(context).icon;
+                iconResId = activityInfo.icon;
             }
         }
         if (iconResId != 0) {
-            return Icon.createWithResource(getActivityInfo(context).packageName, iconResId);
+            return Icon.createWithResource(activityInfo.packageName, iconResId);
         } else {
             return null;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index da140aa..8c3fcc0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -70,13 +70,18 @@
         final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
         final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
 
+        // Some device may not have HearingAidProfile, consider all situation to set active device.
         boolean isConnected = false;
-
         if (hapProfile != null && a2dpProfile != null) {
             isConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null);
-            updateSummary(true);
-            setConnectedRecord();
+        } else if (a2dpProfile != null) {
+            isConnected = a2dpProfile.setActiveDevice(null);
+        } else if (hapProfile != null) {
+            isConnected = hapProfile.setActiveDevice(null);
         }
+        updateSummary(isConnected);
+        setConnectedRecord();
+
         Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected);
         return isConnected;
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
index a098ecc..b27efd0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
@@ -16,11 +16,17 @@
 
 package com.android.settingslib.applications;
 
+import static android.os.UserHandle.MU_ENABLED;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.shadow.api.Shadow.extract;
@@ -40,10 +46,13 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.text.TextUtils;
 import android.util.IconDrawableFactory;
 
@@ -70,6 +79,7 @@
 import org.robolectric.shadows.ShadowLooper;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
@@ -82,6 +92,19 @@
     private final static String HOME_PACKAGE_NAME = "com.android.home";
     private final static String LAUNCHABLE_PACKAGE_NAME = "com.android.launchable";
 
+    private static final int PROFILE_USERID = 10;
+
+    private static final String PKG_1 = "PKG1";
+    private static final int OWNER_UID_1 = 1001;
+    private static final int PROFILE_UID_1 = UserHandle.getUid(PROFILE_USERID, OWNER_UID_1);
+
+    private static final String PKG_2 = "PKG2";
+    private static final int OWNER_UID_2 = 1002;
+    private static final int PROFILE_UID_2 = UserHandle.getUid(PROFILE_USERID, OWNER_UID_2);
+
+    private static final String PKG_3 = "PKG3";
+    private static final int OWNER_UID_3 = 1003;
+
     /** Class under test */
     private ApplicationsState mApplicationsState;
     private Session mSession;
@@ -171,7 +194,7 @@
         storageStats.dataBytes = 20;
         storageStats.cacheBytes = 30;
         when(mStorageStatsManager.queryStatsForPackage(any(UUID.class),
-                anyString(), any(UserHandle.class))).thenReturn(storageStats);
+            anyString(), any(UserHandle.class))).thenReturn(storageStats);
 
         // Set up 3 installed apps, in which 1 is hidden module
         final List<ApplicationInfo> infos = new ArrayList<>();
@@ -195,11 +218,16 @@
     }
 
     private ApplicationInfo createApplicationInfo(String packageName) {
+        return createApplicationInfo(packageName, 0);
+    }
+
+    private ApplicationInfo createApplicationInfo(String packageName, int uid) {
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.sourceDir = "foo";
         appInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
         appInfo.storageUuid = UUID.randomUUID();
         appInfo.packageName = packageName;
+        appInfo.uid = uid;
         return appInfo;
     }
 
@@ -211,10 +239,14 @@
     }
 
     private void addApp(String packageName, int id) {
-        ApplicationInfo appInfo = createApplicationInfo(packageName);
+        addApp(packageName, id, 0);
+    }
+
+    private void addApp(String packageName, int id, int userId) {
+        ApplicationInfo appInfo = createApplicationInfo(packageName, id);
         AppEntry appEntry = createAppEntry(appInfo, id);
         mApplicationsState.mAppEntries.add(appEntry);
-        mApplicationsState.mEntriesMap.get(0).put(appInfo.packageName, appEntry);
+        mApplicationsState.mEntriesMap.get(userId).put(appInfo.packageName, appEntry);
     }
 
     private void processAllMessages() {
@@ -351,4 +383,328 @@
         assertThat(mApplications.get(1).packageName).isEqualTo("test.package.3");
     }
 
+    @Test
+    public void removeAndInstall_noWorkprofile_doResumeIfNeededLocked_shouldClearEntries()
+            throws RemoteException {
+        // scenario: only owner user
+        // (PKG_1, PKG_2) -> (PKG_2, PKG_3)
+        // PKG_1 is removed and PKG_3 is installed before app is resumed.
+        ApplicationsState.sInstance = null;
+        mApplicationsState = spy(
+            ApplicationsState
+                .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+        // Previous Applications:
+        ApplicationInfo appInfo;
+        final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        prevAppList.add(appInfo);
+        mApplicationsState.mApplications = prevAppList;
+
+        // Previous Entries:
+        // (PKG_1, PKG_2)
+        addApp(PKG_1, OWNER_UID_1, 0);
+        addApp(PKG_2, OWNER_UID_2, 0);
+
+        // latest Applications:
+        // (PKG_2, PKG_3)
+        final ArrayList<ApplicationInfo> appList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        appList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_3, OWNER_UID_3);
+        appList.add(appInfo);
+        setupDoResumeIfNeededLocked(appList, null);
+
+        mApplicationsState.doResumeIfNeededLocked();
+
+        verify(mApplicationsState).clearEntries();
+    }
+
+    @Test
+    public void noAppRemoved_noWorkprofile_doResumeIfNeededLocked_shouldNotClearEntries()
+            throws RemoteException {
+        // scenario: only owner user
+        // (PKG_1, PKG_2)
+        ApplicationsState.sInstance = null;
+        mApplicationsState = spy(
+            ApplicationsState
+                .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+        ApplicationInfo appInfo;
+        // Previous Applications
+        final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        prevAppList.add(appInfo);
+        mApplicationsState.mApplications = prevAppList;
+
+        // Previous Entries:
+        // (pk1, PKG_2)
+        addApp(PKG_1, OWNER_UID_1, 0);
+        addApp(PKG_2, OWNER_UID_2, 0);
+
+        // latest Applications:
+        // (PKG_2, PKG_3)
+        final ArrayList<ApplicationInfo> appList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        appList.add(appInfo);
+        setupDoResumeIfNeededLocked(appList, null);
+
+        mApplicationsState.doResumeIfNeededLocked();
+
+        verify(mApplicationsState, never()).clearEntries();
+    }
+
+    @Test
+    public void removeProfileApp_workprofileExists_doResumeIfNeededLocked_shouldClearEntries()
+            throws RemoteException {
+        if (!MU_ENABLED) {
+            return;
+        }
+        // [Preconditions]
+        // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+        // 2 apps (PKG_1, PKG_2) for non-owner.
+        //
+        // [Actions]
+        // profile user's PKG_2 is removed before resume
+        //
+        // Applications:
+        // owner -  (PKG_1 - uninstalled, PKG_2) -> (PKG_1 - uninstalled, PKG_2)
+        // profile - (PKG_1, PKG_2) -> (PKG_1)
+        //
+        // Previous Entries:
+        // owner - (PKG_2)
+        // profile - (PKG_1, PKG_2)
+
+        ShadowUserManager shadowUserManager = Shadow
+                .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+        shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+        ApplicationsState.sInstance = null;
+        mApplicationsState = spy(
+            ApplicationsState
+                .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+        ApplicationInfo appInfo;
+        // Previous Applications
+        // owner -  (PKG_1 - uninstalled, PKG_2)
+        // profile - (PKG_1, PKG_2)
+        final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        prevAppList.add(appInfo);
+
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+        prevAppList.add(appInfo);
+
+        mApplicationsState.mApplications = prevAppList;
+        // Previous Entries:
+        // owner (PKG_2), profile (pk1, PKG_2)
+        // PKG_1 is not installed for owner, hence it's removed from entries
+        addApp(PKG_2, OWNER_UID_2, 0);
+        addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+        addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+        // latest Applications:
+        // owner (PKG_1, PKG_2), profile (PKG_1)
+        // owner's PKG_1 is still listed and is in non-installed state
+        // profile user's PKG_2 is removed by a user before resume
+        //owner
+        final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        ownerAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        ownerAppList.add(appInfo);
+        //profile
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        setupDoResumeIfNeededLocked(ownerAppList, new ArrayList<>(Arrays.asList(appInfo)));
+
+        mApplicationsState.doResumeIfNeededLocked();
+
+        verify(mApplicationsState).clearEntries();
+    }
+
+    @Test
+    public void removeOwnerApp_workprofileExists_doResumeIfNeededLocked_shouldClearEntries()
+            throws RemoteException {
+        if (!MU_ENABLED) {
+            return;
+        }
+        // [Preconditions]
+        // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+        // 2 apps (PKG_1, PKG_2) for non-owner.
+        //
+        // [Actions]
+        // Owner user's PKG_2 is removed before resume
+        //
+        // Applications:
+        // owner -  (PKG_1 - uninstalled, PKG_2) -> (PKG_1 - uninstalled, PKG_2 - uninstalled)
+        // profile - (PKG_1, PKG_2) -> (PKG_1, PKG_2)
+        //
+        // Previous Entries:
+        // owner - (PKG_2)
+        // profile - (PKG_1, PKG_2)
+
+        ShadowUserManager shadowUserManager = Shadow
+                .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+        shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+        ApplicationsState.sInstance = null;
+        mApplicationsState = spy(
+            ApplicationsState
+                .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+        ApplicationInfo appInfo;
+        // Previous Applications:
+        // owner -  (PKG_1 - uninstalled, PKG_2)
+        // profile - (PKG_1, PKG_2)
+        final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        prevAppList.add(appInfo);
+
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+        prevAppList.add(appInfo);
+
+        mApplicationsState.mApplications = prevAppList;
+
+        // Previous Entries:
+        // owner (PKG_2), profile (pk1, PKG_2)
+        // PKG_1 is not installed for owner, hence it's removed from entries
+        addApp(PKG_2, OWNER_UID_2, 0);
+        addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+        addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+        // latest Applications:
+        // owner (PKG_1 - uninstalled, PKG_2 - uninstalled), profile (PKG_1, PKG_2)
+        // owner's PKG_1, PKG_2 is still listed and is in non-installed state
+        // profile user's PKG_2 is removed before resume
+        //owner
+        final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        ownerAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        ownerAppList.add(appInfo);
+
+        //profile
+        final ArrayList<ApplicationInfo> profileAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        profileAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+        profileAppList.add(appInfo);
+        setupDoResumeIfNeededLocked(ownerAppList, profileAppList);
+
+        mApplicationsState.doResumeIfNeededLocked();
+
+        verify(mApplicationsState).clearEntries();
+    }
+
+    @Test
+    public void noAppRemoved_workprofileExists_doResumeIfNeededLocked_shouldNotClearEntries()
+            throws RemoteException {
+        if (!MU_ENABLED) {
+            return;
+        }
+        // [Preconditions]
+        // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+        // 2 apps (PKG_1, PKG_2) for non-owner.
+        //
+        // Applications:
+        // owner -  (PKG_1 - uninstalled, PKG_2)
+        // profile - (PKG_1, PKG_2)
+        //
+        // Previous Entries:
+        // owner - (PKG_2)
+        // profile - (PKG_1, PKG_2)
+
+        ShadowUserManager shadowUserManager = Shadow
+                .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+        shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+        ApplicationsState.sInstance = null;
+        mApplicationsState = spy(
+            ApplicationsState
+                .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+        ApplicationInfo appInfo;
+        // Previous Applications:
+        // owner -  (PKG_1 - uninstalled, PKG_2)
+        // profile - (PKG_1, PKG_2)
+        final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        prevAppList.add(appInfo);
+
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+        prevAppList.add(appInfo);
+
+        mApplicationsState.mApplications = prevAppList;
+        // Previous Entries:
+        // owner (PKG_2), profile (pk1, PKG_2)
+        // PKG_1 is not installed for owner, hence it's removed from entries
+        addApp(PKG_2, OWNER_UID_2, 0);
+        addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+        addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+        // latest Applications:
+        // owner (PKG_1 - uninstalled, PKG_2), profile (PKG_1, PKG_2)
+        // owner's PKG_1 is still listed and is in non-installed state
+
+        // owner
+        final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        ownerAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        ownerAppList.add(appInfo);
+
+        // profile
+        final ArrayList<ApplicationInfo> profileAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        profileAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+        profileAppList.add(appInfo);
+        setupDoResumeIfNeededLocked(ownerAppList, profileAppList);
+
+        mApplicationsState.doResumeIfNeededLocked();
+
+        verify(mApplicationsState, never()).clearEntries();
+    }
+
+    private void setupDoResumeIfNeededLocked(ArrayList<ApplicationInfo> ownerApps,
+            ArrayList<ApplicationInfo> profileApps)
+            throws RemoteException {
+
+        if (ownerApps != null) {
+            when(mApplicationsState.mIpm.getInstalledApplications(anyInt(), eq(0)))
+                .thenReturn(new ParceledListSlice<>(ownerApps));
+        }
+        if (profileApps != null) {
+            when(mApplicationsState.mIpm.getInstalledApplications(anyInt(), eq(PROFILE_USERID)))
+                .thenReturn(new ParceledListSlice<>(profileApps));
+        }
+        final InterestingConfigChanges configChanges = mock(InterestingConfigChanges.class);
+        when(configChanges.applyNewConfig(any(Resources.class))).thenReturn(false);
+        mApplicationsState.setInterestingConfigChanges(configChanges);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 4e5d38a..79b84b9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -41,14 +41,16 @@
 
 @RunWith(RobolectricTestRunner.class)
 public class CachedBluetoothDeviceTest {
-    private final static String DEVICE_NAME = "TestName";
-    private final static String DEVICE_ALIAS = "TestAlias";
-    private final static String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
-    private final static String DEVICE_ALIAS_NEW = "TestAliasNew";
-    private final static short RSSI_1 = 10;
-    private final static short RSSI_2 = 11;
-    private final static boolean JUSTDISCOVERED_1 = true;
-    private final static boolean JUSTDISCOVERED_2 = false;
+    private static final String DEVICE_NAME = "TestName";
+    private static final String DEVICE_ALIAS = "TestAlias";
+    private static final String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
+    private static final String DEVICE_ALIAS_NEW = "TestAliasNew";
+    private static final String TWS_BATTERY_LEFT = "15";
+    private static final String TWS_BATTERY_RIGHT = "25";
+    private static final short RSSI_1 = 10;
+    private static final short RSSI_2 = 11;
+    private static final boolean JUSTDISCOVERED_1 = true;
+    private static final boolean JUSTDISCOVERED_2 = false;
     @Mock
     private LocalBluetoothProfileManager mProfileManager;
     @Mock
@@ -447,6 +449,41 @@
     }
 
     @Test
+    public void getConnectionSummary_trueWirelessActiveDeviceWithBattery_returnActiveWithBattery() {
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
+                "true");
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
+                TWS_BATTERY_LEFT);
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
+                TWS_BATTERY_RIGHT);
+
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Active, L: 15% battery, R: 25% battery");
+    }
+
+    @Test
+    public void getConnectionSummary_trueWirelessDeviceWithBattery_returnActiveWithBattery() {
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
+                "true");
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
+                TWS_BATTERY_LEFT);
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
+                TWS_BATTERY_RIGHT);
+
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "L: 15% battery, R: 25% battery");
+    }
+
+    @Test
     public void getCarConnectionSummary_singleProfileConnectDisconnect() {
         // Test without battery level
         // Set PAN profile to be connected and test connection state summary
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 50a6a9d..0752dc0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -100,6 +100,30 @@
     }
 
     @Test
+    public void connect_hearingAidProfileIsNullAndA2dpProfileNotNull_isConnectedReturnTrue() {
+        when(mLocalProfileManager.getHearingAidProfile()).thenReturn(null);
+
+        when(mA2dpProfile.setActiveDevice(null)).thenReturn(true);
+        assertThat(mPhoneMediaDevice.connect()).isTrue();
+    }
+
+    @Test
+    public void connect_hearingAidProfileNotNullAndA2dpProfileIsNull_isConnectedReturnTrue() {
+        when(mLocalProfileManager.getA2dpProfile()).thenReturn(null);
+
+        when(mHapProfile.setActiveDevice(null)).thenReturn(true);
+        assertThat(mPhoneMediaDevice.connect()).isTrue();
+    }
+
+    @Test
+    public void connect_hearingAidProfileAndA2dpProfileIsNull_isConnectedReturnFalse() {
+        when(mLocalProfileManager.getA2dpProfile()).thenReturn(null);
+        when(mLocalProfileManager.getHearingAidProfile()).thenReturn(null);
+
+        assertThat(mPhoneMediaDevice.connect()).isFalse();
+    }
+
+    @Test
     public void updateSummary_isActiveIsTrue_returnActiveString() {
         mPhoneMediaDevice.updateSummary(true);
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
index c50d646..ca1eefc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
@@ -29,6 +29,7 @@
 
 @Implements(value = UserManager.class)
 public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
+    private List<UserInfo> mUserInfos = addProfile(0, "Owner");
 
     @Implementation
     protected static UserManager get(Context context) {
@@ -37,16 +38,24 @@
 
     @Implementation
     protected int[] getProfileIdsWithDisabled(int userId) {
-        return new int[]{0};
+        return mUserInfos.stream().mapToInt(s -> s.id).toArray();
     }
 
     @Implementation
     protected List<UserInfo> getProfiles() {
-        UserInfo userInfo = new UserInfo();
-        userInfo.id = 0;
-        List<UserInfo> userInfos = new ArrayList<>();
-        userInfos.add(userInfo);
-        return userInfos;
+        return mUserInfos;
+    }
+
+    public List<UserInfo> addProfile(int id, String name) {
+        List<UserInfo> userInfoList = mUserInfos;
+        if (userInfoList == null) {
+            userInfoList = new ArrayList<>();
+        }
+        final UserInfo userInfo = new UserInfo();
+        userInfo.id = id;
+        userInfo.name = name;
+        userInfoList.add(userInfo);
+        return userInfoList;
     }
 
     @Implementation
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d639e5e..f0399c5 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -86,6 +86,7 @@
     <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
     <uses-permission android:name="android.permission.DELETE_PACKAGES" />
     <uses-permission android:name="android.permission.MANAGE_ROLLBACKS" />
+    <uses-permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" />
     <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
index e1bf6cb..5da7611 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
@@ -17,15 +17,24 @@
 */
 -->
 
-<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
-<com.android.keyguard.KeyguardMessageArea
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    style="@style/Keyguard.TextView"
-    android:id="@+id/keyguard_message_area"
-    android:singleLine="true"
-    android:ellipsize="marquee"
-    android:focusable="true" />
-
+<!-- This contains error message field and padlock shared by pin/pattern/password screens -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content" >
+    <FrameLayout
+        android:id="@+id/lock_icon_container"
+        android:layout_gravity="center"
+        android:layout_marginBottom="@dimen/keyguard_lock_padding"
+        android:layout_width="@dimen/keyguard_lock_width"
+        android:layout_height="@dimen/keyguard_lock_height" />
+    <com.android.keyguard.KeyguardMessageArea
+        android:id="@+id/keyguard_message_area"
+        style="@style/Keyguard.TextView"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:focusable="true" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
index 38d2ecc3..91ca5c5 100644
--- a/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
@@ -21,6 +21,6 @@
 
     <!-- Height of the sliding KeyguardSecurityContainer
          (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">345dp</dimen>
+    <dimen name="keyguard_security_height">395dp</dimen>
 
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
index 90c4795..d7c9975 100644
--- a/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
@@ -21,5 +21,5 @@
 
     <!-- Height of the sliding KeyguardSecurityContainer (includes 2x
          keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">400dp</dimen>
+    <dimen name="keyguard_security_height">450dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
index 9ea04dc..a3c37e4 100644
--- a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
@@ -20,5 +20,5 @@
 <resources>
     <!-- Height of the sliding KeyguardSecurityContainer
         (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">500dp</dimen>
+    <dimen name="keyguard_security_height">550dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
index 9157822..1dc61c5 100644
--- a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
@@ -20,7 +20,7 @@
 
     <!-- Height of the sliding KeyguardSecurityContainer
          (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">420dp</dimen>
+    <dimen name="keyguard_security_height">470dp</dimen>
 
     <dimen name="widget_big_font_size">100dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index b6a41c1..d67c98a 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -27,11 +27,11 @@
 
     <!-- Height of the sliding KeyguardSecurityContainer
          (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">400dp</dimen>
+    <dimen name="keyguard_security_height">450dp</dimen>
 
     <!-- Max Height of the sliding KeyguardSecurityContainer
          (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_max_height">455dp</dimen>
+    <dimen name="keyguard_security_max_height">505dp</dimen>
 
     <!-- Margin around the various security views -->
     <dimen name="keyguard_security_view_top_margin">8dp</dimen>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 0fed96e..27d2bcd 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -18,8 +18,6 @@
     <declare-styleable name="KeyButtonView">
         <!-- key code to send when pressed; if absent or 0, no key is sent -->
         <attr name="keyCode" format="integer" />
-        <!-- does this button generate longpress / repeat events? -->
-        <attr name="keyRepeat" format="boolean" />
         <!-- Should this button play sound effects, default true -->
         <attr name="playSound" format="boolean" />
         <attr name="android:contentDescription" />
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index e0ed111..4a2731e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -61,6 +61,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import java.lang.annotation.Retention;
 
@@ -74,7 +75,8 @@
  * The controller manages addition, removal, and visible state of bubbles on screen.
  */
 @Singleton
-public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener {
+public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener,
+        ConfigurationController.ConfigurationListener {
 
     private static final String TAG = "BubbleController";
 
@@ -84,6 +86,7 @@
     @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
             DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION})
     @interface DismissReason {}
+
     static final int DISMISS_USER_GESTURE = 1;
     static final int DISMISS_AGED = 2;
     static final int DISMISS_TASK_FINISHED = 3;
@@ -151,6 +154,7 @@
     public interface BubbleExpandListener {
         /**
          * Called when the expansion state of the bubble stack changes.
+         *
          * @param isExpanding whether it's expanding or collapsing
          * @param key the notification key associated with bubble being expanded
          */
@@ -179,13 +183,16 @@
 
     @Inject
     public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
-                            BubbleData data) {
-        this(context, statusBarWindowController, data, null /* synchronizer */);
+            BubbleData data, ConfigurationController configurationController) {
+        this(context, statusBarWindowController, data, null /* synchronizer */,
+                configurationController);
     }
 
     public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
-            BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer) {
+            BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
+            ConfigurationController configurationController) {
         mContext = context;
+        configurationController.addCallback(this /* configurationListener */);
 
         mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
         mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
@@ -215,6 +222,20 @@
         mSurfaceSynchronizer = synchronizer;
     }
 
+    @Override
+    public void onUiModeChanged() {
+        if (mStackView != null) {
+            mStackView.onConfigChanged();
+        }
+    }
+
+    @Override
+    public void onOverlayChanged() {
+        if (mStackView != null) {
+            mStackView.onConfigChanged();
+        }
+    }
+
     /**
      * Set a listener to be notified when some states of the bubbles change.
      */
@@ -295,7 +316,7 @@
     /**
      * Adds or updates a bubble associated with the provided notification entry.
      *
-     * @param notif the notification associated with this bubble.
+     * @param notif          the notification associated with this bubble.
      * @param updatePosition whether this update should promote the bubble to the top of the stack.
      */
     public void updateBubble(NotificationEntry notif, boolean updatePosition) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 856b9d6..e8b346e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -354,6 +354,13 @@
         }
     }
 
+    /**
+     * Update bubble expanded view header when user toggles dark mode.
+     */
+    void updateHeaderColor() {
+        mHeaderView.setBackgroundColor(mContext.getColor(R.attr.colorAccent));
+    }
+
     private void updateHeaderView() {
         mSettingsIcon.setContentDescription(getResources().getString(
                 R.string.bubbles_settings_button_description, mAppName));
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 1cc6b87..461e79c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -238,6 +238,13 @@
         mBubbleContainer.bringToFront();
     }
 
+    /**
+     * Handle config changes.
+     */
+    public void onConfigChanged() {
+        mExpandedBubble.expandedView.updateHeaderColor();
+    }
+
     @Override
     public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
         getBoundsOnScreen(outRect);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index d06feed..2db7306 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -61,7 +61,9 @@
 
     @Override
     public void onDestroy() {
-        mPluginManager.removePluginListener(this);
+        if (mPluginManager != null) {
+            mPluginManager.removePluginListener(this);
+        }
         super.onDestroy();
         mDozeMachine = null;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 7ed3a80..f07887e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1499,12 +1499,12 @@
         private final Context mContext;
         private final MyAdapter mAdapter;
         private MultiListLayout mGlobalActionsLayout;
-        private final Drawable mBackgroundDrawable;
+        private Drawable mBackgroundDrawable;
         private final ColorExtractor mColorExtractor;
         private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
         private boolean mKeyguardShowing;
         private boolean mShowing;
-        private final float mScrimAlpha;
+        private float mScrimAlpha;
 
         ActionsDialog(Context context, MyAdapter adapter,
                 GlobalActionsPanelPlugin.PanelViewController plugin) {
@@ -1531,49 +1531,37 @@
                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                     | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
             window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
-
-            initializeLayout();
-
             setTitle(R.string.global_actions);
 
             mPanelController = plugin;
-            View panelView = initializePanel();
-            if (panelView == null) {
-                mBackgroundDrawable = new GradientDrawable(context);
-                mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
-            } else {
-                mBackgroundDrawable = context.getDrawable(
-                        com.android.systemui.R.drawable.global_action_panel_scrim);
-                mScrimAlpha = 1f;
-                addContentView(
-                        panelView,
-                        new ViewGroup.LayoutParams(
-                                ViewGroup.LayoutParams.MATCH_PARENT,
-                                ViewGroup.LayoutParams.MATCH_PARENT));
-            }
-            window.setBackgroundDrawable(mBackgroundDrawable);
+            initializeLayout();
         }
 
-        private View initializePanel() {
-            if (isPanelEnabled(mContext) && mPanelController != null) {
-                View panelView = mPanelController.getPanelContent();
-                if (panelView != null) {
-                    FrameLayout panelContainer = new FrameLayout(mContext);
-                    FrameLayout.LayoutParams panelParams =
-                            new FrameLayout.LayoutParams(
-                                    FrameLayout.LayoutParams.MATCH_PARENT,
-                                    FrameLayout.LayoutParams.WRAP_CONTENT);
-                    panelContainer.addView(panelView, panelParams);
-                    return panelContainer;
-                }
+        private boolean initializePanel() {
+            if (!isPanelEnabled(mContext) || mPanelController == null) {
+                return false;
             }
-            return null;
+            View panelView = mPanelController.getPanelContent();
+            if (panelView == null) {
+                return false;
+            }
+            FrameLayout panelContainer = new FrameLayout(mContext);
+            FrameLayout.LayoutParams panelParams =
+                    new FrameLayout.LayoutParams(
+                            FrameLayout.LayoutParams.MATCH_PARENT,
+                            FrameLayout.LayoutParams.WRAP_CONTENT);
+            panelContainer.addView(panelView, panelParams);
+            addContentView(
+                    panelContainer,
+                    new ViewGroup.LayoutParams(
+                            ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.MATCH_PARENT));
+            return true;
         }
 
         private void initializeLayout() {
             setContentView(getGlobalActionsLayoutId(mContext));
-            mGlobalActionsLayout = (MultiListLayout)
-                    findViewById(com.android.systemui.R.id.global_actions_view);
+            mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
             mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
             mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
                 @Override
@@ -1586,8 +1574,18 @@
             });
             mGlobalActionsLayout.setRotationListener(this::onRotate);
             mGlobalActionsLayout.setAdapter(mAdapter);
-            mGlobalActionsLayout.setSnapToEdge(isPanelEnabled(mContext)
-                    && mPanelController != null);
+
+            boolean panelEnabled = initializePanel();
+            if (!panelEnabled) {
+                mBackgroundDrawable = new GradientDrawable(mContext);
+                mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
+            } else {
+                mBackgroundDrawable = mContext.getDrawable(
+                        com.android.systemui.R.drawable.global_action_panel_scrim);
+                mScrimAlpha = 1f;
+            }
+            mGlobalActionsLayout.setSnapToEdge(panelEnabled);
+            getWindow().setBackgroundDrawable(mBackgroundDrawable);
         }
 
         private int getGlobalActionsLayoutId(Context context) {
@@ -1743,7 +1741,8 @@
      */
     private static boolean isPanelEnabled(Context context) {
         return FeatureFlagUtils.isEnabled(
-                context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);    }
+                context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);
+    }
 
     /**
      * Determines whether the Global Actions menu should use a separated view for emergency actions.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 295abcb..2f99cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -596,7 +596,8 @@
     @Override
     public void appTransitionCancelled(int displayId) {
         synchronized (mLock) {
-            mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId).sendToTarget();
+            mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId, 0 /* unused */)
+                    .sendToTarget();
         }
     }
 
@@ -624,7 +625,8 @@
     @Override
     public void appTransitionFinished(int displayId) {
         synchronized (mLock) {
-            mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId).sendToTarget();
+            mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId, 0 /* unused */)
+                    .sendToTarget();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 0a39549..2da6824 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -492,13 +492,10 @@
             int currentAlpha = getImageAlpha();
             ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha);
             mAlphaAnimator = animator;
-            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    int alpha = (int) animation.getAnimatedValue();
-                    if (background != null) background.mutate().setAlpha(alpha);
-                    setImageAlpha(alpha);
-                }
+            animator.addUpdateListener(animation -> {
+                int alpha1 = (int) animation.getAnimatedValue();
+                if (background != null) background.mutate().setAlpha(alpha1);
+                setImageAlpha(alpha1);
             });
             animator.addListener(mAlphaEndListener);
             if (interpolator == null) {
@@ -520,6 +517,10 @@
         }
     }
 
+    public boolean isAnimatingAlpha() {
+        return mAlphaAnimator != null;
+    }
+
     private Animator.AnimatorListener getEndListener(final Runnable runnable) {
         return new AnimatorListenerAdapter() {
             boolean mCancelled;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 14dc272..2bb6e3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -32,6 +32,7 @@
 import android.view.View;
 import android.view.WindowManagerGlobal;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -58,7 +59,8 @@
     private final DisplayManager mDisplayManager;
 
     /** A displayId - nav bar maps. */
-    private SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
+    @VisibleForTesting
+    SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
 
     @Inject
     public NavigationBarController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
@@ -101,7 +103,8 @@
      *
      * @param display the display to add navigation bar on.
      */
-    private void createNavigationBar(Display display) {
+    @VisibleForTesting
+    void createNavigationBar(Display display) {
         if (display == null) {
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
index 2bbc53c..fdf8cce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -28,6 +28,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.statusbar.CommandQueue;
@@ -48,8 +49,10 @@
     private StatusBar mStatusBar;
     private NavigationBarFragment mNavigationBar;
 
-    private int mDisplayId;
-    private int mSystemUiVisibility;
+    @VisibleForTesting
+    int mDisplayId;
+    @VisibleForTesting
+    int mSystemUiVisibility;
     // last value sent to window manager
     private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
 
@@ -123,7 +126,8 @@
         }
     }
 
-    private void notifySystemUiVisibilityChanged(int vis) {
+    @VisibleForTesting
+    void notifySystemUiVisibilityChanged(int vis) {
         try {
             if (mLastDispatchedSystemUiVisibility != vis) {
                 mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
@@ -213,11 +217,12 @@
         return mask;
     }
 
-    private boolean hasNavigationBar() {
+    boolean hasNavigationBar() {
         return mNavigationBar != null;
     }
 
-    private boolean hasStatusBar() {
+    @VisibleForTesting
+    boolean hasStatusBar() {
         return mStatusBar != null;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 6fe23fb..847f3ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -831,6 +831,15 @@
         }
     }
 
+    /**
+     * Sets the alpha of the indication areas and affordances, excluding the lock icon.
+     */
+    public void setAffordanceAlpha(float alpha) {
+        mLeftAffordanceView.setAlpha(alpha);
+        mRightAffordanceView.setAlpha(alpha);
+        mIndicationArea.setAlpha(alpha);
+    }
+
     private class DefaultLeftButton implements IntentButton {
 
         private IconState mIconState = new IconState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 7d13679..19373ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -88,6 +88,7 @@
     private int mBouncerPromptReason;
     private boolean mIsAnimatingAway;
     private boolean mIsScrimmed;
+    private ViewGroup mLockIconContainer;
 
     public KeyguardBouncer(Context context, ViewMediatorCallback callback,
             LockPatternUtils lockPatternUtils, ViewGroup container,
@@ -171,6 +172,10 @@
         return isShowing() && mIsScrimmed;
     }
 
+    public ViewGroup getLockIconContainer() {
+        return mRoot == null || mRoot.getVisibility() != View.VISIBLE ? null : mLockIconContainer;
+    }
+
     /**
      * This method must be called at the end of the bouncer animation when
      * the translation is performed manually by the user, otherwise FalsingManager
@@ -401,6 +406,7 @@
         removeView();
         mHandler.removeCallbacks(mRemoveViewRunnable);
         mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
+        mLockIconContainer = mRoot.findViewById(R.id.lock_icon_container);
         mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view);
         mKeyguardView.setLockPatternUtils(mLockPatternUtils);
         mKeyguardView.setViewMediatorCallback(mCallback);
@@ -420,6 +426,7 @@
         if (mRoot != null && mRoot.getParent() == mContainer) {
             mContainer.removeView(mRoot);
             mRoot = null;
+            mLockIconContainer = null;
         }
     }
 
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 0978901..ea30451 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -159,7 +159,8 @@
 
     private OverviewProxyService mOverviewProxyService;
 
-    private int mDisplayId;
+    @VisibleForTesting
+    public int mDisplayId;
     private boolean mIsOnDefaultDisplay;
     public boolean mHomeBlockedThisTouch;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index babee53..253bdfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -192,7 +192,6 @@
     protected int mQsMinExpansionHeight;
     protected int mQsMaxExpansionHeight;
     private int mQsPeekHeight;
-    private int mBouncerTop;
     private boolean mStackScrollerOverscrolling;
     private boolean mQsExpansionFromOverscroll;
     private float mLastOverscroll;
@@ -325,6 +324,7 @@
     private final ShadeController mShadeController =
             Dependency.get(ShadeController.class);
     private int mDisplayId;
+    private KeyguardBouncer mBouncer;
 
     /**
      * Cache the resource id of the theme to avoid unnecessary work in onThemeChanged.
@@ -690,11 +690,6 @@
         return count;
     }
 
-    public void setBouncerTop(int bouncerTop) {
-        mBouncerTop = bouncerTop;
-        positionClockAndNotifications();
-    }
-
     private void updateClock() {
         if (!mKeyguardStatusViewAnimating) {
             mKeyguardStatusView.setAlpha(mClockPositionResult.clockAlpha);
@@ -1741,7 +1736,6 @@
         }
         updateExpandedHeight(expandedHeight);
         updateHeader();
-        updateUnlockIcon();
         updateNotificationTranslucency();
         updatePanelExpanded();
         if (DEBUG) {
@@ -1834,19 +1828,6 @@
         return mNotificationStackScroller.getCurrentOverScrolledPixels(true /* top */);
     }
 
-    private void updateUnlockIcon() {
-        if (mBarState == StatusBarState.KEYGUARD
-                || mBarState == StatusBarState.SHADE_LOCKED) {
-            boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance;
-            KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
-            if (active != mUnlockIconActive && mTracking) {
-                lockIcon.setImageAlpha(lockIcon.getRestingAlpha(), true, 150,
-                        Interpolators.FAST_OUT_LINEAR_IN, null);
-            }
-            mUnlockIconActive = active;
-        }
-    }
-
     /**
      * Hides the header when notifications are colliding with it.
      */
@@ -1913,7 +1894,7 @@
                         ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f,
                 0f, 1f, getExpandedFraction());
         float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
-        mKeyguardBottomArea.setAlpha(alpha);
+        mKeyguardBottomArea.setAffordanceAlpha(alpha);
         mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
                 ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
                 : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
@@ -2061,11 +2042,6 @@
                 mAffordanceHelper.reset(true);
             }
         }
-        if (!expand && (mBarState == StatusBarState.KEYGUARD
-                || mBarState == StatusBarState.SHADE_LOCKED)) {
-            KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
-            lockIcon.setImageAlpha(0.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN, null);
-        }
     }
 
     @Override
@@ -2215,22 +2191,6 @@
             return;
         }
         super.startUnlockHintAnimation();
-        startHighlightIconAnimation(getCenterIcon());
-    }
-
-    /**
-     * Starts the highlight (making it fully opaque) animation on an icon.
-     */
-    private void startHighlightIconAnimation(final KeyguardAffordanceView icon) {
-        icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
-                Interpolators.FAST_OUT_SLOW_IN, new Runnable() {
-                    @Override
-                    public void run() {
-                        icon.setImageAlpha(icon.getRestingAlpha(),
-                                true /* animate */, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
-                                Interpolators.FAST_OUT_SLOW_IN, null);
-                    }
-                });
     }
 
     @Override
@@ -2969,6 +2929,7 @@
     public void onBouncerPreHideAnimation() {
         setKeyguardStatusViewVisibility(mBarState, true /* keyguardFadingAway */,
                 false /* goingToFullShade */);
+        updateLockIcon();
     }
 
     @Override
@@ -3058,4 +3019,54 @@
     public void showTransientIndication(int id) {
         mKeyguardBottomArea.showTransientIndication(id);
     }
+
+    /**
+     * Sets the reference to the {@link KeyguardBouncer}.
+     */
+    public void setBouncer(KeyguardBouncer bouncer) {
+        mBouncer = bouncer;
+        updateLockIcon();
+    }
+
+    public void updateLockIcon() {
+        if (mBouncer == null) {
+            return;
+        }
+
+        ViewGroup bouncerContainer = mBouncer.getLockIconContainer();
+        LockIcon lockIcon = mKeyguardBottomArea.getLockIcon();
+
+        if (mBouncer.isAnimatingAway()) {
+            if (!lockIcon.isAnimatingAlpha() && lockIcon.getAlpha() != 0) {
+                lockIcon.setImageAlpha(0, true /* animate */);
+            }
+            // Let's not re-apply the translation if the bouncer is animating, its
+            // animation also includes translation and transition would be jarring.
+            return;
+        }
+
+        float translation = 0;
+        if (bouncerContainer != null) {
+            float bottomAreaContainerY = getCommonTop(lockIcon);
+            float bouncerLockY = getCommonTop(bouncerContainer);
+            if (bouncerLockY < bottomAreaContainerY) {
+                translation = bouncerLockY - bottomAreaContainerY;
+            }
+        }
+        lockIcon.setTranslationY(translation);
+
+        if (lockIcon.getAlpha() != 1) {
+            lockIcon.setImageAlpha(1, false /* animate */);
+        }
+    }
+
+    private static float getCommonTop(View view) {
+        float y = view.getTop();
+        ViewGroup parent = (ViewGroup) view.getParent();
+        while (!(parent instanceof StatusBarWindowView)) {
+            y += parent.getY();
+            parent = (ViewGroup) parent.getParent();
+        }
+        return y;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 2495d22..99345d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -1115,6 +1115,7 @@
 
         View[] viewsToAnimate = {
                 mKeyguardBottomArea.getIndicationArea(),
+                mKeyguardBottomArea.getLockIcon(),
                 mStatusBar.getAmbientIndicationContainer()};
         for (View v : viewsToAnimate) {
             if (v == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 8db0822..c4b41d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -122,6 +122,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
@@ -215,7 +216,6 @@
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -533,8 +533,7 @@
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     protected UserSwitcherController mUserSwitcherController;
     private NetworkController mNetworkController;
-    private KeyguardMonitorImpl mKeyguardMonitor
-            = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
+    private KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
     private BatteryController mBatteryController;
     protected boolean mPanelExpanded;
     private UiModeManager mUiModeManager;
@@ -882,7 +881,6 @@
                         mNotificationPanel.getLockIcon());
         mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
 
-
         mAmbientIndicationContainer = mStatusBarWindow.findViewById(
                 R.id.ambient_indication_container);
 
@@ -1058,8 +1056,21 @@
         mNotificationShelf.setOnActivatedListener(mPresenter);
         mRemoteInputManager.getController().addCallback(mStatusBarWindowController);
 
-        mNotificationActivityStarter = new StatusBarNotificationActivityStarter(
-                mContext, mNotificationPanel, mPresenter, mHeadsUpManager, mActivityLaunchAnimator);
+        final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
+                (StatusBarRemoteInputCallback) Dependency.get(
+                        NotificationRemoteInputManager.Callback.class);
+        final ShadeController shadeController = Dependency.get(ShadeController.class);
+        final ActivityStarter activityStarter = Dependency.get(ActivityStarter.class);
+
+        mNotificationActivityStarter = new StatusBarNotificationActivityStarter(mContext,
+                mCommandQueue, mAssistManager, mNotificationPanel, mPresenter, mEntryManager,
+                mHeadsUpManager, activityStarter, mActivityLaunchAnimator,
+                mBarService, mStatusBarStateController, mKeyguardManager, mDreamManager,
+                mRemoteInputManager, mStatusBarRemoteInputCallback, mGroupManager,
+                mLockscreenUserManager, shadeController, mKeyguardMonitor,
+                mNotificationInterruptionStateProvider, mMetricsLogger,
+                new LockPatternUtils(mContext));
+
         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
 
         mEntryManager.setRowBinder(rowBinder);
@@ -1220,6 +1231,7 @@
         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
         mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
         mMediaManager.setBiometricUnlockController(mBiometricUnlockController);
+        mNotificationPanel.setBouncer(mStatusBarKeyguardViewManager.getBouncer());
         Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked);
         Trace.endSection();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5014783..e8a5c7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -166,16 +166,10 @@
         mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
                 mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
                 mExpansionCallback);
-        mContainer.addOnLayoutChangeListener(this::onContainerLayout);
         mNotificationPanelView = notificationPanelView;
         notificationPanelView.setExpansionListener(this::onPanelExpansionChanged);
     }
 
-    private void onContainerLayout(View v, int left, int top, int right, int bottom,
-            int oldLeft, int oldTop, int oldRight, int oldBottom) {
-        mNotificationPanelView.setBouncerTop(mBouncer.getTop());
-    }
-
     @VisibleForTesting
     void onPanelExpansionChanged(float expansion, boolean tracking) {
         // We don't want to translate the bounce when:
@@ -198,6 +192,7 @@
                 mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
             }
         }
+        mNotificationPanelView.updateLockIcon();
     }
 
     /**
@@ -795,6 +790,10 @@
         setDozing(isDozing);
     }
 
+    public KeyguardBouncer getBouncer() {
+        return mBouncer;
+    }
+
     private static class DismissWithActionRequest {
         final OnDismissAction dismissAction;
         final Runnable cancelAction;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 74c0018..7e45507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.Dependency.MAIN_HANDLER;
-import static com.android.systemui.SysUiServiceProvider.getComponent;
 import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions;
 
 import android.app.ActivityManager;
@@ -32,9 +31,7 @@
 import android.os.AsyncTask;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
@@ -78,27 +75,18 @@
     private static final String TAG = "NotificationClickHandler";
     protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private final AssistManager mAssistManager = Dependency.get(AssistManager.class);
-    private final NotificationGroupManager mGroupManager =
-            Dependency.get(NotificationGroupManager.class);
-    private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
-            (StatusBarRemoteInputCallback) Dependency.get(
-                    NotificationRemoteInputManager.Callback.class);
-    private final NotificationRemoteInputManager mRemoteInputManager =
-            Dependency.get(NotificationRemoteInputManager.class);
-    private final NotificationLockscreenUserManager mLockscreenUserManager =
-            Dependency.get(NotificationLockscreenUserManager.class);
-    private final ShadeController mShadeController = Dependency.get(ShadeController.class);
-    private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
-    private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
-    private final NotificationEntryManager mEntryManager =
-            Dependency.get(NotificationEntryManager.class);
-    private final StatusBarStateController mStatusBarStateController =
-            Dependency.get(StatusBarStateController.class);
-    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
-            Dependency.get(NotificationInterruptionStateProvider.class);
-    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
-
+    private final AssistManager mAssistManager;
+    private final NotificationGroupManager mGroupManager;
+    private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback;
+    private final NotificationRemoteInputManager mRemoteInputManager;
+    private final NotificationLockscreenUserManager mLockscreenUserManager;
+    private final ShadeController mShadeController;
+    private final KeyguardMonitor mKeyguardMonitor;
+    private final ActivityStarter mActivityStarter;
+    private final NotificationEntryManager mEntryManager;
+    private final StatusBarStateController mStatusBarStateController;
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+    private final MetricsLogger mMetricsLogger;
     private final Context mContext;
     private final NotificationPanelView mNotificationPanel;
     private final NotificationPresenter mPresenter;
@@ -113,29 +101,55 @@
     private boolean mIsCollapsingToShowActivityOverLockscreen;
 
     public StatusBarNotificationActivityStarter(Context context,
+            CommandQueue commandQueue,
+            AssistManager assistManager,
             NotificationPanelView panel,
             NotificationPresenter presenter,
+            NotificationEntryManager entryManager,
             HeadsUpManagerPhone headsUpManager,
-            ActivityLaunchAnimator activityLaunchAnimator) {
+            ActivityStarter activityStarter,
+            ActivityLaunchAnimator activityLaunchAnimator,
+            IStatusBarService statusBarService,
+            StatusBarStateController statusBarStateController,
+            KeyguardManager keyguardManager,
+            IDreamManager dreamManager,
+            NotificationRemoteInputManager remoteInputManager,
+            StatusBarRemoteInputCallback remoteInputCallback,
+            NotificationGroupManager groupManager,
+            NotificationLockscreenUserManager lockscreenUserManager,
+            ShadeController shadeController,
+            KeyguardMonitor keyguardMonitor,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            MetricsLogger metricsLogger,
+            LockPatternUtils lockPatternUtils) {
         mContext = context;
         mNotificationPanel = panel;
         mPresenter = presenter;
-        mLockPatternUtils = new LockPatternUtils(context);
         mHeadsUpManager = headsUpManager;
-        mKeyguardManager = context.getSystemService(KeyguardManager.class);
         mActivityLaunchAnimator = activityLaunchAnimator;
-        mBarService = IStatusBarService.Stub.asInterface(
-                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        mCommandQueue = getComponent(context, CommandQueue.class);
-        mDreamManager = IDreamManager.Stub.asInterface(
-                ServiceManager.checkService(DreamService.DREAM_SERVICE));
-
+        mBarService = statusBarService;
+        mCommandQueue = commandQueue;
+        mKeyguardManager = keyguardManager;
+        mDreamManager = dreamManager;
+        mRemoteInputManager = remoteInputManager;
+        mLockscreenUserManager = lockscreenUserManager;
+        mShadeController = shadeController;
+        mKeyguardMonitor = keyguardMonitor;
+        mActivityStarter = activityStarter;
+        mEntryManager = entryManager;
+        mStatusBarStateController = statusBarStateController;
+        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+        mMetricsLogger = metricsLogger;
+        mAssistManager = assistManager;
+        mGroupManager = groupManager;
+        mLockPatternUtils = lockPatternUtils;
         mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onPendingEntryAdded(NotificationEntry entry) {
                 handleFullScreenIntent(entry);
             }
         });
+        mStatusBarRemoteInputCallback = remoteInputCallback;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 024404d..1e05983 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -66,7 +66,6 @@
     private int mTouchDownX;
     private int mTouchDownY;
     private boolean mIsVertical;
-    private boolean mSupportsLongpress = true;
     private AudioManager mAudioManager;
     private boolean mGestureAborted;
     private boolean mLongClicked;
@@ -83,7 +82,7 @@
                     // Just an old-fashioned ImageView
                     performLongClick();
                     mLongClicked = true;
-                } else if (mSupportsLongpress) {
+                } else {
                     sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
                     sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
                     mLongClicked = true;
@@ -104,7 +103,6 @@
 
         mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, KEYCODE_UNKNOWN);
 
-        mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
         mPlaySounds = a.getBoolean(R.styleable.KeyButtonView_playSound, true);
 
         TypedValue value = new TypedValue();
@@ -166,7 +164,7 @@
         super.onInitializeAccessibilityNodeInfo(info);
         if (mCode != KEYCODE_UNKNOWN) {
             info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null));
-            if (mSupportsLongpress || isLongClickable()) {
+            if (isLongClickable()) {
                 info.addAction(
                         new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null));
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index aba2377..01498e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -29,6 +29,25 @@
     long getKeyguardFadingAwayDelay();
     long calculateGoingToFullShadeDelay();
 
+    default boolean isDeviceInteractive() {
+        return false;
+    }
+
+    default void setLaunchTransitionFadingAway(boolean b) {
+    }
+
+    default void notifyKeyguardGoingAway(boolean b) {
+    }
+
+    default void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
+    }
+
+    default void notifyKeyguardDoneFading() {
+    }
+
+    default void notifyKeyguardState(boolean showing, boolean methodSecure, boolean occluded) {
+    }
+
     interface Callback {
         void onKeyguardShowingChanged();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index d3164a0..c8f389e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -474,8 +474,8 @@
     private MobileIconGroup getNr5GIconGroup() {
         if (mServiceState == null) return null;
 
-        int nrStatus = mServiceState.getNrStatus();
-        if (nrStatus == NetworkRegistrationInfo.NR_STATUS_CONNECTED) {
+        int nrState = mServiceState.getNrState();
+        if (nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
             // Check if the NR 5G is using millimeter wave and the icon is config.
             if (mServiceState.getNrFrequencyRange() == ServiceState.FREQUENCY_RANGE_MMWAVE) {
                 if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED_MMWAVE)) {
@@ -488,11 +488,11 @@
             if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED)) {
                 return mConfig.nr5GIconMap.get(Config.NR_CONNECTED);
             }
-        } else if (nrStatus == NetworkRegistrationInfo.NR_STATUS_NOT_RESTRICTED) {
+        } else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) {
             if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED)) {
                 return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED);
             }
-        } else if (nrStatus == NetworkRegistrationInfo.NR_STATUS_RESTRICTED) {
+        } else if (nrState == NetworkRegistrationInfo.NR_STATE_RESTRICTED) {
             if (mConfig.nr5GIconMap.containsKey(Config.NR_RESTRICTED)) {
                 return mConfig.nr5GIconMap.get(Config.NR_RESTRICTED);
             }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 4e9d892..63b6673 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -44,6 +44,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -66,6 +67,9 @@
     private IActivityManager mActivityManager;
     @Mock
     private DozeParameters mDozeParameters;
+    @Mock
+    private ConfigurationController mConfigurationController;
+
     private FrameLayout mStatusBarView;
     @Captor
     private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
@@ -97,6 +101,7 @@
         mStatusBarView = new FrameLayout(mContext);
         mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
 
+
         // Bubbles get added to status bar window view
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
                 mActivityManager, mDozeParameters);
@@ -115,7 +120,7 @@
 
         mBubbleData = new BubbleData();
         mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController,
-                mBubbleData);
+                mBubbleData, mConfigurationController);
         mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
         mBubbleController.setExpandListener(mBubbleExpandListener);
 
@@ -331,8 +336,9 @@
     static class TestableBubbleController extends BubbleController {
         // Let's assume surfaces can be synchronized immediately.
         TestableBubbleController(Context context,
-                StatusBarWindowController statusBarWindowController, BubbleData data) {
-            super(context, statusBarWindowController, data, Runnable::run);
+                StatusBarWindowController statusBarWindowController, BubbleData data,
+                ConfigurationController configurationController) {
+            super(context, statusBarWindowController, data, Runnable::run, configurationController);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index dd26368..c2f55e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -41,6 +41,7 @@
 
     private CommandQueue mCommandQueue;
     private Callbacks mCallbacks;
+    private static final int SECONDARY_DISPLAY = 1;
 
     @Before
     public void setup() {
@@ -68,7 +69,6 @@
         verify(mCallbacks).removeIcon(eq(slot));
     }
 
-    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testDisable() {
         int state1 = 14;
@@ -79,6 +79,15 @@
     }
 
     @Test
+    public void testDisableForSecondaryDisplay() {
+        int state1 = 14;
+        int state2 = 42;
+        mCommandQueue.disable(SECONDARY_DISPLAY, state1, state2);
+        waitForIdleSync();
+        verify(mCallbacks).disable(eq(SECONDARY_DISPLAY), eq(state1), eq(state2), eq(true));
+    }
+
+    @Test
     public void testExpandNotifications() {
         mCommandQueue.animateExpandNotificationsPanel();
         waitForIdleSync();
@@ -100,7 +109,6 @@
         verify(mCallbacks).animateExpandSettingsPanel(eq(panel));
     }
 
-    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testSetSystemUiVisibility() {
         Rect r = new Rect();
@@ -110,7 +118,15 @@
                 eq(null), eq(r));
     }
 
-    // TODO(b/117478341): add test case for multi-display
+    @Test
+    public void testSetSystemUiVisibilityForSecondaryDisplay() {
+        Rect r = new Rect();
+        mCommandQueue.setSystemUiVisibility(SECONDARY_DISPLAY, 1, 2, 3, 4, null, r);
+        waitForIdleSync();
+        verify(mCallbacks).setSystemUiVisibility(eq(SECONDARY_DISPLAY), eq(1), eq(2), eq(3), eq(4),
+                eq(null), eq(r));
+    }
+
     @Test
     public void testTopAppWindowChanged() {
         mCommandQueue.topAppWindowChanged(DEFAULT_DISPLAY, true);
@@ -118,7 +134,13 @@
         verify(mCallbacks).topAppWindowChanged(eq(DEFAULT_DISPLAY), eq(true));
     }
 
-    // TODO(b/117478341): add test case for multi-display
+    @Test
+    public void testTopAppWindowChangedForSecondaryDisplay() {
+        mCommandQueue.topAppWindowChanged(SECONDARY_DISPLAY, true);
+        waitForIdleSync();
+        verify(mCallbacks).topAppWindowChanged(eq(SECONDARY_DISPLAY), eq(true));
+    }
+
     @Test
     public void testShowImeButton() {
         mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true);
@@ -128,6 +150,14 @@
     }
 
     @Test
+    public void testShowImeButtonForSecondaryDisplay() {
+        mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true);
+        waitForIdleSync();
+        verify(mCallbacks).setImeWindowStatus(
+                eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true));
+    }
+
+    @Test
     public void testShowRecentApps() {
         mCommandQueue.showRecentApps(true);
         waitForIdleSync();
@@ -176,7 +206,6 @@
         verify(mCallbacks).toggleKeyboardShortcutsMenu(eq(1));
     }
 
-    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testSetWindowState() {
         mCommandQueue.setWindowState(DEFAULT_DISPLAY, 1, 2);
@@ -185,13 +214,19 @@
     }
 
     @Test
+    public void testSetWindowStateForSecondaryDisplay() {
+        mCommandQueue.setWindowState(SECONDARY_DISPLAY, 1, 2);
+        waitForIdleSync();
+        verify(mCallbacks).setWindowState(eq(SECONDARY_DISPLAY), eq(1), eq(2));
+    }
+
+    @Test
     public void testScreenPinRequest() {
         mCommandQueue.showScreenPinningRequest(1);
         waitForIdleSync();
         verify(mCallbacks).showScreenPinningRequest(eq(1));
     }
 
-    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testAppTransitionPending() {
         mCommandQueue.appTransitionPending(DEFAULT_DISPLAY);
@@ -199,7 +234,13 @@
         verify(mCallbacks).appTransitionPending(eq(DEFAULT_DISPLAY), eq(false));
     }
 
-    // TODO(b/117478341): add test case for multi-display
+    @Test
+    public void testAppTransitionPendingForSecondaryDisplay() {
+        mCommandQueue.appTransitionPending(SECONDARY_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionPending(eq(SECONDARY_DISPLAY), eq(false));
+    }
+
     @Test
     public void testAppTransitionCancelled() {
         mCommandQueue.appTransitionCancelled(DEFAULT_DISPLAY);
@@ -207,7 +248,13 @@
         verify(mCallbacks).appTransitionCancelled(eq(DEFAULT_DISPLAY));
     }
 
-    // TODO(b/117478341): add test case for multi-display
+    @Test
+    public void testAppTransitionCancelledForSecondaryDisplay() {
+        mCommandQueue.appTransitionCancelled(SECONDARY_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionCancelled(eq(SECONDARY_DISPLAY));
+    }
+
     @Test
     public void testAppTransitionStarting() {
         mCommandQueue.appTransitionStarting(DEFAULT_DISPLAY, 1, 2);
@@ -216,7 +263,14 @@
                 eq(DEFAULT_DISPLAY), eq(1L), eq(2L), eq(false));
     }
 
-    // TODO(b/117478341): add test case for multi-display
+    @Test
+    public void testAppTransitionStartingForSecondaryDisplay() {
+        mCommandQueue.appTransitionStarting(SECONDARY_DISPLAY, 1, 2);
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionStarting(
+                eq(SECONDARY_DISPLAY), eq(1L), eq(2L), eq(false));
+    }
+
     @Test
     public void testAppTransitionFinished() {
         mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY);
@@ -225,6 +279,13 @@
     }
 
     @Test
+    public void testAppTransitionFinishedForSecondaryDisplay() {
+        mCommandQueue.appTransitionFinished(SECONDARY_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionFinished(eq(SECONDARY_DISPLAY));
+    }
+
+    @Test
     public void testAssistDisclosure() {
         mCommandQueue.showAssistDisclosure();
         waitForIdleSync();
@@ -290,4 +351,25 @@
         waitForIdleSync();
         verify(mCallbacks).handleSystemKey(eq(1));
     }
+
+    @Test
+    public void testOnDisplayReady() {
+        mCommandQueue.onDisplayReady(DEFAULT_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).onDisplayReady(eq(DEFAULT_DISPLAY));
+    }
+
+    @Test
+    public void testOnDisplayReadyForSecondaryDisplay() {
+        mCommandQueue.onDisplayReady(SECONDARY_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).onDisplayReady(eq(SECONDARY_DISPLAY));
+    }
+
+    @Test
+    public void testOnDisplayRemoved() {
+        mCommandQueue.onDisplayRemoved(SECONDARY_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).onDisplayRemoved(eq(SECONDARY_DISPLAY));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
new file mode 100644
index 0000000..34a726d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
@@ -0,0 +1,243 @@
+/*
+ * 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;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.NavigationBarFragment;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest NavigationBarControllerTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class NavigationBarControllerTest extends SysuiTestCase {
+
+    private NavigationBarController mNavigationBarController;
+    private Display mDisplay;
+    private NavigationBarFragment mDefaultNavBar;
+    private NavigationBarFragment mSecondaryNavBar;
+
+    private static final int SECONDARY_DISPLAY = 1;
+
+    @Before
+    public void setUp() {
+        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+        mNavigationBarController = spy(
+                new NavigationBarController(mContext, Dependency.get(Dependency.MAIN_HANDLER)));
+        initializeNavigationBars();
+    }
+
+    private void initializeNavigationBars() {
+        mNavigationBarController.mNavigationBars = mock(SparseArray.class);
+        mDefaultNavBar = mock(NavigationBarFragment.class);
+        mDefaultNavBar.mDisplayId = DEFAULT_DISPLAY;
+        doReturn(mDefaultNavBar)
+                .when(mNavigationBarController.mNavigationBars).get(DEFAULT_DISPLAY);
+
+        mSecondaryNavBar = mock(NavigationBarFragment.class);
+        mSecondaryNavBar.mDisplayId = SECONDARY_DISPLAY;
+        doReturn(mSecondaryNavBar)
+                .when(mNavigationBarController.mNavigationBars).get(SECONDARY_DISPLAY);
+    }
+
+    @After
+    public void tearDown() {
+        mNavigationBarController = null;
+        mDisplay = null;
+        mDefaultNavBar = null;
+        mSecondaryNavBar = null;
+    }
+
+    @Test
+    public void testCreateNavigationBarsIncludeDefaultTrue() {
+        initializeDisplayManager();
+        doNothing().when(mNavigationBarController).createNavigationBar(any());
+
+        mNavigationBarController.createNavigationBars(true);
+
+        verify(mNavigationBarController).createNavigationBar(any(Display.class));
+    }
+
+    @Test
+    public void testCreateNavigationBarsIncludeDefaultFalse() {
+        initializeDisplayManager();
+        doNothing().when(mNavigationBarController).createNavigationBar(any());
+
+        mNavigationBarController.createNavigationBars(false);
+
+        verify(mNavigationBarController, never()).createNavigationBar(any());
+    }
+
+    private void initializeDisplayManager() {
+        DisplayManager displayManager = mock(DisplayManager.class);
+        mDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
+        Display[] displays = {mDisplay};
+        when(displayManager.getDisplays()).thenReturn(displays);
+        mContext.addMockSystemService(Context.DISPLAY_SERVICE, displayManager);
+    }
+
+    // Tests if NPE occurs when call checkNavBarModes() with invalid display.
+    @Test
+    public void testCheckNavBarModesWithInvalidDisplay() {
+        mNavigationBarController.checkNavBarModes(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testCheckNavBarModesWithDefaultDisplay() {
+        doNothing().when(mDefaultNavBar).checkNavBarModes();
+
+        mNavigationBarController.checkNavBarModes(DEFAULT_DISPLAY);
+
+        verify(mDefaultNavBar).checkNavBarModes();
+    }
+
+    @Test
+    public void testCheckNavBarModesWithSecondaryDisplay() {
+        doNothing().when(mSecondaryNavBar).checkNavBarModes();
+
+        mNavigationBarController.checkNavBarModes(SECONDARY_DISPLAY);
+
+        verify(mSecondaryNavBar).checkNavBarModes();
+    }
+
+    // Tests if NPE occurs when call finishBarAnimations() with invalid display.
+    @Test
+    public void testFinishBarAnimationsWithInvalidDisplay() {
+        mNavigationBarController.finishBarAnimations(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testFinishBarAnimationsWithDefaultDisplay() {
+        doNothing().when(mDefaultNavBar).finishBarAnimations();
+
+        mNavigationBarController.finishBarAnimations(DEFAULT_DISPLAY);
+
+        verify(mDefaultNavBar).finishBarAnimations();
+    }
+
+    @Test
+    public void testFinishBarAnimationsWithSecondaryDisplay() {
+        doNothing().when(mSecondaryNavBar).finishBarAnimations();
+
+        mNavigationBarController.finishBarAnimations(SECONDARY_DISPLAY);
+
+        verify(mSecondaryNavBar).finishBarAnimations();
+    }
+
+    // Tests if NPE occurs when call touchAutoDim() with invalid display.
+    @Test
+    public void testTouchAutoDimWithInvalidDisplay() {
+        mNavigationBarController.touchAutoDim(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testTouchAutoDimWithDefaultDisplay() {
+        doNothing().when(mDefaultNavBar).touchAutoDim();
+
+        mNavigationBarController.touchAutoDim(DEFAULT_DISPLAY);
+
+        verify(mDefaultNavBar).touchAutoDim();
+    }
+
+    @Test
+    public void testTouchAutoDimWithSecondaryDisplay() {
+        doNothing().when(mSecondaryNavBar).touchAutoDim();
+
+        mNavigationBarController.touchAutoDim(SECONDARY_DISPLAY);
+
+        verify(mSecondaryNavBar).touchAutoDim();
+    }
+
+    // Tests if NPE occurs when call transitionTo() with invalid display.
+    @Test
+    public void testTransitionToWithInvalidDisplay() {
+        mNavigationBarController.transitionTo(INVALID_DISPLAY, 3, true);
+    }
+
+    @Test
+    public void testTransitionToWithDefaultDisplay() {
+        doNothing().when(mDefaultNavBar).transitionTo(anyInt(), anyBoolean());
+
+        mNavigationBarController.transitionTo(DEFAULT_DISPLAY, 3, true);
+
+        verify(mDefaultNavBar).transitionTo(eq(3), eq(true));
+    }
+
+    @Test
+    public void testTransitionToWithSecondaryDisplay() {
+        doNothing().when(mSecondaryNavBar).transitionTo(anyInt(), anyBoolean());
+
+        mNavigationBarController.transitionTo(SECONDARY_DISPLAY, 3, true);
+
+        verify(mSecondaryNavBar).transitionTo(eq(3), eq(true));
+    }
+
+    // Tests if NPE occurs when call disableAnimationsDuringHide() with invalid display.
+    @Test
+    public void testDisableAnimationsDuringHideWithInvalidDisplay() {
+        mNavigationBarController.disableAnimationsDuringHide(INVALID_DISPLAY, 500L);
+    }
+
+    @Test
+    public void testDisableAnimationsDuringHideWithDefaultDisplay() {
+        doNothing().when(mDefaultNavBar).disableAnimationsDuringHide(anyLong());
+
+        mNavigationBarController.disableAnimationsDuringHide(DEFAULT_DISPLAY, 500L);
+
+        verify(mDefaultNavBar).disableAnimationsDuringHide(eq(500L));
+    }
+
+    @Test
+    public void testDisableAnimationsDuringHideWithSecondaryDisplay() {
+        doNothing().when(mSecondaryNavBar).disableAnimationsDuringHide(anyLong());
+
+        mNavigationBarController.disableAnimationsDuringHide(SECONDARY_DISPLAY, 500L);
+
+        verify(mSecondaryNavBar).disableAnimationsDuringHide(eq(500L));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
new file mode 100644
index 0000000..1b34a75
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.phone;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest AutoHideControllerTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class AutoHideControllerTest extends SysuiTestCase {
+
+    private AutoHideController mAutoHideController;
+
+    private static final int FULL_MASK = 0xffffffff;
+
+    @Before
+    public void setUp() {
+        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+        mAutoHideController =
+                spy(new AutoHideController(mContext, Dependency.get(Dependency.MAIN_HANDLER)));
+        mAutoHideController.mDisplayId = DEFAULT_DISPLAY;
+        mAutoHideController.mSystemUiVisibility = View.VISIBLE;
+    }
+
+    @After
+    public void tearDown() {
+        mAutoHideController = null;
+    }
+
+    @Test
+    public void testSetSystemUiVisibilityEarlyReturnWithDifferentDisplay() {
+        mAutoHideController.setSystemUiVisibility(1, 1, 2, 3, 4, null, new Rect());
+
+        verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt());
+    }
+
+    @Test
+    public void testSetSystemUiVisibilityEarlyReturnWithSameVisibility() {
+        mAutoHideController
+                .setSystemUiVisibility(DEFAULT_DISPLAY, View.VISIBLE, 2, 3, 4, null, new Rect());
+
+        verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt());
+    }
+
+    // Test if status bar unhide status doesn't change without status bar.
+    @Test
+    public void testSetSystemUiVisibilityWithoutStatusBar() {
+        doReturn(false).when(mAutoHideController).hasStatusBar();
+        int expectedStatus = View.STATUS_BAR_UNHIDE;
+        mAutoHideController.mSystemUiVisibility =
+                View.SYSTEM_UI_FLAG_FULLSCREEN | View.STATUS_BAR_UNHIDE;
+
+        mAutoHideController.setSystemUiVisibility(
+                DEFAULT_DISPLAY, expectedStatus, 2, 3, FULL_MASK, null, new Rect());
+
+        assertEquals("System UI visibility should not be changed",
+                expectedStatus, mAutoHideController.mSystemUiVisibility);
+        verify(mAutoHideController, times(1)).notifySystemUiVisibilityChanged(eq(expectedStatus));
+    }
+
+    @Test
+    public void testSetSystemUiVisibilityWithVisChanged() {
+        doReturn(true).when(mAutoHideController).hasStatusBar();
+        doReturn(true).when(mAutoHideController).hasNavigationBar();
+        mAutoHideController.mSystemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
+                | View.STATUS_BAR_UNHIDE
+                | View.NAVIGATION_BAR_UNHIDE;
+
+        mAutoHideController.setSystemUiVisibility(
+                DEFAULT_DISPLAY, View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE,
+                2, 3, FULL_MASK, null, new Rect());
+
+        int expectedStatus = View.VISIBLE;
+        assertEquals(expectedStatus, mAutoHideController.mSystemUiVisibility);
+        verify(mAutoHideController).notifySystemUiVisibilityChanged(eq(expectedStatus));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 1ded6c9..cb5612d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -75,7 +75,6 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.appops.AppOpsControllerImpl;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.classifier.FalsingManager;
@@ -112,7 +111,6 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
 import org.junit.Before;
@@ -161,7 +159,6 @@
     @Mock private NotificationPresenter mNotificationPresenter;
     @Mock
     private NotificationEntryListener mEntryListener;
-    @Mock private BubbleController mBubbleController;
     @Mock
     private NotificationFilter mNotificationFilter;
     @Mock
@@ -192,8 +189,8 @@
                 mViewHierarchyManager);
         mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
         mDependency.injectTestDependency(NotificationListener.class, mNotificationListener);
-        mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class));
-        mDependency.injectTestDependency(AppOpsController.class, mock(AppOpsControllerImpl.class));
+        mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitor.class));
+        mDependency.injectTestDependency(AppOpsController.class, mock(AppOpsController.class));
         mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController);
         mDependency.injectTestDependency(DeviceProvisionedController.class,
                 mDeviceProvisionedController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 5786796..96fad21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -151,7 +151,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_LTE);
         ServiceState ss = Mockito.mock(ServiceState.class);
-        doReturn(NetworkRegistrationInfo.NR_STATUS_CONNECTED).when(ss).getNrStatus();
+        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState();
         doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange();
         mPhoneStateListener.onServiceStateChanged(ss);
 
@@ -165,7 +165,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_LTE);
         ServiceState ss = Mockito.mock(ServiceState.class);
-        doReturn(NetworkRegistrationInfo.NR_STATUS_CONNECTED).when(ss).getNrStatus();
+        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState();
         doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(ss).getNrFrequencyRange();
         mPhoneStateListener.onServiceStateChanged(ss);
 
@@ -179,7 +179,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_LTE);
         ServiceState ss = Mockito.mock(ServiceState.class);
-        doReturn(NetworkRegistrationInfo.NR_STATUS_RESTRICTED).when(ss).getNrStatus();
+        doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(ss).getNrState();
         mPhoneStateListener.onServiceStateChanged(mServiceState);
 
         verifyDataIndicators(TelephonyIcons.ICON_LTE);
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index f106228..c5c4b5a 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7120,6 +7120,10 @@
     // Open: Settings > Special App Access > Do not disturb control for app
     ZEN_ACCESS_DETAIL = 1692;
 
+    // OPEN: Settings > Face > Remove face
+    // OS: Q
+    DIALOG_FACE_REMOVE = 1693;
+
     // ---- 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 0d17f22..1bcc888 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1880,6 +1880,33 @@
     PROBE_STATUS_FAILURE = 3;
   }
 
+  // Codes for cellular data network type
+  enum CellularDataNetworkType {
+    // Unknown network
+    NETWORK_TYPE_UNKNOWN = 0;
+
+    // GSM network
+    NETWORK_TYPE_GSM = 1;
+
+    // CDMA network
+    NETWORK_TYPE_CDMA = 2;
+
+    // CDMA EVDO network
+    NETWORK_TYPE_EVDO_0 = 3;
+
+    // WCDMA network
+    NETWORK_TYPE_UMTS = 4;
+
+    // TDSCDMA network
+    NETWORK_TYPE_TD_SCDMA = 5;
+
+    // LTE network
+    NETWORK_TYPE_LTE = 6;
+
+    // NR network
+    NETWORK_TYPE_NR = 7;
+  }
+
   // Absolute milliseconds from device boot when these stats were sampled
   optional int64 time_stamp_ms = 1;
 
@@ -1971,6 +1998,20 @@
   // Whether current entry is for the same BSSID on the same frequency compared
   // to last entry
   optional bool is_same_bssid_and_freq = 29;
+
+  // Cellular data network type currently in use on the device for data transmission
+  optional CellularDataNetworkType cellular_data_network_type = 30;
+
+  // Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp,
+  // CDMA: Rssi, EVDO: Rssi, GSM: Rssi
+  optional int32 cellular_signal_strength_dbm = 31;
+
+  // Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid,
+  // CDMA: Ecio, EVDO: SNR, GSM: invalid */
+  optional int32 cellular_signal_strength_db = 32;
+
+  // Whether the primary registered cell of current entry is same as that of previous entry
+  optional bool is_same_registered_cell = 33;
 }
 
 message WifiUsabilityStats {
diff --git a/services/Android.bp b/services/Android.bp
index 31385ed..567efac 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -26,7 +26,6 @@
         "services.contentsuggestions",
         "services.coverage",
         "services.devicepolicy",
-        "services.ipmemorystore",
         "services.midi",
         "services.net",
         "services.print",
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 65e31f3..1e3f20e 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -809,13 +809,9 @@
 
         // Announce the end of the gesture recognition.
         sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
+        // Don't announce the end of a the touch interaction if users didn't lift their fingers.
         if (interactionEnd) {
-            // Announce the end of a the touch interaction.
             sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
-        } else {
-            // If gesture detection is end, but user doesn't release the finger, announce the
-            // transition to exploration state.
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
         }
 
         mExitGestureDetectionModeDelayed.cancel();
@@ -1151,10 +1147,7 @@
         public void run() {
             // Announce the end of gesture recognition.
             sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
-            // Clearing puts is in touch exploration state with a finger already
-            // down, so announce the transition to exploration state.
             clear();
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index aaba1ed..3c17ac3 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.autofill;
 
+import static com.android.server.autofill.Helper.sDebug;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -26,6 +28,7 @@
 import android.content.pm.ServiceInfo;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.autofill.augmented.AugmentedAutofillService;
@@ -142,6 +145,16 @@
         scheduleAsyncRequest((s) -> s.onDestroyAllFillWindowsRequest());
     }
 
+    private void dispatchOnFillTimeout(@NonNull ICancellationSignal cancellation) {
+        mHandler.post(() -> {
+            try {
+                cancellation.cancel();
+            } catch (RemoteException e) {
+                Slog.w(mTag, "Error calling cancellation signal: " + e);
+            }
+        });
+    }
+
     // TODO(b/123100811): inline into PendingAutofillRequest if it doesn't have any other subclass
     private abstract static class MyPendingRequest
             extends PendingRequest<RemoteAugmentedAutofillService, IAugmentedAutofillService> {
@@ -161,6 +174,7 @@
         private final int mTaskId;
         private final long mRequestTime = SystemClock.elapsedRealtime();
         private final @NonNull IFillCallback mCallback;
+        private ICancellationSignal mCancellation;
 
         protected PendingAutofillRequest(@NonNull RemoteAugmentedAutofillService service,
                 int sessionId, @NonNull IAutoFillManagerClient client, int taskId,
@@ -178,11 +192,55 @@
                     if (!finish()) return;
                     // NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
                 }
+
+                @Override
+                public void onCancellable(ICancellationSignal cancellation) {
+                    synchronized (mLock) {
+                        final boolean cancelled;
+                        synchronized (mLock) {
+                            mCancellation = cancellation;
+                            cancelled = isCancelledLocked();
+                        }
+                        if (cancelled) {
+                            try {
+                                cancellation.cancel();
+                            } catch (RemoteException e) {
+                                Slog.e(mTag, "Error requesting a cancellation", e);
+                            }
+                        }
+                    }
+                }
+
+                @Override
+                public boolean isCompleted() {
+                    return isRequestCompleted();
+                }
+
+                @Override
+                public void cancel() {
+                    synchronized (mLock) {
+                        final boolean cancelled = isCancelledLocked();
+                        final ICancellationSignal cancellation = mCancellation;
+                        if (!cancelled) {
+                            try {
+                                cancellation.cancel();
+                            } catch (RemoteException e) {
+                                Slog.e(mTag, "Error requesting a cancellation", e);
+                            }
+                        }
+                    }
+                }
             };
         }
 
         @Override
         public void run() {
+            synchronized (mLock) {
+                if (isCancelledLocked()) {
+                    if (sDebug) Slog.d(mTag, "run() called after canceled");
+                    return;
+                }
+            }
             final RemoteAugmentedAutofillService remoteService = getService();
             if (remoteService == null) return;
 
@@ -215,8 +273,33 @@
             Slog.w(TAG, "PendingAutofillRequest timed out (" + remoteService.mRequestTimeoutMs
                     + "ms) for " + remoteService);
             // NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
+            final ICancellationSignal cancellation;
+            synchronized (mLock) {
+                cancellation = mCancellation;
+            }
+            if (cancellation != null) {
+                remoteService.dispatchOnFillTimeout(cancellation);
+            }
             finish();
         }
+
+        @Override
+        public boolean cancel() {
+            if (!super.cancel()) return false;
+
+            final ICancellationSignal cancellation;
+            synchronized (mLock) {
+                cancellation = mCancellation;
+            }
+            if (cancellation != null) {
+                try {
+                    cancellation.cancel();
+                } catch (RemoteException e) {
+                    Slog.e(mTag, "Error cancelling a fill request", e);
+                }
+            }
+            return true;
+        }
     }
 
     public interface RemoteAugmentedAutofillServiceCallbacks
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index a400cc3..3d918fc 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -83,6 +83,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 import android.util.StatsLog;
 import android.util.TimeUtils;
@@ -195,6 +196,7 @@
     private final Injector mInjector;
     int mBroadcastRefCount = 0;
     PowerManager.WakeLock mWakeLock;
+    SparseIntArray mAlarmsPerUid = new SparseIntArray();
     ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
     ArrayList<InFlight> mInFlight = new ArrayList<>();
     private final ArrayList<AlarmManagerInternal.InFlightListener> mInFlightListeners =
@@ -393,6 +395,8 @@
         @VisibleForTesting
         static final String KEY_LISTENER_TIMEOUT = "listener_timeout";
         @VisibleForTesting
+        static final String KEY_MAX_ALARMS_PER_UID = "max_alarms_per_uid";
+        @VisibleForTesting
         static final String KEY_APP_STANDBY_QUOTAS_ENABLED = "app_standby_quotas_enabled";
         private static final String KEY_APP_STANDBY_WINDOW = "app_standby_window";
         @VisibleForTesting
@@ -420,6 +424,7 @@
         private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;
         private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
         private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
+        private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
         private static final boolean DEFAULT_APP_STANDBY_QUOTAS_ENABLED = true;
         private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000;  // 1 hr
         /**
@@ -461,6 +466,8 @@
 
         // Direct alarm listener callback timeout
         public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT;
+        public int MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID;
+
         public boolean APP_STANDBY_QUOTAS_ENABLED = DEFAULT_APP_STANDBY_QUOTAS_ENABLED;
 
         public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW;
@@ -549,6 +556,15 @@
                     APP_STANDBY_QUOTAS[i] = mParser.getInt(KEYS_APP_STANDBY_QUOTAS[i],
                             Math.min(APP_STANDBY_QUOTAS[i - 1], DEFAULT_APP_STANDBY_QUOTAS[i]));
                 }
+
+                MAX_ALARMS_PER_UID = mParser.getInt(KEY_MAX_ALARMS_PER_UID,
+                        DEFAULT_MAX_ALARMS_PER_UID);
+                if (MAX_ALARMS_PER_UID < DEFAULT_MAX_ALARMS_PER_UID) {
+                    Slog.w(TAG, "Cannot set " + KEY_MAX_ALARMS_PER_UID + " lower than "
+                            + DEFAULT_MAX_ALARMS_PER_UID);
+                    MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID;
+                }
+
                 updateAllowWhileIdleWhitelistDurationLocked();
             }
         }
@@ -590,6 +606,9 @@
             TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw);
             pw.println();
 
+            pw.print(KEY_MAX_ALARMS_PER_UID); pw.print("=");
+            pw.println(MAX_ALARMS_PER_UID);
+
             for (int i = 0; i < KEYS_APP_STANDBY_DELAY.length; i++) {
                 pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("=");
                 TimeUtils.formatDuration(APP_STANDBY_MIN_DELAYS[i], pw);
@@ -671,12 +690,6 @@
 
         final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
 
-        Batch() {
-            start = 0;
-            end = Long.MAX_VALUE;
-            flags = 0;
-        }
-
         Batch(Alarm seed) {
             start = seed.whenElapsed;
             end = clampPositive(seed.maxWhenElapsed);
@@ -728,11 +741,16 @@
             return newStart;
         }
 
+        /**
+         * Remove an alarm from this batch.
+         * <p> <b> Should be used only while re-ordering the alarm within the service </b> as it
+         * does not update {@link #mAlarmsPerUid}
+         */
         boolean remove(Alarm alarm) {
-            return remove(a -> (a == alarm));
+            return remove(a -> (a == alarm), true);
         }
 
-        boolean remove(Predicate<Alarm> predicate) {
+        boolean remove(Predicate<Alarm> predicate, boolean reOrdering) {
             boolean didRemove = false;
             long newStart = 0;  // recalculate endpoints as we go
             long newEnd = Long.MAX_VALUE;
@@ -741,6 +759,9 @@
                 Alarm alarm = alarms.get(i);
                 if (predicate.test(alarm)) {
                     alarms.remove(i);
+                    if (!reOrdering) {
+                        decrementAlarmCount(alarm.uid);
+                    }
                     didRemove = true;
                     if (alarm.alarmClock != null) {
                         mNextAlarmClockMayChange = true;
@@ -1734,6 +1755,15 @@
                         + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
                         + " interval=" + interval + " flags=0x" + Integer.toHexString(flags));
             }
+            if (mAlarmsPerUid.get(callingUid, 0) >= mConstants.MAX_ALARMS_PER_UID) {
+                final String errorMsg =
+                        "Maximum limit of concurrent alarms " + mConstants.MAX_ALARMS_PER_UID
+                                + " reached for uid: " + UserHandle.formatUid(callingUid)
+                                + ", callingPackage: " + callingPackage;
+                // STOPSHIP (b/128866264): Just to catch breakages. Remove before final release.
+                Slog.wtf(TAG, errorMsg);
+                throw new UnsupportedOperationException(errorMsg);
+            }
             setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
                     interval, operation, directReceiver, listenerTag, flags, true, workSource,
                     alarmClock, callingUid, callingPackage);
@@ -1756,6 +1786,7 @@
         } catch (RemoteException e) {
         }
         removeLocked(operation, directReceiver);
+        incrementAlarmCount(a.uid);
         setImplLocked(a, false, doValidate);
     }
 
@@ -2197,7 +2228,6 @@
                             ? sdf.format(new Date(nowRTC - (nowELAPSED - time)))
                             : "-");
                 } while (i != mNextTickHistory);
-                pw.println();
             }
 
             SystemServiceManager ssm = LocalServices.getService(SystemServiceManager.class);
@@ -2305,6 +2335,18 @@
             if (!blocked) {
                 pw.println("    none");
             }
+            pw.println();
+            pw.print("  Pending alarms per uid: [");
+            for (int i = 0; i < mAlarmsPerUid.size(); i++) {
+                if (i > 0) {
+                    pw.print(", ");
+                }
+                UserHandle.formatUid(pw, mAlarmsPerUid.keyAt(i));
+                pw.print(":");
+                pw.print(mAlarmsPerUid.valueAt(i));
+            }
+            pw.println("]");
+            pw.println();
 
             mAppWakeupHistory.dump(pw, "  ", nowELAPSED);
 
@@ -3046,7 +3088,7 @@
         final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver);
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(whichAlarms);
+            didRemove |= b.remove(whichAlarms, false);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
@@ -3098,7 +3140,7 @@
         final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid;
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(whichAlarms);
+            didRemove |= b.remove(whichAlarms, false);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
@@ -3145,7 +3187,7 @@
         final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches);
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(whichAlarms);
+            didRemove |= b.remove(whichAlarms, false);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
@@ -3183,6 +3225,7 @@
         }
     }
 
+    // Only called for ephemeral apps
     void removeForStoppedLocked(final int uid) {
         if (uid == Process.SYSTEM_UID) {
             Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for UID=" + uid);
@@ -3200,7 +3243,7 @@
         };
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(whichAlarms);
+            didRemove |= b.remove(whichAlarms, false);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
@@ -3237,7 +3280,7 @@
                 (Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle;
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(whichAlarms);
+            didRemove |= b.remove(whichAlarms, false);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
@@ -3407,8 +3450,7 @@
         return mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
     }
 
-    boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
-            final long nowRTC) {
+    boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) {
         boolean hasWakeup = false;
         // batches are temporally sorted, so we need only pull from the
         // start of the list until we either empty it or hit a batch
@@ -3984,7 +4026,7 @@
                         }
 
                         mLastTrigger = nowELAPSED;
-                        boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+                        boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED);
                         if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
                             // if there are no wakeup alarms and the screen is off, we can
                             // delay what we have so far until the future.
@@ -4108,9 +4150,8 @@
                 case ALARM_EVENT: {
                     ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
                     synchronized (mLock) {
-                        final long nowRTC = mInjector.getCurrentTimeMillis();
                         final long nowELAPSED = mInjector.getElapsedRealtime();
-                        triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+                        triggerAlarmsLocked(triggerList, nowELAPSED);
                         updateNextAlarmClockLocked();
                     }
 
@@ -4719,7 +4760,7 @@
                 mAppWakeupHistory.recordAlarmForPackage(alarm.sourcePackage,
                         UserHandle.getUserId(alarm.creatorUid), nowELAPSED);
             }
-
+            decrementAlarmCount(alarm.uid);
             final BroadcastStats bs = inflight.mBroadcastStats;
             bs.count++;
             if (bs.nesting == 0) {
@@ -4747,6 +4788,27 @@
         }
     }
 
+    private void incrementAlarmCount(int uid) {
+        final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
+        if (uidIndex >= 0) {
+            mAlarmsPerUid.setValueAt(uidIndex, mAlarmsPerUid.valueAt(uidIndex) + 1);
+        } else {
+            mAlarmsPerUid.put(uid, 1);
+        }
+    }
+
+    private void decrementAlarmCount(int uid) {
+        final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
+        if (uidIndex >= 0) {
+            final int newCount = mAlarmsPerUid.valueAt(uidIndex) - 1;
+            if (newCount > 0) {
+                mAlarmsPerUid.setValueAt(uidIndex, newCount);
+            } else {
+                mAlarmsPerUid.removeAt(uidIndex);
+            }
+        }
+    }
+
     private class ShellCmd extends ShellCommand {
 
         IAlarmManager getBinderService() {
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 3ab3c34..833faa6 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -115,7 +115,8 @@
  *
  * Test: atest com.android.server.DeviceIdleControllerTest
  *
- * Current idling state machine (as of Android 9 Pie). This can be visualized using Graphviz:
+ * Current idling state machine (as of Android Q). This can be visualized using Graphviz:
+   <pre>
 
    digraph {
      subgraph deep {
@@ -259,6 +260,7 @@
        ]
      }
    }
+   </pre>
  */
 public class DeviceIdleController extends SystemService
         implements AnyMotionDetector.DeviceIdleCallback {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 7fab2b96..6ef5b54 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -102,6 +102,7 @@
 import com.android.server.location.GeofenceProxy;
 import com.android.server.location.GnssBatchingProvider;
 import com.android.server.location.GnssLocationProvider;
+import com.android.server.location.GnssMeasurementCorrectionsProvider;
 import com.android.server.location.GnssMeasurementsProvider;
 import com.android.server.location.GnssNavigationMessageProvider;
 import com.android.server.location.GnssStatusListenerHelper;
@@ -195,6 +196,7 @@
     private PassiveProvider mPassiveProvider;  // track passive provider for special cases
     private LocationBlacklist mBlacklist;
     private GnssMeasurementsProvider mGnssMeasurementsProvider;
+    private GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
     private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
     @GuardedBy("mLock")
     private String mLocationControllerExtraPackage;
@@ -309,9 +311,13 @@
                 AppOpsManager.WATCH_FOREGROUND_CHANGES,
                 new AppOpsManager.OnOpChangedInternalListener() {
                     public void onOpChanged(int op, String packageName) {
-                        synchronized (mLock) {
-                            onAppOpChangedLocked();
-                        }
+                        // onOpChanged invoked on ui thread, move to our thread to reduce risk of
+                        // blocking ui thread
+                        mHandler.post(() -> {
+                            synchronized (mLock) {
+                                onAppOpChangedLocked();
+                            }
+                        });
                     }
                 });
         mPackageManager.addOnPermissionsChangeListener(
@@ -757,6 +763,8 @@
             mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
             mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
             mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
+            mGnssMeasurementCorrectionsProvider =
+                    gnssProvider.getGnssMeasurementCorrectionsProvider();
             mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
             mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
         }
@@ -2921,22 +2929,28 @@
         mContext.enforceCallingPermission(
                 android.Manifest.permission.LOCATION_HARDWARE,
                 "Location Hardware permission not granted to inject GNSS measurement corrections.");
-        if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
+        if (!hasGnssPermissions(packageName)) {
             Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
-        } else {
-            mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
+            return;
         }
+        if (mGnssMeasurementCorrectionsProvider == null) {
+            Slog.e(TAG, "Can not inject GNSS corrections. GNSS measurement corrections provider "
+                    + "not available.");
+            return;
+        }
+        mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(
+                measurementCorrections);
     }
 
     @Override
     public int getGnssCapabilities(String packageName) {
         mContext.enforceCallingPermission(
                 android.Manifest.permission.LOCATION_HARDWARE,
-                "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
-        if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
+                "Location Hardware permission not granted to obtain GNSS chipset capabilities.");
+        if (!hasGnssPermissions(packageName) || mGnssMeasurementCorrectionsProvider == null) {
             return -1;
         }
-        return mGnssMeasurementsProvider.getGnssCapabilities();
+        return mGnssMeasurementCorrectionsProvider.getCapabilities();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 5582ad7..d3298b9 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -62,6 +62,7 @@
 import android.net.RouteInfo;
 import android.net.TetherStatsParcel;
 import android.net.UidRange;
+import android.net.UidRangeParcel;
 import android.net.util.NetdService;
 import android.os.BatteryStats;
 import android.os.Binder;
@@ -80,6 +81,7 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.telephony.DataConnectionRealTimeInfo;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -1028,6 +1030,46 @@
         }
     }
 
+    /**
+     * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname.
+     */
+    private static InterfaceConfigurationParcel toStableParcel(InterfaceConfiguration cfg,
+            String iface) {
+        InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel();
+        cfgParcel.ifName = iface;
+        String hwAddr = cfg.getHardwareAddress();
+        if (!TextUtils.isEmpty(hwAddr)) {
+            cfgParcel.hwAddr = hwAddr;
+        } else {
+            cfgParcel.hwAddr = "";
+        }
+        cfgParcel.ipv4Addr = cfg.getLinkAddress().getAddress().getHostAddress();
+        cfgParcel.prefixLength = cfg.getLinkAddress().getPrefixLength();
+        ArrayList<String> flags = new ArrayList<>();
+        for (String flag : cfg.getFlags()) {
+            flags.add(flag);
+        }
+        cfgParcel.flags = flags.toArray(new String[0]);
+
+        return cfgParcel;
+    }
+
+    /**
+     * Construct InterfaceConfiguration from InterfaceConfigurationParcel.
+     */
+    public static InterfaceConfiguration fromStableParcel(InterfaceConfigurationParcel p) {
+        InterfaceConfiguration cfg = new InterfaceConfiguration();
+        cfg.setHardwareAddress(p.hwAddr);
+
+        final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr);
+        cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength));
+        for (String flag : p.flags) {
+            cfg.setFlag(flag);
+        }
+
+        return cfg;
+    }
+
     @Override
     public InterfaceConfiguration getInterfaceConfig(String iface) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -1039,7 +1081,7 @@
         }
 
         try {
-            final InterfaceConfiguration cfg = InterfaceConfiguration.fromParcel(result);
+            final InterfaceConfiguration cfg = fromStableParcel(result);
             return cfg;
         } catch (IllegalArgumentException iae) {
             throw new IllegalStateException("Invalid InterfaceConfigurationParcel", iae);
@@ -1054,7 +1096,7 @@
             throw new IllegalStateException("Null LinkAddress given");
         }
 
-        final InterfaceConfigurationParcel cfgParcel = cfg.toParcel(iface);
+        final InterfaceConfigurationParcel cfgParcel = toStableParcel(cfg, iface);
 
         try {
             mNetdService.interfaceSetCfg(cfgParcel);
@@ -1718,12 +1760,27 @@
         }
     }
 
+    private static UidRangeParcel makeUidRangeParcel(int start, int stop) {
+        UidRangeParcel range = new UidRangeParcel();
+        range.start = start;
+        range.stop = stop;
+        return range;
+    }
+
+    private static UidRangeParcel[] toStableParcels(UidRange[] ranges) {
+        UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.length];
+        for (int i = 0; i < ranges.length; i++) {
+            stableRanges[i] = makeUidRangeParcel(ranges[i].start, ranges[i].stop);
+        }
+        return stableRanges;
+    }
+
     @Override
     public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
             throws ServiceSpecificException {
         mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
         try {
-            mNetdService.networkRejectNonSecureVpn(add, uidRanges);
+            mNetdService.networkRejectNonSecureVpn(add, toStableParcels(uidRanges));
         } catch (ServiceSpecificException e) {
             Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
                     + ": netd command failed", e);
@@ -1892,7 +1949,7 @@
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mNetdService.networkAddUidRanges(netId, ranges);
+            mNetdService.networkAddUidRanges(netId, toStableParcels(ranges));
         } catch (RemoteException | ServiceSpecificException e) {
             throw new IllegalStateException(e);
         }
@@ -1902,7 +1959,7 @@
     public void removeVpnUidRanges(int netId, UidRange[] ranges) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
-            mNetdService.networkRemoveUidRanges(netId, ranges);
+            mNetdService.networkRemoveUidRanges(netId, toStableParcels(ranges));
         } catch (RemoteException | ServiceSpecificException e) {
             throw new IllegalStateException(e);
         }
@@ -1940,7 +1997,7 @@
 
     private void closeSocketsForFirewallChainLocked(int chain, String chainName) {
         // UID ranges to close sockets on.
-        UidRange[] ranges;
+        UidRangeParcel[] ranges;
         // UID ranges whose sockets we won't touch.
         int[] exemptUids;
 
@@ -1948,10 +2005,10 @@
         if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
         if (getFirewallType(chain) == FIREWALL_WHITELIST) {
             // Close all sockets on all non-system UIDs...
-            ranges = new UidRange[] {
+            ranges = new UidRangeParcel[] {
                 // TODO: is there a better way of finding all existing users? If so, we could
                 // specify their ranges here.
-                new UidRange(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
+                makeUidRangeParcel(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
             };
             // ... except for the UIDs that have allow rules.
             synchronized (mRulesLock) {
@@ -1978,11 +2035,11 @@
             // Close sockets for every UID that has a deny rule...
             synchronized (mRulesLock) {
                 final SparseIntArray rules = getUidFirewallRulesLR(chain);
-                ranges = new UidRange[rules.size()];
+                ranges = new UidRangeParcel[rules.size()];
                 for (int i = 0; i < ranges.length; i++) {
                     if (rules.valueAt(i) == FIREWALL_RULE_DENY) {
                         int uid = rules.keyAt(i);
-                        ranges[numUids] = new UidRange(uid, uid);
+                        ranges[numUids] = makeUidRangeParcel(uid, uid);
                         numUids++;
                     }
                 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index f416110..19b0bf7 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3741,6 +3741,7 @@
                         case "com.facebook.katana": // b/123996076
                         case "jp.naver.line.android": // b/124767356
                         case "com.mxtech.videoplayer.ad": // b/124531483
+                        case "com.whatsapp": // b/124766614
                             return Zygote.MOUNT_EXTERNAL_LEGACY;
                     }
                 }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index d6fdbe3..26896f5 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -625,6 +625,11 @@
                 r.callingPackage = callingPackage;
                 r.callerUid = Binder.getCallingUid();
                 r.callerPid = Binder.getCallingPid();
+                if (r.subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && r.subId != subId) {
+                    throw new IllegalArgumentException(
+                            "PhoneStateListener cannot concurrently listen on multiple " +
+                                    "subscriptions. Previously registered on subId: " + r.subId);
+                }
                 // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
                 // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
                 if (!SubscriptionManager.isValidSubscriptionId(subId)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c7f18d0..97cc756 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1273,11 +1273,13 @@
 
     static final class ProcessChangeItem {
         static final int CHANGE_ACTIVITIES = 1<<0;
+        static final int CHANGE_FOREGROUND_SERVICES = 1<<1;
         int changes;
         int uid;
         int pid;
         int processState;
         boolean foregroundActivities;
+        int foregroundServiceTypes;
     }
 
     static final class UidObserverRegistration {
@@ -3080,6 +3082,13 @@
                             observer.onForegroundActivitiesChanged(item.pid, item.uid,
                                     item.foregroundActivities);
                         }
+                        if ((item.changes & ProcessChangeItem.CHANGE_FOREGROUND_SERVICES) != 0) {
+                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                                    "FOREGROUND SERVICES CHANGED pid=" + item.pid + " uid="
+                                            + item.uid + ": " + item.foregroundServiceTypes);
+                            observer.onForegroundServicesChanged(item.pid, item.uid,
+                                    item.foregroundServiceTypes);
+                        }
                     }
                 } catch (RemoteException e) {
                 }
@@ -3094,6 +3103,47 @@
         }
     }
 
+    @GuardedBy("this")
+    ProcessChangeItem enqueueProcessChangeItemLocked(int uid, int pid) {
+        int i = mPendingProcessChanges.size()-1;
+        ActivityManagerService.ProcessChangeItem item = null;
+        while (i >= 0) {
+            item = mPendingProcessChanges.get(i);
+            if (item.pid == pid) {
+                if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                        "Re-using existing item: " + item);
+                break;
+            }
+            i--;
+        }
+
+        if (i < 0) {
+            // No existing item in pending changes; need a new one.
+            final int NA = mAvailProcessChanges.size();
+            if (NA > 0) {
+                item = mAvailProcessChanges.remove(NA-1);
+                if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                        "Retrieving available item: " + item);
+            } else {
+                item = new ActivityManagerService.ProcessChangeItem();
+                if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                        "Allocating new item: " + item);
+            }
+            item.changes = 0;
+            item.pid = pid;
+            item.uid = uid;
+            if (mPendingProcessChanges.size() == 0) {
+                if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                        "*** Enqueueing dispatch processes changed!");
+                mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
+                        .sendToTarget();
+            }
+            mPendingProcessChanges.add(item);
+        }
+
+        return item;
+    }
+
     private void dispatchProcessDied(int pid, int uid) {
         int i = mProcessObservers.beginBroadcast();
         while (i > 0) {
@@ -16276,11 +16326,12 @@
     @GuardedBy("this")
     final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
             int fgServiceTypes, boolean oomAdj) {
+        proc.setHasForegroundServices(isForeground, fgServiceTypes);
+
         final boolean hasFgServiceLocationType =
                 (fgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
         if (isForeground != proc.hasForegroundServices()
                 || proc.hasLocationForegroundServices() != hasFgServiceLocationType) {
-            proc.setHasForegroundServices(isForeground, fgServiceTypes);
             ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
                     proc.info.uid);
             if (isForeground) {
@@ -16309,6 +16360,13 @@
                 updateOomAdjLocked();
             }
         }
+
+        if (proc.getForegroundServiceTypes() != fgServiceTypes) {
+            proc.setReportedForegroundServiceTypes(fgServiceTypes);
+            ProcessChangeItem item = enqueueProcessChangeItemLocked(proc.info.uid, proc.pid);
+            item.changes = ProcessChangeItem.CHANGE_FOREGROUND_SERVICES;
+            item.foregroundServiceTypes = fgServiceTypes;
+        }
     }
 
     // TODO(b/111541062): This method is only used for updating OOM adjustments. We need to update
@@ -18102,6 +18160,34 @@
         public void prepareForPossibleShutdown() {
             ActivityManagerService.this.prepareForPossibleShutdown();
         }
+
+        @Override
+        public boolean hasRunningForegroundService(int uid, int foregroundServicetype) {
+            synchronized (ActivityManagerService.this) {
+                for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) {
+                    final ProcessRecord pr = mProcessList.mLruProcesses.get(i);
+                    if (pr.uid != uid) {
+                        continue;
+                    }
+
+                    if ((pr.getForegroundServiceTypes() & foregroundServicetype) != 0) {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        @Override
+        public void registerProcessObserver(IProcessObserver processObserver) {
+            ActivityManagerService.this.registerProcessObserver(processObserver);
+        }
+
+        @Override
+        public void unregisterProcessObserver(IProcessObserver processObserver) {
+            ActivityManagerService.this.unregisterProcessObserver(processObserver);
+        }
     }
 
     long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index 438538f..9216343 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -230,11 +230,8 @@
      */
     @GuardedBy("mPhenotypeFlagLock")
     private void updateUseCompaction() {
-        String useCompactionFlag =
-                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                    KEY_USE_COMPACTION);
-        mUseCompaction = TextUtils.isEmpty(useCompactionFlag)
-                ? DEFAULT_USE_COMPACTION : Boolean.parseBoolean(useCompactionFlag);
+        mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
         if (mUseCompaction && !mCompactionThread.isAlive()) {
             mCompactionThread.start();
             mCompactionHandler = new MemCompactionHandler();
@@ -243,28 +240,11 @@
 
     @GuardedBy("mPhenotypeFlagLock")
     private void updateCompactionActions() {
-        String compactAction1Flag =
-                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                        KEY_COMPACT_ACTION_1);
-        String compactAction2Flag =
-                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                        KEY_COMPACT_ACTION_2);
+        int compactAction1 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1);
 
-        int compactAction1 = DEFAULT_COMPACT_ACTION_1;
-        try {
-            compactAction1 = TextUtils.isEmpty(compactAction1Flag)
-                    ? DEFAULT_COMPACT_ACTION_1 : Integer.parseInt(compactAction1Flag);
-        } catch (NumberFormatException e) {
-          // Do nothing, leave default.
-        }
-
-        int compactAction2 = DEFAULT_COMPACT_ACTION_2;
-        try {
-            compactAction2 = TextUtils.isEmpty(compactAction2Flag)
-                    ? DEFAULT_COMPACT_ACTION_2 : Integer.parseInt(compactAction2Flag);
-        } catch (NumberFormatException e) {
-            // Do nothing, leave default.
-        }
+        int compactAction2 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2);
 
         mCompactActionSome = compactActionIntToString(compactAction1);
         mCompactActionFull = compactActionIntToString(compactAction2);
@@ -312,14 +292,8 @@
 
     @GuardedBy("mPhenotypeFlagLock")
     private void updateStatsdSampleRate() {
-        String sampleRateFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                KEY_COMPACT_STATSD_SAMPLE_RATE);
-        try {
-            mStatsdSampleRate = TextUtils.isEmpty(sampleRateFlag)
-                    ? DEFAULT_STATSD_SAMPLE_RATE : Float.parseFloat(sampleRateFlag);
-        } catch (NumberFormatException e) {
-            mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
-        }
+        mStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_COMPACT_STATSD_SAMPLE_RATE, DEFAULT_STATSD_SAMPLE_RATE);
         mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate));
     }
 
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index 09df7e20..d8d6528 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -24,6 +24,7 @@
 
 import android.app.ActivityTaskManager;
 import android.app.AppOpsManager;
+import android.app.IActivityTaskManager;
 import android.app.IAssistDataReceiver;
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -33,6 +34,7 @@
 import android.view.IWindowManager;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 
 import java.io.PrintWriter;
@@ -50,6 +52,8 @@
     public static final String KEY_RECEIVER_EXTRA_INDEX = "index";
 
     private IWindowManager mWindowManager;
+    @VisibleForTesting
+    public IActivityTaskManager mActivityTaskManager;
     private Context mContext;
     private AppOpsManager mAppOpsManager;
 
@@ -128,6 +132,7 @@
         mCallbacks = callbacks;
         mCallbacksLock = callbacksLock;
         mWindowManager = windowManager;
+        mActivityTaskManager = ActivityTaskManager.getService();
         mContext = context;
         mAppOpsManager = appOpsManager;
         mRequestStructureAppOps = requestStructureAppOps;
@@ -195,8 +200,7 @@
         // Ensure that the current activity supports assist data
         boolean isAssistDataAllowed = false;
         try {
-            isAssistDataAllowed =
-                    ActivityTaskManager.getService().isAssistDataAllowedOnCurrentActivity();
+            isAssistDataAllowed = mActivityTaskManager.isAssistDataAllowedOnCurrentActivity();
         } catch (RemoteException e) {
             // Should never happen
         }
@@ -222,9 +226,9 @@
                         receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
                         receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, numActivities);
                         boolean result = requestAutofillData
-                                ? ActivityTaskManager.getService().requestAutofillData(this,
+                                ? mActivityTaskManager.requestAutofillData(this,
                                         receiverExtras, topActivity, 0 /* flags */)
-                                : ActivityTaskManager.getService().requestAssistContextExtras(
+                                : mActivityTaskManager.requestAssistContextExtras(
                                         ASSIST_CONTEXT_FULL, this, receiverExtras, topActivity,
                                         /* focused= */ i == 0, /* newSessionId= */ i == 0);
                         if (result) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 9056f76..aa03de1 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -38,7 +38,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
 import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG;
-import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESSES_CHANGED_UI_MSG;
 import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
 import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
 import static com.android.server.am.ActivityManagerService.TAG_LRU;
@@ -1921,41 +1920,9 @@
         if (changes != 0) {
             if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                     "Changes in " + app + ": " + changes);
-            int i = mService.mPendingProcessChanges.size()-1;
-            ActivityManagerService.ProcessChangeItem item = null;
-            while (i >= 0) {
-                item = mService.mPendingProcessChanges.get(i);
-                if (item.pid == app.pid) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "Re-using existing item: " + item);
-                    break;
-                }
-                i--;
-            }
-            if (i < 0) {
-                // No existing item in pending changes; need a new one.
-                final int NA = mService.mAvailProcessChanges.size();
-                if (NA > 0) {
-                    item = mService.mAvailProcessChanges.remove(NA-1);
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "Retrieving available item: " + item);
-                } else {
-                    item = new ActivityManagerService.ProcessChangeItem();
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "Allocating new item: " + item);
-                }
-                item.changes = 0;
-                item.pid = app.pid;
-                item.uid = app.info.uid;
-                if (mService.mPendingProcessChanges.size() == 0) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "*** Enqueueing dispatch processes changed!");
-                    mService.mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
-                            .sendToTarget();
-                }
-                mService.mPendingProcessChanges.add(item);
-            }
-            item.changes |= changes;
+            ActivityManagerService.ProcessChangeItem item =
+                    mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
+            item.changes = changes;
             item.foregroundActivities = app.repForegroundActivities;
             if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                     "Item " + Integer.toHexString(System.identityHashCode(item))
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 51b1ae1..17b244c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -174,6 +174,7 @@
     boolean hasStartedServices; // Are there any started services running in this process?
     private boolean mHasForegroundServices; // Running any services that are foreground?
     private int mFgServiceTypes; // Type of foreground service, if there is a foreground service.
+    private int mRepFgServiceTypes; // Last reported foreground service types.
     private boolean mHasForegroundActivities; // Running any activities that are foreground?
     boolean repForegroundActivities; // Last reported foreground activities.
     boolean systemNoUi;         // This is a system process, but not currently showing UI.
@@ -1079,6 +1080,18 @@
                 && (mFgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
     }
 
+    int getForegroundServiceTypes() {
+        return mHasForegroundServices ? mFgServiceTypes : 0;
+    }
+
+    int getReportedForegroundServiceTypes() {
+        return mRepFgServiceTypes;
+    }
+
+    void setReportedForegroundServiceTypes(int foregroundServiceTypes) {
+        mRepFgServiceTypes = foregroundServiceTypes;
+    }
+
     void setHasForegroundActivities(boolean hasForegroundActivities) {
         mHasForegroundActivities = hasForegroundActivities;
         mWindowProcessController.setHasForegroundActivities(hasForegroundActivities);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 029c3fb..07c9cca 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -389,14 +389,14 @@
      * Step from {@link UserState#STATE_RUNNING_LOCKED} to
      * {@link UserState#STATE_RUNNING_UNLOCKING}.
      */
-    private void finishUserUnlocking(final UserState uss) {
+    private boolean finishUserUnlocking(final UserState uss) {
         final int userId = uss.mHandle.getIdentifier();
         // Only keep marching forward if user is actually unlocked
-        if (!StorageManager.isUserKeyUnlocked(userId)) return;
+        if (!StorageManager.isUserKeyUnlocked(userId)) return false;
         synchronized (mLock) {
             // Do not proceed if unexpected state or a stale user
             if (mStartedUsers.get(userId) != uss || uss.state != STATE_RUNNING_LOCKED) {
-                return;
+                return false;
             }
         }
         uss.mUnlockProgress.start();
@@ -427,6 +427,7 @@
             mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
                     .sendToTarget();
         });
+        return true;
     }
 
     /**
@@ -1209,7 +1210,10 @@
             return false;
         }
 
-        finishUserUnlocking(uss);
+        if (!finishUserUnlocking(uss)) {
+            notifyFinished(userId, listener);
+            return false;
+        }
 
         // We just unlocked a user, so let's now attempt to unlock any
         // managed profiles under that user.
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 7da848c..4e0380d 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -59,6 +59,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 
+import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
 /**
@@ -103,6 +104,7 @@
 
     @Override
     public void onStart() {
+        publishBinderService(Context.ATTENTION_SERVICE, new BinderService());
         publishLocalService(AttentionManagerInternal.class, new LocalService());
     }
 
@@ -329,17 +331,15 @@
         return null;
     }
 
-    private void dumpInternal(PrintWriter pw) {
-        if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
-        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-        ipw.println("Attention Manager Service (dumpsys attention)\n");
+    private void dumpInternal(IndentingPrintWriter ipw) {
+        ipw.println("Attention Manager Service (dumpsys attention) state:\n");
 
         ipw.printPair("context", mContext);
-        pw.println();
+        ipw.println();
         synchronized (mLock) {
             int size = mUserStates.size();
             ipw.print("Number user states: ");
-            pw.println(size);
+            ipw.println(size);
             if (size > 0) {
                 ipw.increaseIndent();
                 for (int i = 0; i < size; i++) {
@@ -591,4 +591,15 @@
             }
         }
     }
+
+    private final class BinderService extends Binder {
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) {
+                return;
+            }
+
+            dumpInternal(new IndentingPrintWriter(pw, "  "));
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 69a9e7e..b774647 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -170,8 +170,15 @@
         }
     }
 
-    /*package*/ void setSpeakerphoneOn(boolean on, String eventSource) {
+    /**
+     * Turns speakerphone on/off
+     * @param on
+     * @param eventSource for logging purposes
+     * @return true if speakerphone state changed
+     */
+    /*package*/ boolean setSpeakerphoneOn(boolean on, String eventSource) {
         synchronized (mDeviceStateLock) {
+            final boolean wasOn = isSpeakerphoneOn();
             if (on) {
                 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
                     setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
@@ -183,6 +190,7 @@
 
             mForcedUseForCommExt = mForcedUseForComm;
             setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+            return (wasOn != isSpeakerphoneOn());
         }
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 68f76ab..a14a638 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3331,7 +3331,11 @@
         final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
                 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
                 .append(Binder.getCallingPid()).toString();
-        mDeviceBroker.setSpeakerphoneOn(on, eventSource);
+        final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource);
+        if (stateChanged) {
+            mContext.sendBroadcast(new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
+                    .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
+        }
     }
 
     /** @see AudioManager#isSpeakerphoneOn() */
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index aca02bf..c820841 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -30,6 +30,9 @@
 import android.net.NetworkPolicyManager;
 import android.net.NetworkRequest;
 import android.net.TrafficStats;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.UserHandle;
 import android.text.format.DateUtils;
 import android.util.ArraySet;
@@ -85,8 +88,14 @@
     @GuardedBy("mLock")
     private final ArraySet<Network> mAvailableNetworks = new ArraySet<>();
 
+    private static final int MSG_DATA_SAVER_TOGGLED = 0;
+    private static final int MSG_UID_RULES_CHANGES = 1;
+
+    private final Handler mHandler;
+
     public ConnectivityController(JobSchedulerService service) {
         super(service);
+        mHandler = new CcHandler(mContext.getMainLooper());
 
         mConnManager = mContext.getSystemService(ConnectivityManager.class);
         mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
@@ -545,11 +554,39 @@
 
     private final INetworkPolicyListener mNetPolicyListener = new NetworkPolicyManager.Listener() {
         @Override
+        public void onRestrictBackgroundChanged(boolean restrictBackground) {
+            if (DEBUG) {
+                Slog.v(TAG, "onRestrictBackgroundChanged: " + restrictBackground);
+            }
+            mHandler.obtainMessage(MSG_DATA_SAVER_TOGGLED).sendToTarget();
+        }
+
+        @Override
         public void onUidRulesChanged(int uid, int uidRules) {
             if (DEBUG) {
                 Slog.v(TAG, "onUidRulesChanged: " + uid);
             }
-            updateTrackedJobs(uid, null);
+            mHandler.obtainMessage(MSG_UID_RULES_CHANGES, uid, 0).sendToTarget();
+        }
+    };
+
+    private class CcHandler extends Handler {
+        CcHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            synchronized (mLock) {
+                switch (msg.what) {
+                    case MSG_DATA_SAVER_TOGGLED:
+                        updateTrackedJobs(-1, null);
+                        break;
+                    case MSG_UID_RULES_CHANGES:
+                        updateTrackedJobs(msg.arg1, null);
+                        break;
+                }
+            }
         }
     };
 
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c173d66..8249999 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -166,9 +166,15 @@
     private static final int GPS_CAPABILITY_MSA = 0x0000004;
     private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
     private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
-    private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
+
+    // The following three capability flags are removed in IGnssCallback.hal@2.0 and their values
+    // are marked reserved and not reused in 2.0 to avoid confusion with prior versions.
+    public static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
     public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
-    private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
+    public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
+
+    private static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
+    private static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200;
 
     // The AGPS SUPL mode
     private static final int AGPS_SUPL_MODE_MSA = 0x02;
@@ -333,7 +339,7 @@
     private boolean mStarted;
 
     // capabilities of the GPS engine
-    private int mEngineCapabilities;
+    private volatile int mEngineCapabilities;
 
     // true if XTRA is supported
     private boolean mSupportsXtra;
@@ -372,6 +378,7 @@
     private final LocationExtras mLocationExtras = new LocationExtras();
     private final GnssStatusListenerHelper mGnssStatusListenerHelper;
     private final GnssMeasurementsProvider mGnssMeasurementsProvider;
+    private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
     private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
     private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
     private final LocationChangeListener mFusedLocationListener = new FusedLocationListener();
@@ -437,6 +444,10 @@
         return mGnssMeasurementsProvider;
     }
 
+    public GnssMeasurementCorrectionsProvider getGnssMeasurementCorrectionsProvider() {
+        return mGnssMeasurementCorrectionsProvider;
+    }
+
     public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
         return mGnssNavigationMessageProvider;
     }
@@ -627,6 +638,8 @@
             }
         };
 
+        mGnssMeasurementCorrectionsProvider = new GnssMeasurementCorrectionsProvider(mHandler);
+
         mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mContext, mHandler) {
             @Override
             protected boolean isGpsEnabled() {
@@ -1258,6 +1271,10 @@
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
     }
 
+    public int getGnssCapabilities() {
+        return mEngineCapabilities;
+    }
+
     private boolean hasCapability(int capability) {
         return ((mEngineCapabilities & capability) != 0);
     }
@@ -1467,22 +1484,27 @@
     }
 
     @NativeEntryPoint
-    private void setEngineCapabilities(final int capabilities) {
+    private void setEngineCapabilities(final int capabilities, boolean hasSubHalCapabilityFlags) {
         // send to handler thread for fast native return, and in-order handling
-        mHandler.post(
-                () -> {
-                    mEngineCapabilities = capabilities;
+        mHandler.post(() -> {
+            mEngineCapabilities = capabilities;
 
-                    if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
-                        mNtpTimeHelper.enablePeriodicTimeInjection();
-                        requestUtcTime();
-                    }
+            if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
+                mNtpTimeHelper.enablePeriodicTimeInjection();
+                requestUtcTime();
+            }
 
-                    mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities);
-                    mGnssNavigationMessageProvider.onCapabilitiesUpdated(
-                            hasCapability(GPS_CAPABILITY_NAV_MESSAGES));
-                    restartRequests();
-                });
+            mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities, hasSubHalCapabilityFlags);
+            mGnssNavigationMessageProvider.onCapabilitiesUpdated(capabilities,
+                    hasSubHalCapabilityFlags);
+            restartRequests();
+        });
+    }
+
+    @NativeEntryPoint
+    private void setMeasurementCorrectionsCapabilities(final int capabilities) {
+        mHandler.post(() -> mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(
+                capabilities));
     }
 
     private void restartRequests() {
@@ -2122,7 +2144,23 @@
         if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
         if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
         if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
+        if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) s.append("LOW_POWER_MODE ");
+        if (hasCapability(GPS_CAPABILITY_SATELLITE_BLACKLIST)) s.append("SATELLITE_BLACKLIST ");
         s.append(")\n");
+        if (mGnssGeofenceProvider.isHardwareGeofenceSupported()) {
+            s.append("  hasSubHal=GEOFENCING\n");
+        }
+        if (mGnssMeasurementsProvider.isAvailableInPlatform()) {
+            s.append("  hasSubHal=MEASUREMENTS\n");
+        }
+        if (mGnssNavigationMessageProvider.isAvailableInPlatform()) {
+            s.append("  hasSubHal=NAV_MESSAGES\n");
+        }
+        if (mGnssMeasurementCorrectionsProvider.isAvailableInPlatform()) {
+            s.append("  hasSubHal=MEASUREMENT_CORRECTIONS [");
+            s.append(mGnssMeasurementCorrectionsProvider.toStringCapabilities());
+            s.append("]\n");
+        }
         s.append(mGnssMetrics.dumpGnssMetricsAsText());
         s.append("  native internal state: ").append(native_get_internal_state());
         s.append("\n");
diff --git a/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java
new file mode 100644
index 0000000..2162787
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java
@@ -0,0 +1,149 @@
+/*
+ * 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.server.location;
+
+import android.location.GnssMeasurementCorrections;
+import android.os.Handler;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Manages GNSS measurement corrections.
+ *
+ * <p>Implements the framework side of the GNSS HAL interfaces {@code IMeasurementCorrections.hal}
+ * and {@code IMeasurementCorrectionsCallback.hal).
+ *
+ * @hide
+ */
+public class GnssMeasurementCorrectionsProvider {
+    private static final String TAG = "GnssMeasurementCorrectionsProvider";
+
+    // These must match with the Capabilities enum in IMeasurementCorrectionsCallback.hal.
+    private static final int CAPABILITY_LOS_SATS = 0x0000001;
+    private static final int CAPABILITY_EXCESS_PATH_LENGTH = 0x0000002;
+    private static final int CAPABILITY_REFLECTING_PLANE = 0x0000004;
+
+    private static final int INVALID_CAPABILITIES = 1 << 31;
+
+    private final Handler mHandler;
+    private final GnssMeasurementCorrectionsProviderNative mNative;
+    private volatile int mCapabilities = INVALID_CAPABILITIES;
+
+    GnssMeasurementCorrectionsProvider(Handler handler) {
+        this(handler, new GnssMeasurementCorrectionsProviderNative());
+    }
+
+    @VisibleForTesting
+    GnssMeasurementCorrectionsProvider(Handler handler,
+            GnssMeasurementCorrectionsProviderNative aNative) {
+        mHandler = handler;
+        mNative = aNative;
+    }
+
+    /**
+     * Returns {@code true} if the GNSS HAL implementation supports measurement corrections.
+     */
+    public boolean isAvailableInPlatform() {
+        return mNative.isMeasurementCorrectionsSupported();
+    }
+
+    /**
+     * Injects GNSS measurement corrections into the GNSS chipset.
+     *
+     * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
+     *     measurement corrections to be injected into the GNSS chipset.
+     */
+    public void injectGnssMeasurementCorrections(
+            GnssMeasurementCorrections measurementCorrections) {
+        if (!isCapabilitiesReceived()) {
+            Log.w(TAG, "Failed to inject GNSS measurement corrections. Capabilities "
+                    + "not received yet.");
+            return;
+        }
+        mHandler.post(() -> {
+            if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) {
+                Log.e(TAG, "Failure in injecting GNSS corrections.");
+            }
+        });
+    }
+
+    /** Handle measurement corrections capabilities update from the GNSS HAL implementation. */
+    void onCapabilitiesUpdated(int capabilities) {
+        if (hasCapability(capabilities, CAPABILITY_LOS_SATS) || hasCapability(capabilities,
+                CAPABILITY_EXCESS_PATH_LENGTH)) {
+            mCapabilities = capabilities;
+        } else {
+            Log.e(TAG, "Failed to set capabilities. Received capabilities 0x"
+                    + Integer.toHexString(capabilities) + " does not contain the mandatory "
+                    + "LOS_SATS or the EXCESS_PATH_LENGTH capability.");
+        }
+    }
+
+    /**
+     * Returns the measurement corrections specific capabilities of the GNSS HAL implementation.
+     */
+    public int getCapabilities() {
+        return mCapabilities;
+    }
+
+    /**
+     * Returns the string representation of the GNSS measurement capabilities.
+     */
+    String toStringCapabilities() {
+        final int capabilities = getCapabilities();
+        StringBuilder s = new StringBuilder();
+        s.append("mCapabilities=0x").append(Integer.toHexString(capabilities));
+        s.append(" ( ");
+        if (hasCapability(capabilities, CAPABILITY_LOS_SATS)) {
+            s.append("LOS_SATS ");
+        }
+        if (hasCapability(capabilities, CAPABILITY_EXCESS_PATH_LENGTH)) {
+            s.append("EXCESS_PATH_LENGTH ");
+        }
+        if (hasCapability(capabilities, CAPABILITY_REFLECTING_PLANE)) {
+            s.append("REFLECTING_PLANE ");
+        }
+        s.append(")");
+        return s.toString();
+    }
+
+    private boolean isCapabilitiesReceived() {
+        return mCapabilities != INVALID_CAPABILITIES;
+    }
+
+    private static  boolean hasCapability(int halCapabilities, int capability) {
+        return (halCapabilities & capability) != 0;
+    }
+
+    @VisibleForTesting
+    static class GnssMeasurementCorrectionsProviderNative {
+        public boolean isMeasurementCorrectionsSupported() {
+            return native_is_measurement_corrections_supported();
+        }
+
+        public boolean injectGnssMeasurementCorrections(
+                GnssMeasurementCorrections measurementCorrections) {
+            return native_inject_gnss_measurement_corrections(measurementCorrections);
+        }
+    }
+
+    private static native boolean native_is_measurement_corrections_supported();
+
+    private static native boolean native_inject_gnss_measurement_corrections(
+            GnssMeasurementCorrections measurementCorrections);
+}
diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
index 1fc7192..844735a 100644
--- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
@@ -11,13 +11,12 @@
  * 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
+ * limitations under the License.
  */
 
 package com.android.server.location;
 
 import android.content.Context;
-import android.location.GnssMeasurementCorrections;
 import android.location.GnssMeasurementsEvent;
 import android.location.IGnssMeasurementsListener;
 import android.os.Handler;
@@ -42,7 +41,6 @@
 
     private boolean mIsCollectionStarted;
     private boolean mEnableFullTracking;
-    private int mGnssEngineCapabilities;
 
     protected GnssMeasurementsProvider(Context context, Handler handler) {
         this(context, handler, new GnssMeasurementProviderNative());
@@ -87,21 +85,6 @@
         }
     }
 
-    /**
-     * Injects GNSS measurement corrections into the GNSS chipset.
-     *
-     * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
-     *     measurement corrections to be injected into the GNSS chipset.
-     */
-    public void injectGnssMeasurementCorrections(
-            GnssMeasurementCorrections measurementCorrections) {
-        mHandler.post(() -> {
-            if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) {
-                Log.e(TAG, "Failure in injecting GNSS corrections.");
-            }
-        });
-    }
-
     @Override
     protected void unregisterFromService() {
         boolean stopped = mNative.stopMeasurementCollection();
@@ -121,20 +104,20 @@
         });
     }
 
-    /** Updates the framework about the capabilities of the GNSS chipset */
-    public void onCapabilitiesUpdated(int capabilities) {
-        mGnssEngineCapabilities = capabilities;
-        boolean isGnssMeasurementsSupported =
-                (capabilities & GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS) != 0;
+    /** Handle GNSS capabilities update from the GNSS HAL implementation. */
+    public void onCapabilitiesUpdated(int capabilities, boolean hasSubHalCapabilityFlags) {
+        // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+        // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+        // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+        // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+        // which explicitly set the sub-HAL capability bits must continue to work.
+        final boolean isGnssMeasurementsSupported = hasSubHalCapabilityFlags
+                ? (capabilities & GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS) != 0
+                : mNative.isMeasurementSupported();
         setSupported(isGnssMeasurementsSupported);
         updateResult();
     }
 
-    /** Obtains the GNSS engine capabilities. */
-    public int getGnssCapabilities() {
-        return mGnssEngineCapabilities;
-    }
-
     public void onGpsEnabledChanged() {
         tryUpdateRegistrationWithService();
         updateResult();
@@ -195,11 +178,6 @@
         public boolean stopMeasurementCollection() {
             return native_stop_measurement_collection();
         }
-
-        public boolean injectGnssMeasurementCorrections(
-                GnssMeasurementCorrections measurementCorrections) {
-            return native_inject_gnss_measurement_corrections(measurementCorrections);
-        }
     }
 
     private static native boolean native_is_measurement_supported();
@@ -207,7 +185,4 @@
     private static native boolean native_start_measurement_collection(boolean enableFullTracking);
 
     private static native boolean native_stop_measurement_collection();
-
-    private static native boolean native_inject_gnss_measurement_corrections(
-            GnssMeasurementCorrections measurementCorrections);
 }
diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
index 80a3f9b..7e8b599 100644
--- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
@@ -11,7 +11,7 @@
  * 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
+ * limitations under the License.
  */
 
 package com.android.server.location;
@@ -51,7 +51,6 @@
         mNative = aNative;
     }
 
-    // TODO(b/37460011): Use this with death recovery logic.
     void resumeIfStarted() {
         if (DEBUG) {
             Log.d(TAG, "resumeIfStarted");
@@ -92,7 +91,16 @@
         );
     }
 
-    public void onCapabilitiesUpdated(boolean isGnssNavigationMessageSupported) {
+    /** Handle GNSS capabilities update from the GNSS HAL implementation */
+    public void onCapabilitiesUpdated(int capabilities, boolean hasSubHalCapabilityFlags) {
+        // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+        // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+        // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+        // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+        // which explicitly set the sub-HAL capability bits must continue to work.
+        final boolean isGnssNavigationMessageSupported = hasSubHalCapabilityFlags
+                ? (capabilities & GnssLocationProvider.GPS_CAPABILITY_NAV_MESSAGES) != 0
+                : mNative.isNavigationMessageSupported();
         setSupported(isGnssNavigationMessageSupported);
         updateResult();
     }
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 192ad6d..7b691b4 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -28,6 +28,7 @@
 import android.media.Rating;
 import android.media.VolumeProvider;
 import android.media.session.ControllerCallbackLink;
+import android.media.session.ISession;
 import android.media.session.ISessionController;
 import android.media.session.MediaController;
 import android.media.session.MediaController.PlaybackInfo;
@@ -35,7 +36,6 @@
 import android.media.session.MediaSession.QueueItem;
 import android.media.session.PlaybackState;
 import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -45,6 +45,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SystemClock;
 import android.util.Log;
@@ -81,7 +82,7 @@
     private final Bundle mSessionInfo;
     private final ControllerStub mController;
     private final MediaSession.Token mSessionToken;
-    private final SessionLink mSession;
+    private final SessionStub mSession;
     private final SessionCb mSessionCb;
     private final MediaSessionService.ServiceImpl mService;
     private final Context mContext;
@@ -133,7 +134,7 @@
         mSessionInfo = sessionInfo;
         mController = new ControllerStub();
         mSessionToken = new MediaSession.Token(mController);
-        mSession = new SessionLink(new SessionStub());
+        mSession = new SessionStub();
         mSessionCb = new SessionCb(cb);
         mService = service;
         mContext = mService.getContext();
@@ -144,11 +145,11 @@
     }
 
     /**
-     * Get the session link for the {@link MediaSession}.
+     * Get the session binder for the {@link MediaSession}.
      *
-     * @return The session link apps talk to.
+     * @return The session binder apps talk to.
      */
-    public SessionLink getSessionBinder() {
+    public ISession getSessionBinder() {
         return mSession;
     }
 
@@ -818,9 +819,9 @@
         }
     };
 
-    private final class SessionStub extends SessionLink.SessionStub {
+    private final class SessionStub extends ISession.Stub {
         @Override
-        public void destroySession() {
+        public void destroySession() throws RemoteException {
             final long token = Binder.clearCallingIdentity();
             try {
                 mService.destroySession(MediaSessionRecord.this);
@@ -830,18 +831,18 @@
         }
 
         @Override
-        public void sendEvent(String event, Bundle data) {
+        public void sendEvent(String event, Bundle data) throws RemoteException {
             mHandler.post(MessageHandler.MSG_SEND_EVENT, event,
                     data == null ? null : new Bundle(data));
         }
 
         @Override
-        public ISessionController getController() {
+        public ISessionController getController() throws RemoteException {
             return mController;
         }
 
         @Override
-        public void setActive(boolean active) {
+        public void setActive(boolean active) throws RemoteException {
             mIsActive = active;
             final long token = Binder.clearCallingIdentity();
             try {
@@ -853,7 +854,7 @@
         }
 
         @Override
-        public void setFlags(int flags) {
+        public void setFlags(int flags) throws RemoteException {
             if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
                 int pid = Binder.getCallingPid();
                 int uid = Binder.getCallingUid();
@@ -872,7 +873,7 @@
         }
 
         @Override
-        public void setMediaButtonReceiver(PendingIntent pi) {
+        public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException {
             mMediaButtonReceiver = pi;
             final long token = Binder.clearCallingIdentity();
             try {
@@ -883,12 +884,13 @@
         }
 
         @Override
-        public void setLaunchPendingIntent(PendingIntent pi) {
+        public void setLaunchPendingIntent(PendingIntent pi) throws RemoteException {
             mLaunchIntent = pi;
         }
 
         @Override
-        public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) {
+        public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription)
+                throws RemoteException {
             synchronized (mLock) {
                 MediaMetadata temp = metadata == null ? null : new MediaMetadata.Builder(metadata)
                         .build();
@@ -906,7 +908,7 @@
         }
 
         @Override
-        public void setPlaybackState(PlaybackState state) {
+        public void setPlaybackState(PlaybackState state) throws RemoteException {
             int oldState = mPlaybackState == null
                     ? PlaybackState.STATE_NONE : mPlaybackState.getState();
             int newState = state == null
@@ -924,21 +926,21 @@
         }
 
         @Override
-        public void setQueue(List<QueueItem> queue) {
+        public void setQueue(MediaParceledListSlice queue) throws RemoteException {
             synchronized (mLock) {
-                mQueue = queue;
+                mQueue = queue == null ? null : (List<QueueItem>) queue.getList();
             }
             mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
         }
 
         @Override
-        public void setQueueTitle(CharSequence title) {
+        public void setQueueTitle(CharSequence title) throws RemoteException {
             mQueueTitle = title;
             mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
         }
 
         @Override
-        public void setExtras(Bundle extras) {
+        public void setExtras(Bundle extras) throws RemoteException {
             synchronized (mLock) {
                 mExtras = extras == null ? null : new Bundle(extras);
             }
@@ -946,18 +948,18 @@
         }
 
         @Override
-        public void setRatingType(int type) {
+        public void setRatingType(int type) throws RemoteException {
             mRatingType = type;
         }
 
         @Override
-        public void setCurrentVolume(int volume) {
+        public void setCurrentVolume(int volume) throws RemoteException {
             mCurrentVolume = volume;
             mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
         }
 
         @Override
-        public void setPlaybackToLocal(AudioAttributes attributes) {
+        public void setPlaybackToLocal(AudioAttributes attributes) throws RemoteException {
             boolean typeChanged;
             synchronized (mLock) {
                 typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
@@ -980,7 +982,7 @@
         }
 
         @Override
-        public void setPlaybackToRemote(int control, int max) {
+        public void setPlaybackToRemote(int control, int max) throws RemoteException {
             boolean typeChanged;
             synchronized (mLock) {
                 typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index 94f289f..7c8dc74 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -49,12 +49,12 @@
 import android.media.session.ICallback;
 import android.media.session.IOnMediaKeyListener;
 import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession;
 import android.media.session.ISession2TokensListener;
 import android.media.session.ISessionManager;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
 import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -1001,7 +1001,7 @@
         private boolean mVoiceButtonHandled = false;
 
         @Override
-        public SessionLink createSession(String packageName, SessionCallbackLink cb, String tag,
+        public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
                 Bundle sessionInfo, int userId) throws RemoteException {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 270fbc6..3872523 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -17,9 +17,14 @@
 package com.android.server.media.projection;
 
 import android.Manifest;
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
+import android.app.IProcessObserver;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
 import android.hardware.display.DisplayManager;
 import android.media.MediaRouter;
 import android.media.projection.IMediaProjection;
@@ -29,6 +34,8 @@
 import android.media.projection.MediaProjectionInfo;
 import android.media.projection.MediaProjectionManager;
 import android.os.Binder;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -38,6 +45,7 @@
 import android.util.Slog;
 
 import com.android.internal.util.DumpUtils;
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
 
@@ -63,6 +71,8 @@
 
     private final Context mContext;
     private final AppOpsManager mAppOps;
+    private final ActivityManagerInternal mActivityManagerInternal;
+    private final PackageManager mPackageManager;
 
     private final MediaRouter mMediaRouter;
     private final MediaRouterCallback mMediaRouterCallback;
@@ -77,6 +87,8 @@
         mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
         mCallbackDelegate = new CallbackDelegate();
         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mPackageManager = mContext.getPackageManager();
         mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
         mMediaRouterCallback = new MediaRouterCallback();
         Watchdog.getInstance().addMonitor(this);
@@ -88,6 +100,21 @@
                 false /*allowIsolated*/);
         mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback,
                 MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+        mActivityManagerInternal.registerProcessObserver(new IProcessObserver.Stub() {
+            @Override
+            public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+            }
+
+            @Override
+            public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+                MediaProjectionManagerService.this.handleForegroundServicesChanged(pid, uid,
+                        serviceTypes);
+            }
+
+            @Override
+            public void onProcessDied(int pid, int uid) {
+            }
+        });
     }
 
     @Override
@@ -105,6 +132,29 @@
         synchronized (mLock) { /* check for deadlock */ }
     }
 
+    /**
+     * Called when the set of active foreground service types for a given {@code uid / pid} changes.
+     * We will stop the active projection grant if its owner targets {@code Q} or higher and has no
+     * started foreground services of type {@code FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}.
+     */
+    private void handleForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+        synchronized (mLock) {
+            if (mProjectionGrant == null || mProjectionGrant.uid != uid) {
+                return;
+            }
+
+            if (mProjectionGrant.targetSdkVersion < VERSION_CODES.Q) {
+                return;
+            }
+
+            if ((serviceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION) != 0) {
+                return;
+            }
+
+            mProjectionGrant.stop();
+        }
+    }
+
     private void startProjectionLocked(final MediaProjection projection) {
         if (mProjectionGrant != null) {
             mProjectionGrant.stop();
@@ -229,10 +279,19 @@
             if (packageName == null || packageName.isEmpty()) {
                 throw new IllegalArgumentException("package name must not be empty");
             }
+
             long callingToken = Binder.clearCallingIdentity();
+
             MediaProjection projection;
             try {
-                projection = new MediaProjection(type, uid, packageName);
+                ApplicationInfo ai;
+                try {
+                    ai = mPackageManager.getApplicationInfo(packageName, 0);
+                } catch (NameNotFoundException e) {
+                    throw new IllegalArgumentException("No package matching :" + packageName);
+                }
+
+                projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion);
                 if (isPermanentGrant) {
                     mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA,
                             projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED);
@@ -334,17 +393,19 @@
         public final int uid;
         public final String packageName;
         public final UserHandle userHandle;
+        public final int targetSdkVersion;
 
         private IMediaProjectionCallback mCallback;
         private IBinder mToken;
         private IBinder.DeathRecipient mDeathEater;
         private int mType;
 
-        public MediaProjection(int type, int uid, String packageName) {
+        MediaProjection(int type, int uid, String packageName, int targetSdkVersion) {
             mType = type;
             this.uid = uid;
             this.packageName = packageName;
             userHandle = new UserHandle(UserHandle.getUserId(uid));
+            this.targetSdkVersion = targetSdkVersion;
         }
 
         @Override // Binder call
@@ -400,6 +461,14 @@
                             + " attempted to start already started MediaProjection");
                     return;
                 }
+
+                if (targetSdkVersion >= Build.VERSION_CODES.Q
+                        && !mActivityManagerInternal.hasRunningForegroundService(
+                                uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
+                    throw new SecurityException("Media projections require a foreground service"
+                            + " of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION");
+                }
+
                 mCallback = callback;
                 registerCallback(mCallback);
                 try {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index d9ab132..de93120 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -438,6 +438,8 @@
         if (getAudioAttributes() != null) {
             getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
         }
+        proto.write(NotificationRecordProto.PACKAGE, sbn.getPackageName());
+        proto.write(NotificationRecordProto.DELEGATE_PACKAGE, sbn.getOpPkg());
 
         proto.end(token);
     }
@@ -458,6 +460,7 @@
         pw.println(prefix + this);
         prefix = prefix + "  ";
         pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
+        pw.println(prefix + "opPkg=" + sbn.getOpPkg());
         pw.println(prefix + "icon=" + iconStr);
         pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
         pw.println(prefix + "pri=" + notification.priority);
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 8905eb9..37dd63a 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -758,7 +758,7 @@
          * @throws SecurityException if the permission check fails
          */
         private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
-            getContext().enforceCallingPermission(
+            getContext().enforceCallingOrSelfPermission(
                     android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
         }
 
@@ -769,7 +769,7 @@
          * @throws SecurityException if the permission check fails
          */
         private void enforceDumpPermission(@NonNull final String message) {
-            getContext().enforceCallingPermission(android.Manifest.permission.DUMP, message);
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, message);
         }
     };
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4e8ef71..ec2ff28 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -552,10 +552,21 @@
     private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
 
     /**
+     * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
+     * rollback within that period, the install will proceed without rollback enabled.
+     *
+     * <p>If flag value is negative, the default value will be assigned.
+     *
+     * Flag type: {@code long}
+     * Namespace: NAMESPACE_ROLLBACK
+     */
+    private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
+
+    /**
      * The default duration to wait for rollback to be enabled in
      * milliseconds.
      */
-    private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT = 10 * 1000;
+    private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
 
     /**
      * The default response for package verification timeout.
@@ -14754,11 +14765,11 @@
                                 public void onReceive(Context context, Intent intent) {
                                     // the duration to wait for rollback to be enabled, in millis
                                     long rollbackTimeout = DeviceConfig.getLong(
-                                            DeviceConfig.Rollback.NAMESPACE,
-                                            DeviceConfig.Rollback.ENABLE_ROLLBACK_TIMEOUT,
-                                            DEFAULT_ENABLE_ROLLBACK_TIMEOUT);
+                                            DeviceConfig.NAMESPACE_ROLLBACK,
+                                            PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
+                                            DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
                                     if (rollbackTimeout < 0) {
-                                        rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT;
+                                        rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
                                     }
                                     final Message msg = mHandler.obtainMessage(
                                             ENABLE_ROLLBACK_TIMEOUT);
@@ -20162,21 +20173,20 @@
     }
 
     @Override
-    public String getContentCaptureServicePackageName() {
-        String contentCaptureServiceName =
-                mContext.getString(R.string.config_defaultContentCaptureService);
+    public String getSystemCaptionsServicePackageName() {
+        String flattenedSystemCaptionsServiceComponentName =
+                mContext.getString(R.string.config_defaultSystemCaptionsService);
 
-        if (TextUtils.isEmpty(contentCaptureServiceName)) {
+        if (TextUtils.isEmpty(flattenedSystemCaptionsServiceComponentName)) {
             return null;
         }
 
-        int separatorIndex = contentCaptureServiceName.indexOf("/");
-
-        if (separatorIndex < 0) {
+        ComponentName systemCaptionsServiceComponentName =
+                ComponentName.unflattenFromString(flattenedSystemCaptionsServiceComponentName);
+        if (systemCaptionsServiceComponentName == null) {
             return null;
         }
-
-        return contentCaptureServiceName.substring(0, separatorIndex);
+        return systemCaptionsServiceComponentName.getPackageName();
     }
 
     public String getIncidentReportApproverPackageName() {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index aced1a2..459de1a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2693,6 +2693,7 @@
                 // seinfo     - seinfo label for the app (assigned at install time)
                 // gids       - supplementary gids this app launches with
                 // profileableFromShellFlag  - 0 or 1 if the package is profileable from shell.
+                // longVersionCode - integer version of the package.
                 //
                 // NOTE: We prefer not to expose all ApplicationInfo flags for now.
                 //
@@ -2720,6 +2721,8 @@
                 }
                 sb.append(" ");
                 sb.append(ai.isProfileableByShell() ? "1" : "0");
+                sb.append(" ");
+                sb.append(String.valueOf(ai.longVersionCode));
                 sb.append("\n");
                 writer.append(sb);
             }
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index e9077a9..0a17e130 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -748,11 +748,11 @@
         grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId,
                 STORAGE_PERMISSIONS);
 
-        // Content Capture Service
-        String contentCaptureServicePackageName =
-                mContext.getPackageManager().getContentCaptureServicePackageName();
-        if (!TextUtils.isEmpty(contentCaptureServicePackageName)) {
-            grantPermissionsToSystemPackage(contentCaptureServicePackageName, userId,
+        // System Captions Service
+        String systemCaptionsServicePackageName =
+                mContext.getPackageManager().getSystemCaptionsServicePackageName();
+        if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
+            grantPermissionsToSystemPackage(systemCaptionsServicePackageName, userId,
                     MICROPHONE_PERMISSIONS);
         }
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5810636..e7c9a08 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -104,7 +104,6 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.AppOpsManager;
 import android.app.IUiModeManager;
@@ -5114,6 +5113,7 @@
             awakenDreams();
         }
 
+        // Start dock.
         Intent dock = createHomeDockIntent();
         if (dock != null) {
             try {
@@ -5126,21 +5126,9 @@
             }
         }
 
-        Intent intent;
-
-        if (fromHomeKey) {
-            intent = new Intent(mHomeIntent);
-            intent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey);
-        } else {
-            intent = mHomeIntent;
-        }
-        final Bundle bundle = getLaunchDisplayIdBundle(displayId);
-        startActivityAsUser(intent, bundle, UserHandle.CURRENT);
-    }
-
-    private @Nullable Bundle getLaunchDisplayIdBundle(int displayId) {
-        return (displayId == INVALID_DISPLAY) ? null
-                : ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
+        // Start home.
+        mActivityTaskManagerInternal.startHomeOnDisplay(mCurrentUserId, "startDockOrHome",
+                displayId, fromHomeKey);
     }
 
     /**
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 5adcf35..f0e4625 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -115,9 +115,41 @@
     public static final int REASON_SETTING_CHANGED = 8;
     public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON = 9;
     public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF = 10;
-    public static final int REASON_STICKY_RESTORE_OFF = 11;
-    public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 12;
-    public static final int REASON_TIMEOUT = 13;
+    public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 11;
+    public static final int REASON_TIMEOUT = 12;
+
+    static String reasonToString(int reason) {
+        switch (reason) {
+            case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON:
+                return "Percentage Auto ON";
+            case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF:
+                return "Percentage Auto OFF";
+            case BatterySaverController.REASON_MANUAL_ON:
+                return "Manual ON";
+            case BatterySaverController.REASON_MANUAL_OFF:
+                return "Manual OFF";
+            case BatterySaverController.REASON_STICKY_RESTORE:
+                return "Sticky restore";
+            case BatterySaverController.REASON_INTERACTIVE_CHANGED:
+                return "Interactivity changed";
+            case BatterySaverController.REASON_POLICY_CHANGED:
+                return "Policy changed";
+            case BatterySaverController.REASON_PLUGGED_IN:
+                return "Plugged in";
+            case BatterySaverController.REASON_SETTING_CHANGED:
+                return "Setting changed";
+            case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON:
+                return "Dynamic Warning Auto ON";
+            case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF:
+                return "Dynamic Warning Auto OFF";
+            case BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED:
+                return "Adaptive Power Savings changed";
+            case BatterySaverController.REASON_TIMEOUT:
+                return "timeout";
+            default:
+                return "Unknown reason: " + reason;
+        }
+    }
 
     /**
      * Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index af5d40bf..8f2e997 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.power.batterysaver;
 
+import static com.android.server.power.batterysaver.BatterySaverController.reasonToString;
+
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
@@ -49,6 +51,42 @@
  * Do not call out with the lock held. (Settings provider is okay.)
  *
  * Test: atest com.android.server.power.batterysaver.BatterySaverStateMachineTest
+ *
+ * Current state machine. This can be visualized using Graphviz:
+   <pre>
+
+   digraph {
+     STATE_OFF
+     STATE_MANUAL_ON [label="STATE_MANUAL_ON\nTurned on manually by the user"]
+     STATE_AUTOMATIC_ON [label="STATE_AUTOMATIC_ON\nTurned on automatically by the system"]
+     STATE_OFF_AUTOMATIC_SNOOZED [
+       label="STATE_OFF_AUTOMATIC_SNOOZED\nTurned off manually by the user."
+           + " The system should not turn it back on automatically."
+     ]
+     STATE_PENDING_STICKY_ON [
+       label="STATE_PENDING_STICKY_ON\n"
+           + " Turned on manually by the user and then plugged in. Will turn back on after unplug."
+     ]
+
+     STATE_OFF -> STATE_MANUAL_ON [label="manual"]
+     STATE_OFF -> STATE_AUTOMATIC_ON [label="Auto on AND charge <= auto threshold"]
+
+     STATE_MANUAL_ON -> STATE_OFF [label="manual\nOR\nPlugged & sticky disabled"]
+     STATE_MANUAL_ON -> STATE_PENDING_STICKY_ON [label="Plugged & sticky enabled"]
+
+     STATE_PENDING_STICKY_ON -> STATE_MANUAL_ON [label="Unplugged & sticky enabled"]
+     STATE_PENDING_STICKY_ON -> STATE_OFF [
+       label="Sticky disabled\nOR\nSticky auto off enabled AND charge >= sticky auto off threshold"
+     ]
+
+     STATE_AUTOMATIC_ON -> STATE_OFF [label="Plugged"]
+     STATE_AUTOMATIC_ON -> STATE_OFF_AUTOMATIC_SNOOZED [label="Manual"]
+
+     STATE_OFF_AUTOMATIC_SNOOZED -> STATE_OFF [label="Plug\nOR\nCharge > auto threshold"]
+     STATE_OFF_AUTOMATIC_SNOOZED -> STATE_MANUAL_ON [label="manual"]
+
+     </pre>
+   }
  */
 public class BatterySaverStateMachine {
     private static final String TAG = "BatterySaverStateMachine";
@@ -60,6 +98,25 @@
 
     private static final long ADAPTIVE_CHANGE_TIMEOUT_MS = 24 * 60 * 60 * 1000L;
 
+    /** Turn off adaptive battery saver if the device has charged above this level. */
+    private static final int ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL = 80;
+
+    private static final int STATE_OFF = BatterySaverStateMachineProto.STATE_OFF;
+
+    /** Turned on manually by the user. */
+    private static final int STATE_MANUAL_ON = BatterySaverStateMachineProto.STATE_MANUAL_ON;
+
+    /** Turned on automatically by the system. */
+    private static final int STATE_AUTOMATIC_ON = BatterySaverStateMachineProto.STATE_AUTOMATIC_ON;
+
+    /** Turned off manually by the user. The system should not turn it back on automatically. */
+    private static final int STATE_OFF_AUTOMATIC_SNOOZED =
+            BatterySaverStateMachineProto.STATE_OFF_AUTOMATIC_SNOOZED;
+
+    /** Turned on manually by the user and then plugged in. Will turn back on after unplug. */
+    private static final int STATE_PENDING_STICKY_ON =
+            BatterySaverStateMachineProto.STATE_PENDING_STICKY_ON;
+
     private final Context mContext;
     private final BatterySaverController mBatterySaverController;
 
@@ -75,6 +132,9 @@
     @GuardedBy("mLock")
     private boolean mBatteryStatusSet;
 
+    @GuardedBy("mLock")
+    private int mState;
+
     /** Whether the device is connected to any power source. */
     @GuardedBy("mLock")
     private boolean mIsPowered;
@@ -142,13 +202,6 @@
     private boolean mDynamicPowerSavingsBatterySaver;
 
     /**
-     * Whether BS has been manually disabled while the battery level is low, in which case we
-     * shouldn't auto re-enable it until the battery level is not low.
-     */
-    @GuardedBy("mLock")
-    private boolean mBatterySaverSnoozing;
-
-    /**
      * Last reason passed to {@link #enableBatterySaverLocked}.
      */
     @GuardedBy("mLock")
@@ -181,6 +234,7 @@
         mLock = lock;
         mContext = context;
         mBatterySaverController = batterySaverController;
+        mState = STATE_OFF;
 
         mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled);
@@ -188,8 +242,36 @@
                 com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold);
     }
 
-    private boolean isAutoBatterySaverConfiguredLocked() {
-        return mSettingBatterySaverTriggerThreshold > 0;
+    /** @return true if the automatic percentage based mode should be used */
+    private boolean isAutomaticModeActiveLocked() {
+        return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
+                && mSettingBatterySaverTriggerThreshold > 0;
+    }
+
+    /**
+     * The returned value won't necessarily make sense if {@link #isAutomaticModeActiveLocked()}
+     * returns {@code false}.
+     *
+     * @return true if the battery level is below automatic's threshold.
+     */
+    private boolean isInAutomaticLowZoneLocked() {
+        return mIsBatteryLevelLow;
+    }
+
+    /** @return true if the dynamic mode should be used */
+    private boolean isDynamicModeActiveLocked() {
+        return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
+                && mDynamicPowerSavingsBatterySaver;
+    }
+
+    /**
+     * The returned value won't necessarily make sense if {@link #isDynamicModeActiveLocked()}
+     * returns {@code false}.
+     *
+     * @return true if the battery level is below dynamic's threshold.
+     */
+    private boolean isInDynamicLowZoneLocked() {
+        return mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
     }
 
     /**
@@ -233,7 +315,14 @@
                     Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL),
                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
 
+
             synchronized (mLock) {
+                final boolean lowPowerModeEnabledSticky = getGlobalSetting(
+                        Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0;
+
+                if (lowPowerModeEnabledSticky) {
+                    mState = STATE_PENDING_STICKY_ON;
+                }
 
                 mBootCompleted = true;
 
@@ -362,6 +451,8 @@
                     ? "Global.low_power changed to 1" : "Global.low_power changed to 0";
             enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true,
                     BatterySaverController.REASON_SETTING_CHANGED, reason);
+        } else {
+            doAutoBatterySaverLocked();
         }
     }
 
@@ -428,17 +519,6 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private boolean isBatteryLowLocked() {
-        final boolean percentageLow =
-                mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
-                && mIsBatteryLevelLow;
-        final boolean dynamicPowerSavingsLow =
-                mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
-                && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
-        return percentageLow || dynamicPowerSavingsLow;
-    }
-
     /**
      * Decide whether to auto-start / stop battery saver.
      */
@@ -449,7 +529,6 @@
                     + " mSettingsLoaded=" + mSettingsLoaded
                     + " mBatteryStatusSet=" + mBatteryStatusSet
                     + " mIsBatteryLevelLow=" + mIsBatteryLevelLow
-                    + " mBatterySaverSnoozing=" + mBatterySaverSnoozing
                     + " mIsPowered=" + mIsPowered
                     + " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver
                     + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky
@@ -460,66 +539,166 @@
             return; // Not fully initialized yet.
         }
 
-        if (!isBatteryLowLocked()) {
-            updateSnoozingLocked(false, "Battery not low");
-        }
+        updateStateLocked(false, false);
 
+        // Adaptive control.
         if (SystemClock.elapsedRealtime() - mLastAdaptiveBatterySaverChangedExternallyElapsed
                 > ADAPTIVE_CHANGE_TIMEOUT_MS) {
             mBatterySaverController.setAdaptivePolicyEnabledLocked(
                     false, BatterySaverController.REASON_TIMEOUT);
             mBatterySaverController.resetAdaptivePolicyLocked(
                     BatterySaverController.REASON_TIMEOUT);
+        } else if (mIsPowered && mBatteryLevel >= ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL) {
+            mBatterySaverController.setAdaptivePolicyEnabledLocked(false,
+                    BatterySaverController.REASON_PLUGGED_IN);
+        }
+    }
+
+    /**
+     * Update the state machine based on the current settings and battery/charge status.
+     *
+     * @param manual Whether the change was made by the user.
+     * @param enable Whether the user wants to turn battery saver on or off. Is only used if {@param
+     *               manual} is true.
+     */
+    @GuardedBy("mLock")
+    private void updateStateLocked(boolean manual, boolean enable) {
+        if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
+            return; // Not fully initialized yet.
         }
 
-        if (mIsPowered) {
-            updateSnoozingLocked(false, "Plugged in");
-            enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
-                    BatterySaverController.REASON_PLUGGED_IN,
-                    "Plugged in");
-
-            if (mBatteryLevel >= 80 /* Arbitrary level */) {
-                mBatterySaverController.setAdaptivePolicyEnabledLocked(
-                        false, BatterySaverController.REASON_PLUGGED_IN);
+        switch (mState) {
+            case STATE_OFF: {
+                if (!mIsPowered) {
+                    if (manual) {
+                        if (!enable) {
+                            Slog.e(TAG, "Tried to disable BS when it's already OFF");
+                            return;
+                        }
+                        enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+                                BatterySaverController.REASON_MANUAL_ON);
+                        mState = STATE_MANUAL_ON;
+                    } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
+                        enableBatterySaverLocked(/*enable*/ true, /*manual*/ false,
+                                BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON);
+                        mState = STATE_AUTOMATIC_ON;
+                    } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) {
+                        enableBatterySaverLocked(/*enable*/ true, /*manual*/ false,
+                                BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON);
+                        mState = STATE_AUTOMATIC_ON;
+                    }
+                }
+                break;
             }
 
-        } else if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) {
-            if (mSettingBatterySaverStickyAutoDisableEnabled
-                    && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold) {
-                setStickyActive(false);
-            } else {
-                // Re-enable BS.
-                enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
-                        BatterySaverController.REASON_STICKY_RESTORE,
-                        "Sticky restore");
+            case STATE_MANUAL_ON: {
+                if (manual) {
+                    if (enable) {
+                        Slog.e(TAG, "Tried to enable BS when it's already MANUAL_ON");
+                        return;
+                    }
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ true,
+                            BatterySaverController.REASON_MANUAL_OFF);
+                    mState = STATE_OFF;
+                } else if (mIsPowered) {
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+                            BatterySaverController.REASON_PLUGGED_IN);
+                    if (mSettingBatterySaverEnabledSticky
+                            && !mBatterySaverStickyBehaviourDisabled) {
+                        mState = STATE_PENDING_STICKY_ON;
+                    } else {
+                        mState = STATE_OFF;
+                    }
+                }
+                break;
             }
 
-        } else if (mSettingAutomaticBatterySaver
-                == PowerManager.POWER_SAVER_MODE_PERCENTAGE
-                && isAutoBatterySaverConfiguredLocked()) {
-            if (mIsBatteryLevelLow && !mBatterySaverSnoozing) {
-                enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
-                        BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON,
-                        "Percentage Auto ON");
-            } else {
-                // Battery not low
-                enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
-                        BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF,
-                        "Percentage Auto OFF");
+            case STATE_AUTOMATIC_ON: {
+                if (mIsPowered) {
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+                            BatterySaverController.REASON_PLUGGED_IN);
+                    mState = STATE_OFF;
+                } else if (manual) {
+                    if (enable) {
+                        Slog.e(TAG, "Tried to enable BS when it's already AUTO_ON");
+                        return;
+                    }
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ true,
+                            BatterySaverController.REASON_MANUAL_OFF);
+                    // When battery saver is disabled manually (while battery saver is enabled)
+                    // when the battery level is low, we "snooze" BS -- i.e. disable auto battery
+                    // saver.
+                    // We resume auto-BS once the battery level is not low, or the device is
+                    // plugged in.
+                    mState = STATE_OFF_AUTOMATIC_SNOOZED;
+                } else if (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) {
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+                            BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF);
+                    mState = STATE_OFF;
+                } else if (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) {
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+                            BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF);
+                    mState = STATE_OFF;
+                } else if (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked()) {
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+                            BatterySaverController.REASON_SETTING_CHANGED);
+                    mState = STATE_OFF;
+                }
+                break;
             }
-        } else if (mSettingAutomaticBatterySaver
-                == PowerManager.POWER_SAVER_MODE_DYNAMIC) {
-            if (mBatteryLevel >= mDynamicPowerSavingsDisableThreshold) {
-                enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
-                        BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF,
-                        "Dynamic Warning Auto OFF");
-            } else if (mDynamicPowerSavingsBatterySaver && !mBatterySaverSnoozing) {
-                enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
-                        BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON,
-                        "Dynamic Warning Auto ON");
+
+            case STATE_OFF_AUTOMATIC_SNOOZED: {
+                if (manual) {
+                    if (!enable) {
+                        Slog.e(TAG, "Tried to disable BS when it's already AUTO_SNOOZED");
+                        return;
+                    }
+                    enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+                            BatterySaverController.REASON_MANUAL_ON);
+                    mState = STATE_MANUAL_ON;
+                } else if (mIsPowered // Plugging in resets snooze.
+                        || (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked())
+                        || (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked())
+                        || (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked())) {
+                    mState = STATE_OFF;
+                }
+                break;
             }
+
+            case STATE_PENDING_STICKY_ON: {
+                if (manual) {
+                    // This shouldn't be possible. We'll only be in this state when the device is
+                    // plugged in, so the user shouldn't be able to manually change state.
+                    Slog.e(TAG, "Tried to manually change BS state from PENDING_STICKY_ON");
+                    return;
+                }
+                final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled
+                        && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold;
+                final boolean isStickyDisabled =
+                        mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky;
+                if (isStickyDisabled || shouldTurnOffSticky) {
+                    setStickyActive(false);
+                    mState = STATE_OFF;
+                } else if (!mIsPowered) {
+                    // Re-enable BS.
+                    enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+                            BatterySaverController.REASON_STICKY_RESTORE);
+                    mState = STATE_MANUAL_ON;
+                }
+                break;
+            }
+
+            default:
+                Slog.wtf(TAG, "Unknown state: " + mState);
+                break;
         }
-        // do nothing if automatic battery saver mode = PERCENTAGE and low warning threshold = 0%
+    }
+
+    @VisibleForTesting
+    int getState() {
+        synchronized (mLock) {
+            return mState;
+        }
     }
 
     /**
@@ -533,13 +712,17 @@
             Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled);
         }
         synchronized (mLock) {
-            enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
-                    (enabled ? BatterySaverController.REASON_MANUAL_ON
-                            : BatterySaverController.REASON_MANUAL_OFF),
-                    (enabled ? "Manual ON" : "Manual OFF"));
+            updateStateLocked(true, enabled);
+            // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true and
+            //  enabled is false
         }
     }
 
+    @GuardedBy("mLock")
+    private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason) {
+        enableBatterySaverLocked(enable, manual, intReason, reasonToString(intReason));
+    }
+
     /**
      * Actually enable / disable battery saver. Write the new state to the global settings
      * and propagate it to {@link #mBatterySaverController}.
@@ -566,20 +749,6 @@
         mLastChangedIntReason = intReason;
         mLastChangedStrReason = strReason;
 
-        if (manual) {
-            if (enable) {
-                updateSnoozingLocked(false, "Manual snooze OFF");
-            } else {
-                // When battery saver is disabled manually (while battery saver is enabled)
-                // when the battery level is low, we "snooze" BS -- i.e. disable auto battery saver.
-                // We resume auto-BS once the battery level is not low, or the device is plugged in.
-                if (mBatterySaverController.isFullEnabled() && isBatteryLowLocked()) {
-                    updateSnoozingLocked(true, "Manual snooze");
-                }
-                // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true
-            }
-        }
-
         mSettingBatterySaverEnabled = enable;
         putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0);
 
@@ -641,15 +810,6 @@
         manager.cancel(DYNAMIC_MODE_NOTIFICATION_ID);
     }
 
-    @GuardedBy("mLock")
-    private void updateSnoozingLocked(boolean snoozing, String reason) {
-        if (mBatterySaverSnoozing == snoozing) {
-            return;
-        }
-        if (DEBUG) Slog.d(TAG, "Snooze: " + (snoozing ? "start" : "stop")  + " reason=" + reason);
-        mBatterySaverSnoozing = snoozing;
-    }
-
     private void setStickyActive(boolean active) {
         mSettingBatterySaverEnabledSticky = active;
         putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY,
@@ -684,6 +844,8 @@
                 pw.print(")");
             }
             pw.println();
+            pw.print("  mState=");
+            pw.println(mState);
 
             pw.print("  mLastChangedIntReason=");
             pw.println(mLastChangedIntReason);
@@ -697,9 +859,6 @@
             pw.print("  mBatteryStatusSet=");
             pw.println(mBatteryStatusSet);
 
-            pw.print("  mBatterySaverSnoozing=");
-            pw.println(mBatterySaverSnoozing);
-
             pw.print("  mIsPowered=");
             pw.println(mIsPowered);
             pw.print("  mBatteryLevel=");
@@ -731,6 +890,7 @@
 
             proto.write(BatterySaverStateMachineProto.ENABLED,
                     mBatterySaverController.isEnabled());
+            proto.write(BatterySaverStateMachineProto.STATE, mState);
             proto.write(BatterySaverStateMachineProto.IS_FULL_ENABLED,
                     mBatterySaverController.isFullEnabled());
             proto.write(BatterySaverStateMachineProto.IS_ADAPTIVE_ENABLED,
@@ -742,8 +902,6 @@
             proto.write(BatterySaverStateMachineProto.SETTINGS_LOADED, mSettingsLoaded);
             proto.write(BatterySaverStateMachineProto.BATTERY_STATUS_SET, mBatteryStatusSet);
 
-            proto.write(BatterySaverStateMachineProto.BATTERY_SAVER_SNOOZING,
-                    mBatterySaverSnoozing);
 
             proto.write(BatterySaverStateMachineProto.IS_POWERED, mIsPowered);
             proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 83d18a6..1e2dad9 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.rollback;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
@@ -24,6 +25,7 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ModuleInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
@@ -220,9 +222,7 @@
 
     @Override
     public ParceledListSlice getAvailableRollbacks() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
-                "getAvailableRollbacks");
+        enforceManageRollbacks("getAvailableRollbacks");
 
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
@@ -239,9 +239,7 @@
 
     @Override
     public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
-                "getRecentlyExecutedRollbacks");
+        enforceManageRollbacks("getRecentlyCommittedRollbacks");
 
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
@@ -259,9 +257,7 @@
     @Override
     public void commitRollback(int rollbackId, ParceledListSlice causePackages,
             String callerPackageName, IntentSender statusReceiver) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
-                "executeRollback");
+        enforceManageRollbacks("executeRollback");
 
         final int callingUid = Binder.getCallingUid();
         AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -462,7 +458,7 @@
                             // TODO: This call emits the warning "Calling a method in the
                             // system process without a qualified user". Fix that.
                             // TODO: Limit this to receivers holding the
-                            // MANAGE_ROLLBACKS permission?
+                            // MANAGE_ROLLBACKS or TEST_MANAGE_ROLLBACKS permissions?
                             mContext.sendBroadcast(broadcast);
                         });
                     }
@@ -484,7 +480,7 @@
     @Override
     public void reloadPersistedData() {
         mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
+                Manifest.permission.TEST_MANAGE_ROLLBACKS,
                 "reloadPersistedData");
 
         synchronized (mLock) {
@@ -499,7 +495,7 @@
     @Override
     public void expireRollbackForPackage(String packageName) {
         mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
+                Manifest.permission.TEST_MANAGE_ROLLBACKS,
                 "expireRollbackForPackage");
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
@@ -535,8 +531,8 @@
 
     private void updateRollbackLifetimeDurationInMillis() {
         mRollbackLifetimeDurationInMillis = DeviceConfig.getLong(
-                DeviceConfig.Rollback.BOOT_NAMESPACE,
-                DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+                DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+                RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                 DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS);
         if (mRollbackLifetimeDurationInMillis < 0) {
             mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS;
@@ -894,12 +890,19 @@
         Log.i(TAG, "Enabling rollback for install of " + packageName
                 + ", session:" + session.sessionId);
 
+        String installerPackageName = session.getInstallerPackageName();
+        if (!enableRollbackAllowed(installerPackageName, packageName)) {
+            Log.e(TAG, "Installer " + installerPackageName
+                    + " is not allowed to enable rollback on " + packageName);
+            return false;
+        }
+
         VersionedPackage newVersion = new VersionedPackage(packageName, newPackage.versionCode);
         final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0);
 
         // Get information about the currently installed package.
         PackageManager pm = mContext.getPackageManager();
-        PackageInfo pkgInfo = null;
+        final PackageInfo pkgInfo;
         try {
             pkgInfo = pm.getPackageInfo(packageName, isApex ? PackageManager.MATCH_APEX : 0);
         } catch (PackageManager.NameNotFoundException e) {
@@ -1086,6 +1089,44 @@
     }
 
     /**
+     * Returns true if the installer is allowed to enable rollback for the
+     * given named package, false otherwise.
+     */
+    private boolean enableRollbackAllowed(String installerPackageName, String packageName) {
+        if (installerPackageName == null) {
+            return false;
+        }
+
+        PackageManager pm = mContext.getPackageManager();
+        boolean manageRollbacksGranted = pm.checkPermission(
+                Manifest.permission.MANAGE_ROLLBACKS,
+                installerPackageName) == PackageManager.PERMISSION_GRANTED;
+
+        boolean testManageRollbacksGranted = pm.checkPermission(
+                Manifest.permission.TEST_MANAGE_ROLLBACKS,
+                installerPackageName) == PackageManager.PERMISSION_GRANTED;
+
+        // For now only allow rollbacks for modules or for testing.
+        return (isModule(packageName) && manageRollbacksGranted)
+            || testManageRollbacksGranted;
+    }
+
+    /**
+     * Returns true if the package name is the name of a module.
+     */
+    private boolean isModule(String packageName) {
+        PackageManager pm = mContext.getPackageManager();
+        final ModuleInfo moduleInfo;
+        try {
+            moduleInfo = pm.getModuleInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+
+        return moduleInfo != null;
+    }
+
+    /**
      * Gets the version of the package currently installed.
      * Returns null if the package is not currently installed.
      */
@@ -1311,4 +1352,15 @@
             }
         }
     }
+
+    private void enforceManageRollbacks(@NonNull String message) {
+        if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
+                        Manifest.permission.MANAGE_ROLLBACKS))
+                && (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
+                        Manifest.permission.TEST_MANAGE_ROLLBACKS))) {
+            throw new SecurityException(message + " requires "
+                    + Manifest.permission.MANAGE_ROLLBACKS + " or "
+                    + Manifest.permission.TEST_MANAGE_ROLLBACKS);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 2b17d19..1800433 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -19,6 +19,8 @@
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
 import static android.os.Process.getPidsForCommands;
 import static android.os.Process.getUidForPid;
+import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
+import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
@@ -89,6 +91,7 @@
 import android.os.storage.DiskInfo;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.stats.storage.StorageEnums;
 import android.telephony.ModemActivityInfo;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
@@ -1968,7 +1971,7 @@
         pulledData.add(e);
     }
 
-    private void pullSDCardInfo(int tagId, long elapsedNanos, long wallClockNanos,
+    private void pullExternalStorageInfo(int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
         StorageManager storageManager = mContext.getSystemService(StorageManager.class);
         if (storageManager != null) {
@@ -1976,11 +1979,29 @@
             for (VolumeInfo vol : volumes) {
                 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
                 final DiskInfo diskInfo = vol.getDisk();
-                if (diskInfo != null && diskInfo.isSd()) {
+                if (diskInfo != null) {
                     if (envState.equals(Environment.MEDIA_MOUNTED)) {
+                        // Get the type of the volume, if it is adoptable or portable.
+                        int volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__OTHER;
+                        if (vol.getType() == TYPE_PUBLIC) {
+                            volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__PUBLIC;
+                        } else if (vol.getType() == TYPE_PRIVATE) {
+                            volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__PRIVATE;
+                        }
+                        // Get the type of external storage inserted in the device (sd cards,
+                        // usb, etc)
+                        int externalStorageType;
+                        if (diskInfo.isSd()) {
+                            externalStorageType = StorageEnums.SD_CARD;
+                        } else if (diskInfo.isUsb()) {
+                            externalStorageType = StorageEnums.USB;
+                        } else {
+                            externalStorageType = StorageEnums.OTHER;
+                        }
                         StatsLogEventWrapper e =
                                 new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
-                        e.writeInt(vol.getType() + 1);
+                        e.writeInt(externalStorageType);
+                        e.writeInt(volumeType);
                         e.writeLong(diskInfo.size);
                         pulledData.add(e);
                     }
@@ -2185,8 +2206,8 @@
                 pullTimeZoneDataInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
-            case StatsLog.SDCARD_INFO: {
-                pullSDCardInfo(tagId, elapsedNanos, wallClockNanos, ret);
+            case StatsLog.EXTERNAL_STORAGE_INFO: {
+                pullExternalStorageInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             default:
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 5a20959..b262a00 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -352,6 +352,19 @@
     /** @return The intent used to launch the home activity. */
     public abstract Intent getHomeIntent();
     public abstract boolean startHomeActivity(int userId, String reason);
+    /**
+     * This starts home activity on displays that can have system decorations based on displayId -
+     * Default display always use primary home component.
+     * For Secondary displays, the home activity must have category SECONDARY_HOME and then resolves
+     * according to the priorities listed below.
+     *  - If default home is not set, always use the secondary home defined in the config.
+     *  - Use currently selected primary home activity.
+     *  - Use the activity in the same package as currently selected primary home activity.
+     *    If there are multiple activities matched, use first one.
+     *  - Use the secondary home defined in the config.
+     */
+    public abstract boolean startHomeOnDisplay(int userId, String reason, int displayId,
+            boolean fromHomeKey);
     /** Start home activities on all displays that support system decorations. */
     public abstract boolean startHomeOnAllDisplays(int userId, String reason);
     /** @return true if the given process is the factory test process. */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a1dbbab..118eb5b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6491,6 +6491,13 @@
         }
 
         @Override
+        public boolean startHomeOnDisplay(int userId, String reason, int displayId,
+                boolean fromHomeKey) {
+            return mRootActivityContainer.startHomeOnDisplay(userId, reason, displayId,
+                    fromHomeKey);
+        }
+
+        @Override
         public boolean startHomeOnAllDisplays(int userId, String reason) {
             synchronized (mGlobalLock) {
                 return mRootActivityContainer.startHomeOnAllDisplays(userId, reason);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 8c8b05f..72a1a2f 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -269,7 +269,8 @@
      * @return True if we may show an activity while Keyguard is occluded, false otherwise.
      */
     boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
-        return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
+        return showWhenLocked || dismissKeyguard
+                && !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
     }
 
     private void visibilitiesUpdated() {
@@ -317,7 +318,7 @@
         // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
         // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
         // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
-        if (!mWindowManager.isKeyguardSecure()) {
+        if (!mWindowManager.isKeyguardSecure(mService.getCurrentUserId())) {
             return;
         }
 
@@ -345,7 +346,8 @@
      * @return true if Keyguard can be currently dismissed without entering credentials.
      */
     boolean canDismissKeyguard() {
-        return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
+        return mWindowManager.isKeyguardTrusted()
+                || !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
     }
 
     private int resolveOccludeTransit() {
@@ -487,7 +489,8 @@
             }
             if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded
                     && mDismissingKeyguardActivity != null
-                    && controller.mWindowManager.isKeyguardSecure()) {
+                    && controller.mWindowManager.isKeyguardSecure(
+                            controller.mService.getCurrentUserId())) {
                 mRequestDismissKeyguard = true;
             }
         }
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index e6e6275..2411e00 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -762,7 +762,7 @@
             } else {
                 // If keyguard is not secure and it is locked, dismiss the keyguard before
                 // disabling it, which avoids the platform to think the keyguard is still on.
-                if (mWindowManager.isKeyguardLocked() && !mWindowManager.isKeyguardSecure()) {
+                if (mWindowManager.isKeyguardLocked() && !mWindowManager.isKeyguardSecure(userId)) {
                     mPendingDisableFromDismiss = userId;
                     mWindowManager.dismissKeyguard(new IKeyguardDismissCallback.Stub() {
                         @Override
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index f964b57..24cf7f1 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -114,6 +114,7 @@
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.AppTimeTracker;
 import com.android.server.am.UserState;
+import com.android.server.policy.WindowManagerPolicy;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -345,6 +346,10 @@
         }
     }
 
+    boolean startHomeOnDisplay(int userId, String reason, int displayId) {
+        return startHomeOnDisplay(userId, reason, displayId, false /*fromHomeKey*/);
+    }
+
     /**
      * This starts home activity on displays that can have system decorations based on displayId -
      * Default display always use primary home component.
@@ -356,7 +361,12 @@
      *    If there are multiple activities matched, use first one.
      *  - Use the secondary home defined in the config.
      */
-    boolean startHomeOnDisplay(int userId, String reason, int displayId) {
+    boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean fromHomeKey) {
+        // Fallback to top focused display if the displayId is invalid.
+        if (displayId == INVALID_DISPLAY) {
+            displayId = getTopDisplayFocusedStack().mDisplayId;
+        }
+
         Intent homeIntent;
         ActivityInfo aInfo;
         if (displayId == DEFAULT_DISPLAY) {
@@ -380,6 +390,10 @@
         // Updates the home component of the intent.
         homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
         homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
+        // Updates the extra information of the intent.
+        if (fromHomeKey) {
+            homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
+        }
         // Update the reason for ANR debugging to verify if the user activity is the one that
         // actually launched.
         final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a6c9257..4a9d798f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2868,8 +2868,13 @@
     }
 
     @Override
-    public boolean isKeyguardSecure() {
-        int userId = UserHandle.getCallingUserId();
+    public boolean isKeyguardSecure(int userId) {
+        if (userId != UserHandle.getCallingUserId()
+                && !checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS,
+                "isKeyguardSecure")) {
+            throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
+        }
+
         long origId = Binder.clearCallingIdentity();
         try {
             return mPolicy.isKeyguardSecure(userId);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 050a079..00b815a 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -109,6 +109,7 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
+        "android.hardware.gnss.measurement_corrections@1.0",
         "android.hardware.gnss.visibility_control@1.0",
         "android.hardware.input.classifier@1.0",
         "android.hardware.ir@1.0",
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index caba3af..a4955f0 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -71,6 +71,7 @@
 static jmethodID method_reportNavigationMessages;
 static jmethodID method_reportLocationBatch;
 static jmethodID method_reportGnssServiceDied;
+static jmethodID method_setMeasurementCorrectionsCapabilities;
 static jmethodID method_correctionsGetLatitudeDegrees;
 static jmethodID method_correctionsGetLongitudeDegrees;
 static jmethodID method_correctionsGetAltitudeMeters;
@@ -158,10 +159,9 @@
 using IAGnssCallback_V1_0 = android::hardware::gnss::V1_0::IAGnssCallback;
 using IAGnssCallback_V2_0 = android::hardware::gnss::V2_0::IAGnssCallback;
 
-using IMeasurementCorrections =
-    android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
-using GnssSingleSatCorrectionFlags =
-    android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+using android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
 
 using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
 using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback;
@@ -201,7 +201,6 @@
 sp<IGnssMeasurement_V2_0> gnssMeasurementIface_V2_0 = nullptr;
 sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr;
 sp<IMeasurementCorrections> gnssCorrectionsIface = nullptr;
-
 sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
 
 #define WAKE_LOCK_NAME  "GPS"
@@ -572,7 +571,9 @@
     template <class T>
     Return<void> gnssLocationCbImpl(const T& location);
 
-    // TODO(b/73306084): Reconsider allocation cost vs threadsafety on these statics
+    Return<void> gnssSetCapabilitesCbImpl(uint32_t capabilities, bool hasSubHalCapabilityFlags);
+
+    // TODO: Reconsider allocation cost vs threadsafety on these statics
     static const char* sNmeaString;
     static size_t sNmeaStringLength;
 };
@@ -694,16 +695,29 @@
 }
 
 Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
-    ALOGD("%s: %du\n", __func__, capabilities);
-
-    JNIEnv* env = getJniEnv();
-    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-    return Void();
+    return GnssCallback::gnssSetCapabilitesCbImpl(capabilities,
+        /* hasSubHalCapabilityFlags = */ true);
 }
 
 Return<void> GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
-    return GnssCallback::gnssSetCapabilitesCb(capabilities);
+    return GnssCallback::gnssSetCapabilitesCbImpl(capabilities,
+        /* hasSubHalCapabilityFlags = */ false);
+}
+
+Return <void> GnssCallback::gnssSetCapabilitesCbImpl(uint32_t capabilities,
+        bool hasSubHalCapabilityFlags) {
+    // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+    // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+    // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+    // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+    // which explicitly set the sub-HAL capability bits must continue to work.
+    ALOGD("%s: capabilities=%du, hasSubHalCapabilityFlags=%d\n", __func__, capabilities,
+        hasSubHalCapabilityFlags);
+    JNIEnv* env = getJniEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities,
+            boolToJbool(hasSubHalCapabilityFlags));
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
 }
 
 Return<void> GnssCallback::gnssAcquireWakelockCb() {
@@ -1153,6 +1167,22 @@
 }
 
 /*
+ * MeasurementCorrectionsCallback implements callback methods of interface
+ * IMeasurementCorrectionsCallback.hal.
+ */
+struct MeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
+    Return<void> setCapabilitiesCb(uint32_t capabilities) override;
+};
+
+Return<void> MeasurementCorrectionsCallback::setCapabilitiesCb(uint32_t capabilities) {
+    ALOGD("%s: %du\n", __func__, capabilities);
+    JNIEnv* env = getJniEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setMeasurementCorrectionsCapabilities, capabilities);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+/*
  * GnssNiCallback implements callback methods required by the IGnssNi interface.
  */
 struct GnssNiCallback : public IGnssNiCallback {
@@ -1434,7 +1464,7 @@
     method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F)V");
     method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
     method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
-    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
+    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(IZ)V");
     method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
     method_setGnssHardwareModelName = env->GetMethodID(clazz, "setGnssHardwareModelName",
             "(Ljava/lang/String;)V");
@@ -1474,6 +1504,9 @@
             "(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V");
     method_isInEmergencySession = env->GetMethodID(clazz, "isInEmergencySession", "()Z");
 
+    method_setMeasurementCorrectionsCapabilities = env->GetMethodID(clazz,
+            "setMeasurementCorrectionsCapabilities", "(I)V");
+
     jclass measCorrClass = env->FindClass("android/location/GnssMeasurementCorrections");
     method_correctionsGetLatitudeDegrees = env->GetMethodID(
             measCorrClass,"getLatitudeDegrees", "()D");
@@ -1591,7 +1624,7 @@
     }
 
     if (gnssHal_V2_0 != nullptr) {
-        // TODO(b/119638366): getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
+        // TODO: getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
         auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
         if (!gnssMeasurement.isOk()) {
             ALOGD("Unable to get a handle to GnssMeasurement_V2_0");
@@ -1795,6 +1828,12 @@
         gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
     }
 
+    if (gnssCorrectionsIface != nullptr) {
+        sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
+                new MeasurementCorrectionsCallback();
+        gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface);
+    }
+
     return JNI_TRUE;
 }
 
@@ -2154,7 +2193,7 @@
                                                                        jobject /* obj */) {
     jstring result = nullptr;
     /*
-     * TODO(b/33089503) : Create a jobject to represent GnssDebug.
+     * TODO: Create a jobject to represent GnssDebug.
      */
 
     std::stringstream internalState;
@@ -2380,13 +2419,25 @@
     return boolToJbool(result.isOk());
 }
 
-static jboolean android_location_GnssMeasurementsProvider_inject_gnss_measurement_corrections(
+static jboolean
+    android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported(
+    JNIEnv* env, jclass clazz) {
+    if (gnssCorrectionsIface != nullptr) {
+        return JNI_TRUE;
+    }
+
+    return JNI_FALSE;
+}
+
+static jboolean
+    android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections(
         JNIEnv* env,
         jobject obj /* clazz*/,
         jobject correctionsObj) {
 
     if (gnssCorrectionsIface == nullptr) {
-        ALOGW("Trying to inject GNSS corrections on a chipset that does not support them.");
+        ALOGW("Trying to inject GNSS measurement corrections on a chipset that does not"
+            " support them.");
         return JNI_FALSE;
     }
 
@@ -2882,18 +2933,25 @@
 static const JNINativeMethod sMeasurementMethods[] = {
     /* name, signature, funcPtr */
     {"native_is_measurement_supported", "()Z",
-     reinterpret_cast<void*>(
-         android_location_GnssMeasurementsProvider_is_measurement_supported)},
+            reinterpret_cast<void*>(
+            android_location_GnssMeasurementsProvider_is_measurement_supported)},
     {"native_start_measurement_collection", "(Z)Z",
-     reinterpret_cast<void*>(
-         android_location_GnssMeasurementsProvider_start_measurement_collection)},
+            reinterpret_cast<void*>(
+            android_location_GnssMeasurementsProvider_start_measurement_collection)},
     {"native_stop_measurement_collection", "()Z",
-     reinterpret_cast<void*>(
-         android_location_GnssMeasurementsProvider_stop_measurement_collection)},
+            reinterpret_cast<void*>(
+            android_location_GnssMeasurementsProvider_stop_measurement_collection)},
+};
+
+static const JNINativeMethod sMeasurementCorrectionsMethods[] = {
+    /* name, signature, funcPtr */
+    {"native_is_measurement_corrections_supported", "()Z",
+            reinterpret_cast<void*>(
+            android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported)},
     {"native_inject_gnss_measurement_corrections",
-     "(Landroid/location/GnssMeasurementCorrections;)Z",
-     reinterpret_cast<void*>(
-         android_location_GnssMeasurementsProvider_inject_gnss_measurement_corrections)},
+            "(Landroid/location/GnssMeasurementCorrections;)Z",
+            reinterpret_cast<void*>(
+            android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections)},
 };
 
 static const JNINativeMethod sNavigationMessageMethods[] = {
@@ -2992,6 +3050,11 @@
             NELEM(sMeasurementMethods));
     jniRegisterNativeMethods(
             env,
+            "com/android/server/location/GnssMeasurementCorrectionsProvider",
+            sMeasurementCorrectionsMethods,
+            NELEM(sMeasurementCorrectionsMethods));
+    jniRegisterNativeMethods(
+            env,
             "com/android/server/location/GnssNavigationMessageProvider",
             sNavigationMessageMethods,
             NELEM(sNavigationMessageMethods));
diff --git a/services/ipmemorystore/Android.bp b/services/ipmemorystore/Android.bp
deleted file mode 100644
index 013cf56..0000000
--- a/services/ipmemorystore/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-java_library_static {
-    name: "services.ipmemorystore",
-    srcs: ["java/**/*.java"],
-}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3f323d9..39af565 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -108,7 +108,6 @@
 import com.android.server.media.projection.MediaProjectionManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
-import com.android.server.net.ipmemorystore.IpMemoryStoreService;
 import com.android.server.net.watchlist.NetworkWatchlistService;
 import com.android.server.notification.NotificationManagerService;
 import com.android.server.oemlock.OemLockService;
@@ -1264,14 +1263,6 @@
             }
             traceEnd();
 
-            traceBeginAndSlog("StartIpMemoryStoreService");
-            try {
-                ServiceManager.addService(Context.IP_MEMORY_STORE_SERVICE,
-                        new IpMemoryStoreService(context));
-            } catch (Throwable e) {
-                reportWtf("starting IP Memory Store Service", e);
-            }
-            traceEnd();
 
             traceBeginAndSlog("StartIpSecService");
             try {
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 8ad4d76..486d15d 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -7,6 +7,19 @@
     ]
 }
 
+java_library_static {
+    name: "ipmemorystore-client",
+    sdk_version: "system_current",
+    srcs: [
+        ":framework-annotations",
+        "java/android/net/IpMemoryStoreClient.java",
+        "java/android/net/ipmemorystore/**.java",
+    ],
+    static_libs: [
+        "ipmemorystore-aidl-interfaces-java",
+    ]
+}
+
 filegroup {
     name: "services-networkstack-shared-srcs",
     srcs: [
diff --git a/services/net/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStore.java
new file mode 100644
index 0000000..9248299
--- /dev/null
+++ b/services/net/java/android/net/IpMemoryStore.java
@@ -0,0 +1,62 @@
+/*
+ * 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 android.net;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Manager class used to communicate with the ip memory store service in the network stack,
+ * which is running in a separate module.
+ * @hide
+*/
+public class IpMemoryStore extends IpMemoryStoreClient {
+    private final CompletableFuture<IIpMemoryStore> mService;
+
+    public IpMemoryStore(@NonNull final Context context) {
+        super(context);
+        mService = new CompletableFuture<>();
+        getNetworkStackClient().fetchIpMemoryStore(
+                new IIpMemoryStoreCallbacks.Stub() {
+                    @Override
+                    public void onIpMemoryStoreFetched(final IIpMemoryStore memoryStore) {
+                        mService.complete(memoryStore);
+                    }
+                });
+    }
+
+    @Override
+    protected IIpMemoryStore getService() throws InterruptedException, ExecutionException {
+        return mService.get();
+    }
+
+    @VisibleForTesting
+    protected NetworkStackClient getNetworkStackClient() {
+        return NetworkStackClient.getInstance();
+    }
+
+    /** Gets an instance of the memory store */
+    @NonNull
+    public static IpMemoryStore getMemoryStore(final Context context) {
+        return new IpMemoryStore(context);
+    }
+}
diff --git a/core/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStoreClient.java
similarity index 68%
rename from core/java/android/net/IpMemoryStore.java
rename to services/net/java/android/net/IpMemoryStoreClient.java
index 2f4d9bc..2f4fdbd 100644
--- a/core/java/android/net/IpMemoryStore.java
+++ b/services/net/java/android/net/IpMemoryStoreClient.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemService;
 import android.content.Context;
 import android.net.ipmemorystore.Blob;
 import android.net.ipmemorystore.IOnBlobRetrievedListener;
@@ -27,23 +26,34 @@
 import android.net.ipmemorystore.IOnSameNetworkResponseListener;
 import android.net.ipmemorystore.IOnStatusListener;
 import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.Status;
+import android.net.ipmemorystore.StatusParcelable;
 import android.os.RemoteException;
+import android.util.Log;
 
-import com.android.internal.util.Preconditions;
+import java.util.concurrent.ExecutionException;
 
 /**
- * The interface for system components to access the IP memory store.
- * @see com.android.server.net.ipmemorystore.IpMemoryStoreService
+ * service used to communicate with the ip memory store service in network stack,
+ * which is running in a separate module.
  * @hide
  */
-@SystemService(Context.IP_MEMORY_STORE_SERVICE)
-public class IpMemoryStore {
-    @NonNull final Context mContext;
-    @NonNull final IIpMemoryStore mService;
+public abstract class IpMemoryStoreClient {
+    private static final String TAG = IpMemoryStoreClient.class.getSimpleName();
+    private final Context mContext;
 
-    public IpMemoryStore(@NonNull final Context context, @NonNull final IIpMemoryStore service) {
-        mContext = Preconditions.checkNotNull(context, "missing context");
-        mService = Preconditions.checkNotNull(service, "missing IIpMemoryStore");
+    public IpMemoryStoreClient(@NonNull final Context context) {
+        if (context == null) throw new IllegalArgumentException("missing context");
+        mContext = context;
+    }
+
+    @NonNull
+    protected abstract IIpMemoryStore getService() throws InterruptedException, ExecutionException;
+
+    protected StatusParcelable internalErrorStatus() {
+        final StatusParcelable error = new StatusParcelable();
+        error.resultCode = Status.ERROR_UNKNOWN;
+        return error;
     }
 
     /**
@@ -66,9 +76,13 @@
             @NonNull final NetworkAttributes attributes,
             @Nullable final IOnStatusListener listener) {
         try {
-            mService.storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+            try {
+                getService().storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onComplete(internalErrorStatus());
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error storing network attributes", e);
         }
     }
 
@@ -87,9 +101,13 @@
             @NonNull final String name, @NonNull final Blob data,
             @Nullable final IOnStatusListener listener) {
         try {
-            mService.storeBlob(l2Key, clientId, name, data, listener);
+            try {
+                getService().storeBlob(l2Key, clientId, name, data, listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onComplete(internalErrorStatus());
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error storing blob", e);
         }
     }
 
@@ -110,9 +128,13 @@
     public void findL2Key(@NonNull final NetworkAttributes attributes,
             @NonNull final IOnL2KeyResponseListener listener) {
         try {
-            mService.findL2Key(attributes.toParcelable(), listener);
+            try {
+                getService().findL2Key(attributes.toParcelable(), listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onL2KeyResponse(internalErrorStatus(), null);
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error finding L2 Key", e);
         }
     }
 
@@ -128,9 +150,13 @@
     public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
             @NonNull final IOnSameNetworkResponseListener listener) {
         try {
-            mService.isSameNetwork(l2Key1, l2Key2, listener);
+            try {
+                getService().isSameNetwork(l2Key1, l2Key2, listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onSameNetworkResponse(internalErrorStatus(), null);
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error checking for network sameness", e);
         }
     }
 
@@ -146,9 +172,13 @@
     public void retrieveNetworkAttributes(@NonNull final String l2Key,
             @NonNull final IOnNetworkAttributesRetrieved listener) {
         try {
-            mService.retrieveNetworkAttributes(l2Key, listener);
+            try {
+                getService().retrieveNetworkAttributes(l2Key, listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onNetworkAttributesRetrieved(internalErrorStatus(), null, null);
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error retrieving network attributes", e);
         }
     }
 
@@ -166,14 +196,13 @@
     public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
             @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
         try {
-            mService.retrieveBlob(l2Key, clientId, name, listener);
+            try {
+                getService().retrieveBlob(l2Key, clientId, name, listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onBlobRetrieved(internalErrorStatus(), null, null, null);
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error retrieving blob", e);
         }
     }
-
-    /** Gets an instance of the memory store */
-    public static IpMemoryStore getMemoryStore(final Context context) {
-        return (IpMemoryStore) context.getSystemService(Context.IP_MEMORY_STORE_SERVICE);
-    }
 }
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index cc09fe3..7befd087 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -130,6 +130,21 @@
         });
     }
 
+    /**
+     * Get an instance of the IpMemoryStore.
+     *
+     * <p>The IpMemoryStore will be returned asynchronously through the provided callbacks.
+     */
+    public void fetchIpMemoryStore(IIpMemoryStoreCallbacks cb) {
+        requestConnector(connector -> {
+            try {
+                connector.fetchIpMemoryStore(cb);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        });
+    }
+
     private class NetworkStackConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java
similarity index 97%
rename from core/java/android/net/TcpKeepalivePacketData.java
rename to services/net/java/android/net/TcpKeepalivePacketData.java
index 99d36c5..398a6b31 100644
--- a/core/java/android/net/TcpKeepalivePacketData.java
+++ b/services/net/java/android/net/TcpKeepalivePacketData.java
@@ -167,8 +167,9 @@
                 tcpWndScale);
     }
 
-    /* Parcelable Implementation. */
-    /* Note that this object implements parcelable (and needs to keep doing this as it inherits
+    /**
+     * Parcelable Implementation.
+     * Note that this object implements parcelable (and needs to keep doing this as it inherits
      * from a class that does), but should usually be parceled as a stable parcelable using
      * the toStableParcelable() and fromStableParcelable() methods.
      */
@@ -194,7 +195,7 @@
     }
 
     /** Parcelable Creator. */
-    public static final @android.annotation.NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
+    public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
             new Parcelable.Creator<TcpKeepalivePacketData>() {
                 public TcpKeepalivePacketData createFromParcel(Parcel in) {
                     return new TcpKeepalivePacketData(in);
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/services/net/java/android/net/ipmemorystore/NetworkAttributes.java
similarity index 100%
rename from core/java/android/net/ipmemorystore/NetworkAttributes.java
rename to services/net/java/android/net/ipmemorystore/NetworkAttributes.java
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/services/net/java/android/net/ipmemorystore/SameL3NetworkResponse.java
similarity index 100%
rename from core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
rename to services/net/java/android/net/ipmemorystore/SameL3NetworkResponse.java
diff --git a/core/java/android/net/ipmemorystore/Status.java b/services/net/java/android/net/ipmemorystore/Status.java
similarity index 97%
rename from core/java/android/net/ipmemorystore/Status.java
rename to services/net/java/android/net/ipmemorystore/Status.java
index cacd42d..13242c0 100644
--- a/core/java/android/net/ipmemorystore/Status.java
+++ b/services/net/java/android/net/ipmemorystore/Status.java
@@ -32,6 +32,7 @@
     public static final int ERROR_ILLEGAL_ARGUMENT = -2;
     public static final int ERROR_DATABASE_CANNOT_BE_OPENED = -3;
     public static final int ERROR_STORAGE = -4;
+    public static final int ERROR_UNKNOWN = -5;
 
     public final int resultCode;
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 6386b3b3..7c91b64 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -15,7 +15,10 @@
  */
 package com.android.server;
 
+import static android.app.AlarmManager.ELAPSED_REALTIME;
 import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.RTC;
+import static android.app.AlarmManager.RTC_WAKEUP;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
@@ -254,14 +257,22 @@
     }
 
     private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
+        setTestAlarm(type, triggerTime, operation, TEST_CALLING_UID);
+    }
+
+    private void setTestAlarm(int type, long triggerTime, PendingIntent operation, int callingUid) {
         mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0,
                 operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null,
-                TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+                callingUid, TEST_CALLING_PACKAGE);
     }
 
     private PendingIntent getNewMockPendingIntent() {
+        return getNewMockPendingIntent(TEST_CALLING_UID);
+    }
+
+    private PendingIntent getNewMockPendingIntent(int mockUid) {
         final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS);
-        when(mockPi.getCreatorUid()).thenReturn(TEST_CALLING_UID);
+        when(mockPi.getCreatorUid()).thenReturn(mockUid);
         when(mockPi.getCreatorPackage()).thenReturn(TEST_CALLING_PACKAGE);
         return mockPi;
     }
@@ -724,6 +735,91 @@
         verify(mMockContext).sendBroadcastAsUser(mService.mTimeTickIntent, UserHandle.ALL);
     }
 
+    @Test
+    public void alarmCountKeyedOnCallingUid() {
+        final int mockCreatorUid = 431412;
+        final PendingIntent pi = getNewMockPendingIntent(mockCreatorUid);
+        setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 5, pi);
+        assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        assertEquals(-1, mService.mAlarmsPerUid.get(mockCreatorUid, -1));
+    }
+
+    @Test
+    public void alarmCountOnSet() {
+        final int numAlarms = 103;
+        final int[] types = {RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME};
+        for (int i = 1; i <= numAlarms; i++) {
+            setTestAlarm(types[i % 4], mNowElapsedTest + i, getNewMockPendingIntent());
+            assertEquals(i, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        }
+    }
+
+    @Test
+    public void alarmCountOnExpiration() throws InterruptedException {
+        final int numAlarms = 8; // This test is slow
+        for (int i = 0; i < numAlarms; i++) {
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+        }
+        int expired = 0;
+        while (expired < numAlarms) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            mTestTimer.expire();
+            expired++;
+            assertEquals(numAlarms - expired, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+        }
+    }
+
+    @Test
+    public void alarmCountOnUidRemoved() {
+        final int numAlarms = 10;
+        for (int i = 0; i < numAlarms; i++) {
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+        }
+        assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        mService.removeLocked(TEST_CALLING_UID);
+        assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+    }
+
+    @Test
+    public void alarmCountOnPackageRemoved() {
+        final int numAlarms = 10;
+        for (int i = 0; i < numAlarms; i++) {
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+        }
+        assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        mService.removeLocked(TEST_CALLING_PACKAGE);
+        assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+    }
+
+    @Test
+    public void alarmCountOnUserRemoved() {
+        final int mockUserId = 15;
+        final int numAlarms = 10;
+        for (int i = 0; i < numAlarms; i++) {
+            int mockUid = UserHandle.getUid(mockUserId, 1234 + i);
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10,
+                    getNewMockPendingIntent(mockUid), mockUid);
+        }
+        assertEquals(numAlarms, mService.mAlarmsPerUid.size());
+        mService.removeUserLocked(mockUserId);
+        assertEquals(0, mService.mAlarmsPerUid.size());
+    }
+
+    @Test
+    public void alarmCountOnAlarmRemoved() {
+        final int numAlarms = 10;
+        final PendingIntent[] pis = new PendingIntent[numAlarms];
+        for (int i = 0; i < numAlarms; i++) {
+            pis[i] = getNewMockPendingIntent();
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]);
+        }
+        assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        for (int i = 0; i < numAlarms; i++) {
+            mService.removeLocked(pis[i], null);
+            assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+        }
+    }
+
     @After
     public void tearDown() {
         if (mMockingSession != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 8e78a56..c45122e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -52,6 +52,7 @@
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkPolicyManager;
 import android.os.Build;
+import android.os.Looper;
 import android.os.SystemClock;
 import android.util.DataUnit;
 
@@ -102,6 +103,8 @@
         LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
         LocalServices.addService(NetworkPolicyManagerInternal.class, mNetPolicyManagerInternal);
 
+        when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+
         // Freeze the clocks at this moment in time
         JobSchedulerService.sSystemClock =
                 Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index 86e8598..2e5efbd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -28,6 +28,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.PowerManager;
 import android.provider.Settings.Global;
 
 import androidx.test.filters.SmallTest;
@@ -452,6 +453,21 @@
         assertEquals(true, mDevice.batterySaverEnabled);
         assertEquals(30, mPersistedState.batteryLevel);
         assertEquals(true, mPersistedState.batteryLow);
+
+        // Disable auto battery saver.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+        mDevice.setBatteryLevel(25);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(25, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // PowerManager sets batteryLow to true at 15% if battery saver trigger level is lower.
+        mDevice.setBatteryLevel(15);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(15, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
     }
 
     @Test
@@ -542,6 +558,12 @@
         assertEquals(100, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
 
+        mDevice.setBatteryLevel(97);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
+        assertEquals(97, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
         mDevice.setBatteryLevel(95);
 
         assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
@@ -719,6 +741,48 @@
     }
 
     @Test
+    public void testAutoBatterySaver_withSticky_withAutoOffToggled() {
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
+
+        // Scenario 1: User turns BS on manually above the threshold, it shouldn't turn off even
+        // with battery level change above threshold.
+        mDevice.setBatteryLevel(100);
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(95);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
+        assertEquals(95, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Disable auto disable while in the pending sticky state. BS should reactivate after
+        // unplug.
+        mDevice.setPowered(true);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0);
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Sticky BS should activate.
+        assertEquals(95, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Enable auto disable while in the pending sticky state. Sticky should turn off after
+        // unplug.
+        mDevice.setPowered(true);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+        mDevice.setPowered(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
+        assertEquals(95, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+    }
+
+    @Test
     public void testAutoBatterySaver_withStickyDisabled() {
         when(mMockResources.getBoolean(
                 com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
@@ -739,7 +803,9 @@
         assertEquals(30, mPersistedState.batteryLevel);
         assertEquals(true, mPersistedState.batteryLow);
 
+        mDevice.setPowered(true);
         mDevice.setBatteryLevel(80);
+        mDevice.setPowered(false);
 
         assertEquals(false, mDevice.batterySaverEnabled); // Not sticky.
         assertEquals(80, mPersistedState.batteryLevel);
@@ -830,10 +896,9 @@
         assertEquals(90, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
 
-        // Reboot -- setting BS from adb is also sticky.
+        // Reboot -- LOW_POWER_MODE shouldn't be persisted.
         initDevice();
-
-        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(false, mDevice.batterySaverEnabled);
         assertEquals(90, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
     }
@@ -841,7 +906,8 @@
     @Test
     public void testAutoBatterySaver_smartBatterySaverEnabled() {
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
-        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 1);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+                PowerManager.POWER_SAVER_MODE_DYNAMIC);
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
 
         assertEquals(false, mDevice.batterySaverEnabled);
@@ -922,8 +988,8 @@
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 71);
         mDevice.setBatteryLevel(mPersistedState.batteryLevel);
 
-        // changes are only registered if some battery level changed
-        assertEquals(false, mDevice.batterySaverEnabled);
+        // Changes should register immediately.
+        assertEquals(true, mDevice.batterySaverEnabled);
         assertEquals(70, mPersistedState.batteryLevel);
 
         mDevice.setBatteryLevel(69);
@@ -935,8 +1001,8 @@
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 60);
         mDevice.setBatteryLevel(mPersistedState.batteryLevel);
 
-        // changes are only registered if battery level changed
-        assertEquals(true, mDevice.batterySaverEnabled);
+        // Changes should register immediately.
+        assertEquals(false, mDevice.batterySaverEnabled);
         assertEquals(69, mPersistedState.batteryLevel);
 
         mDevice.setBatteryLevel(68);
@@ -956,4 +1022,220 @@
         assertEquals(true, mDevice.batterySaverEnabled);
         assertEquals(30, mPersistedState.batteryLevel);
     }
+
+    @Test
+    public void testAutoBatterySaver_snoozed_autoEnabled() {
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 30);
+        // Test dynamic threshold higher than automatic to make sure it doesn't interfere when it's
+        // not enabled.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+                PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(51);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(51, mPersistedState.batteryLevel);
+
+        // Hit dynamic threshold. BS should be disabled since dynamic is off
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(20);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(20, mPersistedState.batteryLevel);
+
+        // Lower threshold. Level is still below, so should still be snoozed.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 25);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(20, mPersistedState.batteryLevel);
+
+        // Lower threshold even more. Battery no longer considered "low" so snoozing should be
+        // disabled.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 10);
+        // "batteryLow" is set in setBatteryLevel.
+        mDevice.setBatteryLevel(19);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(19, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(10);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // No longer snoozing.
+        assertEquals(10, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        // Plug in and out, snooze will reset.
+        mDevice.setPowered(true);
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(10, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(60);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+
+        // Test toggling resets snooze.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+        mDevice.setPowered(false);
+        mDevice.setBatteryLevel(45);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(45, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(45, mPersistedState.batteryLevel);
+
+        // Disable and re-enable.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Snooze reset
+        assertEquals(45, mPersistedState.batteryLevel);
+    }
+
+    @Test
+    public void testAutoBatterySaver_snoozed_dynamicEnabled() {
+        // Test auto threshold higher than dynamic to make sure it doesn't interfere when it's
+        // not enabled.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 30);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+                PowerManager.POWER_SAVER_MODE_DYNAMIC);
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(51);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(51, mPersistedState.batteryLevel);
+
+        // Hit automatic threshold. BS should be disabled since automatic is off
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(20);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(20, mPersistedState.batteryLevel);
+
+        // Lower threshold. Level is still below, so should still be snoozed.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 25);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(20, mPersistedState.batteryLevel);
+
+        // Lower threshold even more. Battery no longer considered "low" so snoozing should be
+        // disabled.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 10);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(20, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(10);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // No longer snoozing.
+        assertEquals(10, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        // Plug in and out, snooze will reset.
+        mDevice.setPowered(true);
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(10, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(60);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+
+        // Test toggling resets snooze.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
+        mDevice.setPowered(false);
+        mDevice.setBatteryLevel(45);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(45, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(45, mPersistedState.batteryLevel);
+
+        // Disable and re-enable.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Snooze reset
+        assertEquals(45, mPersistedState.batteryLevel);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 26b1224..caf6c9c 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -1138,7 +1138,7 @@
     }
 
     @Override
-    public String getContentCaptureServicePackageName() throws RemoteException {
+    public String getSystemCaptionsServicePackageName() throws RemoteException {
         return null;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 9504381..cd095a5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -250,7 +250,7 @@
                 .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                 .setRank(123)
                 .setPerson(makePerson("person", "personKey", "personUri"))
-                .setLongLived()
+                .setLongLived(true)
                 .setExtras(pb)
                 .build();
         si.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -352,7 +352,7 @@
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                 .setRank(123)
                 .setPerson(makePerson("person", "personKey", "personUri"))
-                .setLongLived()
+                .setLongLived(true)
                 .setExtras(pb)
                 .build();
         sorig.addFlags(ShortcutInfo.FLAG_PINNED);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
index 5556a15..febb795 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
@@ -43,7 +43,6 @@
  */
 @SmallTest
 @Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
 public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase {
 
     @Mock
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index 1e02a12..329af95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -38,9 +38,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 
 import android.app.AppOpsManager;
-import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
-import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.os.Handler;
@@ -50,7 +48,6 @@
 import android.util.Log;
 import android.view.IWindowManager;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 
 import com.android.server.am.AssistDataRequester;
@@ -88,12 +85,10 @@
     private static final int TEST_UID = 0;
     private static final String TEST_PACKAGE = "";
 
-    private Context mContext;
     private AssistDataRequester mDataRequester;
     private Callbacks mCallbacks;
     private Object mCallbacksLock;
     private Handler mHandler;
-    private IActivityManager mAm;
     private IActivityTaskManager mAtm;
     private IWindowManager mWm;
     private AppOpsManager mAppOpsManager;
@@ -109,7 +104,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mAm = mock(IActivityManager.class);
         mAtm = mock(IActivityTaskManager.class);
         mWm = mock(IWindowManager.class);
         mAppOpsManager = mock(AppOpsManager.class);
@@ -118,7 +112,7 @@
         mCallbacks = new Callbacks();
         mDataRequester = new AssistDataRequester(mContext, mWm, mAppOpsManager, mCallbacks,
                 mCallbacksLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT);
-
+        mDataRequester.mActivityTaskManager = mAtm;
         // Gate the continuation of the assist data callbacks until we are ready within the tests
         mGate = new CountDownLatch(1);
         doAnswer(invocation -> {
@@ -155,7 +149,6 @@
                 .checkOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString());
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testRequestData() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -176,7 +169,6 @@
         assertReceivedDataCount(0, 0, 0, 0);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testCurrentAppDisallow_expectNullCallbacks() throws Exception {
         setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -187,7 +179,6 @@
         assertReceivedDataCount(0, 1, 0, 1);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testProcessPendingData() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -245,7 +236,6 @@
         assertReceivedDataCount(0, 1, 0, 1);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testDisallowAssistContextExtras_expectNullDataCallbacks() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -259,7 +249,6 @@
         assertReceivedDataCount(0, 1, 0, 1);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -270,7 +259,6 @@
         assertReceivedDataCount(5, 5, 0, 0);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index b9e9909..d8a01b9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -159,7 +159,6 @@
      * Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
      */
     @Test
-    @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
     public void testTaskChangeCallBacks() throws Exception {
         final Object[] params = new Object[2];
         final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index b03f63b..4f8fe5b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -87,7 +87,6 @@
  */
 @SmallTest
 @Presubmit
-@FlakyTest(bugId = 124127512)
 public class WindowStateTests extends WindowTestsBase {
     private static int sPreviousNewInsetsMode;
 
@@ -363,7 +362,6 @@
         assertFalse(app.canAffectSystemUiFlags());
     }
 
-    @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
     @Test
     public void testVisibleWithInsetsProvider() throws Exception {
         final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar");
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index f0a26f5..ca264f7 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -318,8 +318,8 @@
     public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 0x7FC;
     /** APN has been disabled. */
     public static final int APN_DISABLED = 0x7FD;
-    /** PPP inactivity timer expired. */
-    public static final int PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
+    /** Maximum PPP inactivity timer expired. */
+    public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
     /** IPv6 address transfer failed. */
     public static final int IPV6_ADDRESS_TRANSFER_FAILED = 0x7FF;
     /** Target RAT swap failed. */
@@ -339,12 +339,12 @@
      * IPv4 data call bring up is rejected because the UE already maintains the allotted maximum
      * number of IPv4 data connections.
      */
-    public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 0x804;
+    public static final int MAX_IPV4_CONNECTIONS = 0x804;
     /**
      * IPv6 data call bring up is rejected because the UE already maintains the allotted maximum
      * number of IPv6 data connections.
      */
-    public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 0x805;
+    public static final int MAX_IPV6_CONNECTIONS = 0x805;
     /**
      * New PDN bring up is rejected during interface selection because the UE has already allotted
      * the available interfaces for other PDNs.
@@ -416,7 +416,7 @@
      */
     public static final int CHANNEL_ACQUISITION_FAILURE = 0x81E;
     /** Maximum access probes transmitted. */
-    public static final int ACCESS_PROBE_LIMIT_REACHED = 0x81F;
+    public static final int MAX_ACCESS_PROBE = 0x81F;
     /** Concurrent service is not supported by base station. */
     public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 0x820;
     /** There was no response received from the base station. */
@@ -1079,14 +1079,14 @@
             SIM_CARD_CHANGED,
             LOW_POWER_MODE_OR_POWERING_DOWN,
             APN_DISABLED,
-            PPP_INACTIVITY_TIMER_EXPIRED,
+            MAX_PPP_INACTIVITY_TIMER_EXPIRED,
             IPV6_ADDRESS_TRANSFER_FAILED,
             TRAT_SWAP_FAILED,
             EHRPD_TO_HRPD_FALLBACK,
             MIP_CONFIG_FAILURE,
             PDN_INACTIVITY_TIMER_EXPIRED,
-            IPV4_CONNECTIONS_LIMIT_REACHED,
-            IPV6_CONNECTIONS_LIMIT_REACHED,
+            MAX_IPV4_CONNECTIONS,
+            MAX_IPV6_CONNECTIONS,
             APN_MISMATCH,
             IP_VERSION_MISMATCH,
             DUN_CALL_DISALLOWED,
@@ -1112,7 +1112,7 @@
             CDMA_INCOMING_CALL,
             CDMA_ALERT_STOP,
             CHANNEL_ACQUISITION_FAILURE,
-            ACCESS_PROBE_LIMIT_REACHED,
+            MAX_ACCESS_PROBE,
             CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
             NO_RESPONSE_FROM_BASE_STATION,
             REJECTED_BY_BASE_STATION,
@@ -1447,14 +1447,14 @@
         sFailCauseMap.put(SIM_CARD_CHANGED, "SIM_CARD_CHANGED");
         sFailCauseMap.put(LOW_POWER_MODE_OR_POWERING_DOWN, "LOW_POWER_MODE_OR_POWERING_DOWN");
         sFailCauseMap.put(APN_DISABLED, "APN_DISABLED");
-        sFailCauseMap.put(PPP_INACTIVITY_TIMER_EXPIRED, "PPP_INACTIVITY_TIMER_EXPIRED");
+        sFailCauseMap.put(MAX_PPP_INACTIVITY_TIMER_EXPIRED, "MAX_PPP_INACTIVITY_TIMER_EXPIRED");
         sFailCauseMap.put(IPV6_ADDRESS_TRANSFER_FAILED, "IPV6_ADDRESS_TRANSFER_FAILED");
         sFailCauseMap.put(TRAT_SWAP_FAILED, "TRAT_SWAP_FAILED");
         sFailCauseMap.put(EHRPD_TO_HRPD_FALLBACK, "EHRPD_TO_HRPD_FALLBACK");
         sFailCauseMap.put(MIP_CONFIG_FAILURE, "MIP_CONFIG_FAILURE");
         sFailCauseMap.put(PDN_INACTIVITY_TIMER_EXPIRED, "PDN_INACTIVITY_TIMER_EXPIRED");
-        sFailCauseMap.put(IPV4_CONNECTIONS_LIMIT_REACHED, "IPV4_CONNECTIONS_LIMIT_REACHED");
-        sFailCauseMap.put(IPV6_CONNECTIONS_LIMIT_REACHED, "IPV6_CONNECTIONS_LIMIT_REACHED");
+        sFailCauseMap.put(MAX_IPV4_CONNECTIONS, "MAX_IPV4_CONNECTIONS");
+        sFailCauseMap.put(MAX_IPV6_CONNECTIONS, "MAX_IPV6_CONNECTIONS");
         sFailCauseMap.put(APN_MISMATCH, "APN_MISMATCH");
         sFailCauseMap.put(IP_VERSION_MISMATCH, "IP_VERSION_MISMATCH");
         sFailCauseMap.put(DUN_CALL_DISALLOWED, "DUN_CALL_DISALLOWED");
@@ -1480,7 +1480,7 @@
         sFailCauseMap.put(CDMA_INCOMING_CALL, "CDMA_INCOMING_CALL");
         sFailCauseMap.put(CDMA_ALERT_STOP, "CDMA_ALERT_STOP");
         sFailCauseMap.put(CHANNEL_ACQUISITION_FAILURE, "CHANNEL_ACQUISITION_FAILURE");
-        sFailCauseMap.put(ACCESS_PROBE_LIMIT_REACHED, "ACCESS_PROBE_LIMIT_REACHED");
+        sFailCauseMap.put(MAX_ACCESS_PROBE, "MAX_ACCESS_PROBE");
         sFailCauseMap.put(CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
                 "CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION");
         sFailCauseMap.put(NO_RESPONSE_FROM_BASE_STATION, "NO_RESPONSE_FROM_BASE_STATION");
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c31a14e..9145b25 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -27,7 +27,9 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
@@ -36,7 +38,7 @@
  * @hide
  */
 @SystemApi
-public class NetworkRegistrationInfo implements Parcelable {
+public final class NetworkRegistrationInfo implements Parcelable {
     /**
      * Network domain
      * @hide
@@ -51,41 +53,42 @@
     public static final int DOMAIN_PS = 2;
 
     /**
-     * Registration state
+     * Network registration state
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "REG_STATE_",
-            value = {REG_STATE_NOT_REG_NOT_SEARCHING, REG_STATE_HOME, REG_STATE_NOT_REG_SEARCHING,
-                    REG_STATE_DENIED, REG_STATE_UNKNOWN, REG_STATE_ROAMING})
-    public @interface RegState {}
+    @IntDef(prefix = "REGISTRATION_STATE_",
+            value = {REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, REGISTRATION_STATE_HOME,
+                    REGISTRATION_STATE_NOT_REGISTERED_SEARCHING, REGISTRATION_STATE_DENIED,
+                    REGISTRATION_STATE_UNKNOWN, REGISTRATION_STATE_ROAMING})
+    public @interface RegistrationState {}
 
-    /** Not registered. The device is not currently searching a new operator to register */
-    public static final int REG_STATE_NOT_REG_NOT_SEARCHING = 0;
-    /** Registered on home network */
-    public static final int REG_STATE_HOME                  = 1;
-    /** Not registered. The device is currently searching a new operator to register */
-    public static final int REG_STATE_NOT_REG_SEARCHING     = 2;
-    /** Registration denied */
-    public static final int REG_STATE_DENIED                = 3;
-    /** Registration state is unknown */
-    public static final int REG_STATE_UNKNOWN               = 4;
-    /** Registered on roaming network */
-    public static final int REG_STATE_ROAMING               = 5;
+    /** Not registered. The device is not currently searching a new operator to register. */
+    public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0;
+    /** Registered on home network. */
+    public static final int REGISTRATION_STATE_HOME = 1;
+    /** Not registered. The device is currently searching a new operator to register. */
+    public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2;
+    /** Registration denied. */
+    public static final int REGISTRATION_STATE_DENIED = 3;
+    /** Registration state is unknown. */
+    public static final int REGISTRATION_STATE_UNKNOWN = 4;
+    /** Registered on roaming network. */
+    public static final int REGISTRATION_STATE_ROAMING = 5;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "NR_STATUS_",
-            value = {NR_STATUS_NONE, NR_STATUS_RESTRICTED, NR_STATUS_NOT_RESTRICTED,
-                    NR_STATUS_CONNECTED})
-    public @interface NRStatus {}
+    @IntDef(prefix = "NR_STATE_",
+            value = {NR_STATE_NONE, NR_STATE_RESTRICTED, NR_STATE_NOT_RESTRICTED,
+                    NR_STATE_CONNECTED})
+    public @interface NRState {}
 
     /**
      * The device isn't camped on an LTE cell or the LTE cell doesn't support E-UTRA-NR
      * Dual Connectivity(EN-DC).
      * @hide
      */
-    public static final int NR_STATUS_NONE = -1;
+    public static final int NR_STATE_NONE = -1;
 
     /**
      * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) but
@@ -93,7 +96,7 @@
      * the selected PLMN.
      * @hide
      */
-    public static final int NR_STATUS_RESTRICTED = 1;
+    public static final int NR_STATE_RESTRICTED = 1;
 
     /**
      * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and both
@@ -101,14 +104,14 @@
      * selected PLMN.
      * @hide
      */
-    public static final int NR_STATUS_NOT_RESTRICTED = 2;
+    public static final int NR_STATE_NOT_RESTRICTED = 2;
 
     /**
      * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and
      * also connected to at least one 5G cell as a secondary serving cell.
      * @hide
      */
-    public static final int NR_STATUS_CONNECTED = 3;
+    public static final int NR_STATE_CONNECTED = 3;
 
     /**
      * Supported service type
@@ -116,23 +119,36 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "SERVICE_TYPE_",
-            value = {SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS, SERVICE_TYPE_VIDEO,
-                    SERVICE_TYPE_EMERGENCY})
+            value = {SERVICE_TYPE_UNKNOWN, SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS,
+                    SERVICE_TYPE_VIDEO, SERVICE_TYPE_EMERGENCY})
     public @interface ServiceType {}
 
+    /** Unkown service */
+    public static final int SERVICE_TYPE_UNKNOWN    = 0;
+
+    /** Voice service */
     public static final int SERVICE_TYPE_VOICE      = 1;
+
+    /** Data service */
     public static final int SERVICE_TYPE_DATA       = 2;
+
+    /** SMS service */
     public static final int SERVICE_TYPE_SMS        = 3;
+
+    /** Video service */
     public static final int SERVICE_TYPE_VIDEO      = 4;
+
+    /** Emergency service */
     public static final int SERVICE_TYPE_EMERGENCY  = 5;
 
     @Domain
     private final int mDomain;
 
+    @TransportType
     private final int mTransportType;
 
-    @RegState
-    private final int mRegState;
+    @RegistrationState
+    private final int mRegistrationState;
 
     /**
      * Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type
@@ -144,15 +160,15 @@
     @NetworkType
     private int mAccessNetworkTechnology;
 
-    @NRStatus
-    private int mNrStatus;
+    @NRState
+    private int mNrState;
 
     private final int mRejectCause;
 
     private final boolean mEmergencyOnly;
 
     @ServiceType
-    private final int[] mAvailableServices;
+    private final ArrayList<Integer> mAvailableServices;
 
     @Nullable
     private CellIdentity mCellIdentity;
@@ -167,54 +183,56 @@
      * @param domain Network domain. Must be a {@link Domain}. For transport type
      * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, this must set to {@link #DOMAIN_PS}.
      * @param transportType Transport type.
-     * @param regState Network registration state. Must be one of the {@link RegState}. For
-     * transport type {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, only
-     * {@link #REG_STATE_HOME} and {@link #REG_STATE_NOT_REG_NOT_SEARCHING} are valid states.
+     * @param registrationState Network registration state. For transport type
+     * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, only
+     * {@link #REGISTRATION_STATE_HOME} and {@link #REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING}
+     * are valid states.
      * @param accessNetworkTechnology Access network technology.For transport type
      * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, set to
      * {@link TelephonyManager#NETWORK_TYPE_IWLAN}.
-     * @param rejectCause Reason for denial if the registration state is {@link #REG_STATE_DENIED}.
-     * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008
-     * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA. If
-     * the reject cause is not supported or unknown, set it to 0.
+     * @param rejectCause Reason for denial if the registration state is
+     * {@link #REGISTRATION_STATE_DENIED}. Depending on {@code accessNetworkTechnology}, the values
+     * are defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2
+     * A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set it to 0.
      * // TODO: Add IWLAN reject cause reference
      * @param emergencyOnly True if this registration is for emergency only.
-     * @param availableServices The list of the supported services. Each element must be one of
-     * the {@link ServiceType}.
+     * @param availableServices The list of the supported services.
      * @param cellIdentity The identity representing a unique cell or wifi AP. Set to null if the
      * information is not available.
      */
-    public NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType,
-                                   @RegState int regState,
+    private NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType,
+                                   @RegistrationState int registrationState,
                                    @NetworkType int accessNetworkTechnology, int rejectCause,
                                    boolean emergencyOnly,
-                                   @NonNull @ServiceType int[] availableServices,
+                                   @Nullable @ServiceType List<Integer> availableServices,
                                    @Nullable CellIdentity cellIdentity) {
         mDomain = domain;
         mTransportType = transportType;
-        mRegState = regState;
-        mRoamingType = (regState == REG_STATE_ROAMING)
+        mRegistrationState = registrationState;
+        mRoamingType = (registrationState == REGISTRATION_STATE_ROAMING)
                 ? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
         mAccessNetworkTechnology = accessNetworkTechnology;
         mRejectCause = rejectCause;
-        mAvailableServices = availableServices;
+        mAvailableServices = (availableServices != null)
+                ? new ArrayList<>(availableServices) : new ArrayList<>();
         mCellIdentity = cellIdentity;
         mEmergencyOnly = emergencyOnly;
-        mNrStatus = NR_STATUS_NONE;
+        mNrState = NR_STATE_NONE;
     }
 
     /**
      * Constructor for voice network registration info.
      * @hide
      */
-    public NetworkRegistrationInfo(int domain, @TransportType int transportType, int regState,
-                                   int accessNetworkTechnology, int rejectCause,
-                                   boolean emergencyOnly, int[] availableServices,
+    public NetworkRegistrationInfo(int domain, @TransportType int transportType,
+                                   int registrationState, int accessNetworkTechnology,
+                                   int rejectCause, boolean emergencyOnly,
+                                   @Nullable List<Integer> availableServices,
                                    @Nullable CellIdentity cellIdentity, boolean cssSupported,
                                    int roamingIndicator, int systemIsInPrl,
                                    int defaultRoamingIndicator) {
-        this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly,
-                availableServices, cellIdentity);
+        this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
+                emergencyOnly, availableServices, cellIdentity);
 
         mVoiceSpecificStates = new VoiceSpecificRegistrationStates(cssSupported, roamingIndicator,
                 systemIsInPrl, defaultRoamingIndicator);
@@ -224,42 +242,44 @@
      * Constructor for data network registration info.
      * @hide
      */
-    public NetworkRegistrationInfo(int domain, @TransportType int transportType, int regState,
-                                   int accessNetworkTechnology, int rejectCause,
-                                   boolean emergencyOnly, int[] availableServices,
+    public NetworkRegistrationInfo(int domain, @TransportType int transportType,
+                                   int registrationState, int accessNetworkTechnology,
+                                   int rejectCause, boolean emergencyOnly,
+                                   @Nullable List<Integer> availableServices,
                                    @Nullable CellIdentity cellIdentity, int maxDataCalls,
                                    boolean isDcNrRestricted, boolean isNrAvailable,
                                    boolean isEndcAvailable,
                                    LteVopsSupportInfo lteVopsSupportInfo) {
-        this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly,
-                availableServices, cellIdentity);
+        this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
+                emergencyOnly, availableServices, cellIdentity);
 
         mDataSpecificStates = new DataSpecificRegistrationStates(
                 maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo);
-        updateNrStatus(mDataSpecificStates);
+        updateNrState(mDataSpecificStates);
     }
 
     private NetworkRegistrationInfo(Parcel source) {
         mDomain = source.readInt();
         mTransportType = source.readInt();
-        mRegState = source.readInt();
+        mRegistrationState = source.readInt();
         mRoamingType = source.readInt();
         mAccessNetworkTechnology = source.readInt();
         mRejectCause = source.readInt();
         mEmergencyOnly = source.readBoolean();
-        mAvailableServices = source.createIntArray();
+        mAvailableServices = new ArrayList<>();
+        source.readList(mAvailableServices, Integer.class.getClassLoader());
         mCellIdentity = source.readParcelable(CellIdentity.class.getClassLoader());
         mVoiceSpecificStates = source.readParcelable(
                 VoiceSpecificRegistrationStates.class.getClassLoader());
         mDataSpecificStates = source.readParcelable(
                 DataSpecificRegistrationStates.class.getClassLoader());
-        mNrStatus = source.readInt();
+        mNrState = source.readInt();
     }
 
     /**
      * @return The transport type.
      */
-    public int getTransportType() { return mTransportType; }
+    public @TransportType int getTransportType() { return mTransportType; }
 
     /**
      * @return The network domain.
@@ -267,23 +287,23 @@
     public @Domain int getDomain() { return mDomain; }
 
     /**
-     * @return the 5G NR connection status.
+     * @return the 5G NR connection state.
      * @hide
      */
-    public @NRStatus int getNrStatus() {
-        return mNrStatus;
+    public @NRState int getNrState() {
+        return mNrState;
     }
 
     /** @hide */
-    public void setNrStatus(@NRStatus int nrStatus) {
-        mNrStatus = nrStatus;
+    public void setNrState(@NRState int nrState) {
+        mNrState = nrState;
     }
 
     /**
      * @return The registration state.
      */
-    public @RegState int getRegState() {
-        return mRegState;
+    public @RegistrationState int getRegistrationState() {
+        return mRegistrationState;
     }
 
     /**
@@ -298,7 +318,8 @@
      * @return {@code true} if in service.
      */
     public boolean isInService() {
-        return mRegState == REG_STATE_HOME || mRegState == REG_STATE_ROAMING;
+        return mRegistrationState == REGISTRATION_STATE_HOME
+                || mRegistrationState == REGISTRATION_STATE_ROAMING;
     }
 
     /**
@@ -328,7 +349,9 @@
      */
     @NonNull
     @ServiceType
-    public int[] getAvailableServices() { return mAvailableServices; }
+    public List<Integer> getAvailableServices() {
+        return Collections.unmodifiableList(mAvailableServices);
+    }
 
     /**
      * @return The access network technology {@link NetworkType}.
@@ -346,7 +369,7 @@
     }
 
     /**
-     * @return Reason for denial if the registration state is {@link #REG_STATE_DENIED}.
+     * @return Reason for denial if the registration state is {@link #REGISTRATION_STATE_DENIED}.
      * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008
      * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA
      */
@@ -407,28 +430,28 @@
      *
      * @hide
      *
-     * @param regState The registration state
+     * @param registrationState The registration state
      * @return The reg state in string
      */
-    public static String regStateToString(@RegState int regState) {
-        switch (regState) {
-            case REG_STATE_NOT_REG_NOT_SEARCHING: return "NOT_REG_NOT_SEARCHING";
-            case REG_STATE_HOME: return "HOME";
-            case REG_STATE_NOT_REG_SEARCHING: return "NOT_REG_SEARCHING";
-            case REG_STATE_DENIED: return "DENIED";
-            case REG_STATE_UNKNOWN: return "UNKNOWN";
-            case REG_STATE_ROAMING: return "ROAMING";
+    public static String registrationStateToString(@RegistrationState int registrationState) {
+        switch (registrationState) {
+            case REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING: return "NOT_REG_OR_SEARCHING";
+            case REGISTRATION_STATE_HOME: return "HOME";
+            case REGISTRATION_STATE_NOT_REGISTERED_SEARCHING: return "NOT_REG_SEARCHING";
+            case REGISTRATION_STATE_DENIED: return "DENIED";
+            case REGISTRATION_STATE_UNKNOWN: return "UNKNOWN";
+            case REGISTRATION_STATE_ROAMING: return "ROAMING";
         }
-        return "Unknown reg state " + regState;
+        return "Unknown reg state " + registrationState;
     }
 
-    private static String nrStatusToString(@NRStatus int nrStatus) {
-        switch (nrStatus) {
-            case NR_STATUS_RESTRICTED:
+    private static String nrStateToString(@NRState int nrState) {
+        switch (nrState) {
+            case NR_STATE_RESTRICTED:
                 return "RESTRICTED";
-            case NR_STATUS_NOT_RESTRICTED:
+            case NR_STATE_NOT_RESTRICTED:
                 return "NOT_RESTRICTED";
-            case NR_STATUS_CONNECTED:
+            case NR_STATE_CONNECTED:
                 return "CONNECTED";
             default:
                 return "NONE";
@@ -441,28 +464,27 @@
                 .append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
                 .append(" transportType=").append(
                         AccessNetworkConstants.transportTypeToString(mTransportType))
-                .append(" regState=").append(regStateToString(mRegState))
+                .append(" registrationState=").append(registrationStateToString(mRegistrationState))
                 .append(" roamingType=").append(ServiceState.roamingTypeToString(mRoamingType))
                 .append(" accessNetworkTechnology=")
                 .append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
                 .append(" rejectCause=").append(mRejectCause)
                 .append(" emergencyEnabled=").append(mEmergencyOnly)
                 .append(" availableServices=").append("[" + (mAvailableServices != null
-                        ? Arrays.stream(mAvailableServices)
-                        .mapToObj(type -> serviceTypeToString(type))
+                        ? mAvailableServices.stream().map(type -> serviceTypeToString(type))
                         .collect(Collectors.joining(",")) : null) + "]")
                 .append(" cellIdentity=").append(mCellIdentity)
                 .append(" voiceSpecificStates=").append(mVoiceSpecificStates)
                 .append(" dataSpecificStates=").append(mDataSpecificStates)
-                .append(" nrStatus=").append(nrStatusToString(mNrStatus))
+                .append(" nrState=").append(nrStateToString(mNrState))
                 .append("}").toString();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mDomain, mTransportType, mRegState, mRoamingType,
+        return Objects.hash(mDomain, mTransportType, mRegistrationState, mRoamingType,
                 mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
-                mCellIdentity, mVoiceSpecificStates, mDataSpecificStates, mNrStatus);
+                mCellIdentity, mVoiceSpecificStates, mDataSpecificStates, mNrState);
     }
 
     @Override
@@ -476,37 +498,37 @@
         NetworkRegistrationInfo other = (NetworkRegistrationInfo) o;
         return mDomain == other.mDomain
                 && mTransportType == other.mTransportType
-                && mRegState == other.mRegState
+                && mRegistrationState == other.mRegistrationState
                 && mRoamingType == other.mRoamingType
                 && mAccessNetworkTechnology == other.mAccessNetworkTechnology
                 && mRejectCause == other.mRejectCause
                 && mEmergencyOnly == other.mEmergencyOnly
-                && Arrays.equals(mAvailableServices, other.mAvailableServices)
+                && mAvailableServices.equals(other.mAvailableServices)
                 && Objects.equals(mCellIdentity, other.mCellIdentity)
                 && Objects.equals(mVoiceSpecificStates, other.mVoiceSpecificStates)
                 && Objects.equals(mDataSpecificStates, other.mDataSpecificStates)
-                && mNrStatus == other.mNrStatus;
+                && mNrState == other.mNrState;
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mDomain);
         dest.writeInt(mTransportType);
-        dest.writeInt(mRegState);
+        dest.writeInt(mRegistrationState);
         dest.writeInt(mRoamingType);
         dest.writeInt(mAccessNetworkTechnology);
         dest.writeInt(mRejectCause);
         dest.writeBoolean(mEmergencyOnly);
-        dest.writeIntArray(mAvailableServices);
+        dest.writeList(mAvailableServices);
         dest.writeParcelable(mCellIdentity, 0);
         dest.writeParcelable(mVoiceSpecificStates, 0);
         dest.writeParcelable(mDataSpecificStates, 0);
-        dest.writeInt(mNrStatus);
+        dest.writeInt(mNrState);
     }
 
     /**
      * Use the 5G NR Non-Standalone indicators from the network registration state to update the
-     * NR status. There are 3 indicators in the network registration state:
+     * NR state. There are 3 indicators in the network registration state:
      *
      * 1. if E-UTRA-NR Dual Connectivity (EN-DC) is supported by the primary serving cell.
      * 2. if NR is supported by the selected PLMN.
@@ -521,13 +543,13 @@
      *
      * @param state data specific registration state contains the 5G NR indicators.
      */
-    private void updateNrStatus(DataSpecificRegistrationStates state) {
-        mNrStatus = NR_STATUS_NONE;
+    private void updateNrState(DataSpecificRegistrationStates state) {
+        mNrState = NR_STATE_NONE;
         if (state.isEnDcAvailable) {
             if (!state.isDcNrRestricted && state.isNrAvailable) {
-                mNrStatus = NR_STATUS_NOT_RESTRICTED;
+                mNrState = NR_STATE_NOT_RESTRICTED;
             } else {
-                mNrStatus = NR_STATUS_RESTRICTED;
+                mNrState = NR_STATE_RESTRICTED;
             }
         }
     }
@@ -571,40 +593,31 @@
      *
      * <pre><code>
      *
-     * NetworkRegistrationInfo nrs = new NetworkRegistrationInfo.Builder()
-     *     .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS)
-     *     .setApnName("apn.example.com")
-     *     .setEntryName("Example Carrier APN")
-     *     .setMmsc(Uri.parse("http://mms.example.com:8002"))
-     *     .setMmsProxyAddress(mmsProxy)
-     *     .setMmsProxyPort(8799)
+     * NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+     *     .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+     *     .setRegistrationState(REGISTRATION_STATE_HOME)
      *     .build();
      * </code></pre>
      */
-    public static class Builder{
+    public static final class Builder{
         @Domain
         private int mDomain;
 
+        @TransportType
         private int mTransportType;
 
-        @RegState
-        private int mRegState;
-
-        @ServiceState.RoamingType
-        private int mRoamingType;
+        @RegistrationState
+        private int mRegistrationState;
 
         @NetworkType
         private int mAccessNetworkTechnology;
 
-        @NRStatus
-        private int mNrStatus;
-
         private int mRejectCause;
 
         private boolean mEmergencyOnly;
 
         @ServiceType
-        private int[] mAvailableServices;
+        private List<Integer> mAvailableServices;
 
         @Nullable
         private CellIdentity mCellIdentity;
@@ -641,24 +654,12 @@
         /**
          * Set the registration state.
          *
-         * @param regState The registration state.
+         * @param registrationState The registration state.
          *
          * @return The same instance of the builder.
          */
-        public @NonNull Builder setRegState(@RegState int regState) {
-            mRegState = regState;
-            return this;
-        }
-
-        /**
-         * Set the roaming type.
-         *
-         * @param roamingType Roaming type.
-         *
-         * @return The same instance of the builder.
-         */
-        public @NonNull Builder setRoamingType(@ServiceState.RoamingType int roamingType) {
-            mRoamingType = roamingType;
+        public @NonNull Builder setRegistrationState(@RegistrationState int registrationState) {
+            mRegistrationState = registrationState;
             return this;
         }
 
@@ -676,24 +677,13 @@
         }
 
         /**
-         * Set the 5G NR connection status.
-         *
-         * @param nrStatus 5G NR connection status.
-         *
-         * @return The same instance of the builder.
-         */
-        public @NonNull Builder setNrStatus(@NRStatus int nrStatus) {
-            mNrStatus = nrStatus;
-            return this;
-        }
-
-        /**
          * Set the network reject cause.
          *
          * @param rejectCause Reason for denial if the registration state is
-         * {@link #REG_STATE_DENIED}.Depending on {@code accessNetworkTechnology}, the values are
-         * defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2
-         * A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set it to 0.
+         * {@link #REGISTRATION_STATE_DENIED}.Depending on {@code accessNetworkTechnology}, the
+         * values are defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE,
+         * and 3GPP2 A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set
+         * it to 0.
          *
          * @return The same instance of the builder.
          */
@@ -722,7 +712,7 @@
          * @return The same instance of the builder.
          */
         public @NonNull Builder setAvailableServices(
-                @NonNull @ServiceType int[] availableServices) {
+                @NonNull @ServiceType List<Integer> availableServices) {
             mAvailableServices = availableServices;
             return this;
         }
@@ -745,7 +735,7 @@
          * @return the NetworkRegistrationInfo object.
          */
         public @NonNull NetworkRegistrationInfo build() {
-            return new NetworkRegistrationInfo(mDomain, mTransportType, mRegState,
+            return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState,
                     mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
                     mCellIdentity);
         }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index adbe295..30dcaa0 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -30,7 +30,7 @@
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.NetworkRegistrationInfo.Domain;
-import android.telephony.NetworkRegistrationInfo.NRStatus;
+import android.telephony.NetworkRegistrationInfo.NRState;
 import android.text.TextUtils;
 
 import java.lang.annotation.Retention;
@@ -53,6 +53,9 @@
  *   <li>Operator name, short name and numeric id
  *   <li>Network selection mode
  * </ul>
+ *
+ * For historical reasons this class is not declared as final; however,
+ * it should be treated as though it were final.
  */
 public class ServiceState implements Parcelable {
 
@@ -647,7 +650,8 @@
         final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState != null) {
-            return (regState.getRegState() == NetworkRegistrationInfo.REG_STATE_ROAMING);
+            return regState.getRegistrationState()
+                    == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
         }
         return false;
     }
@@ -1133,10 +1137,10 @@
         NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState == null) {
-            regState = new NetworkRegistrationInfo(
-                    NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                    ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
-                    false, null, null);
+            regState = new NetworkRegistrationInfo.Builder()
+                    .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+                    .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                    .build();
             addNetworkRegistrationInfo(regState);
         }
         regState.setRoamingType(type);
@@ -1154,10 +1158,10 @@
         NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState == null) {
-            regState = new NetworkRegistrationInfo(
-                    NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                    ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
-                    false, null, null);
+            regState = new NetworkRegistrationInfo.Builder()
+                    .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                    .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                    .build();
             addNetworkRegistrationInfo(regState);
         }
         regState.setRoamingType(type);
@@ -1329,10 +1333,10 @@
         NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState == null) {
-            regState = new NetworkRegistrationInfo(
-                    NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                    ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                    0, false, null, null);
+            regState = new NetworkRegistrationInfo.Builder()
+                    .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+                    .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                    .build();
             addNetworkRegistrationInfo(regState);
         }
         regState.setAccessNetworkTechnology(
@@ -1357,10 +1361,10 @@
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         if (regState == null) {
-            regState = new NetworkRegistrationInfo(
-                    NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                    ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                    0, false, null, null);
+            regState = new NetworkRegistrationInfo.Builder()
+                    .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                    .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                    .build();
             addNetworkRegistrationInfo(regState);
         }
         regState.setAccessNetworkTechnology(
@@ -1386,15 +1390,15 @@
     }
 
     /**
-     * Get the NR 5G status of the mobile data network.
-     * @return the NR 5G status.
+     * Get the NR 5G state of the mobile data network.
+     * @return the NR 5G state.
      * @hide
      */
-    public @NRStatus int getNrStatus() {
+    public @NRState int getNrState() {
         final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-        if (regState == null) return NetworkRegistrationInfo.NR_STATUS_NONE;
-        return regState.getNrStatus();
+        if (regState == null) return NetworkRegistrationInfo.NR_STATE_NONE;
+        return regState.getNrState();
     }
 
     /**
@@ -1578,8 +1582,8 @@
     public @TelephonyManager.NetworkType int getDataNetworkType() {
         final NetworkRegistrationInfo iwlanRegState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
-        if (iwlanRegState != null
-                && iwlanRegState.getRegState() == NetworkRegistrationInfo.REG_STATE_HOME) {
+        if (iwlanRegState != null && iwlanRegState.getRegistrationState()
+                == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) {
             // If the device is on IWLAN, return IWLAN as the network type. This is to simulate the
             // behavior of legacy mode device. In the future caller should use
             // getNetworkRegistrationInfo() to retrieve the actual data network type on cellular
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 245f5b3..ac11940 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -161,11 +161,6 @@
     private String mGroupUUID;
 
     /**
-     *  A property in opportunistic subscription to indicate whether it is metered or not.
-     */
-    private boolean mIsMetered;
-
-    /**
      * Whether group of the subscription is disabled.
      * This is only useful if it's a grouped opportunistic subscription. In this case, if all
      * primary (non-opportunistic) subscriptions in the group are deactivated (unplugged pSIM
@@ -197,7 +192,7 @@
             @Nullable UiccAccessRule[] accessRules, String cardString) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString,
-                false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID,
+                false, null, TelephonyManager.UNKNOWN_CARRIER_ID,
                 SubscriptionManager.PROFILE_CLASS_DEFAULT);
     }
 
@@ -208,10 +203,10 @@
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
             @Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic,
-            @Nullable String groupUUID, boolean isMetered, int carrierId, int profileClass) {
+            @Nullable String groupUUID, int carrierId, int profileClass) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
-                isOpportunistic, groupUUID, isMetered, false, carrierId, profileClass,
+                isOpportunistic, groupUUID, false, carrierId, profileClass,
                 SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
     }
 
@@ -222,7 +217,7 @@
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
             @Nullable UiccAccessRule[] accessRules, String cardString, int cardId,
-            boolean isOpportunistic, @Nullable String groupUUID, boolean isMetered,
+            boolean isOpportunistic, @Nullable String groupUUID,
             boolean isGroupDisabled, int carrierId, int profileClass, int subType) {
         this.mId = id;
         this.mIccId = iccId;
@@ -243,7 +238,6 @@
         this.mCardId = cardId;
         this.mIsOpportunistic = isOpportunistic;
         this.mGroupUUID = groupUUID;
-        this.mIsMetered = isMetered;
         this.mIsGroupDisabled = isGroupDisabled;
         this.mCarrierId = carrierId;
         this.mProfileClass = profileClass;
@@ -472,18 +466,6 @@
     }
 
     /**
-     * Used in opportunistic subscription ({@link #isOpportunistic()}) to indicate whether it's
-     * metered or not.This is one of the factors when deciding to switch to the subscription.
-     * (a non-metered subscription, for example, would likely be preferred over a metered one).
-     *
-     * @return whether subscription is metered.
-     * @hide
-     */
-    public boolean isMetered() {
-        return mIsMetered;
-    }
-
-    /**
      * @return the profile class of this subscription.
      * @hide
      */
@@ -624,7 +606,6 @@
             int cardId = source.readInt();
             boolean isOpportunistic = source.readBoolean();
             String groupUUID = source.readString();
-            boolean isMetered = source.readBoolean();
             boolean isGroupDisabled = source.readBoolean();
             int carrierid = source.readInt();
             int profileClass = source.readInt();
@@ -633,7 +614,7 @@
             return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
                     nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
                     isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID,
-                    isMetered, isGroupDisabled, carrierid, profileClass, subType);
+                    isGroupDisabled, carrierid, profileClass, subType);
         }
 
         @Override
@@ -663,7 +644,6 @@
         dest.writeInt(mCardId);
         dest.writeBoolean(mIsOpportunistic);
         dest.writeString(mGroupUUID);
-        dest.writeBoolean(mIsMetered);
         dest.writeBoolean(mIsGroupDisabled);
         dest.writeInt(mCarrierId);
         dest.writeInt(mProfileClass);
@@ -703,7 +683,7 @@
                 + " accessRules " + Arrays.toString(mAccessRules)
                 + " cardString=" + cardStringToPrint + " cardId=" + mCardId
                 + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
-                + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled
+                + " mIsGroupDisabled=" + mIsGroupDisabled
                 + " profileClass=" + mProfileClass
                 + " subscriptionType=" + mSubscriptionType + "}";
     }
@@ -711,7 +691,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
-                mIsOpportunistic, mGroupUUID, mIsMetered, mIccId, mNumber, mMcc, mMnc,
+                mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc,
                 mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules,
                 mIsGroupDisabled, mCarrierId, mProfileClass);
     }
@@ -737,7 +717,6 @@
                 && mIsOpportunistic == toCompare.mIsOpportunistic
                 && mIsGroupDisabled == toCompare.mIsGroupDisabled
                 && mCarrierId == toCompare.mCarrierId
-                && mIsMetered == toCompare.mIsMetered
                 && Objects.equals(mGroupUUID, toCompare.mGroupUUID)
                 && Objects.equals(mIccId, toCompare.mIccId)
                 && Objects.equals(mNumber, toCompare.mNumber)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 3707aa4..2edef83 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2595,7 +2595,9 @@
      *              {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means
      *              it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()}
      *              is used to determine which modem is preferred.
-     * @param needValidation whether validation is needed before switch happens.
+     * @param needValidation whether Telephony will wait until the network is validated by
+     *              connectivity service before switching data to it. More details see
+     *              {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}.
      * @param executor The executor of where the callback will execute.
      * @param callback Callback will be triggered once it succeeds or failed.
      *                 See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
@@ -2853,29 +2855,6 @@
     }
 
     /**
-     * Set if a subscription is metered or not. Similar to Wi-Fi, metered means
-     * user may be charged more if more data is used.
-     *
-     * By default all Cellular networks are considered metered. System or carrier privileged apps
-     * can set a subscription un-metered which will be considered when system switches data between
-     * primary subscription and opportunistic subscription.
-     *
-     * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
-     * privilege permission of the subscription.
-     *
-     * @param isMetered whether it’s a metered subscription.
-     * @param subId the unique SubscriptionInfo index in database
-     * @return {@code true} if the operation is succeed, {@code false} otherwise.
-     */
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public boolean setMetered(boolean isMetered, int subId) {
-        if (VDBG) logd("[setIsMetered]+ isMetered:" + isMetered + " subId:" + subId);
-        return setSubscriptionPropertyHelper(subId, "setIsMetered",
-                (iSub)-> iSub.setMetered(isMetered, subId, mContext.getOpPackageName())) == 1;
-    }
-
-    /**
      * Whether a subscription is visible to API caller. If it's a bundled opportunistic
      * subscription, it should be hidden anywhere in Settings, dialer, status bar etc.
      * Exception is if caller owns carrier privilege, in which case they will
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 66ef531..282b1ff 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4779,18 +4779,22 @@
      * Registers a listener object to receive notification of changes
      * in specified telephony states.
      * <p>
-     * To register a listener, pass a {@link PhoneStateListener}
-     * and specify at least one telephony state of interest in
-     * the events argument.
+     * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony
+     * state of interest in the events argument.
      *
-     * At registration, and when a specified telephony state
-     * changes, the telephony manager invokes the appropriate
-     * callback method on the listener object and passes the
-     * current (updated) values.
+     * At registration, and when a specified telephony state changes, the telephony manager invokes
+     * the appropriate callback method on the listener object and passes the current (updated)
+     * values.
      * <p>
-     * To unregister a listener, pass the listener object and set the
-     * events argument to
+     * To un-register a listener, pass the listener object and set the events argument to
      * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
+     *
+     * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+     * applies to the given subId. Otherwise, applies to
+     * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
+     * pass a separate listener object to each TelephonyManager object created with
+     * {@link #createForSubscriptionId}.
+     *
      * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
      * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
      * {@link SecurityException} will be thrown otherwise.
@@ -4805,17 +4809,18 @@
         if (mContext == null) return;
         try {
             boolean notifyNow = (getITelephony() != null);
-            // If the listener has not explicitly set the subId (for example, created with the
-            // default constructor), replace the subId so it will listen to the account the
-            // telephony manager is created with.
-            if (listener.mSubId == null) {
-                listener.mSubId = mSubId;
-            }
-
             ITelephonyRegistry registry = getTelephonyRegistry();
             if (registry != null) {
-                registry.listenForSubscriber(listener.mSubId, getOpPackageName(),
+                // listen to the subId the telephony manager is created with. Ignore subId in
+                // PhoneStateListener.
+                registry.listenForSubscriber(mSubId, getOpPackageName(),
                         listener.callback, events, notifyNow);
+                // TODO: remove this once we remove PhoneStateListener constructor with subId.
+                if (events == PhoneStateListener.LISTEN_NONE) {
+                    listener.mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                } else {
+                    listener.mSubId = mSubId;
+                }
             } else {
                 Rlog.w(TAG, "telephony registry not ready.");
             }
@@ -8293,7 +8298,7 @@
      * @see SubscriptionManager#getDefaultSubscriptionId()
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     public boolean isVolteAvailable() {
         try {
             return getITelephony().isAvailable(getSubId(),
@@ -8312,7 +8317,7 @@
      * @return true if VT is available, or false if it is unavailable or unknown.
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     public boolean isVideoTelephonyAvailable() {
         try {
             return getITelephony().isVideoTelephonyAvailable(getSubId());
@@ -8327,7 +8332,7 @@
      * @return true if VoWiFi is available, or false if it is unavailable or unknown.
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     public boolean isWifiCallingAvailable() {
        try {
            return getITelephony().isWifiCallingAvailable(getSubId());
@@ -9865,8 +9870,11 @@
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
      *
+     *
+     * @deprecated
      * @hide
      */
+    @Deprecated
     @TestApi
     public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
             String gid2, String plmn, String spn) {
@@ -9874,7 +9882,35 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 telephony.setCarrierTestOverride(
-                        getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn);
+                        getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn,
+                        null, null);
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+    }
+
+    /**
+     * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
+     * plmn, spn, apn and carrier priviledge. This would be handy for, eg, forcing a particular
+     * carrier id, carrier's config (also any country or carrier overlays) to be loaded when using
+     * a test SIM with a call box.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     *
+     * @hide
+     */
+    @TestApi
+    public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
+                                       String gid2, String plmn, String spn,
+                                       String carrierPriviledgeRules, String apn) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.setCarrierTestOverride(
+                        getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn,
+                        carrierPriviledgeRules, apn);
             }
         } catch (RemoteException ex) {
             // This could happen if binder process crashes.
@@ -10337,7 +10373,7 @@
     @IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = {
             SET_OPPORTUNISTIC_SUB_SUCCESS,
             SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED,
-            SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER})
+            SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION})
     public @interface SetOpportunisticSubscriptionResult {}
 
     /**
@@ -10351,9 +10387,9 @@
     public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1;
 
     /**
-     * The parameter passed in is invalid.
+     * The subscription is not valid. It must be an active opportunistic subscription.
      */
-    public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2;
+    public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index e651783..875bd78 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -285,6 +285,8 @@
      * {@link #ACTION_DELETE_SUBSCRIPTION_PRIVILEGED}, and
      * {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing the ID of the targeted subscription.
      *
+     * <p>Expected type of the extra data: int
+     *
      * @hide
      */
     @SystemApi
@@ -295,6 +297,8 @@
      * Key for an extra set on {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} providing a boolean
      * value of whether to enable or disable the targeted subscription.
      *
+     * <p>Expected type of the extra data: boolean
+     *
      * @hide
      */
     @SystemApi
@@ -305,6 +309,8 @@
      * Key for an extra set on {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing a new
      * nickname for the targeted subscription.
      *
+     * <p>Expected type of the extra data: String
+     *
      * @hide
      */
     @SystemApi
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 79e0aa1..3bbf7a4 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -205,15 +205,6 @@
     String setSubscriptionGroup(in int[] subIdList, String callingPackage);
 
     /**
-     * Set whether a subscription is metered
-     *
-     * @param isMetered whether it’s a metered subscription.
-     * @param subId the unique SubscriptionInfo index in database
-     * @return the number of records updated
-     */
-    int setMetered(boolean isMetered, int subId, String callingPackage);
-
-    /**
      * Set which subscription is preferred for cellular data. It's
      * designed to overwrite default data subscription temporarily.
      *
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 62b92fd..c2c31cc 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1683,7 +1683,7 @@
      * (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
      */
     void setCarrierTestOverride(int subId, String mccmnc, String imsi, String iccid, String gid1,
-            String gid2, String plmn, String spn);
+            String gid2, String plmn, String spn, String carrierPrivilegeRules, String apn);
 
     /**
      * A test API to return installed carrier id list version.
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 9d78bf4..4886a3f 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -317,7 +317,8 @@
                 Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED, 0) == 1;
         ApplicationInfo callingPackageInfo = null;
         try {
-            callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0);
+            callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
+                    callingPackage, 0, UserHandle.getUserId(uid));
             if (callingPackageInfo.isSystemApp()) {
                 isPreinstalled = true;
                 if (callingPackageInfo.isPrivilegedApp()) {
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index b31235b..41cb74a 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -4,7 +4,7 @@
  -->
 <configuration description="Runs WindowManager Flicker Tests">
     <option name="test-tag" value="FlickerTests" />
-    <target_preparer class="com.google.android.tradefed.targetprep.GoogleDeviceSetup">
+    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
         <!-- keeps the screen on during tests -->
         <option name="screen-always-on" value="on" />
         <!-- prevents the phone from restarting -->
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 7505230..377abc3 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -87,7 +87,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             // Register a broadcast receiver for notification when the
             // rollback has been committed.
@@ -175,7 +175,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
@@ -233,7 +233,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
@@ -290,7 +290,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
@@ -343,11 +343,11 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS,
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS,
                     Manifest.permission.WRITE_DEVICE_CONFIG);
 
-            DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
-                    DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+                    RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                     Long.toString(expirationTime), false /* makeDefault*/);
 
             // Pull the new expiration time from DeviceConfig
@@ -382,8 +382,8 @@
             assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
 
         } finally {
-            DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
-                    DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+                    RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                     Long.toString(defaultExpirationTime), false /* makeDefault*/);
             RollbackTestUtils.dropShellPermissionIdentity();
         }
@@ -403,12 +403,12 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS,
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS,
                     Manifest.permission.WRITE_DEVICE_CONFIG,
                     Manifest.permission.SET_TIME);
 
-            DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
-                    DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+                    RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                     Long.toString(expirationTime), false /* makeDefault*/);
 
             // Pull the new expiration time from DeviceConfig
@@ -458,8 +458,8 @@
                 RollbackTestUtils.forwardTimeBy(-expirationTime);
             }
         } finally {
-            DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
-                    DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+                    RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                     Long.toString(defaultExpirationTime), false /* makeDefault*/);
             RollbackTestUtils.dropShellPermissionIdentity();
         }
@@ -475,7 +475,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
             RollbackTestUtils.uninstall(TEST_APP_A);
@@ -512,7 +512,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackTestUtils.uninstall(TEST_APP_A);
             RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
@@ -540,7 +540,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackTestUtils.uninstall(TEST_APP_A);
             RollbackTestUtils.installSplit(false,
@@ -598,7 +598,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
             // Prep installation of the test apps.
@@ -693,6 +693,75 @@
     }
 
     /**
+     * Test that you cannot enable rollback for a package without the
+     * MANAGE_ROLLBACKS permission.
+     */
+    @Test
+    public void testEnableRollbackPermission() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES);
+
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+
+            // We expect v2 of the app was installed, but rollback has not
+            // been enabled.
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // would be made available.
+            Thread.sleep(1000);
+
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
+     * Test that you cannot enable rollback for a non-module package when
+     * holding the MANAGE_ROLLBACKS permission.
+     */
+    @Test
+    public void testNonModuleEnableRollback() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
+
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+
+            // We expect v2 of the app was installed, but rollback has not
+            // been enabled because the test app is not a module.
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // would be made available.
+            Thread.sleep(1000);
+
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
      * Test rollback of multi-package installs is implemented.
      */
     @Test
@@ -701,7 +770,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
             // Prep installation of the test apps.
@@ -760,7 +829,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS,
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS,
                     Manifest.permission.KILL_BACKGROUND_PROCESSES,
                     Manifest.permission.RESTART_PACKAGES);
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
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 047451b..7e711c2 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -63,7 +63,7 @@
         RollbackTestUtils.adoptShellPermissionIdentity(
                 Manifest.permission.INSTALL_PACKAGES,
                 Manifest.permission.DELETE_PACKAGES,
-                Manifest.permission.MANAGE_ROLLBACKS);
+                Manifest.permission.TEST_MANAGE_ROLLBACKS);
     }
 
     /**
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 2539c0f..c62d85e 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -13,7 +13,6 @@
         "mockito-target-minus-junit4",
         "platform-test-annotations",
         "services.core",
-        "services.ipmemorystore",
         "services.net",
     ],
     libs: [
diff --git a/tests/net/java/android/net/DnsPacketTest.java b/tests/net/java/android/net/DnsPacketTest.java
index 9ede2b8..975abf4 100644
--- a/tests/net/java/android/net/DnsPacketTest.java
+++ b/tests/net/java/android/net/DnsPacketTest.java
@@ -69,7 +69,7 @@
         try {
             new TestDnsPacket(null);
             fail("Exception not thrown for null byte array");
-        } catch (DnsPacket.ParseException e) {
+        } catch (ParseException e) {
         }
     }
 
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
index 57ecc8f..18c6768 100644
--- a/tests/net/java/android/net/IpMemoryStoreTest.java
+++ b/tests/net/java/android/net/IpMemoryStoreTest.java
@@ -16,6 +16,9 @@
 
 package android.net;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+
 import android.content.Context;
 
 import androidx.test.filters.SmallTest;
@@ -33,13 +36,25 @@
     @Mock
     Context mMockContext;
     @Mock
+    NetworkStackClient mNetworkStackClient;
+    @Mock
     IIpMemoryStore mMockService;
     IpMemoryStore mStore;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mStore = new IpMemoryStore(mMockContext, mMockService);
+        doAnswer(invocation -> {
+            ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
+                    .onIpMemoryStoreFetched(mMockService);
+            return null;
+        }).when(mNetworkStackClient).fetchIpMemoryStore(any());
+        mStore = new IpMemoryStore(mMockContext) {
+            @Override
+            protected NetworkStackClient getNetworkStackClient() {
+                return mNetworkStackClient;
+            }
+        };
     }
 
     @Test
diff --git a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/java/android/net/apf/ApfCapabilitiesTest.java
new file mode 100644
index 0000000..75752c3
--- /dev/null
+++ b/tests/net/java/android/net/apf/ApfCapabilitiesTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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 android.net.apf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.shared.ParcelableTestUtil;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.TestUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ApfCapabilitiesTest {
+    @Test
+    public void testParcelUnparcel() {
+        final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
+        ParcelableTestUtil.assertFieldCountEquals(3, ApfCapabilities.class);
+
+        TestUtils.assertParcelingIsLossless(caps, ApfCapabilities.CREATOR);
+    }
+
+    @Test
+    public void testEquals() {
+        assertEquals(new ApfCapabilities(1, 2, 3), new ApfCapabilities(1, 2, 3));
+        assertNotEquals(new ApfCapabilities(2, 2, 3), new ApfCapabilities(1, 2, 3));
+        assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3));
+        assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3));
+    }
+}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 830c928..9b4f49c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -101,6 +101,7 @@
     @After
     public void tearDown() throws Exception {
         RecurrenceRule.sClock = sOriginalClock;
+        NetworkTemplate.resetForceAllNetworkTypes();
     }
 
     private void setClock(Instant instant) {
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 598448b..bce526d 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -19,6 +19,7 @@
 import static android.content.Intent.ACTION_UID_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -41,6 +42,7 @@
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UID_REMOVED;
@@ -132,6 +134,8 @@
 
     private static final String TEST_IFACE = "test0";
     private static final String TEST_IFACE2 = "test1";
+    private static final String TUN_IFACE = "test_nss_tun0";
+
     private static final long TEST_START = 1194220800000L;
 
     private static final String IMSI_1 = "310004";
@@ -145,10 +149,12 @@
     private static final int UID_RED = 1001;
     private static final int UID_BLUE = 1002;
     private static final int UID_GREEN = 1003;
-
+    private static final int UID_VPN = 1004;
 
     private static final Network WIFI_NETWORK =  new Network(100);
     private static final Network MOBILE_NETWORK =  new Network(101);
+    private static final Network VPN_NETWORK = new Network(102);
+
     private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK };
     private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK };
 
@@ -914,7 +920,113 @@
         assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
         assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
         assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0);
+    }
 
+    @Test
+    public void vpnWithOneUnderlyingIface() throws Exception {
+        // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+        expectDefaultSettings();
+        NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
+        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces(
+                new Network[] {WIFI_NETWORK, VPN_NETWORK},
+                vpnInfos,
+                networkStates,
+                getActiveIface(networkStates));
+        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+        // overhead per packet):
+        // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+        // 500 bytes (50 packets) were sent/received by UID_BLUE over VPN.
+        // VPN sent/received 1650 bytes (150 packets) over WiFi.
+        // Of 1650 bytes over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes attributed to
+        // UID_BLUE, and 150 bytes attributed to UID_VPN for both rx/tx traffic.
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+                .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+                .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L)
+                .addValues(
+                    TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 1650L, 150L, 2L));
+
+        forcePollAndWaitForIdle();
+
+        assertUidTotal(sTemplateWifi, UID_RED, 1000L, 100L, 1000L, 100L, 1);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1);
+        assertUidTotal(sTemplateWifi, UID_VPN, 150L, 0L, 150L, 0L, 2);
+    }
+
+    @Test
+    public void vpnWithOneUnderlyingIface_withCompression() throws Exception {
+        // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+        expectDefaultSettings();
+        NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
+        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces(
+                new Network[] {WIFI_NETWORK, VPN_NETWORK},
+                vpnInfos,
+                networkStates,
+                getActiveIface(networkStates));
+        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+        // overhead per packet):
+        // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+        // 3000 bytes (300 packets) were sent/received by UID_BLUE over VPN.
+        // VPN sent/received 1000 bytes (100 packets) over WiFi.
+        // Of 1000 bytes over WiFi, expect 250 bytes attributed UID_RED and 750 bytes to UID_BLUE,
+        // with nothing attributed to UID_VPN for both rx/tx traffic.
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+                .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+                .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 3000L, 300L, 3000L, 300L, 1L)
+                .addValues(
+                    TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 0L));
+
+        forcePollAndWaitForIdle();
+
+        assertUidTotal(sTemplateWifi, UID_RED, 250L, 25L, 250L, 25L, 0);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 750L, 75L, 750L, 75L, 0);
+        assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
+    }
+
+    @Test
+    public void vpnWithIncorrectUnderlyingIface() throws Exception {
+        // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
+        // but has declared only WiFi (TEST_IFACE) in its underlying network set.
+        expectDefaultSettings();
+        NetworkState[] networkStates =
+                new NetworkState[] {
+                    buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState()
+                };
+        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces(
+                new Network[] {WIFI_NETWORK, VPN_NETWORK},
+                vpnInfos,
+                networkStates,
+                getActiveIface(networkStates));
+        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+        // overhead per packet):
+        // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+        // VPN sent/received 1100 bytes (100 packets) over Cell.
+        // Of 1100 bytes over Cell, expect all of it attributed to UID_VPN for both rx/tx traffic.
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
+                .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+                .addValues(
+                    TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 1100L, 100L, 1L));
+
+        forcePollAndWaitForIdle();
+
+        assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L, 0L, 0L, 0);
+        assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
+        assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 0L, 0L, 0L, 0L, 0);
+        assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1100L, 100L, 1100L, 100L, 1);
     }
 
     @Test
@@ -1262,6 +1374,22 @@
         return new NetworkStats(getElapsedRealtime(), 0);
     }
 
+    private static NetworkState buildVpnState() {
+        final NetworkInfo info = new NetworkInfo(TYPE_VPN, 0, null, null);
+        info.setDetailedState(DetailedState.CONNECTED, null, null);
+        final LinkProperties prop = new LinkProperties();
+        prop.setInterfaceName(TUN_IFACE);
+        return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null);
+    }
+
+    private static VpnInfo createVpnInfo(String underlyingIface) {
+        VpnInfo info = new VpnInfo();
+        info.ownerUid = UID_VPN;
+        info.vpnIface = TUN_IFACE;
+        info.primaryUnderlyingIface = underlyingIface;
+        return info;
+    }
+
     private long getElapsedRealtime() {
         return mElapsedRealtime;
     }
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index 5cf056e..7ded9bc 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -32,6 +32,7 @@
  public:
   explicit DumpApkCommand(const std::string&& name, text::Printer* printer, IDiagnostics* diag)
       : Command(name), printer_(printer), diag_(diag) {
+        SetDescription("Dump information about an APK or APC.");
   }
 
   text::Printer* GetPrinter() {
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
index 2042a68..7f5f9ca 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
@@ -635,14 +635,14 @@
             final String name = mAnnotationUtils.typedValueByName(
                     "name", String.class, accessor, enumAnnotation)
                     .orElseThrow(() -> new ProcessingException(
-                            "Name is required for @EnumMap",
+                            "Name is required for @EnumEntry",
                             accessor,
                             enumAnnotation));
 
             final int value = mAnnotationUtils.typedValueByName(
                     "value", Integer.class, accessor, enumAnnotation)
                     .orElseThrow(() -> new ProcessingException(
-                            "Value is required for @EnumMap",
+                            "Value is required for @EnumEntry",
                             accessor,
                             enumAnnotation));
 
@@ -684,14 +684,14 @@
             final String name = mAnnotationUtils.typedValueByName(
                     "name", String.class, accessor, flagAnnotation)
                     .orElseThrow(() -> new ProcessingException(
-                            "Name is required for @FlagMap",
+                            "Name is required for @FlagEntry",
                             accessor,
                             flagAnnotation));
 
             final int target = mAnnotationUtils.typedValueByName(
                     "target", Integer.class, accessor, flagAnnotation)
                     .orElseThrow(() -> new ProcessingException(
-                            "Target is required for @FlagMap",
+                            "Target is required for @FlagEntry",
                             accessor,
                             flagAnnotation));
 
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
index 51aa93a..01176f2 100644
--- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.TelephonyManager.NetworkType;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -98,6 +99,10 @@
     private final int mProbeMcsRateSinceLastUpdate;
     /** Rx link speed at the sample time in Mbps */
     private final int mRxLinkSpeedMbps;
+    private final @NetworkType int mCellularDataNetworkType;
+    private final int mCellularSignalStrengthDbm;
+    private final int mCellularSignalStrengthDb;
+    private final boolean mIsSameRegisteredCell;
 
     /** Constructor function {@hide} */
     public WifiUsabilityStatsEntry(long timeStampMillis, int rssi, int linkSpeedMbps,
@@ -109,7 +114,10 @@
             long totalHotspot2ScanTimeMillis,
             long totalCcaBusyFreqTimeMillis, long totalRadioOnFreqTimeMillis, long totalBeaconRx,
             @ProbeStatus int probeStatusSinceLastUpdate, int probeElapsedTimeSinceLastUpdateMillis,
-            int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps) {
+            int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps,
+            @NetworkType int cellularDataNetworkType,
+            int cellularSignalStrengthDbm, int cellularSignalStrengthDb,
+            boolean isSameRegisteredCell) {
         mTimeStampMillis = timeStampMillis;
         mRssi = rssi;
         mLinkSpeedMbps = linkSpeedMbps;
@@ -133,6 +141,10 @@
         mProbeElapsedTimeSinceLastUpdateMillis = probeElapsedTimeSinceLastUpdateMillis;
         mProbeMcsRateSinceLastUpdate = probeMcsRateSinceLastUpdate;
         mRxLinkSpeedMbps = rxLinkSpeedMbps;
+        mCellularDataNetworkType = cellularDataNetworkType;
+        mCellularSignalStrengthDbm = cellularSignalStrengthDbm;
+        mCellularSignalStrengthDb = cellularSignalStrengthDb;
+        mIsSameRegisteredCell = isSameRegisteredCell;
     }
 
     /** Implement the Parcelable interface */
@@ -165,6 +177,10 @@
         dest.writeInt(mProbeElapsedTimeSinceLastUpdateMillis);
         dest.writeInt(mProbeMcsRateSinceLastUpdate);
         dest.writeInt(mRxLinkSpeedMbps);
+        dest.writeInt(mCellularDataNetworkType);
+        dest.writeInt(mCellularSignalStrengthDbm);
+        dest.writeInt(mCellularSignalStrengthDb);
+        dest.writeBoolean(mIsSameRegisteredCell);
     }
 
     /** Implement the Parcelable interface */
@@ -179,7 +195,9 @@
                     in.readLong(), in.readLong(), in.readLong(),
                     in.readLong(), in.readLong(), in.readLong(),
                     in.readLong(), in.readLong(), in.readInt(),
-                    in.readInt(), in.readInt(), in.readInt()
+                    in.readInt(), in.readInt(), in.readInt(),
+                    in.readInt(), in.readInt(), in.readInt(),
+                    in.readBoolean()
             );
         }
 
@@ -304,4 +322,30 @@
     public int getRxLinkSpeedMbps() {
         return mRxLinkSpeedMbps;
     }
+
+    /** Cellular data network type currently in use on the device for data transmission */
+    @NetworkType public int getCellularDataNetworkType() {
+        return mCellularDataNetworkType;
+    }
+
+    /**
+     * Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp,
+     * CDMA: Rssi, EVDO: Rssi, GSM: Rssi
+     */
+    public int getCellularSignalStrengthDbm() {
+        return mCellularSignalStrengthDbm;
+    }
+
+    /**
+     * Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid,
+     * CDMA: Ecio, EVDO: SNR, GSM: invalid
+     */
+    public int getCellularSignalStrengthDb() {
+        return mCellularSignalStrengthDb;
+    }
+
+    /** Whether the primary registered cell of current entry is same as that of previous entry */
+    public boolean getIsSameRegisteredCell() {
+        return mIsSameRegisteredCell;
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
index 8e37113..cd60f02 100644
--- a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
@@ -74,7 +74,8 @@
 
     private static WifiUsabilityStatsEntry createResult() {
         return new WifiUsabilityStatsEntry(
-                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
+                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+                14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, true
         );
     }
 
@@ -111,5 +112,10 @@
         assertEquals(expected.getProbeMcsRateSinceLastUpdate(),
                 actual.getProbeMcsRateSinceLastUpdate());
         assertEquals(expected.getRxLinkSpeedMbps(), actual.getRxLinkSpeedMbps());
+        assertEquals(expected.getCellularDataNetworkType(), actual.getCellularDataNetworkType());
+        assertEquals(expected.getCellularSignalStrengthDbm(),
+                actual.getCellularSignalStrengthDbm());
+        assertEquals(expected.getCellularSignalStrengthDb(), actual.getCellularSignalStrengthDb());
+        assertEquals(expected.getIsSameRegisteredCell(), actual.getIsSameRegisteredCell());
     }
 }